boneIO 0.7.0dev1__py3-none-any.whl → 0.7.0dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of boneIO might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.7.0dev1
3
+ Version: 0.7.0dev2
4
4
  Summary: Python App for BoneIO
5
5
  License: GNU General Public License v3.0
6
6
  Author-email: Paweł Szafer <pszafer@gmail.com>
@@ -14,6 +14,7 @@ Requires-Dist: adafruit-circuitpython-mcp230xx>=2.5.11
14
14
  Requires-Dist: adafruit-circuitpython-mcp9808>=3.3.21
15
15
  Requires-Dist: adafruit-circuitpython-onewire>=2.0.5
16
16
  Requires-Dist: adafruit-circuitpython-pca9685>=3.4.10
17
+ Requires-Dist: adafruit-circuitpython-pcf8575>=1.0.2
17
18
  Requires-Dist: adafruit-circuitpython-pct2075>=1.1.19
18
19
  Requires-Dist: aiomqtt>=1.1.0
19
20
  Requires-Dist: colorlog>=6.7.0
@@ -1,6 +1,6 @@
1
1
  boneio/__init__.py,sha256=hoLKnu6h1uEsiCHA9Ql2MMDC7VQS0E-s_2cxBS-CTOg,147
2
2
  boneio/bonecli.py,sha256=VhY1BMt6OaZz-752UjhEexdn8fDJkJaDWcGQNhCmgN0,3341
3
- boneio/const.py,sha256=4HRCWvh1dslJ37vMUp_NL2weeQjEkzi-z4iAcmik4MU,2947
3
+ boneio/const.py,sha256=NwdWZaL2Jjk7eizYhjXcaPGB5PjEeg9TJGhKBbj2bkg,3049
4
4
  boneio/cover.py,sha256=nr76ft5smAPdBB8Jytk-uFd6RWuqtcZiG6EE129OUjw,8454
5
5
  boneio/example_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  boneio/example_config/adc_v0_4.yaml,sha256=GKNpl2t7ebsH57UhJlJioXNuBflsL6eO4JMnyYwZrFs,168
@@ -17,12 +17,12 @@ boneio/helper/__init__.py,sha256=zizPsGPbEtcqUsFWOxhs8s4H6PeJvJq8tP0OvCVJ_C4,203
17
17
  boneio/helper/async_updater.py,sha256=BVh5mXFxgaZqoekjQbQSCTssfyVIdCQ80LCJny-rOo4,985
18
18
  boneio/helper/click_timer.py,sha256=dVYdX3VNpAEKHCIqWs3u0PCJLSPIGr0K2kMffc_kGdc,1138
19
19
  boneio/helper/config.py,sha256=HUl7iF7os1-YNfl1neJf2aDwiS2VE43biGefU5EhW3s,2321
20
- boneio/helper/events.py,sha256=EHYJy507RF1LikWQ2s4r990JRvR9rO4z7FkaJqt1Mrk,7494
20
+ boneio/helper/events.py,sha256=i-5FLyVwcAO3m3TpctxtbTcb7SCyQv8lX04mLHHhYk8,7592
21
21
  boneio/helper/exceptions.py,sha256=vyYSUojwB7OttOPUjbxeHFM7C_o5ZQmRUcZ_vYpxYYI,717
22
22
  boneio/helper/filter.py,sha256=UcjifjaC5wHDW2He7wmwCX2IjSSeLVhXyhrXHeT8RmA,885
23
23
  boneio/helper/gpio.py,sha256=sxvkYtKVt5alGoXFBRzG8ONEo112fsKsX-zK2C-_YKg,3249
24
24
  boneio/helper/ha_discovery.py,sha256=ErAub0LK9y2fUieqUsHpixQATO1NQ_ZABGELVYDAZtE,6359
25
- boneio/helper/loader.py,sha256=qrTntQ_AhkY-8-kL54H65pqAfyMFEwoXPIll6q5EyXw,14895
25
+ boneio/helper/loader.py,sha256=6t9q3ns0EamuI0hn7_pCydAIWhOab5LoJ1AxPSHetZE,14687
26
26
  boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
27
27
  boneio/helper/mqtt.py,sha256=UVa4KaxvVif6By_sVMdSMiYI_doZjiXF4LS9RFltxJk,765
28
28
  boneio/helper/oled.py,sha256=f0XYbaFstUbJ6ISmFe1vQCnmNVMctQWtnStNdROrblc,351
