boneIO 0.7.0dev3__py3-none-any.whl → 0.7.0dev6__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.0dev3
3
+ Version: 0.7.0dev6
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>
@@ -1,7 +1,7 @@
1
1
  boneio/__init__.py,sha256=hoLKnu6h1uEsiCHA9Ql2MMDC7VQS0E-s_2cxBS-CTOg,147
2
2
  boneio/bonecli.py,sha256=o2DWcsKqw4IJklPmbdq7bwgcISOWPZfYVAUuMltNUP0,3435
3
- boneio/const.py,sha256=NwdWZaL2Jjk7eizYhjXcaPGB5PjEeg9TJGhKBbj2bkg,3049
4
- boneio/cover.py,sha256=nr76ft5smAPdBB8Jytk-uFd6RWuqtcZiG6EE129OUjw,8454
3
+ boneio/const.py,sha256=Drge50hdQpxW7gYbYIC6DPVHHibFOKH0OAV3lWzhH-Q,3256
4
+ boneio/cover.py,sha256=EfO1DAOGTPQykfgJHzg1WqPs0U8b1AnD2NMI-sLZccM,8444
5
5
  boneio/example_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  boneio/example_config/adc_v0_4.yaml,sha256=GKNpl2t7ebsH57UhJlJioXNuBflsL6eO4JMnyYwZrFs,168
7
7
  boneio/example_config/binary_sensor.yaml,sha256=0-KfPuACU6Q8krtNLQ_Bu8135xLEeCrs8UhGXR7kCxU,238
@@ -13,18 +13,20 @@ boneio/example_config/output24x16A.yaml,sha256=BTtHToRgz-U_rMMDbmHkM4wQxHakdzInb
13
13
  boneio/example_config/output24x16A_v0.3.yaml,sha256=XkI4rHn_XdX37xG02-wHieZzSHKiKN5mtnyfRE24NII,1713
14
14
  boneio/example_config/output32x5A.yaml,sha256=G2Pb6qL8mXs6MliIM1roAanPag9ozRe3McYYuFsiBc0,2403
15
15
  boneio/fonts/danube__.ttf,sha256=KBRPUcGvmroCjrWC8zK4MulUb9lV8R0lXkOY7lNnQWc,19372
16
+ boneio/group/__init__.py,sha256=eUN51J6nU1MdQfcl6JQ2AQwkP6K91mR9caDZyZ18rig,80
17
+ boneio/group/output.py,sha256=byaYz1etz2LWFpRnvLMH0EpzeP5JMF_PH2W2pGDTnEY,2005
16
18
  boneio/helper/__init__.py,sha256=zizPsGPbEtcqUsFWOxhs8s4H6PeJvJq8tP0OvCVJ_C4,2039
17
- boneio/helper/async_updater.py,sha256=BVh5mXFxgaZqoekjQbQSCTssfyVIdCQ80LCJny-rOo4,985
19
+ boneio/helper/async_updater.py,sha256=K1xXpVAFeTOKfcmTGBnBgOvwZHfZQQKOWVEOnEMm0BY,993
18
20
  boneio/helper/click_timer.py,sha256=yZ2nfnreSCBfJkkWDE_RhDfV7YHgwfoehMLh3ia2BEI,1184
19
- boneio/helper/config.py,sha256=HUl7iF7os1-YNfl1neJf2aDwiS2VE43biGefU5EhW3s,2321
20
- boneio/helper/events.py,sha256=X3kPA6C_S3_24gBeE87jUqBTX6XpjcBH1KvKhokkquU,7495
21
+ boneio/helper/config.py,sha256=5cDnJ7usJDlUvXv8K2rSWEx30OFcU2k1U1vUEjO69WY,2431
22
+ boneio/helper/events.py,sha256=mK6boHpgMf3mMudnrUOesHL28udX8E2BGNwHFuEN2XA,8059
21
23
  boneio/helper/exceptions.py,sha256=vyYSUojwB7OttOPUjbxeHFM7C_o5ZQmRUcZ_vYpxYYI,717
22
24
  boneio/helper/filter.py,sha256=UcjifjaC5wHDW2He7wmwCX2IjSSeLVhXyhrXHeT8RmA,885
23
- boneio/helper/gpio.py,sha256=fmI5Hiot8f-5qp2mPiPCg49DEZwBX0m9xVGiDNZHATM,3297
24
- boneio/helper/ha_discovery.py,sha256=ErAub0LK9y2fUieqUsHpixQATO1NQ_ZABGELVYDAZtE,6359
25
- boneio/helper/loader.py,sha256=BLny6xKUipQXkrGh8sJMVBijuUeo2LdGHImKeCMq80Y,15152
25
+ boneio/helper/gpio.py,sha256=GKSg6Ke9FSnx8P3dAr48JYrJygrez9N8Ej1W5H3WdPc,3557
26
+ boneio/helper/ha_discovery.py,sha256=_2ADUnqo4a2FOaTR4LDJblF2z18sioaOOnVxX5R9aQE,6437
27
+ boneio/helper/loader.py,sha256=a22t1Bu4I_M9Z7k_tVcABgSUBheV9cx7UtPQvfeEjjA,17577
26
28
  boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
