boneIO 0.9.0.dev7__py3-none-any.whl → 0.9.0.dev9__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.
- boneio/boards/0.7/input.yaml +110 -0
- boneio/helper/events.py +75 -23
- boneio/helper/gpio.py +5 -1
- boneio/helper/ha_discovery.py +3 -3
- boneio/helper/loader.py +35 -12
- boneio/helper/stats.py +32 -12
- boneio/manager.py +42 -24
- boneio/modbus/sensor.py +4 -1
- boneio/models/__init__.py +9 -1
- boneio/oled.py +82 -27
- boneio/relay/basic.py +10 -5
- boneio/relay/mcp.py +0 -5
- boneio/relay/pcf.py +1 -7
- boneio/schema/schema.yaml +5 -0
- boneio/sensor/serial_number.py +39 -0
- boneio/version.py +1 -1
- boneio/webui/app.py +8 -9
- boneio/webui/frontend-dist/assets/{index-JxJAopze.js → index-Bzix_ULo.js} +14 -14
- boneio/webui/frontend-dist/assets/{index-Bs_Dk8Uy.css → index-Dt_UdFzp.css} +1 -1
- boneio/webui/frontend-dist/index.html +2 -2
- boneio/webui/web_server.py +2 -0
- {boneio-0.9.0.dev7.dist-info → boneio-0.9.0.dev9.dist-info}/METADATA +2 -1
- {boneio-0.9.0.dev7.dist-info → boneio-0.9.0.dev9.dist-info}/RECORD +26 -24
- {boneio-0.9.0.dev7.dist-info → boneio-0.9.0.dev9.dist-info}/WHEEL +0 -0
- {boneio-0.9.0.dev7.dist-info → boneio-0.9.0.dev9.dist-info}/entry_points.txt +0 -0
- {boneio-0.9.0.dev7.dist-info → boneio-0.9.0.dev9.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
input_mapping:
|
|
2
|
+
in_01:
|
|
3
|
+
pin: P8_37
|
|
4
|
+
gpio_mode: gpio_pu
|
|
5
|
+
in_02:
|
|
6
|
+
pin: P8_38
|
|
7
|
+
gpio_mode: gpio_pu
|
|
8
|
+
in_03:
|
|
9
|
+
pin: P8_39
|
|
10
|
+
in_04:
|
|
11
|
+
pin: P8_40
|
|
12
|
+
in_05:
|
|
13
|
+
pin: P8_41
|
|
14
|
+
in_06:
|
|
15
|
+
pin: P8_42
|
|
16
|
+
in_07:
|
|
17
|
+
pin: P8_43
|
|
18
|
+
in_08:
|
|
19
|
+
pin: P8_44
|
|
20
|
+
in_09:
|
|
21
|
+
pin: P8_45
|
|
22
|
+
in_10:
|
|
23
|
+
pin: P8_46
|
|
24
|
+
gpio_mode: gpio_pu
|
|
25
|
+
in_11:
|
|
26
|
+
pin: P9_42
|
|
27
|
+
in_12:
|
|
28
|
+
pin: P9_31
|
|
29
|
+
in_13:
|
|
30
|
+
pin: P9_30
|
|
31
|
+
in_14:
|
|
32
|
+
pin: P9_29
|
|
33
|
+
in_15:
|
|
34
|
+
pin: P9_28
|
|
35
|
+
in_16:
|
|
36
|
+
pin: P9_27
|
|
37
|
+
in_17:
|
|
38
|
+
pin: P9_25
|
|
39
|
+
in_18:
|
|
40
|
+
pin: P9_23
|
|
41
|
+
in_19:
|
|
42
|
+
pin: P9_22
|
|
43
|
+
gpio_mode: gpio_pu
|
|
44
|
+
in_20:
|
|
45
|
+
pin: P9_21
|
|
46
|
+
gpio_mode: gpio_pu
|
|
47
|
+
in_21:
|
|
48
|
+
pin: P9_18
|
|
49
|
+
in_22:
|
|
50
|
+
pin: P9_17
|
|
51
|
+
in_23:
|
|
52
|
+
pin: P9_16
|
|
53
|
+
in_24:
|
|
54
|
+
pin: P9_15
|
|
55
|
+
in_25:
|
|
56
|
+
pin: P9_14
|
|
57
|
+
in_26:
|
|
58
|
+
pin: P8_7
|
|
59
|
+
in_27:
|
|
60
|
+
pin: P8_8
|
|
61
|
+
in_28:
|
|
62
|
+
pin: P8_9
|
|
63
|
+
in_29:
|
|
64
|
+
pin: P8_36
|
|
65
|
+
gpio_mode: gpio_pu
|
|
66
|
+
in_30:
|
|
67
|
+
pin: P8_35
|
|
68
|
+
gpio_mode: gpio_pu
|
|
69
|
+
in_31:
|
|
70
|
+
pin: P8_34
|
|
71
|
+
gpio_mode: gpio_pu
|
|
72
|
+
in_32:
|
|
73
|
+
pin: P8_33
|
|
74
|
+
gpio_mode: gpio_pu
|
|
75
|
+
in_33:
|
|
76
|
+
pin: P8_32
|
|
77
|
+
gpio_mode: gpio_pu
|
|
78
|
+
in_34:
|
|
79
|
+
pin: P8_31
|
|
80
|
+
gpio_mode: gpio_pu
|
|
81
|
+
in_35:
|
|
82
|
+
pin: P8_30
|
|
83
|
+
in_36:
|
|
84
|
+
pin: P8_29
|
|
85
|
+
in_37:
|
|
86
|
+
pin: P8_28
|
|
87
|
+
in_38:
|
|
88
|
+
pin: P8_27
|
|
89
|
+
in_39:
|
|
90
|
+
pin: P8_26
|
|
91
|
+
in_40:
|
|
92
|
+
pin: P8_19
|
|
93
|
+
in_41:
|
|
94
|
+
pin: P8_18
|
|
95
|
+
in_42:
|
|
96
|
+
pin: P8_17
|
|
97
|
+
in_43:
|
|
98
|
+
pin: P8_16
|
|
99
|
+
in_44:
|
|
100
|
+
pin: P8_15
|
|
101
|
+
in_45:
|
|
102
|
+
pin: P8_14
|
|
103
|
+
in_46:
|
|
104
|
+
pin: P8_13
|
|
105
|
+
in_47:
|
|
106
|
+
pin: P8_12
|
|
107
|
+
in_48:
|
|
108
|
+
pin: P8_11
|
|
109
|
+
in_49:
|
|
110
|
+
pin: P8_10
|
boneio/helper/events.py
CHANGED
|
@@ -86,7 +86,15 @@ class EventBus:
|
|
|
86
86
|
self._loop = loop or asyncio.get_event_loop()
|
|
87
87
|
self._every_second_listeners = {}
|
|
88
88
|
self._output_listeners = {}
|
|
89
|
-
self._event_listeners = {
|
|
89
|
+
self._event_listeners = {
|
|
90
|
+
"input": {},
|
|
91
|
+
"output": {},
|
|
92
|
+
"modbus_sensor": {},
|
|
93
|
+
"sensor": {},
|
|
94
|
+
"host": {}
|
|
95
|
+
}
|
|
96
|
+
# Index to track listener_ids across all event types
|
|
97
|
+
self._listener_id_index = {}
|
|
90
98
|
self._sigterm_listeners = []
|
|
91
99
|
self._haonline_listeners = []
|
|
92
100
|
self._timer_handle = _async_create_timer(
|
|
@@ -188,7 +196,7 @@ class EventBus:
|
|
|
188
196
|
"""Add sigterm listener."""
|
|
189
197
|
self._sigterm_listeners.append(target)
|
|
190
198
|
|
|
191
|
-
def add_output_listener(self, output_id, listener_id, target):
|
|
199
|
+
def add_output_listener(self, output_id, listener_id, target) -> ListenerJob:
|
|
192
200
|
"""Add output listener.
|
|
193
201
|
|
|
194
202
|
listener_id is typically group_id for group outputs or ws (websocket)
|
|
@@ -200,7 +208,7 @@ class EventBus:
|
|
|
200
208
|
listener.set_target(target)
|
|
201
209
|
return listener
|
|
202
210
|
self._output_listeners[output_id][listener_id] = ListenerJob(target=target)
|
|
203
|
-
return self._output_listeners[output_id]
|
|
211
|
+
return self._output_listeners[output_id][listener_id]
|
|
204
212
|
|
|
205
213
|
def remove_output_listener(self, output_id, listener_id):
|
|
206
214
|
"""Add output listener.
|
|
@@ -215,36 +223,80 @@ class EventBus:
|
|
|
215
223
|
for listener in listeners.values():
|
|
216
224
|
await listener.target(event)
|
|
217
225
|
|
|
218
|
-
def
|
|
219
|
-
"""
|
|
226
|
+
async def async_trigger_event(self, event_type: str, entity_id: str, event: Any):
|
|
227
|
+
"""Trigger event for all listeners of given type and entity."""
|
|
228
|
+
listeners = self._event_listeners.get(event_type, {}).get(entity_id, {})
|
|
229
|
+
for listener in listeners.values():
|
|
230
|
+
await listener.target(event)
|
|
231
|
+
|
|
232
|
+
def add_event_listener(
|
|
233
|
+
self, event_type: str, entity_id: str, listener_id: str, target
|
|
234
|
+
) -> ListenerJob:
|
|
235
|
+
"""Add event listener.
|
|
220
236
|
|
|
221
237
|
listener_id is typically group_id for group outputs or ws (websocket)
|
|
222
238
|
"""
|
|
223
|
-
if
|
|
224
|
-
|
|
239
|
+
if not target:
|
|
240
|
+
return
|
|
225
241
|
if entity_id not in self._event_listeners[event_type]:
|
|
226
242
|
self._event_listeners[event_type][entity_id] = {}
|
|
227
243
|
if listener_id in self._event_listeners[event_type][entity_id]:
|
|
228
244
|
listener = self._event_listeners[event_type][entity_id][listener_id]
|
|
229
245
|
listener.set_target(target)
|
|
230
246
|
return listener
|
|
231
|
-
self._event_listeners[event_type][entity_id][listener_id] = ListenerJob(target=target)
|
|
232
|
-
return self._event_listeners[event_type][entity_id][listener_id]
|
|
233
247
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
# Add to main listeners
|
|
249
|
+
listener_job = ListenerJob(target=target)
|
|
250
|
+
self._event_listeners[event_type][entity_id][listener_id] = listener_job
|
|
251
|
+
|
|
252
|
+
# Add to index
|
|
253
|
+
if listener_id not in self._listener_id_index:
|
|
254
|
+
self._listener_id_index[listener_id] = []
|
|
255
|
+
self._listener_id_index[listener_id].append((event_type, entity_id))
|
|
256
|
+
|
|
257
|
+
return listener_job
|
|
258
|
+
|
|
259
|
+
def remove_event_listener(self, event_type: str = None, entity_id: str = None, listener_id: str = None) -> None:
|
|
260
|
+
"""Remove event listener. Can remove by event_type, listener_id, or both."""
|
|
261
|
+
if listener_id and listener_id in self._listener_id_index:
|
|
262
|
+
# Remove by listener_id
|
|
263
|
+
for evt_type, ent_id in self._listener_id_index[listener_id]:
|
|
264
|
+
if event_type and evt_type != event_type:
|
|
265
|
+
continue
|
|
266
|
+
if entity_id and ent_id != entity_id:
|
|
267
|
+
continue
|
|
268
|
+
if ent_id in self._event_listeners[evt_type]:
|
|
269
|
+
if listener_id in self._event_listeners[evt_type][ent_id]:
|
|
270
|
+
del self._event_listeners[evt_type][ent_id][listener_id]
|
|
271
|
+
if not self._event_listeners[evt_type][ent_id]:
|
|
272
|
+
del self._event_listeners[evt_type][ent_id]
|
|
273
|
+
|
|
274
|
+
if event_type is None and entity_id is None:
|
|
275
|
+
# If removing all references to this listener_id
|
|
276
|
+
del self._listener_id_index[listener_id]
|
|
277
|
+
else:
|
|
278
|
+
# Update index to remove only specific references
|
|
279
|
+
self._listener_id_index[listener_id] = [
|
|
280
|
+
(evt_type, ent_id)
|
|
281
|
+
for evt_type, ent_id in self._listener_id_index[listener_id]
|
|
282
|
+
if (event_type and evt_type != event_type) or (entity_id and ent_id != entity_id)
|
|
283
|
+
]
|
|
284
|
+
if not self._listener_id_index[listener_id]:
|
|
285
|
+
del self._listener_id_index[listener_id]
|
|
286
|
+
|
|
287
|
+
elif event_type:
|
|
288
|
+
# Remove by event_type
|
|
289
|
+
if entity_id:
|
|
290
|
+
# Remove specific entity
|
|
291
|
+
if entity_id in self._event_listeners[event_type]:
|
|
292
|
+
for lid in list(self._event_listeners[event_type][entity_id].keys()):
|
|
293
|
+
self.remove_event_listener(event_type, entity_id, lid)
|
|
294
|
+
del self._event_listeners[event_type][entity_id]
|
|
295
|
+
else:
|
|
296
|
+
# Remove entire event_type
|
|
297
|
+
for ent_id in list(self._event_listeners[event_type].keys()):
|
|
298
|
+
for lid in list(self._event_listeners[event_type][ent_id].keys()):
|
|
299
|
+
self.remove_event_listener(event_type, ent_id, lid)
|
|
248
300
|
|
|
249
301
|
def add_haonline_listener(self, target: Callable) -> None:
|
|
250
302
|
"""Add HA Online listener."""
|
boneio/helper/gpio.py
CHANGED
|
@@ -194,7 +194,7 @@ class GpioBaseClass:
|
|
|
194
194
|
timestamp=self.last_press_timestamp,
|
|
195
195
|
boneio_input=self.boneio_input,
|
|
196
196
|
)
|
|
197
|
-
await self._event_bus.async_trigger_event(event_type="input", entity_id=self.
|
|
197
|
+
await self._event_bus.async_trigger_event(event_type="input", entity_id=self.id, event=event)
|
|
198
198
|
|
|
199
199
|
def set_actions(self, actions: dict) -> None:
|
|
200
200
|
self._actions = actions
|
|
@@ -222,6 +222,10 @@ class GpioBaseClass:
|
|
|
222
222
|
"""Return configured pin."""
|
|
223
223
|
return self._pin
|
|
224
224
|
|
|
225
|
+
@property
|
|
226
|
+
def id(self) -> str:
|
|
227
|
+
return self._pin
|
|
228
|
+
|
|
225
229
|
@property
|
|
226
230
|
def last_state(self) -> str:
|
|
227
231
|
return self._last_state
|
boneio/helper/ha_discovery.py
CHANGED
|
@@ -3,19 +3,19 @@ from boneio.const import (
|
|
|
3
3
|
CLOSED,
|
|
4
4
|
CLOSING,
|
|
5
5
|
COVER,
|
|
6
|
+
DOUBLE,
|
|
6
7
|
INPUT,
|
|
7
8
|
INPUT_SENSOR,
|
|
9
|
+
LONG,
|
|
8
10
|
OFF,
|
|
9
11
|
ON,
|
|
10
12
|
OPEN,
|
|
11
13
|
OPENING,
|
|
12
14
|
RELAY,
|
|
13
15
|
SENSOR,
|
|
16
|
+
SINGLE,
|
|
14
17
|
STATE,
|
|
15
18
|
STOP,
|
|
16
|
-
SINGLE,
|
|
17
|
-
DOUBLE,
|
|
18
|
-
LONG
|
|
19
19
|
)
|
|
20
20
|
from boneio.version import __version__
|
|
21
21
|
|
boneio/helper/loader.py
CHANGED
|
@@ -56,7 +56,10 @@ from boneio.helper import (
|
|
|
56
56
|
ha_sensor_temp_availabilty_message,
|
|
57
57
|
)
|
|
58
58
|
from boneio.helper.events import EventBus
|
|
59
|
-
from boneio.helper.ha_discovery import
|
|
59
|
+
from boneio.helper.ha_discovery import (
|
|
60
|
+
ha_cover_availabilty_message,
|
|
61
|
+
ha_sensor_availabilty_message,
|
|
62
|
+
)
|
|
60
63
|
from boneio.helper.onewire import (
|
|
61
64
|
DS2482,
|
|
62
65
|
DS2482_ADDRESS,
|
|
@@ -67,12 +70,12 @@ from boneio.helper.onewire import (
|
|
|
67
70
|
from boneio.helper.pcf8575 import PCF8575
|
|
68
71
|
from boneio.helper.timeperiod import TimePeriod
|
|
69
72
|
from boneio.input import GpioEventButtonNew, GpioEventButtonOld
|
|
70
|
-
from boneio.models import OutputState
|
|
71
73
|
from boneio.sensor import (
|
|
72
74
|
DallasSensorDS2482,
|
|
73
75
|
GpioInputBinarySensorNew,
|
|
74
76
|
GpioInputBinarySensorOld,
|
|
75
77
|
)
|
|
78
|
+
from boneio.sensor.serial_number import SerialNumberSensor
|
|
76
79
|
from boneio.sensor.temp.dallas import DallasSensorW1
|
|
77
80
|
|
|
78
81
|
# Typing imports that create a circular dependency
|
|
@@ -166,6 +169,27 @@ def create_temp_sensor(
|
|
|
166
169
|
pass
|
|
167
170
|
|
|
168
171
|
|
|
172
|
+
def create_serial_number_sensor(
|
|
173
|
+
manager: Manager,
|
|
174
|
+
topic_prefix: str,
|
|
175
|
+
):
|
|
176
|
+
"""Create Serial number sensor in manager."""
|
|
177
|
+
sensor = SerialNumberSensor(
|
|
178
|
+
id="serial_number",
|
|
179
|
+
name="Serial number",
|
|
180
|
+
manager=manager,
|
|
181
|
+
send_message=manager.send_message,
|
|
182
|
+
topic_prefix=topic_prefix,
|
|
183
|
+
)
|
|
184
|
+
manager.send_ha_autodiscovery(
|
|
185
|
+
id="serial_number",
|
|
186
|
+
name="Serial number",
|
|
187
|
+
ha_type=SENSOR,
|
|
188
|
+
entity_category="diagnostic",
|
|
189
|
+
availability_msg_func=ha_sensor_availabilty_message,
|
|
190
|
+
)
|
|
191
|
+
return sensor
|
|
192
|
+
|
|
169
193
|
expander_class = {MCP: MCP23017, PCA: PCA9685, PCF: PCF8575}
|
|
170
194
|
|
|
171
195
|
|
|
@@ -275,12 +299,11 @@ def configure_relay(
|
|
|
275
299
|
topic_prefix: str,
|
|
276
300
|
relay_id: str,
|
|
277
301
|
name: str,
|
|
278
|
-
relay_callback: Callable,
|
|
279
302
|
config: dict,
|
|
303
|
+
restore_state: bool = False,
|
|
280
304
|
**kwargs,
|
|
281
305
|
) -> Any:
|
|
282
306
|
"""Configure kind of relay. Most common MCP."""
|
|
283
|
-
restore_state = config.pop(RESTORE_STATE, False)
|
|
284
307
|
output_type = config.pop(OUTPUT_TYPE)
|
|
285
308
|
restored_state = (
|
|
286
309
|
state_manager.get(attr_type=RELAY, attr=relay_id, default_value=False)
|
|
@@ -342,13 +365,13 @@ def configure_relay(
|
|
|
342
365
|
)
|
|
343
366
|
return
|
|
344
367
|
|
|
345
|
-
# Create async callback wrapper
|
|
346
|
-
async def relay_callback_wrapper(event: OutputState):
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
368
|
+
# # Create async callback wrapper
|
|
369
|
+
# async def relay_callback_wrapper(event: OutputState):
|
|
370
|
+
# await relay_callback(
|
|
371
|
+
# expander_id=expander_id,
|
|
372
|
+
# event=event,
|
|
373
|
+
# restore_state=False if output_type == NONE else restore_state,
|
|
374
|
+
# )
|
|
352
375
|
|
|
353
376
|
relay = getattr(output, "OutputClass")(
|
|
354
377
|
send_message=manager.send_message,
|
|
@@ -359,7 +382,7 @@ def configure_relay(
|
|
|
359
382
|
**config,
|
|
360
383
|
**kwargs,
|
|
361
384
|
**extra_args,
|
|
362
|
-
callback=relay_callback_wrapper,
|
|
385
|
+
# callback=relay_callback_wrapper,
|
|
363
386
|
)
|
|
364
387
|
manager.grouped_outputs[expander_id][relay_id] = relay
|
|
365
388
|
return relay
|
boneio/helper/stats.py
CHANGED
|
@@ -4,7 +4,6 @@ import asyncio
|
|
|
4
4
|
import logging
|
|
5
5
|
import socket
|
|
6
6
|
import time
|
|
7
|
-
from functools import partial
|
|
8
7
|
from math import floor
|
|
9
8
|
|
|
10
9
|
# Typing imports that create a circular dependency
|
|
@@ -28,7 +27,9 @@ from boneio.const import (
|
|
|
28
27
|
SWAP,
|
|
29
28
|
UPTIME,
|
|
30
29
|
)
|
|
30
|
+
from boneio.helper.events import EventBus
|
|
31
31
|
from boneio.helper.gpio import GpioBaseClass
|
|
32
|
+
from boneio.models import HostSensorState
|
|
32
33
|
|
|
33
34
|
if TYPE_CHECKING:
|
|
34
35
|
from boneio.manager import Manager
|
|
@@ -124,8 +125,8 @@ class HostSensor(AsyncUpdater):
|
|
|
124
125
|
|
|
125
126
|
def __init__(
|
|
126
127
|
self,
|
|
128
|
+
event_bus: EventBus,
|
|
127
129
|
update_function: Callable,
|
|
128
|
-
manager_callback: Callable,
|
|
129
130
|
static_data: dict | None,
|
|
130
131
|
id: str,
|
|
131
132
|
type: str,
|
|
@@ -135,16 +136,21 @@ class HostSensor(AsyncUpdater):
|
|
|
135
136
|
self._static_data = static_data
|
|
136
137
|
self._state = {}
|
|
137
138
|
self._type = type
|
|
138
|
-
self.
|
|
139
|
+
self._event_bus = event_bus
|
|
139
140
|
self._loop = asyncio.get_event_loop()
|
|
140
141
|
self.id = id
|
|
141
142
|
super().__init__(**kwargs)
|
|
143
|
+
self._loop.create_task(self.async_update(time.time()))
|
|
142
144
|
|
|
143
145
|
async def async_update(self, timestamp: float) -> None:
|
|
144
146
|
self._state = self._update_function()
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
sensor_state = HostSensorState(
|
|
148
|
+
id=self.id,
|
|
149
|
+
name=self._type,
|
|
150
|
+
state="new_state", #doesn't matter here, as we fetch everything in Oled.
|
|
151
|
+
timestamp=timestamp,
|
|
147
152
|
)
|
|
153
|
+
await self._event_bus.async_trigger_event(event_type="host", entity_id=self.id, event=sensor_state)
|
|
148
154
|
|
|
149
155
|
@property
|
|
150
156
|
def state(self) -> dict:
|
|
@@ -160,14 +166,15 @@ class HostData:
|
|
|
160
166
|
self,
|
|
161
167
|
output: dict,
|
|
162
168
|
inputs: dict[str, GpioBaseClass],
|
|
163
|
-
callback: Callable,
|
|
164
169
|
temp_sensor: Callable[[LM75Sensor, MCP9808Sensor], None] | None,
|
|
165
170
|
ina219: INA219Class | None,
|
|
166
171
|
manager: Manager,
|
|
172
|
+
event_bus: EventBus,
|
|
167
173
|
enabled_screens: List[str],
|
|
168
174
|
extra_sensors: List[dict],
|
|
169
175
|
) -> None:
|
|
170
176
|
"""Initialize HostData."""
|
|
177
|
+
self._manager = manager
|
|
171
178
|
self._hostname = socket.gethostname()
|
|
172
179
|
self._temp_sensor = temp_sensor
|
|
173
180
|
host_stats = {
|
|
@@ -293,8 +300,8 @@ class HostData:
|
|
|
293
300
|
self._data[k] = HostSensor(
|
|
294
301
|
update_function=_v["f"],
|
|
295
302
|
static_data=_v.get("static"),
|
|
303
|
+
event_bus=event_bus,
|
|
296
304
|
manager=manager,
|
|
297
|
-
manager_callback=callback,
|
|
298
305
|
id=f"{k}_hoststats",
|
|
299
306
|
type=k,
|
|
300
307
|
update_interval=_v["update_interval"],
|
|
@@ -306,31 +313,44 @@ class HostData:
|
|
|
306
313
|
]
|
|
307
314
|
for i in range((len(inputs) + 24) // 25)
|
|
308
315
|
}
|
|
309
|
-
self._callback = callback
|
|
310
316
|
self._loop = asyncio.get_running_loop()
|
|
311
317
|
|
|
318
|
+
def web_url(self) -> str | None:
|
|
319
|
+
if not self._manager.is_web_on:
|
|
320
|
+
return None
|
|
321
|
+
network_state = self._data[NETWORK].state
|
|
322
|
+
if IP in network_state:
|
|
323
|
+
return f"http://{network_state[IP]}:{self._manager.web_bind_port}"
|
|
324
|
+
return None
|
|
325
|
+
|
|
312
326
|
def get(self, type: str) -> dict:
|
|
313
327
|
"""Get saved stats."""
|
|
314
328
|
if type in self._output:
|
|
315
329
|
return self._get_output(type)
|
|
316
330
|
if type in self._inputs:
|
|
317
331
|
return self._get_input(type)
|
|
332
|
+
if type == "web":
|
|
333
|
+
return self.web_url()
|
|
318
334
|
return self._data[type].state
|
|
319
335
|
|
|
320
336
|
def _get_output(self, type: str) -> dict:
|
|
321
337
|
"""Get stats for output."""
|
|
322
338
|
out = {}
|
|
323
339
|
for output in self._output[type].values():
|
|
324
|
-
out[output.id] =
|
|
340
|
+
out[output.id] = {
|
|
341
|
+
"name": output.name, "state": output.state
|
|
342
|
+
}
|
|
343
|
+
|
|
325
344
|
return out
|
|
326
345
|
|
|
327
346
|
def _get_input(self, type: str) -> dict:
|
|
328
347
|
"""Get stats for input."""
|
|
329
348
|
inputs = {}
|
|
330
349
|
for input in self._inputs[type]:
|
|
331
|
-
inputs[input.
|
|
332
|
-
|
|
333
|
-
|
|
350
|
+
inputs[input.id] = {
|
|
351
|
+
"name": input.name,
|
|
352
|
+
"state": input.last_state[0].upper() if input.last_state and input.last_state != "Unknown" else ""
|
|
353
|
+
}
|
|
334
354
|
return inputs
|
|
335
355
|
|
|
336
356
|
@property
|
boneio/manager.py
CHANGED
|
@@ -29,6 +29,7 @@ from boneio.const import (
|
|
|
29
29
|
MODBUS,
|
|
30
30
|
MQTT,
|
|
31
31
|
NONE,
|
|
32
|
+
ON,
|
|
32
33
|
ONEWIRE,
|
|
33
34
|
ONLINE,
|
|
34
35
|
OPEN,
|
|
@@ -37,6 +38,7 @@ from boneio.const import (
|
|
|
37
38
|
PCF,
|
|
38
39
|
PIN,
|
|
39
40
|
RELAY,
|
|
41
|
+
RESTORE_STATE,
|
|
40
42
|
SET_BRIGHTNESS,
|
|
41
43
|
STATE,
|
|
42
44
|
STOP,
|
|
@@ -69,6 +71,7 @@ from boneio.helper.loader import (
|
|
|
69
71
|
configure_relay,
|
|
70
72
|
create_dallas_sensor,
|
|
71
73
|
create_expander,
|
|
74
|
+
create_serial_number_sensor,
|
|
72
75
|
create_temp_sensor,
|
|
73
76
|
)
|
|
74
77
|
from boneio.helper.logger import configure_logger
|
|
@@ -122,6 +125,8 @@ class Manager:
|
|
|
122
125
|
self._config_file_path = config_file_path
|
|
123
126
|
self._state_manager = state_manager
|
|
124
127
|
self._event_bus = event_bus
|
|
128
|
+
self._is_web_on = False
|
|
129
|
+
self._web_bind_port = None
|
|
125
130
|
|
|
126
131
|
self.send_message = send_message
|
|
127
132
|
self._mqtt_state = mqtt_state
|
|
@@ -147,7 +152,7 @@ class Manager:
|
|
|
147
152
|
|
|
148
153
|
self._configure_temp_sensors(sensors=sensors)
|
|
149
154
|
|
|
150
|
-
self._modbus_sensors =
|
|
155
|
+
self._modbus_sensors = {}
|
|
151
156
|
self._configure_ina219_sensors(sensors=sensors)
|
|
152
157
|
self._configure_sensors(
|
|
153
158
|
dallas=dallas, ds2482=ds2482, sensors=sensors.get(ONEWIRE)
|
|
@@ -180,19 +185,26 @@ class Manager:
|
|
|
180
185
|
|
|
181
186
|
for _config in relay_pins:
|
|
182
187
|
_name = _config.pop(ID)
|
|
188
|
+
restore_state = _config.pop(RESTORE_STATE, False)
|
|
183
189
|
_id = strip_accents(_name)
|
|
184
190
|
out = configure_relay(
|
|
185
191
|
manager=self,
|
|
186
192
|
state_manager=self._state_manager,
|
|
187
193
|
topic_prefix=self._config_helper.topic_prefix,
|
|
188
194
|
name=_name,
|
|
195
|
+
restore_state=restore_state,
|
|
189
196
|
relay_id=_id,
|
|
190
|
-
relay_callback=self._relay_callback,
|
|
191
197
|
config=_config,
|
|
192
198
|
event_bus=self._event_bus,
|
|
193
199
|
)
|
|
194
200
|
if not out:
|
|
195
201
|
continue
|
|
202
|
+
if restore_state:
|
|
203
|
+
self._event_bus.add_output_listener(
|
|
204
|
+
output_id=out.id,
|
|
205
|
+
listener_id="manager",
|
|
206
|
+
target=self._relay_callback,
|
|
207
|
+
)
|
|
196
208
|
self._outputs[_id] = out
|
|
197
209
|
if out.output_type not in (NONE, COVER):
|
|
198
210
|
self.send_ha_autodiscovery(
|
|
@@ -253,6 +265,11 @@ class Manager:
|
|
|
253
265
|
_LOGGER.info("Initializing inputs. This will take a while.")
|
|
254
266
|
self.configure_inputs(reload_config=False)
|
|
255
267
|
|
|
268
|
+
self._serial_number_sensor = create_serial_number_sensor(
|
|
269
|
+
manager=self,
|
|
270
|
+
topic_prefix=self._config_helper.topic_prefix)
|
|
271
|
+
self._modbus_sensors = self._configure_modbus_sensors(sensors=sensors)
|
|
272
|
+
|
|
256
273
|
if oled.get("enabled", False):
|
|
257
274
|
from boneio.oled import Oled
|
|
258
275
|
|
|
@@ -261,6 +278,7 @@ class Manager:
|
|
|
261
278
|
|
|
262
279
|
self._host_data = HostData(
|
|
263
280
|
manager=self,
|
|
281
|
+
event_bus=self._event_bus,
|
|
264
282
|
enabled_screens=self._screens,
|
|
265
283
|
output=self.grouped_outputs,
|
|
266
284
|
inputs=self._inputs,
|
|
@@ -271,7 +289,6 @@ class Manager:
|
|
|
271
289
|
self._ina219_sensors[0] if self._ina219_sensors else None
|
|
272
290
|
),
|
|
273
291
|
extra_sensors=extra_sensors,
|
|
274
|
-
callback=self._host_data_callback,
|
|
275
292
|
)
|
|
276
293
|
try:
|
|
277
294
|
self._oled = Oled(
|
|
@@ -279,12 +296,28 @@ class Manager:
|
|
|
279
296
|
screen_order=self._screens,
|
|
280
297
|
grouped_outputs=list(self.grouped_outputs),
|
|
281
298
|
sleep_timeout=oled.get("screensaver_timeout", 60),
|
|
299
|
+
event_bus=self._event_bus,
|
|
282
300
|
)
|
|
283
301
|
except (GPIOInputException, I2CError) as err:
|
|
284
302
|
_LOGGER.error("Can't configure OLED display. %s", err)
|
|
303
|
+
finally:
|
|
304
|
+
if self._oled:
|
|
305
|
+
self._oled.render_display()
|
|
285
306
|
self.prepare_ha_buttons()
|
|
286
307
|
_LOGGER.info("BoneIO manager is ready.")
|
|
287
308
|
|
|
309
|
+
def set_web_server_status(self, status: bool, bind: int):
|
|
310
|
+
self._is_web_on = status
|
|
311
|
+
self._web_bind_port = bind
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def is_web_on(self) -> bool:
|
|
315
|
+
return self._is_web_on
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def web_bind_port(self) -> int | None:
|
|
319
|
+
return self._web_bind_port
|
|
320
|
+
|
|
288
321
|
@property
|
|
289
322
|
def mqtt_state(self) -> bool:
|
|
290
323
|
return self._mqtt_state()
|
|
@@ -321,7 +354,7 @@ class Manager:
|
|
|
321
354
|
for group in self._outputs_group:
|
|
322
355
|
members = get_outputs(group.pop("outputs"))
|
|
323
356
|
if not members:
|
|
324
|
-
_LOGGER.
|
|
357
|
+
_LOGGER.warning(
|
|
325
358
|
"This group %s doesn't have any valid members. Not adding it.",
|
|
326
359
|
group[ID],
|
|
327
360
|
)
|
|
@@ -592,19 +625,13 @@ class Manager:
|
|
|
592
625
|
async def _relay_callback(
|
|
593
626
|
self,
|
|
594
627
|
event: OutputState,
|
|
595
|
-
restore_state: bool,
|
|
596
|
-
save_host_data: bool = True,
|
|
597
|
-
expander_id: str | None = None,
|
|
598
628
|
) -> None:
|
|
599
629
|
"""Relay callback function."""
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
)
|
|
606
|
-
if save_host_data and expander_id:
|
|
607
|
-
self._host_data_callback(type=expander_id)
|
|
630
|
+
self._state_manager.save_attribute(
|
|
631
|
+
attr_type=RELAY,
|
|
632
|
+
attribute=event.id,
|
|
633
|
+
value=event.state == ON,
|
|
634
|
+
)
|
|
608
635
|
|
|
609
636
|
def _logger_reload(self) -> None:
|
|
610
637
|
"""_Logger reload function."""
|
|
@@ -613,10 +640,6 @@ class Manager:
|
|
|
613
640
|
return
|
|
614
641
|
configure_logger(log_config=_config.get("logger"), debug=-1)
|
|
615
642
|
|
|
616
|
-
def _host_data_callback(self, type: str) -> None:
|
|
617
|
-
if self._oled:
|
|
618
|
-
self._oled.handle_data_update(type)
|
|
619
|
-
|
|
620
643
|
def get_tasks(self) -> Set[asyncio.Task]:
|
|
621
644
|
"""Retrieve asyncio tasks to run."""
|
|
622
645
|
return self._tasks
|
|
@@ -743,11 +766,6 @@ class Manager:
|
|
|
743
766
|
self._loop.call_soon_threadsafe(
|
|
744
767
|
self._loop.call_later, 0.2, self.send_message, topic, ""
|
|
745
768
|
)
|
|
746
|
-
if (
|
|
747
|
-
"Inputs screen 1" in self._screens
|
|
748
|
-
or "Inputs screen 2" in self._screens
|
|
749
|
-
):
|
|
750
|
-
self._host_data_callback(type="inputs")
|
|
751
769
|
|
|
752
770
|
async def toggle_output(self, output_id: str) -> None:
|
|
753
771
|
"""Toggle output state."""
|