@@ -39,16 +39,17 @@ boneio/helper/yaml_util.py,sha256=gAX7hCaHUlPgkhGCIQ4zjv0Vj9JmLzQsSyF51ZmSb9g,11
39
39
  boneio/input/__init__.py,sha256=ZM6G2XX621lQUy8Tk6S8zf_jBp_NxsK6OHMMrdsOsDo,178
40
40
  boneio/input/gpio.py,sha256=4YPzwtyWuEWdDQWte5YU-X_vaId2wFy_XWv7WkjzFoQ,2611
41
41
  boneio/input/gpio_beta.py,sha256=mBMIpVUEyH-CJpb2TtHDiiYaVFYdzjExcDGeOxx9PYQ,3133
42
- boneio/manager.py,sha256=RRKiKq26hNWf2MXaVWnh07_AFObajsMiAeerJxvN2uU,21785
42
+ boneio/manager.py,sha256=YwTm-5Loi9deUFokXFNW-FDQDtnrZUlpW9xreyW6Vlw,22339
43
43
  boneio/modbus.py,sha256=eA_sGnmdcIneXX75ZcXOI223-UkKN1UYmWFqiJBAhJo,4176
44
- boneio/mqtt_client.py,sha256=xADbqvQQnSqGBFw294_DyDkgIomwCveY6e1RaJC0Igk,8302
44
+ boneio/mqtt_client.py,sha256=OakqsF5q6JSOMR___EldxuG_Xg9YVDPYAV6CSwyJAjs,8645
45
45
  boneio/oled.py,sha256=d_ofDQHc7zr3j0qOR0B_L3C8TJhvRH85nnb9Le-88nk,5244
46
46
  boneio/relay/__init__.py,sha256=iLEUL8kxnEndCQtgDIJfHqUZOfyWfWmuOrqSYAUxb2w,181
47
- boneio/relay/basic.py,sha256=QEWG8HodBqEqLpQxcQm29hdPIxO7c6ep0uDgfo3pcco,2623
47
+ boneio/relay/basic.py,sha256=uMQWSgcCVH-ieGKirW_Faj1rVEivt0kmCE9XCDCu47s,2798
48
48
  boneio/relay/gpio.py,sha256=s64FBf6zlxciF57xJ6nrvy0t5Rie0uiXlwos0HL3RKM,1163
49
- boneio/relay/mcp.py,sha256=DhgqZbFHB6TucL9hJaJiqdVAbkw4Rv5VPHm_khSBIFo,2669
50
- boneio/relay/pca.py,sha256=tCwXvMJcsxzFj48ZO2tPYyvElZfyIRTFmEMp7ENKvtk,4873
51
- boneio/runner.py,sha256=8cOWpFFf02IwC9vaCdexcCTN1kP0_yKMBPT35PEHwHM,2653
49
+ boneio/relay/mcp.py,sha256=y23yvOsyBEs9d8A6QOgtmJpjd4cDx6DyW-cBz8Y-488,2506
50
+ boneio/relay/pca.py,sha256=vYQbDoBQ6iRK0HN3M8gW402PEwM5utON1hmdw5E0cIE,4871
51
+ boneio/relay/pcf.py,sha256=N_4d2u7nMUL-s5LwxsHGOKtGXneKFm-lCpezpKvrJvs,2504
52
+ boneio/runner.py,sha256=VL0q7P4VeDhoQIqooE8gg8Q7wOYCGIcHSZk7g9SDZHU,2876
52
53
  boneio/schema/actions.yaml,sha256=WD0LR9SxVPgwU12x10RvFaTeyDiCjdRiicfkrCGLNvc,1030
53
54
  boneio/schema/actions_sensor.yaml,sha256=U_VfdjqdorQZHYD6dZOzhlRKnOGwsnTJ3CDGiqrKxW8,124
54
55
  boneio/schema/actions_switch.yaml,sha256=sdqhwz0LrcfaiAN3-RfAR_xApxo5dh9RxXQubuKcsjk,129
@@ -61,7 +62,7 @@ boneio/schema/update_interval.yaml,sha256=L_YLddAZdybcdO-T57Qhlv1GaWIVDwhvH-GadD
61
62
  boneio/sensor/__init__.py,sha256=u-fSBKy1gcXTNclra5KzLYDxpHeo9G0vuNiMexIZSDw,538
62
63
  boneio/sensor/adc.py,sha256=tCUdr3KN5uSbgXiwhNXbMjeNkO2CzPYhIOncHR5_LD0,1328
63
64
  boneio/sensor/gpio.py,sha256=a9HljBbXr5YdCImZ85dBlTgIZZBsL38UEmAmRcDMp0w,1296