27
- boneio/helper/mqtt.py,sha256=UVa4KaxvVif6By_sVMdSMiYI_doZjiXF4LS9RFltxJk,765
29
+ boneio/helper/mqtt.py,sha256=dXH87TYyDTd1MJz5zHBEJDVmrqFoL38N7uyBeyiieyY,771
28
30
  boneio/helper/oled.py,sha256=f0XYbaFstUbJ6ISmFe1vQCnmNVMctQWtnStNdROrblc,351
29
31
  boneio/helper/onewire/W1ThermSensor.py,sha256=Pu5Fp29pKbxjJqDbFs05Mjg3Vy-9z_DTVoBpSWM_byA,2430
30
32
  boneio/helper/onewire/__init__.py,sha256=4djH-uxiq5XhAiFTOxyqjvWVoJe0c8U8iN0BfmH8nSU,448
@@ -32,32 +34,32 @@ boneio/helper/onewire/ds2482.py,sha256=c2t_hdAMtFsHw4Vw41QzO_hEDDNMeb3J71mEwEMUB
32
34
  boneio/helper/onewire/onewire.py,sha256=tHofTu1l0qG7hH2XoSf-lj8gW7wVKe27j57qQWpVMPg,2497
33
35
  boneio/helper/pcf8575.py,sha256=qeNYLqV5foDEQCyAz1WRQRi1CYYxtbPIha06Z5TyZVQ,311
34
36
  boneio/helper/queue.py,sha256=7fE7d344-BEW8sljN40wmqsbBr4kPLvz4ShBjkT04p8,1066
35
- boneio/helper/state_manager.py,sha256=LsMQRrD7WXu5jXFoltYXvzHDeiNDDEx6UWYebFw18gc,1994
37
+ boneio/helper/state_manager.py,sha256=PiNCL_uHElVH34ztIXBgVgKnpN0Mje2pspCLBiRIsgk,2145
36
38
  boneio/helper/stats.py,sha256=XNQDU-ixIobKQ2batzZno2UOMzNGWHSFQ-EXChNBJzM,5853
37
39
  boneio/helper/timeperiod.py,sha256=xpg9oe30Z5WiLDQPq3EBKKScejOnN47NhcpeFvDd3bY,5806
38
40
  boneio/helper/util.py,sha256=QfSoT3H3WnOQAKO5bFRIBCy62HT5NMa9Ek-FmfTW_rw,508
39
41
  boneio/helper/yaml_util.py,sha256=gAX7hCaHUlPgkhGCIQ4zjv0Vj9JmLzQsSyF51ZmSb9g,11304
40
42
  boneio/input/__init__.py,sha256=ZM6G2XX621lQUy8Tk6S8zf_jBp_NxsK6OHMMrdsOsDo,178
41
- boneio/input/gpio.py,sha256=4YPzwtyWuEWdDQWte5YU-X_vaId2wFy_XWv7WkjzFoQ,2611
43
+ boneio/input/gpio.py,sha256=j6tiZmUC934Yc_Lu8FjSNQIdRb0iJLiucJu0UuU_cAQ,2709
42
44
  boneio/input/gpio_beta.py,sha256=ZsiY5oeSsqo-JuZ9uglwfsmJ_MySQqxuGU6PbWcO1Hw,3231
43
- boneio/manager.py,sha256=md1lvU0k414R3ALU8U_Rhyil8EnrCeU8cLb7KYGBxm8,22653
45
+ boneio/manager.py,sha256=rITALbKkdzkaNLdza2lw9DvtlrhrS-ydLv3W2KKTNWw,27086
44
46
  boneio/modbus.py,sha256=eA_sGnmdcIneXX75ZcXOI223-UkKN1UYmWFqiJBAhJo,4176
45
- boneio/mqtt_client.py,sha256=xcK3Ac88deZvpatEVqIin0pBfpgIqfcles2_3qi9wGQ,8551
47
+ boneio/mqtt_client.py,sha256=5_ilaYqsCIIdKjsspQxPoNkSpSuCjrwD16HTcfH0Lxk,8551
46
48
  boneio/oled.py,sha256=d_ofDQHc7zr3j0qOR0B_L3C8TJhvRH85nnb9Le-88nk,5244
47
49
  boneio/relay/__init__.py,sha256=Cz6D37GKHxm8DiuPuxE2EMaey2wdUdJYVet_hfR0lzA,231
48
- boneio/relay/basic.py,sha256=uMQWSgcCVH-ieGKirW_Faj1rVEivt0kmCE9XCDCu47s,2798
50
+ boneio/relay/basic.py,sha256=BeA4v4eq2uyMDnIvZFHBl7EIs5scJ0efJQbvZqwMstc,3276
49
51
  boneio/relay/gpio.py,sha256=s64FBf6zlxciF57xJ6nrvy0t5Rie0uiXlwos0HL3RKM,1163