64
- boneio/sensor/gpio_beta.py,sha256=K1sxxnRDWmhTcRjmWZ-tjDAza4rLDamsx_8_jK3TMxU,1284
65
+ boneio/sensor/gpio_beta.py,sha256=Szl_5Q9jRCxTLJNwmry8tkrC2u1Pxelhe8DJa1C-27U,1291
65
66
  boneio/sensor/modbus/__init__.py,sha256=IUwGdGn_egqOcSZrt4tTu0n8APnc0M7uau7XUWDlhes,8520
66
67
  boneio/sensor/modbus/dts1964_3f.json,sha256=WABph_2X4OgMidSM28vw4dLd9ZByRoiUP-RqE0UMpR8,8810
67
68
  boneio/sensor/modbus/pt100.json,sha256=bzKNYDc3lMto94Ut8gutVIsHytQiMobwFCkonOiMegs,526
@@ -73,9 +74,9 @@ boneio/sensor/temp/__init__.py,sha256=OViqBb7DwVn_aFIy6V0iqkSUDjsDNLQ5sOS_4frYdw
73
74
  boneio/sensor/temp/dallas.py,sha256=xrvd1LNBh1fRcjz_yd_9S29Lv26ItVtLCmhZgVQWJos,2485
74
75
  boneio/sensor/temp/lm75.py,sha256=-mpOv78429plRPBp9s09Ljz1x2Bdxuagalqz40vlAKE,243
75
76
  boneio/sensor/temp/mcp9808.py,sha256=yAh5yJzZLGTqa39xV4fyqsruj7oy3niOZAUV2W6eyCM,271
76
- boneio/version.py,sha256=ig8n6Qd2PUEB4oYuBg_tNATNBQRkzy1TPKoHWipXRX0,41
77
- boneIO-0.7.0.dev1.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
78
- boneIO-0.7.0.dev1.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
79
- boneIO-0.7.0.dev1.dist-info/METADATA,sha256=6jXEUsPHVyv_Ym0uIFA0Wfrk130xp7059FuIjrkv7jY,1696
80
- boneIO-0.7.0.dev1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
81
- boneIO-0.7.0.dev1.dist-info/RECORD,,
77
+ boneio/version.py,sha256=17EUCA3ZgMyhHFifjToUvLPBUn7Sc12qa42ebBpttH8,41
78
+ boneIO-0.7.0.dev2.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
79
+ boneIO-0.7.0.dev2.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
80
+ boneIO-0.7.0.dev2.dist-info/METADATA,sha256=F57mc0Y6T-8X1avMDVEnxuG80U7zMx5oLq7vtc-kOTA,1749
81
+ boneIO-0.7.0.dev2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
82
+ boneIO-0.7.0.dev2.dist-info/RECORD,,
boneio/const.py CHANGED
@@ -104,10 +104,13 @@ TOPIC_PREFIX = "topic_prefix"
104
104
  # I2C, PCA and MCP CONST
105
105
  ADDRESS = "address"
106
106
  MCP23017 = "mcp23017"
107
+ PCF8575 = "pcf8575"
107
108
  PCA9685 = "pca9685"
108
109
  MCP = "mcp"
110
+ PCF = "pcf"
109
111
  MCP_ID = "mcp_id"
110
112
  PCA_ID = "pca_id"
113
+ PCF_ID = "pcf_id"
111
114
  INIT_SLEEP = "init_sleep"
112
115
 
113
116
  # SENSOR CONST
@@ -141,6 +144,7 @@ OledDataTypes = Literal[UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP, OUTPUT]
141
144
  Gpio_States = Literal[HIGH, LOW]
142
145
  Gpio_Edges = Literal[BOTH, FALLING]
143
146
  InputTypes = Literal[INPUT, INPUT_SENSOR]
147
+ ExpanderTypes = Literal[MCP23017, PCA9685, PCF8575]
144
148
  DEVICE_CLASS = "device_class"
145
149
  DallasBusTypes = Literal[DS2482, DALLAS]
146
150
  FILTERS = "filters"
boneio/helper/events.py CHANGED
@@ -77,9 +77,11 @@ class ListenerJob:
77
77
  class EventBus:
78
78
  """Simple event bus which ticks every second."""
79
79
 
80
- def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
80
+ def __init__(self, last_will_mqtt = Callable) -> None:
81
81
  """Initialize handler"""