50
- boneio/relay/mcp.py,sha256=y23yvOsyBEs9d8A6QOgtmJpjd4cDx6DyW-cBz8Y-488,2506
51
- boneio/relay/pca.py,sha256=vYQbDoBQ6iRK0HN3M8gW402PEwM5utON1hmdw5E0cIE,4871
52
+ boneio/relay/mcp.py,sha256=4NZJLVtR_f-vuwGA1vbTLqzPoEZO2_in-RJSORfwC60,2508
53
+ boneio/relay/pca.py,sha256=YBrClCM_dvPF92gdDmyjfGumhan0UdHWQBDv-J7DrzA,4594
52
54
  boneio/relay/pcf.py,sha256=15uw3i3n06AfILcd6fWRgHjibKDkvRbiAntoTrlwHx4,2635
53
- boneio/runner.py,sha256=w8FMG1_Esd2BA7cQ9crnxkwvJWpQKiQy-Z1kWf-5t-8,2769
54
- boneio/schema/actions.yaml,sha256=WD0LR9SxVPgwU12x10RvFaTeyDiCjdRiicfkrCGLNvc,1030
55
+ boneio/runner.py,sha256=wHi1R3sI6OSBdjQ5-G44r8WGiTiTqv5n7x5aB-_GIrw,2789
56
+ boneio/schema/actions.yaml,sha256=kaJZ9B6SOl4Wbujtnr5k-g5JcAi2NSC1oGc0wZy8fnQ,1039
55
57
  boneio/schema/actions_sensor.yaml,sha256=U_VfdjqdorQZHYD6dZOzhlRKnOGwsnTJ3CDGiqrKxW8,124
56
58
  boneio/schema/actions_switch.yaml,sha256=sdqhwz0LrcfaiAN3-RfAR_xApxo5dh9RxXQubuKcsjk,129
57
59
  boneio/schema/filters.yaml,sha256=WopX1SmCZsSZXNiGccLoi7uMCsUpdbs0eVfsAjmbay4,286
58
60
  boneio/schema/filters_adc.yaml,sha256=3e0ts92MoFKOnfGOOn6WYIHxu0-tnZe9OjAjN9m7hiI,304
59
61
  boneio/schema/id.yaml,sha256=vHI_6dxkJwoiGp5ien_pPpyaWA1F06eirTgfWMyWa1E,75
60
- boneio/schema/schema.yaml,sha256=NoHUCKGMTdHbQySep3XCdNmWA9tj4fkwICUVvQl7_VQ,15692
62
+ boneio/schema/schema.yaml,sha256=4udNBm8dlUUuZtZat1D-9fUua-gCekPEaZTpqIxPYx4,16585
61
63
  boneio/schema/temp_unit.yaml,sha256=m32VGz9RTW92Lz08l9n6RftkcVNZquOGPPr5mc3eZVc,65
62
64
  boneio/schema/update_interval.yaml,sha256=L_YLddAZdybcdO-T57Qhlv1GaWIVDwhvH-GadD1oOIo,133
63
65
  boneio/sensor/__init__.py,sha256=u-fSBKy1gcXTNclra5KzLYDxpHeo9G0vuNiMexIZSDw,538
@@ -75,9 +77,9 @@ boneio/sensor/temp/__init__.py,sha256=OViqBb7DwVn_aFIy6V0iqkSUDjsDNLQ5sOS_4frYdw
75
77
  boneio/sensor/temp/dallas.py,sha256=xrvd1LNBh1fRcjz_yd_9S29Lv26ItVtLCmhZgVQWJos,2485
76
78
  boneio/sensor/temp/lm75.py,sha256=-mpOv78429plRPBp9s09Ljz1x2Bdxuagalqz40vlAKE,243
77
79
  boneio/sensor/temp/mcp9808.py,sha256=yAh5yJzZLGTqa39xV4fyqsruj7oy3niOZAUV2W6eyCM,271
78
- boneio/version.py,sha256=jCQXHF3DO-ig-EyH6gbdxNzgJ2HZQdHqthxS9o0iAkc,41
79
- boneIO-0.7.0.dev3.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
80
- boneIO-0.7.0.dev3.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
81
- boneIO-0.7.0.dev3.dist-info/METADATA,sha256=Zywv9O3UY21h9Hz00HBn9w3dv6kJXMX0gP6rNznSzeE,1749
82
- boneIO-0.7.0.dev3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
83
- boneIO-0.7.0.dev3.dist-info/RECORD,,
80
+ boneio/version.py,sha256=rJDui3QaSbG5XAefsT7-R72wn-eEkq3cia9pkFCPBBU,41
81
+ boneIO-0.7.0.dev6.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
82
+ boneIO-0.7.0.dev6.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
83
+ boneIO-0.7.0.dev6.dist-info/METADATA,sha256=kZrIdKcI9WKh2t8Pj8KmoETz47_wUhZ-ywRm-ycOfN4,1749
84
+ boneIO-0.7.0.dev6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
85
+ boneIO-0.7.0.dev6.dist-info/RECORD,,
boneio/const.py CHANGED
@@ -112,6 +112,7 @@ MCP_ID = "mcp_id"
112
112
  PCA_ID = "pca_id"
113
113
  PCF_ID = "pcf_id"
114
114
  INIT_SLEEP = "init_sleep"
115
+ OUTPUT_GROUP = "output_group"
115
116
 
116
117
  # SENSOR CONST
117
118
  TEMPERATURE = "temperature"
@@ -148,3 +149,12 @@ ExpanderTypes = Literal[MCP23017, PCA9685, PCF8575]
148
149
  DEVICE_CLASS = "device_class"
149
150
  DallasBusTypes = Literal[DS2482, DALLAS]
150
151
  FILTERS = "filters"
152
+
153
+ cover_actions = {
154
+ "OPEN": "open",
155
+ "CLOSE": "close",
156
+ "TOGGLE": "toggle",
157
+ "STOP": "stop",
158
+ "TOGGLE_OPEN": "toggle_open",
159
+ "TOGGLE_CLOSE": "toggle_close",
160
+ }
boneio/cover.py CHANGED
@@ -109,7 +109,7 @@ class Cover(BasicMqtt):
109
109
  self._stop_cover(on_exit=True)
110
110
 
111
111
  @property
112
- def cover_state(self) -> CLOSED | OPEN:
112
+ def cover_state(self) -> str:
113
113
  """Current state of cover."""
114
114
  return CLOSED if self._closed else OPEN
115
115
 
@@ -0,0 +1,4 @@
1
+ """Group classes."""
2
+ from .output import OutputGroup
3
+
4
+ __all__ = ["OutputGroup"]
boneio/group/output.py ADDED
@@ -0,0 +1,64 @@
1
+ """Cover module."""
2
+ from __future__ import annotations
3
+ import logging
4
+ import asyncio
5
+ from typing import List
6
+
7
+ from boneio.const import COVER, SWITCH, ON, OFF
8
+ from boneio.relay.basic import BasicRelay
9
+
10
+ _LOGGER = logging.getLogger(__name__)
11
+
12
+
13
+ class OutputGroup(BasicRelay):
14
+ """Cover class of boneIO"""
15
+
16
+ def __init__(
17
+ self,
18
+ members: List[BasicRelay],
19
+ output_type: str = SWITCH,
20
+ restored_state: bool = True,
21
+ **kwargs,
22
+ ) -> None:
23
+ """Initialize cover class."""
24
+ self._loop = asyncio.get_event_loop()
25
+ super().__init__(
26
+ **kwargs, output_type=output_type, restored_state=restored_state, topic_type="group"
27
+ )
28
+ self._group_members = [x for x in members if x.output_type != COVER]
29
+ self._timer_handle = None
30
+ for member in self._group_members:
31
+ self._event_bus.add_output_listener(member.id, self.event_listener)
32
+
33
+ async def event_listener(self, relay_id=None) -> None:
34
+ """Listen for events called by children relays."""
35
+ state = OFF
36
+ for x in self._group_members:
37
+ if x.state == ON:
38
+ state = ON
39
+ break
40
+ if state != self._state or not relay_id:
41
+ self._state = state
42
+ self._loop.call_soon_threadsafe(self.send_state)
43
+
44
+ def turn_on(self) -> None:
45
+ """Call turn on action."""
46
+ for x in self._group_members:
47
+ asyncio.create_task(x.async_turn_on())
48
+
49
+ def turn_off(self) -> None:
50
+ """Call turn off action."""
51
+ for x in self._group_members:
52
+ asyncio.create_task(x.async_turn_off())
53
+
54
+ def toggle(self) -> None:
55
+ """Toggle group."""
56
+ _LOGGER.debug("Toggle relay.")
57
+ if self._state == ON:
58
+ self.turn_off()
59
+ else:
60
+ self.turn_on()
61
+
62
+ def send_state(self) -> None:
63
+ """Send state to Mqtt on action."""
64
+ self._send_message(topic=self._send_topic, payload=self.payload(), retain=True)
@@ -15,7 +15,7 @@ class AsyncUpdater:
15
15
  self._update_interval = update_interval or TimePeriod(seconds=60)
16
16
  self.manager.append_task(coro=self._refresh, name=self.id)
17
17
 
18
- async def _refresh(self):
18
+ async def _refresh(self) -> None:
19
19
  while True:
20
20
  if hasattr(self, "async_update"):