82
- self._loop = loop or asyncio.get_event_loop()
82
+ self._loop = asyncio.get_event_loop()
83
+ self._last_will = last_will_mqtt
84
+
83
85
  self._listeners = {}
84
86
  self._sigterm_listeners = []
85
87
  self._haonline_listeners = []
@@ -87,7 +89,7 @@ class EventBus:
87
89
  for signame in {"SIGINT", "SIGTERM"}:
88
90
  self._loop.add_signal_handler(
89
91
  getattr(signal, signame),
90
- self.ask_exit,
92
+ lambda: asyncio.create_task(self.ask_exit()),
91
93
  )
92
94
 
93
95
  def _run_second_event(self, time):
@@ -98,13 +100,15 @@ class EventBus:
98
100
  self._loop.call_soon(listener.target, time)
99
101
  )
100
102
 
101
- def ask_exit(self):
103
+ async def ask_exit(self):
102
104
  """Function to call on exit. Should invoke all sigterm listeners."""
103
105
  _LOGGER.debug("Exiting process started.")
104
106
  self._listeners = {}
105
107
  for target in self._sigterm_listeners:
106
108
  target()
107
109
  self._timer_handle()
110
+
111
+ await self._last_will()
108
112
  _LOGGER.info("Shutdown gracefully.")
109
113
  raise GracefulExit(code=0)
110
114
 
boneio/helper/loader.py CHANGED
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Union
7
7
 
8
8
  from adafruit_mcp230xx.mcp23017 import MCP23017
9
9
  from adafruit_pca9685 import PCA9685
10
+ from adafruit_pcf8575 import PCF8575
10
11
 
11
12
  from boneio.const import (
12
13
  ACTIONS,
@@ -37,7 +38,11 @@ from boneio.const import (
37
38
  SHOW_HA,
38
39
  UPDATE_INTERVAL,
39
40
  DallasBusTypes,
40
- EVENT_ENTITY
41
+ EVENT_ENTITY,
42
+ ExpanderTypes,
43
+ PCF,
44
+ PCA,
45
+ PCF_ID
41
46
  )
42
47
  from boneio.cover import Cover
43
48
  from boneio.helper import (
@@ -148,53 +153,40 @@ def create_temp_sensor(
148
153
  _LOGGER.error("Can't configure Temp sensor. %s", err)
149
154
  pass
150
155
 
151
-
152
- def create_mcp23017(
153
- manager: Manager,
154
- mcp23017: list,
155
- i2cbusio: I2C,
156
+ expander_class = {
157
+ MCP: MCP23017,
158
+ PCA: PCA9685,
159
+ PCF: PCF8575
160
+ }
161
+
162
+ def create_expander(
163
+ expander_dict: dict,
164
+ expander_config: list,
165
+ exp_type: ExpanderTypes,
166
+ i2cbusio: I2C
156
167
  ) -> dict:
157
- """Create MCP23017."""
158
168
  grouped_outputs = {}
159
- for mcp in mcp23017:
160
- id = mcp[ID] or mcp[ADDRESS]
169
+ for expander in expander_config:
170
+ id = expander[ID] or expander[ADDRESS]
161
171
  try:
162
- manager._mcp[id] = MCP23017(i2c=i2cbusio, address=mcp[ADDRESS], reset=False)
163
- sleep_time = mcp.get(INIT_SLEEP, TimePeriod(seconds=0))
164
- _LOGGER.debug(
165
- f"Sleeping for {sleep_time.total_seconds}s while MCP {id} is initializing."
166
- )
167
- time.sleep(sleep_time.total_seconds)
172
+ expander_dict[id] = expander_class[exp_type](i2c=i2cbusio, address=expander[ADDRESS], reset=False)
173
+ sleep_time = expander.get(INIT_SLEEP, TimePeriod(seconds=0))
174
+ if sleep_time.total_seconds > 0:
175
+ _LOGGER.debug(
176
+ f"Sleeping for {sleep_time.total_seconds}s while {exp_type} {id} is initializing."
177
+ )
178
+ time.sleep(sleep_time.total_seconds)
179
+ else:
180
+ _LOGGER.debug(
181
+ f"{exp_type} {id} is initializing."
182
+ )
168
183
  grouped_outputs[id] = {}
169
184
  except TimeoutError as err:
170
- _LOGGER.error("Can't connect to MCP %s. %s", id, err)
185
+ _LOGGER.error("Can't connect to %s %s. %s", exp_type, id, err)
171
186
  pass
172
187
  return grouped_outputs
173
188
 
174
189
 
175
- def create_pca9685(
176
- manager: Manager,
177
- pca9685: list,
178
- i2cbusio: I2C,
179
- ) -> dict:
180
- """Create MCP23017."""
181
- grouped_outputs = {}
182
- for pca in pca9685:
183
- id = pca[ID] or pca[ADDRESS]
184
- try:
185
- manager._pca[id] = PCA9685(i2c_bus=i2cbusio, address=pca[ADDRESS])
186
- manager._pca[id].frequency = 500
187
- sleep_time = pca.get(INIT_SLEEP, TimePeriod(seconds=0))
188
- _LOGGER.debug(
189
- f"Sleeping for {sleep_time.total_seconds}s while PCA {id} is initializing."
190
- )
191
- time.sleep(sleep_time.total_seconds)
192
- grouped_outputs[id] = {}
193
- except TimeoutError as err:
194
- _LOGGER.error("Can't connect to PCA %s. %s", id, err)
195
- pass
196
- return grouped_outputs
197
-
198
190
 
199
191
  def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
200
192
  """Create Modbus sensor for each device."""
@@ -236,6 +228,9 @@ def output_chooser(output_kind: str, config):
236
228
  elif output_kind == PCA:
237
229
  output_id = config.pop(PCA_ID, None)
238
230
  return OutputEntry(PWMPCA, PCA, output_id)
231
+ elif output_kind == PCF:
232
+ output_id = config.pop(PCF_ID, None)
233
+ return OutputEntry(PWMPCA, PCF, output_id)
239
234
  else:
240
235
  raise GPIOOutputException(f"""Output type {output_kind} dont exists""")
241
236
 
@@ -373,7 +368,7 @@ def configure_binary_sensor(
373
368
  """Configure input sensor or button."""
374
369
  try:
375
370
  GpioInputBinarySensorClass = GpioInputBinarySensor if gpio.get("detection_type", "stable") == "stable" else GpioInputBinarySensorBeta
376
- GpioInputBinarySensor(
371
+ GpioInputBinarySensorClass(
377
372
  pin=pin,
378
373
  press_callback=lambda x, i: press_callback(
379
374
  x=x,
boneio/manager.py CHANGED
@@ -37,6 +37,9 @@ from boneio.const import (
37
37
  LIGHT,
38
38
  LED,
39
39
  SET_BRIGHTNESS,
40
+ MCP,
41
+ PCA,
42
+ PCF
40
43
  )
41
44
  from boneio.helper import (
42
45
  GPIOInputException,
@@ -57,8 +60,7 @@ from boneio.helper.loader import (
57
60
  configure_binary_sensor,
58
61
  configure_relay,
59
62
  create_dallas_sensor,
60
- create_mcp23017,
61
- create_pca9685,
63
+ create_expander,
62
64
  create_temp_sensor,
63
65
  )
64
66
  from boneio.helper.logger import configure_logger
@@ -84,6 +86,7 @@ class Manager:
84
86
  stop_client: Callable[[], Awaitable[None]],
85
87
  state_manager: StateManager,
86
88
  config_helper: ConfigHelper,
89
+ event_bus: EventBus,
87
90
  config_file_path: str,
88
91
  relay_pins: List = [],
89
92
  event_pins: List = [],
@@ -92,6 +95,7 @@ class Manager:
92
95
  modbus: dict = {},
93
96
  pca9685: list = [],
94
97
  mcp23017: list = [],
98
+ pcf8575: list = [],
95
99
  ds2482: Optional[List] = [],
96
100
  dallas: Optional[dict] = None,
97
101
  oled: dict = {},
@@ -107,7 +111,7 @@ class Manager:
107
111
  self._host_data = None
108
112
  self._config_file_path = config_file_path
109
113
  self._state_manager = state_manager
110
- self._event_bus = EventBus(self._loop)
114
+ self._event_bus = event_bus
111
115
 
112
116
  self.send_message = send_message
113
117
  self.stop_client = stop_client
@@ -115,6 +119,7 @@ class Manager:
115
119
  self._binary_pins = binary_pins
116
120
  self._i2cbusio = I2C(SCL, SDA)
117
121
  self._mcp = {}
122
+ self._pcf = {}
118
123
  self._pca = {}
119
124
  self._output = {}
120
125
  self._oled = None
@@ -132,11 +137,27 @@ class Manager:
132
137
  dallas=dallas, ds2482=ds2482, sensors=sensors.get(ONEWIRE)
133
138
  )
134
139
 
135
- self.grouped_outputs = create_mcp23017(
136
- manager=self, mcp23017=mcp23017, i2cbusio=self._i2cbusio
140
+ self.grouped_outputs = create_expander(
141
+ expander_dict=self._mcp,
142
+ expander_config=mcp23017,
143
+ exp_type=MCP,
144
+ i2cbusio=self._i2cbusio
137
145
  )
138
146
  self.grouped_outputs.update(
139
- create_pca9685(manager=self, pca9685=pca9685, i2cbusio=self._i2cbusio)
147
+ create_expander(
148
+ expander_dict=self._pcf,
149
+ expander_config=pcf8575,
150
+ exp_type=PCF,
151
+ i2cbusio=self._i2cbusio
152
+ )
153
+ )
154
+ self.grouped_outputs.update(
155
+ create_expander(
156
+ expander_dict=self._pca,
157
+ expander_config=pca9685,
158
+ exp_type=PCA,
159
+ i2cbusio=self._i2cbusio
160
+ )
140
161
  )
141
162
 
142
163
  self._configure_adc(adc_list=adc)
@@ -456,6 +477,11 @@ class Manager:
456
477
  def pca(self):
457
478
  """Get PCA by it's id."""
458
479
  return self._pca
480
+
481
+ @property
482
+ def pcf(self):
483
+ """Get PCF by it's id."""
484
+ return self._pcf
459
485
 
460
486
  def press_callback(
461
487
  self, x: ClickTypes, inpin: str, actions: List, input_type: InputTypes = INPUT, empty_message_after: bool = False
boneio/mqtt_client.py CHANGED
@@ -15,7 +15,7 @@ from aiomqtt import Client as AsyncioClient, MqttError, Will
15
15
  from paho.mqtt.properties import Properties
16
16
  from paho.mqtt.subscribeoptions import SubscribeOptions
17
17
 
18
- from boneio.const import ONLINE, PAHO, STATE
18
+ from boneio.const import ONLINE, OFFLINE, PAHO, STATE
19
19
  from boneio.helper import UniqueQueue
20
20
  from boneio.helper.config import ConfigHelper
21
21
  from boneio.manager import Manager
@@ -128,7 +128,7 @@ class MQTTClient:
128
128
  await self.asyncio_client.unsubscribe(topic=topics, **params)
129
129
 
130
130
  def send_message(
131
- self, topic: str, payload: Union[str, dict, None], retain: bool = False
131
+ self, topic: str, payload: Union[str, int, dict, None], retain: bool = False
132
132
  ) -> None:
133
133
  """Send a message from the manager options."""
134
134
  to_publish = (
@@ -161,12 +161,19 @@ class MQTTClient:
161
161
  self._connection_established = False
162
162
  await asyncio.sleep(self.reconnect_interval)
163
163
  self.create_client() # reset connect/reconnect futures
164
+ except asyncio.CancelledError:
165
+ _LOGGER.info("MQTT client task canceled.")
164
166
 
165
167
  async def stop_client(self) -> None:
166
168
  await self.unsubscribe(
167
169
  topics=self._topics
168
170
  )
169
171
  raise RestartRequestException("Restart requested.")
172
+
173
+ async def last_will_mqtt(self) -> None:
174
+ _LOGGER.info("Sending offline state.")
175
+ topic = f"{self._config_helper.topic_prefix}/{STATE}"
176
+ self.send_message(topic=topic, payload=OFFLINE, retain=True)
170
177
 
171
178
  async def _subscribe_manager(self, manager: Manager) -> None:
172
179
  """Connect and subscribe to manager topics + host stats."""
boneio/relay/basic.py CHANGED
@@ -3,7 +3,7 @@
3
3
  import asyncio
4
4
  import logging
5
5
  from typing import Callable
6
-
6
+ from boneio.helper.util import callback
7
7
  from boneio.const import LIGHT, NONE, OFF, ON, RELAY, STATE, SWITCH
8
8
  from boneio.helper import BasicMqtt
9
9
 
@@ -82,6 +82,11 @@ class BasicRelay(BasicMqtt):
82
82
  else:
83
83
  self.turn_on()
84
84
 
85
+ @callback
86
+ def _momentary_callback(self, time, action):
87
+ _LOGGER.info("Momentary callback at %s", time)
88
+ action()
89
+
85
90
  @property
86
91
  def is_active(self) -> bool:
87
92
  """Is active check."""
boneio/relay/mcp.py CHANGED
@@ -4,9 +4,8 @@ import logging
4
4
 
5
5
  from adafruit_mcp230xx.mcp23017 import MCP23017, DigitalInOut
6
6
 
7
- from boneio.const import NONE, SWITCH
7
+ from boneio.const import NONE, SWITCH, MCP
8
8
  from boneio.helper.events import async_track_point_in_time, utcnow
9
- from boneio.helper.util import callback
10
9
  from boneio.relay.basic import BasicRelay
11
10
 
12
11
  _LOGGER = logging.getLogger(__name__)
@@ -34,23 +33,23 @@ class MCPRelay(BasicRelay):
34
33
  **kwargs, output_type=output_type, restored_state=restored_state
35
34
  )
36
35
  self._pin_id = pin
37
- self._mcp_id = mcp_id
36
+ self._expander_id = mcp_id
38
37
  _LOGGER.debug("Setup MCP with pin %s", self._pin_id)
39
38
 
40
39
  @property
41
- def is_mcp_type(self) -> bool:
42
- """Check if relay is mcp type."""
43
- return True
40
+ def expander_type(self) -> str:
41
+ """Check expander type."""
42
+ return MCP
44
43
 
45
44
  @property
46
- def pin_id(self) -> str:
45
+ def pin_id(self) -> int:
47
46
  """Return PIN id."""
48
47
  return self._pin_id
49
48
 
50
49
  @property
51
- def mcp_id(self) -> str:
50
+ def expander_id(self) -> str:
52
51
  """Retrieve parent MCP ID."""
53
- return self._mcp_id
52
+ return self._expander_id
54
53
 
55
54
  @property
56
55
  def is_active(self) -> bool:
@@ -62,11 +61,6 @@ class MCPRelay(BasicRelay):
62
61
  """PIN of the relay"""
63
62
  return self._pin
64
63
 
65
- @callback
66
- def _momentary_callback(self, time, action):
67
- _LOGGER.info("Momentary callback at %s", time)
68
- action()
69
-
70
64
  def turn_on(self) -> None:
71
65
  """Call turn on action."""
72
66
  self.pin.value = True
boneio/relay/pca.py CHANGED
@@ -9,7 +9,7 @@ from adafruit_pca9685 import PCA9685, PCAChannels
9
9
  from boneio.helper.events import async_track_point_in_time, utcnow
10
10
  from boneio.helper.util import callback
11
11
 
12
- from boneio.const import LED, NONE, OFF, ON, STATE, SWITCH, BRIGHTNESS, RELAY
12
+ from boneio.const import LED, NONE, OFF, ON, STATE, SWITCH, BRIGHTNESS, RELAY, PCA
13
13
  from boneio.helper import BasicMqtt
14
14
 
15
15
  _LOGGER = logging.getLogger(__name__)
@@ -58,9 +58,9 @@ class PWMPCA(BasicMqtt):
58
58
  _LOGGER.debug("Setup PCA with pin %s", self._pin_id)
59
59
 
60
60
  @property
61
- def is_pca_type(self) -> bool:
62
- """Check if relay is pca type."""
63
- return True
61
+ def expander_type(self) -> str:
62
+ """Check expander type."""
63
+ return PCA
64
64
 
65
65
  @property
66
66
  def output_type(self) -> str:
boneio/relay/pcf.py ADDED
@@ -0,0 +1,84 @@
1
+ """PCF8575 Relay module."""
2
+
3
+ import logging
4
+
5
+ from adafruit_pcf8575 import PCF8575, DigitalInOut
6
+
7
+ from boneio.const import NONE, SWITCH, PCF
8
+ from boneio.helper.events import async_track_point_in_time, utcnow
9
+ from boneio.relay.basic import BasicRelay
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ class PCFRelay(BasicRelay):
15
+ """Represents PCF Relay output"""
16
+
17
+ def __init__(
18
+ self,
19
+ pin: int,
20
+ mcp: PCF8575,
21
+ expander_id: str,
22
+ output_type: str = SWITCH,
23
+ restored_state: bool = False,
24
+ **kwargs,
25
+ ) -> None:
26
+ """Initialize MCP relay."""
27
+ self._pin: DigitalInOut = mcp.get_pin(pin)
28
+ if output_type == NONE:
29
+ """Just in case to not restore state of covers etc."""
30
+ restored_state = False
31
+ self._pin.switch_to_output(value=restored_state)
32
+ super().__init__(
33
+ **kwargs, output_type=output_type, restored_state=restored_state
34
+ )
35
+ self._pin_id = pin
36
+ self._expander_id = expander_id
37
+ _LOGGER.debug("Setup PCF with pin %s", self._pin_id)
38
+
39
+ @property
40
+ def expander_type(self) -> str:
41
+ """Check expander type."""
42
+ return PCF
43
+
44
+ @property
45
+ def pin_id(self) -> int:
46
+ """Return PIN id."""
47
+ return self._pin_id
48
+
49
+ @property
50
+ def expander_id(self) -> str:
51
+ """Retrieve parent MCP ID."""
52
+ return self._expander_id
53
+
54
+ @property
55
+ def is_active(self) -> bool:
56
+ """Is relay active."""
57
+ return self.pin.value
58
+
59
+ @property
60
+ def pin(self) -> str:
61
+ """PIN of the relay"""
62
+ return self._pin
63
+
64
+ def turn_on(self) -> None:
65
+ """Call turn on action."""
66
+ self.pin.value = True
67
+ if self._momentary_turn_on:
68
+ async_track_point_in_time(
69
+ loop=self._loop,
70
+ action=lambda x: self._momentary_callback(time=x, action=self.turn_off),
71
+ point_in_time=utcnow() + self._momentary_turn_on.as_timedelta,
72
+ )
73
+ self._loop.call_soon_threadsafe(self.send_state)
74
+
75
+ def turn_off(self) -> None:
76
+ """Call turn off action."""
77
+ self.pin.value = False
78
+ if self._momentary_turn_off:
79
+ async_track_point_in_time(
80
+ loop=self._loop,
81
+ action=lambda x: self._momentary_callback(time=x, action=self.turn_on),
82
+ point_in_time=utcnow() + self._momentary_turn_off.as_timedelta,
83
+ )
84
+ self._loop.call_soon_threadsafe(self.send_state)
boneio/runner.py CHANGED
@@ -17,6 +17,7 @@ from boneio.const import (
17
17
  EVENT_ENTITY,
18
18
  LM75,
19
19
  MCP23017,
20
+ PCF8575,
20
21
  PCA9685,
21
22
  MCP_TEMP_9808,
22
23
  MODBUS,
@@ -34,11 +35,13 @@ from boneio.helper import StateManager
34
35
  from boneio.helper.config import ConfigHelper
35
36
  from boneio.manager import Manager
36
37
  from boneio.mqtt_client import MQTTClient
38
+ from boneio.helper.events import EventBus
37
39
 
38
40
  _LOGGER = logging.getLogger(__name__)
39
41
 
40
42
  config_modules = [
41
43
  {"name": MCP23017, "default": []},
44
+ {"name": PCF8575, "default": []},
42
45
  {"name": PCA9685, "default": []},
43
46
  {"name": DS2482, "default": []},
44
47
  {"name": ADC, "default": []},
@@ -56,6 +59,7 @@ async def async_run(
56
59
  mqttpassword: str = "",
57
60
  ) -> list[Any]:
58
61
  """Run BoneIO."""
62
+ _loop = asyncio.get_event_loop()
59
63
 
60
64
  _config_helper = ConfigHelper(
61
65
  topic_prefix=config[MQTT].pop(TOPIC_PREFIX),
@@ -70,6 +74,7 @@ async def async_run(
70
74
  port=config[MQTT].get(PORT, 1883),
71
75
  config_helper=_config_helper,
72
76
  )
77
+ event_bus = EventBus(last_will_mqtt=client.last_will_mqtt)
73
78
  manager_kwargs = {
74
79
  item["name"]: config.get(item["name"], item["default"])
75
80
  for item in config_modules
@@ -78,6 +83,7 @@ async def async_run(
78
83
  manager = Manager(
79
84
  send_message=client.send_message,
80
85
  stop_client=client.stop_client,
86
+ event_bus=event_bus,
81
87
  relay_pins=config.get(OUTPUT, []),
82
88
  event_pins=config.get(EVENT_ENTITY, []),
83
89
  binary_pins=config.get(BINARY_SENSOR, []),
@@ -1,9 +1,10 @@
1
1
  """GpioInputBinarySensor to receive signals."""
2
2
  import logging
3
3
  from functools import partial
4
- from boneio.const import PRESSED, RELEASED
4
+ from boneio.const import PRESSED, RELEASED, BOTH
5
5
  from boneio.helper import GpioBaseClass
6
6
  from boneio.helper.gpio import add_event_callback, add_event_detect
7
+
7
8
  _LOGGER = logging.getLogger(__name__)
8
9
 
9
10
 
boneio/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # flake8: noqa
2
- __version__ = "0.7.0dev1"
2
+ __version__ = "0.7.0dev2"