21
21
  update_interval = (
boneio/helper/config.py CHANGED
@@ -64,6 +64,9 @@ class ConfigHelper:
64
64
  if topic in self._autodiscovery_messages[ha_type]:
65
65
  return True
66
66
  return False
67
+
68
+ def clear_autodiscovery_type(self, ha_type: str):
69
+ self._autodiscovery_messages[ha_type] = {}
67
70
 
68
71
 
69
72
 
boneio/helper/events.py CHANGED
@@ -81,6 +81,7 @@ class EventBus:
81
81
  """Initialize handler"""
82
82
  self._loop = loop or asyncio.get_event_loop()
83
83
  self._listeners = {}
84
+ self._output_listeners = {}
84
85
  self._sigterm_listeners = []
85
86
  self._haonline_listeners = []
86
87
  self._timer_handle = _async_create_timer(self._loop, self._run_second_event)
@@ -102,6 +103,7 @@ class EventBus:
102
103
  """Function to call on exit. Should invoke all sigterm listeners."""
103
104
  _LOGGER.debug("Exiting process started.")
104
105
  self._listeners = {}
106
+ self._output_listeners = {}
105
107
  for target in self._sigterm_listeners:
106
108
  target()
107
109
  self._timer_handle()
@@ -118,6 +120,19 @@ class EventBus:
118
120
  """Add sigterm listener."""
119
121
  self._sigterm_listeners.append(target)
120
122
 
123
+ def add_output_listener(self, name, target):
124
+ """Add output listener."""
125
+ self._output_listeners[name] = ListenerJob(target=target)
126
+ return self._output_listeners[name]
127
+
128
+ def trigger_output_event(self, event):
129
+ asyncio.create_task(self.async_trigger_output_event(event=event))
130
+
131
+ async def async_trigger_output_event(self, event):
132
+ listener = self._output_listeners.get(event)
133
+ if listener:
134
+ await listener.target(event)
135
+
121
136
  def add_haonline_listener(self, target):
122
137
  """Add HA Online listener."""
123
138
  self._haonline_listeners.append(target)
boneio/helper/gpio.py CHANGED
@@ -115,7 +115,15 @@ class GpioBaseClass:
115
115
  self._press_callback = press_callback
116
116
  setup_input(pin=self._pin, pull_mode=gpio_mode)
117
117
 
118
+ def set_press_callback(self, press_callback: Callable[[ClickTypes, str, bool | None], None]) -> None:
119
+ self._press_callback = press_callback
120
+
118
121
  @property
119
122
  def is_pressed(self) -> bool:
120
123
  """Is button pressed."""
121
124
  return read_input(self._pin)
125
+
126
+ @property
127
+ def pin(self) -> str:
128
+ """Return configured pin."""
129
+ return self._pin
@@ -45,10 +45,10 @@ def ha_availabilty_message(
45
45
  }
46
46
 
47
47
 
48
- def ha_light_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
48
+ def ha_light_availabilty_message(id: str, topic: str = "boneIO", device_type: str = RELAY, **kwargs):
49
49
  """Create LIGHT availability topic for HA."""
50
- msg = ha_availabilty_message(device_type=RELAY, topic=topic, id=id, **kwargs)
51
- msg["command_topic"] = f"{topic}/cmd/{RELAY}/{id}/set"
50
+ msg = ha_availabilty_message(device_type=device_type, topic=topic, id=id, **kwargs)
51
+ msg["command_topic"] = f"{topic}/cmd/{device_type}/{id}/set"
52
52
  msg["payload_off"] = OFF
53
53
  msg["payload_on"] = ON
54
54
  msg["state_value_template"] = "{{ value_json.state }}"
@@ -79,10 +79,10 @@ def ha_button_availabilty_message(
79
79
  return msg
80
80
 
81
81
 
82
- def ha_switch_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
82
+ def ha_switch_availabilty_message(id: str, topic: str = "boneIO", device_type: str = RELAY, **kwargs):
83
83
  """Create SWITCH availability topic for HA."""
84
- msg = ha_availabilty_message(device_type=RELAY, topic=topic, id=id, **kwargs)
85
- msg["command_topic"] = f"{topic}/cmd/relay/{id}/set"
84
+ msg = ha_availabilty_message(device_type=device_type, topic=topic, id=id, **kwargs)
85
+ msg["command_topic"] = f"{topic}/cmd/{device_type}/{id}/set"
86
86
  msg["payload_off"] = OFF
87
87
  msg["payload_on"] = ON
88
88
  msg["value_template"] = "{{ value_json.state }}"
boneio/helper/loader.py CHANGED
@@ -41,9 +41,10 @@ from boneio.const import (
41
41
  ExpanderTypes,
42
42
  PCF,
43
43
  PCA,
44
- PCF_ID
44
+ PCF_ID,
45
45
  )
46
46
  from boneio.cover import Cover
47
+ from boneio.group import OutputGroup
47
48
  from boneio.helper import (
48
49
  GPIOInputException,
49
50
  GPIOOutputException,
@@ -65,7 +66,11 @@ from boneio.helper.ha_discovery import ha_cover_availabilty_message
65
66
  from boneio.helper.timeperiod import TimePeriod
66
67
  from boneio.helper.pcf8575 import PCF8575
67
68
  from boneio.input import GpioEventButton, GpioEventButtonBeta
68
- from boneio.sensor import DallasSensorDS2482, GpioInputBinarySensor, GpioInputBinarySensorBeta
69
+ from boneio.sensor import (
70
+ DallasSensorDS2482,
71
+ GpioInputBinarySensor,
72
+ GpioInputBinarySensorBeta,
73
+ )
69
74
  from boneio.sensor.temp.dallas import DallasSensorW1
70
75
 
71
76
  # Typing imports that create a circular dependency
@@ -154,24 +159,19 @@ def create_temp_sensor(
154
159
  pass
155
160
 
156
161
 
157
- expander_class = {
158
- MCP: MCP23017,
159
- PCA: PCA9685,
160
- PCF: PCF8575
161
- }
162
+ expander_class = {MCP: MCP23017, PCA: PCA9685, PCF: PCF8575}
162
163
 
163
164
 
164
165
  def create_expander(
165
- expander_dict: dict,
166
- expander_config: list,
167
- exp_type: ExpanderTypes,
168
- i2cbusio: I2C
166
+ expander_dict: dict, expander_config: list, exp_type: ExpanderTypes, i2cbusio: I2C
169
167
  ) -> dict:
170
168
  grouped_outputs = {}
171
169
  for expander in expander_config:
172
170
  id = expander[ID] or expander[ADDRESS]
173
171
  try:
174
- expander_dict[id] = expander_class[exp_type](i2c=i2cbusio, address=expander[ADDRESS], reset=False)
172
+ expander_dict[id] = expander_class[exp_type](
173
+ i2c=i2cbusio, address=expander[ADDRESS], reset=False
174
+ )
175
175
  sleep_time = expander.get(INIT_SLEEP, TimePeriod(seconds=0))
176
176
  if sleep_time.total_seconds > 0:
177
177
  _LOGGER.debug(
@@ -179,9 +179,7 @@ def create_expander(
179
179
  )
180
180
  time.sleep(sleep_time.total_seconds)
181
181
  else:
182
- _LOGGER.debug(
183
- f"{exp_type} {id} is initializing."
184
- )
182
+ _LOGGER.debug(f"{exp_type} {id} is initializing.")
185
183
  grouped_outputs[id] = {}
186
184
  except TimeoutError as err:
187
185
  _LOGGER.error("Can't connect to %s %s. %s", exp_type, id, err)
@@ -216,26 +214,54 @@ def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
216
214
  pass
217
215
 
218
216
 
219
- OutputEntry = namedtuple("OutputEntry", "OutputClass output_kind output_id")
217
+ OutputEntry = namedtuple("OutputEntry", "OutputClass output_kind expander_id")
220
218
 
221
219
 
222
220
  def output_chooser(output_kind: str, config):
223
221
  """Get named tuple based on input."""
224
222
  if output_kind == MCP:
225
- output_id = config.pop(MCP_ID, None)
226
- return OutputEntry(MCPRelay, MCP, output_id)
223
+ expander_id = config.pop(MCP_ID, None)
224
+ return OutputEntry(MCPRelay, MCP, expander_id)
227
225
  elif output_kind == GPIO:
228
226
  return OutputEntry(GpioRelay, GPIO, GPIO)
229
227
  elif output_kind == PCA:
230
- output_id = config.pop(PCA_ID, None)
231
- return OutputEntry(PWMPCA, PCA, output_id)
228
+ expander_id = config.pop(PCA_ID, None)
229
+ return OutputEntry(PWMPCA, PCA, expander_id)
232
230
  elif output_kind == PCF:
233
- output_id = config.pop(PCF_ID, None)
234
- return OutputEntry(PCFRelay, PCF, output_id)
231
+ expander_id = config.pop(PCF_ID, None)
232
+ return OutputEntry(PCFRelay, PCF, expander_id)
235
233
  else:
236
234
  raise GPIOOutputException(f"""Output type {output_kind} dont exists""")
237
235
 
238
236
 
237
+ def configure_output_group(
238
+ manager: Manager,
239
+ state_manager: StateManager,
240
+ topic_prefix: str,
241
+ relay_id: str,
242
+ config: dict,
243
+ **kwargs
244
+ ) -> Any:
245
+ """Configure kind of relay. Most common MCP."""
246
+ restore_state = config.pop(RESTORE_STATE, False)
247
+ _id = config.pop(ID)
248
+ restored_state = (
249
+ state_manager.get(attr_type=RELAY, attr=relay_id, default_value=False)
250
+ if restore_state
251
+ else False
252
+ )
253
+
254
+ output = OutputGroup(
255
+ send_message=manager.send_message,
256
+ topic_prefix=topic_prefix,
257
+ id=_id,
258
+ restored_state=restored_state,
259
+ callback=lambda: None,
260
+ **config,
261
+ **kwargs)
262
+ return output
263
+
264
+
239
265
  def configure_relay(
240
266
  manager: Manager,
241
267
  state_manager: StateManager,
@@ -243,6 +269,7 @@ def configure_relay(
243
269
  relay_id: str,
244
270
  relay_callback: Callable,
245
271
  config: dict,
272
+ **kwargs
246
273
  ) -> Any:
247
274
  """Configure kind of relay. Most common MCP."""
248
275
  restore_state = config.pop(RESTORE_STATE, False)
@@ -259,42 +286,42 @@ def configure_relay(
259
286
  output = output_chooser(output_kind=config.pop(KIND), config=config)
260
287
 
261
288
  if getattr(output, "output_kind") == MCP:
262
- mcp = manager.mcp.get(getattr(output, "output_id"))
289
+ mcp = manager.mcp.get(getattr(output, "expander_id"))
263
290
  if not mcp:
264
291
  _LOGGER.error("No such MCP configured!")
265
292
  return None
266
- kwargs = {
293
+ extra_args = {
267
294
  "pin": int(config.pop(PIN)),
268
295
  "mcp": mcp,
269
- "mcp_id": getattr(output, "output_id"),
296
+ "mcp_id": getattr(output, "expander_id"),
270
297
  "output_type": output_type,
271
298
  }
272
299
  elif getattr(output, "output_kind") == PCA:
273
- pca = manager.pca.get(getattr(output, "output_id"))
300
+ pca = manager.pca.get(getattr(output, "expander_id"))
274
301
  if not pca:
275
302
  _LOGGER.error("No such PCA configured!")
276
303
  return None
277
- kwargs = {
304
+ extra_args = {
278
305
  "pin": int(config.pop(PIN)),
279
306
  "pca": pca,
280
- "pca_id": getattr(output, "output_id"),
307
+ "pca_id": getattr(output, "expander_id"),
281
308
  "output_type": output_type,
282
309
  }
283
310
  elif getattr(output, "output_kind") == PCF:
284
- expander = manager.pcf.get(getattr(output, "output_id"))
311
+ expander = manager.pcf.get(getattr(output, "expander_id"))
285
312
  if not expander:
286
313
  _LOGGER.error("No such PCF configured!")
287
314
  return None
288
- kwargs = {
315
+ extra_args = {
289
316
  "pin": int(config.pop(PIN)),
290
317
  "expander": expander,
291
- "expander_id": getattr(output, "output_id"),
318
+ "expander_id": getattr(output, "expander_id"),
292
319
  "output_type": output_type,
293
320
  }
294
321
  elif getattr(output, "output_kind") == GPIO:
295
322
  if GPIO not in manager.grouped_outputs:
296
323
  manager.grouped_outputs[GPIO] = {}
297
- kwargs = {
324
+ extra_args = {
298
325
  "pin": config.pop(PIN),
299
326
  }
300
327
  else:
@@ -310,13 +337,14 @@ def configure_relay(
310
337
  restored_state=restored_state,
311
338
  **config,
312
339
  **kwargs,
340
+ **extra_args,
313
341
  callback=lambda: relay_callback(
314
- relay_type=getattr(output, "output_id"),
342
+ expander_id=getattr(output, "expander_id"),
315
343
  relay_id=relay_id,
316
344
  restore_state=False if output_type == NONE else restore_state,
317
345
  ),
318
346
  )
319
- manager.grouped_outputs[getattr(output, "output_id")][relay_id] = relay
347
+ manager.grouped_outputs[getattr(output, "expander_id")][relay_id] = relay
320
348
  return relay
321
349
 
322
350
 
@@ -335,7 +363,9 @@ def input_chooser(input_type: str):
335
363
  ha_binary_sensor_availabilty_message,
336
364
  )
337
365
  else:
338
- return InputEntry(GpioEventButton, INPUT, EVENT_ENTITY, ha_event_availabilty_message)
366
+ return InputEntry(
367
+ GpioEventButton, INPUT, EVENT_ENTITY, ha_event_availabilty_message
368
+ )
339
369
 
340
370
 
341
371
  def configure_event_sensor(
@@ -343,22 +373,40 @@ def configure_event_sensor(
343
373
  pin: str,
344
374
  press_callback: Callable,
345
375
  send_ha_autodiscovery: Callable,
346
- ) -> str:
376
+ input: GpioEventButton | GpioEventButtonBeta | None = None
377
+ ) -> GpioEventButton | GpioEventButtonBeta | None:
347
378
  """Configure input sensor or button."""
348
379
  try:
349
- GpioEventButtonClass = GpioEventButton if gpio.get("detection_type", "stable") == "stable" else GpioEventButtonBeta
350
- GpioEventButtonClass(
351
- pin=pin,
352
- press_callback=lambda x, i, z: press_callback(
380
+ GpioEventButtonClass = (
381
+ GpioEventButton
382
+ if gpio.get("detection_type", "stable") == "stable"
383
+ else GpioEventButtonBeta
384
+ )
385
+ if input:
386
+ if not isinstance(input, GpioEventButtonClass):
387
+ _LOGGER.warn("You preconfigured type of input. It's forbidden. Please restart boneIO.")
388
+ return input
389
+ input.set_press_callback(press_callback=lambda x, i, z: press_callback(
353
390
  x=x,
354
391
  inpin=i,
355
392
  actions=gpio.get(ACTIONS, {}).get(x, []),
356
393
  input_type=INPUT,
357
394
  empty_message_after=gpio.get("clear_message", False),
358
- duration=z
359
- ),
360
- **gpio,
361
- )
395
+ duration=z,
396
+ ))
397
+ else:
398
+ input = GpioEventButtonClass(
399
+ pin=pin,
400
+ press_callback=lambda x, i, z: press_callback(
401
+ x=x,
402
+ inpin=i,
403
+ actions=gpio.get(ACTIONS, {}).get(x, []),
404
+ input_type=INPUT,
405
+ empty_message_after=gpio.get("clear_message", False),
406
+ duration=z,
407
+ ),
408
+ **gpio,
409
+ )
362
410
  if gpio.get(SHOW_HA, True):
363
411
  send_ha_autodiscovery(
364
412
  id=pin,
@@ -367,31 +415,50 @@ def configure_event_sensor(
367
415
  device_class=gpio.get(DEVICE_CLASS, None),
368
416
  availability_msg_func=ha_event_availabilty_message,
369
417
  )
370
- return pin
418
+ return input
371
419
  except GPIOInputException as err:
372
420
  _LOGGER.error("This PIN %s can't be configured. %s", pin, err)
373
421
  pass
374
422
 
423
+
375
424
  def configure_binary_sensor(
376
425
  gpio: dict,
377
426
  pin: str,
378
427
  press_callback: Callable,
379
428
  send_ha_autodiscovery: Callable,
380
- ) -> str:
429
+ input: GpioInputBinarySensor | GpioInputBinarySensorBeta | None = None
430
+ ) -> GpioInputBinarySensor | GpioInputBinarySensorBeta | None:
381
431
  """Configure input sensor or button."""
382
432
  try:
383
- GpioInputBinarySensorClass = GpioInputBinarySensor if gpio.get("detection_type", "stable") == "stable" else GpioInputBinarySensorBeta
384
- GpioInputBinarySensorClass(
385
- pin=pin,
386
- press_callback=lambda x, i: press_callback(
433
+ GpioInputBinarySensorClass = (
434
+ GpioInputBinarySensor
435
+ if gpio.get("detection_type", "stable") == "stable"
436
+ else GpioInputBinarySensorBeta
437
+ )
438
+ if input:
439
+ if not isinstance(input, GpioInputBinarySensorClass):
440
+ _LOGGER.warn("You preconfigured type of input. It's forbidden. Please restart boneIO.")
441
+ return input
442
+ input.set_press_callback(press_callback=lambda x, i, z: press_callback(
387
443
  x=x,
388
444
  inpin=i,
389
445
  actions=gpio.get(ACTIONS, {}).get(x, []),
390
- input_type=INPUT_SENSOR,
391
- empty_message_after=gpio.get("clear_message", False)
392
- ),
393
- **gpio,
394
- )
446
+ input_type=INPUT,
447
+ empty_message_after=gpio.get("clear_message", False),
448
+ duration=z,
449
+ ))
450
+ else:
451
+ input = GpioInputBinarySensorClass(
452
+ pin=pin,
453
+ press_callback=lambda x, i: press_callback(
454
+ x=x,
455
+ inpin=i,
456
+ actions=gpio.get(ACTIONS, {}).get(x, []),
457
+ input_type=INPUT_SENSOR,
458
+ empty_message_after=gpio.get("clear_message", False),
459
+ ),
460
+ **gpio,
461
+ )
395
462
  if gpio.get(SHOW_HA, True):
396
463
  send_ha_autodiscovery(
397
464
  id=pin,
@@ -400,11 +467,12 @@ def configure_binary_sensor(
400
467
  device_class=gpio.get(DEVICE_CLASS, None),
401
468
  availability_msg_func=ha_binary_sensor_availabilty_message,
402
469
  )
403
- return pin
470
+ return input
404
471
  except GPIOInputException as err:
405
472
  _LOGGER.error("This PIN %s can't be configured. %s", pin, err)
406
473
  pass
407
474
 
475
+
408
476
  def configure_cover(
409
477
  manager: Manager,
410
478
  cover_id: str,
@@ -440,6 +508,7 @@ def configure_cover(
440
508
  device_class=config.get(DEVICE_CLASS),
441
509
  availability_msg_func=ha_cover_availabilty_message,
442
510
  )
511
+ _LOGGER.debug("Configured cover %s", cover_id)
443
512
  return cover
444
513
 
445
514