boneIO 0.8.0.dev5__tar.gz → 0.8.0.dev7__tar.gz
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-0.8.0.dev5 → boneIO-0.8.0.dev7}/PKG-INFO +1 -1
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/group/output.py +40 -11
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/events.py +13 -9
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/loader.py +2 -1
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/stats.py +68 -22
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/input/gpio.py +13 -3
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/manager.py +1 -1
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/client.py +24 -24
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/modbuscli.py +2 -2
- boneIO-0.8.0.dev7/boneio/modbus/orno-or-we-517.json +36 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/sensor.py +5 -2
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/schema.yaml +6 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/ina219.py +18 -11
- boneIO-0.8.0.dev7/boneio/version.py +2 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/pyproject.toml +1 -1
- boneIO-0.8.0.dev5/boneio/modbus/orno-or-we-517.json +0 -20
- boneIO-0.8.0.dev5/boneio/version.py +0 -2
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/LICENSE +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/README.md +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/bonecli.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/const.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/cover.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/adc.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/binary_sensor.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/config.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/cover.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/event.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/event_all.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/led32x4A.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/output24x16A.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/output24x16A_v0.3.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/example_config/output32x5A.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/fonts/danube__.ttf +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/group/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/async_updater.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/click_timer.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/config.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/exceptions.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/filter.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/gpio.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/ha_discovery.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/logger.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/mqtt.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/oled.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/onewire/W1ThermSensor.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/onewire/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/onewire/ds2482.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/onewire/onewire.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/pcf8575.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/queue.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/sensor/ina_219_smbus.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/state_manager.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/timeperiod.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/util.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/helper/yaml_util.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/input/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/input/gpio_new.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/cwt.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/dts1964_3f.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/pt100.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/r4dcb08.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/sdm120.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/sdm630.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/socomec_e23.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/sofar.json +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/modbus/utils.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/mqtt_client.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/oled.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/basic.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/gpio.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/mcp.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/pca.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/relay/pcf.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/runner.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/actions.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/actions_sensor.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/actions_switch.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/filters.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/filters_adc.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/id.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/temp_unit.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/schema/update_interval.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/adc.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/gpio.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/gpio_new.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/temp/__init__.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/temp/dallas.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/temp/lm75.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/boneio/sensor/temp/mcp9808.py +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/tests/32_5_config.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/tests/bandit.yaml +0 -0
- {boneIO-0.8.0.dev5 → boneIO-0.8.0.dev7}/tests/relay_32_5.py +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Group output module."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
import asyncio
|
|
4
5
|
from typing import List
|
|
@@ -13,26 +14,46 @@ class OutputGroup(BasicRelay):
|
|
|
13
14
|
self,
|
|
14
15
|
members: List[BasicRelay],
|
|
15
16
|
output_type: str = SWITCH,
|
|
16
|
-
restored_state: bool =
|
|
17
|
+
restored_state: bool = False,
|
|
18
|
+
all_on_behaviour: bool = False,
|
|
17
19
|
**kwargs,
|
|
18
20
|
) -> None:
|
|
19
21
|
"""Initialize cover class."""
|
|
20
22
|
self._loop = asyncio.get_event_loop()
|
|
21
23
|
super().__init__(
|
|
22
|
-
**kwargs,
|
|
24
|
+
**kwargs,
|
|
25
|
+
output_type=output_type,
|
|
26
|
+
restored_state=False,
|
|
27
|
+
topic_type="group",
|
|
23
28
|
)
|
|
29
|
+
self._all_on_behaviour = all_on_behaviour
|
|
24
30
|
self._group_members = [x for x in members if x.output_type != COVER]
|
|
25
31
|
self._timer_handle = None
|
|
32
|
+
self.check_state()
|
|
33
|
+
|
|
26
34
|
for member in self._group_members:
|
|
27
|
-
self._event_bus.add_output_listener(
|
|
35
|
+
self._event_bus.add_output_listener(
|
|
36
|
+
output_id=member.id,
|
|
37
|
+
group_id=self.id,
|
|
38
|
+
target=self.event_listener,
|
|
39
|
+
)
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
"""Listen for events called by children relays."""
|
|
31
|
-
state = OFF
|
|
41
|
+
def check_state(self) -> None:
|
|
32
42
|
for x in self._group_members:
|
|
33
43
|
if x.state == ON:
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
self._state = ON
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
async def event_listener(self, relay_id=None) -> None:
|
|
48
|
+
"""Listen for events called by children relays."""
|
|
49
|
+
if self._all_on_behaviour:
|
|
50
|
+
state = (
|
|
51
|
+
ON if all(x.state == ON for x in self._group_members) else OFF
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
state = (
|
|
55
|
+
ON if any(x.state == ON for x in self._group_members) else OFF
|
|
56
|
+
)
|
|
36
57
|
if state != self._state or not relay_id:
|
|
37
58
|
self._state = state
|
|
38
59
|
self._loop.call_soon_threadsafe(self.send_state)
|
|
@@ -40,13 +61,19 @@ class OutputGroup(BasicRelay):
|
|
|
40
61
|
async def async_turn_on(self) -> None:
|
|
41
62
|
"""Call turn on action."""
|
|
42
63
|
await asyncio.gather(
|
|
43
|
-
*[
|
|
64
|
+
*[
|
|
65
|
+
self._loop.run_in_executor(self.executor, x.turn_on)
|
|
66
|
+
for x in self._group_members
|
|
67
|
+
]
|
|
44
68
|
)
|
|
45
69
|
|
|
46
70
|
async def async_turn_off(self) -> None:
|
|
47
71
|
"""Call turn off action."""
|
|
48
72
|
await asyncio.gather(
|
|
49
|
-
*[
|
|
73
|
+
*[
|
|
74
|
+
self._loop.run_in_executor(self.executor, x.turn_off)
|
|
75
|
+
for x in self._group_members
|
|
76
|
+
]
|
|
50
77
|
)
|
|
51
78
|
|
|
52
79
|
@property
|
|
@@ -56,4 +83,6 @@ class OutputGroup(BasicRelay):
|
|
|
56
83
|
|
|
57
84
|
def send_state(self) -> None:
|
|
58
85
|
"""Send state to Mqtt on action."""
|
|
59
|
-
self._send_message(
|
|
86
|
+
self._send_message(
|
|
87
|
+
topic=self._send_topic, payload=self.payload(), retain=True
|
|
88
|
+
)
|
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
import signal
|
|
5
5
|
import time
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import Any, Coroutine, List, Optional, Callable
|
|
7
|
+
from typing import Any, Coroutine, List, Optional, Callable
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
from boneio.helper.util import callback
|
|
@@ -85,7 +85,9 @@ class EventBus:
|
|
|
85
85
|
self._output_listeners = {}
|
|
86
86
|
self._sigterm_listeners = []
|
|
87
87
|
self._haonline_listeners = []
|
|
88
|
-
self._timer_handle = _async_create_timer(
|
|
88
|
+
self._timer_handle = _async_create_timer(
|
|
89
|
+
self._loop, self._run_second_event
|
|
90
|
+
)
|
|
89
91
|
for signame in {"SIGINT", "SIGTERM"}:
|
|
90
92
|
self._loop.add_signal_handler(
|
|
91
93
|
getattr(signal, signame),
|
|
@@ -121,17 +123,19 @@ class EventBus:
|
|
|
121
123
|
"""Add sigterm listener."""
|
|
122
124
|
self._sigterm_listeners.append(target)
|
|
123
125
|
|
|
124
|
-
def add_output_listener(self,
|
|
126
|
+
def add_output_listener(self, output_id, group_id, target):
|
|
125
127
|
"""Add output listener."""
|
|
126
|
-
self._output_listeners
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
if output_id not in self._output_listeners:
|
|
129
|
+
self._output_listeners[output_id] = {}
|
|
130
|
+
self._output_listeners[output_id][group_id] = ListenerJob(target=target)
|
|
131
|
+
return self._output_listeners[output_id]
|
|
132
|
+
|
|
129
133
|
def trigger_output_event(self, event):
|
|
130
134
|
asyncio.create_task(self.async_trigger_output_event(event=event))
|
|
131
|
-
|
|
135
|
+
|
|
132
136
|
async def async_trigger_output_event(self, event):
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
listeners = self._output_listeners.get(event, {})
|
|
138
|
+
for listener in listeners.values():
|
|
135
139
|
await listener.target(event)
|
|
136
140
|
|
|
137
141
|
def add_haonline_listener(self, target):
|
|
@@ -15,7 +15,6 @@ from boneio.const import (
|
|
|
15
15
|
DEVICE_CLASS,
|
|
16
16
|
FILTERS,
|
|
17
17
|
GPIO,
|
|
18
|
-
PCA,
|
|
19
18
|
ID,
|
|
20
19
|
INIT_SLEEP,
|
|
21
20
|
INPUT,
|
|
@@ -135,6 +134,8 @@ def create_temp_sensor(
|
|
|
135
134
|
else:
|
|
136
135
|
return
|
|
137
136
|
name = config.get(ID)
|
|
137
|
+
if not name:
|
|
138
|
+
return
|
|
138
139
|
id = name.replace(" ", "")
|
|
139
140
|
try:
|
|
140
141
|
temp_sensor = TempSensor(
|
|
@@ -63,7 +63,7 @@ def get_network_info():
|
|
|
63
63
|
for addr in addrs:
|
|
64
64
|
if addr.family == socket.AF_INET:
|
|
65
65
|
out["ip"] = addr.address
|
|
66
|
-
out["mask"] = addr.netmask
|
|
66
|
+
out["mask"] = addr.netmask if addr.netmask is not None else ""
|
|
67
67
|
elif addr.family == psutil.AF_LINK:
|
|
68
68
|
out["mac"] = addr.address
|
|
69
69
|
return out
|
|
@@ -139,7 +139,9 @@ class HostSensor(AsyncUpdater):
|
|
|
139
139
|
|
|
140
140
|
async def async_update(self, time: datetime) -> None:
|
|
141
141
|
self._state = self._update_function()
|
|
142
|
-
self._loop.call_soon_threadsafe(
|
|
142
|
+
self._loop.call_soon_threadsafe(
|
|
143
|
+
partial(self._manager_callback, self._type)
|
|
144
|
+
)
|
|
143
145
|
|
|
144
146
|
@property
|
|
145
147
|
def state(self) -> dict:
|
|
@@ -155,7 +157,7 @@ class HostData:
|
|
|
155
157
|
self,
|
|
156
158
|
output: dict,
|
|
157
159
|
callback: Callable,
|
|
158
|
-
temp_sensor: Callable[[LM75Sensor, MCP9808Sensor], None],
|
|
160
|
+
temp_sensor: Callable[[LM75Sensor, MCP9808Sensor], None] | None,
|
|
159
161
|
ina219: INA219Class | None,
|
|
160
162
|
manager: Manager,
|
|
161
163
|
enabled_screens: List[str],
|
|
@@ -164,27 +166,68 @@ class HostData:
|
|
|
164
166
|
self._hostname = socket.gethostname()
|
|
165
167
|
self._temp_sensor = temp_sensor
|
|
166
168
|
host_stats = {
|
|
167
|
-
NETWORK: {
|
|
169
|
+
NETWORK: {
|
|
170
|
+
"f": get_network_info,
|
|
171
|
+
"update_interval": TimePeriod(seconds=60),
|
|
172
|
+
},
|
|
168
173
|
CPU: {"f": get_cpu_info, "update_interval": TimePeriod(seconds=5)},
|
|
169
|
-
DISK: {
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
DISK: {
|
|
175
|
+
"f": get_disk_info,
|
|
176
|
+
"update_interval": TimePeriod(seconds=60),
|
|
177
|
+
},
|
|
178
|
+
MEMORY: {
|
|
179
|
+
"f": get_memory_info,
|
|
180
|
+
"update_interval": TimePeriod(seconds=10),
|
|
181
|
+
},
|
|
182
|
+
SWAP: {
|
|
183
|
+
"f": get_swap_info,
|
|
184
|
+
"update_interval": TimePeriod(seconds=60),
|
|
185
|
+
},
|
|
172
186
|
UPTIME: {
|
|
173
|
-
"f": lambda:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
187
|
+
"f": lambda: (
|
|
188
|
+
{
|
|
189
|
+
"uptime": {
|
|
190
|
+
"data": get_uptime(),
|
|
191
|
+
"fontSize": "small",
|
|
192
|
+
"row": 2,
|
|
193
|
+
"col": 3,
|
|
194
|
+
},
|
|
195
|
+
"MQTT": {
|
|
196
|
+
"data": "CONN" if manager.mqtt_state else "DOWN",
|
|
197
|
+
"fontSize": "small",
|
|
198
|
+
"row": 3,
|
|
199
|
+
"col": 60,
|
|
200
|
+
},
|
|
201
|
+
"T": {
|
|
202
|
+
"data": f"{self._temp_sensor.state} C",
|
|
203
|
+
"fontSize": "small",
|
|
204
|
+
"row": 3,
|
|
205
|
+
"col": 3,
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
if self._temp_sensor
|
|
209
|
+
else {
|
|
210
|
+
"uptime": {
|
|
211
|
+
"data": get_uptime(),
|
|
212
|
+
"fontSize": "small",
|
|
213
|
+
"row": 2,
|
|
214
|
+
"col": 3,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
"static": {
|
|
219
|
+
HOST: {
|
|
220
|
+
"data": self._hostname,
|
|
178
221
|
"fontSize": "small",
|
|
179
|
-
"row":
|
|
180
|
-
"col": 3
|
|
222
|
+
"row": 0,
|
|
223
|
+
"col": 3,
|
|
224
|
+
},
|
|
225
|
+
"ver": {
|
|
226
|
+
"data": __version__,
|
|
227
|
+
"fontSize": "small",
|
|
228
|
+
"row": 1,
|
|
229
|
+
"col": 3,
|
|
181
230
|
},
|
|
182
|
-
}
|
|
183
|
-
if self._temp_sensor
|
|
184
|
-
else {"uptime": {"data": get_uptime(), "fontSize": "small", "row": 2, "col": 3}},
|
|
185
|
-
"static": {
|
|
186
|
-
HOST: {"data": self._hostname, "fontSize": "small", "row": 0, "col": 3},
|
|
187
|
-
"ver": {"data": __version__, "fontSize": "small", "row": 1, "col": 3},
|
|
188
231
|
},
|
|
189
232
|
"update_interval": TimePeriod(seconds=30),
|
|
190
233
|
},
|
|
@@ -192,9 +235,12 @@ class HostData:
|
|
|
192
235
|
if ina219 is not None:
|
|
193
236
|
host_stats[INA219] = {
|
|
194
237
|
"f": lambda: {
|
|
195
|
-
*{
|
|
238
|
+
*{
|
|
239
|
+
sensor.device_class: sensor.state
|
|
240
|
+
for sensor in ina219.sensors.values()
|
|
241
|
+
}
|
|
196
242
|
},
|
|
197
|
-
"update_interval": TimePeriod(seconds=60)
|
|
243
|
+
"update_interval": TimePeriod(seconds=60),
|
|
198
244
|
}
|
|
199
245
|
self._data = {}
|
|
200
246
|
for k, _v in host_stats.items():
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""GpioEventButton to receive signals."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
import logging
|
|
4
5
|
import asyncio
|
|
@@ -39,6 +40,12 @@ class GpioEventButton(GpioBaseClass):
|
|
|
39
40
|
self._is_waiting_for_second_click = False
|
|
40
41
|
if not self._state and not self._timer_long.is_waiting():
|
|
41
42
|
self.press_callback(click_type=SINGLE, duration=None)
|
|
43
|
+
else:
|
|
44
|
+
_LOGGER.error(
|
|
45
|
+
"Thats why it's not working %s %s",
|
|
46
|
+
self._state,
|
|
47
|
+
self._timer_long.is_waiting(),
|
|
48
|
+
)
|
|
42
49
|
|
|
43
50
|
async def _run(self) -> None:
|
|
44
51
|
while True:
|
|
@@ -49,7 +56,7 @@ class GpioEventButton(GpioBaseClass):
|
|
|
49
56
|
if state == self._state:
|
|
50
57
|
return
|
|
51
58
|
self._state = state
|
|
52
|
-
if state:
|
|
59
|
+
if state: # is pressed?
|
|
53
60
|
self._timer_long.start_timer()
|
|
54
61
|
if self._timer_double.is_waiting():
|
|
55
62
|
self._timer_double.reset()
|
|
@@ -59,8 +66,11 @@ class GpioEventButton(GpioBaseClass):
|
|
|
59
66
|
self._timer_double.start_timer()
|
|
60
67
|
self._is_waiting_for_second_click = True
|
|
61
68
|
|
|
62
|
-
else:
|
|
63
|
-
if
|
|
69
|
+
else: # is released?
|
|
70
|
+
if (
|
|
71
|
+
not self._is_waiting_for_second_click
|
|
72
|
+
and not self._double_click_ran
|
|
73
|
+
):
|
|
64
74
|
if self._timer_long.is_waiting():
|
|
65
75
|
self.press_callback(click_type=SINGLE, duration=None)
|
|
66
76
|
self._timer_long.reset()
|
|
@@ -299,7 +299,7 @@ class Manager:
|
|
|
299
299
|
if x in self._output:
|
|
300
300
|
output = self._output[x]
|
|
301
301
|
if output.output_type == COVER:
|
|
302
|
-
_LOGGER.
|
|
302
|
+
_LOGGER.warning("You can't add cover output to group.")
|
|
303
303
|
else:
|
|
304
304
|
outputs.append(output)
|
|
305
305
|
return outputs
|
|
@@ -101,51 +101,51 @@ class Modbus:
|
|
|
101
101
|
_LOGGER.error(exception_error)
|
|
102
102
|
return False
|
|
103
103
|
|
|
104
|
-
async def
|
|
104
|
+
async def read_and_decode(
|
|
105
105
|
self,
|
|
106
106
|
unit: int | str,
|
|
107
107
|
address: int,
|
|
108
|
+
payload_type: str,
|
|
108
109
|
count: int = 2,
|
|
109
110
|
method: str = "input",
|
|
110
111
|
) -> float | None:
|
|
111
|
-
"""Call
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
except (ModbusException, struct.error) as exception_error:
|
|
122
|
-
_LOGGER.error(exception_error)
|
|
123
|
-
return None
|
|
124
|
-
if not hasattr(result, REGISTERS):
|
|
125
|
-
_LOGGER.error(str(result))
|
|
126
|
-
return None
|
|
127
|
-
return BinaryPayloadDecoder.fromRegisters(
|
|
128
|
-
result.registers, byteorder=Endian.Big, wordorder=Endian.Big
|
|
129
|
-
).decode_32bit_float()
|
|
112
|
+
"""Call read_registers and decode."""
|
|
113
|
+
result = await self.read_registers(
|
|
114
|
+
unit=unit, address=address, count=count, method=method
|
|
115
|
+
)
|
|
116
|
+
if not result or result.isError():
|
|
117
|
+
return None
|
|
118
|
+
decoded_value = self.decode_value(
|
|
119
|
+
payload=result.registers, value_type=payload_type
|
|
120
|
+
)
|
|
121
|
+
return decoded_value
|
|
130
122
|
|
|
131
|
-
async def
|
|
123
|
+
async def read_registers(
|
|
132
124
|
self,
|
|
133
125
|
unit: int | str, # device address
|
|
134
126
|
address: int, # modbus register address
|
|
135
127
|
count: int = 2, # number of registers to read
|
|
136
128
|
method: str = "input", # type of register: input, holding
|
|
137
129
|
) -> ModbusResponse:
|
|
138
|
-
"""Call
|
|
130
|
+
"""Call async pymodbus."""
|
|
139
131
|
async with self._lock:
|
|
140
132
|
if not self._pymodbus_connect():
|
|
141
133
|
_LOGGER.error("Can't connect to Modbus.")
|
|
142
134
|
return None
|
|
143
135
|
kwargs = {"unit": unit, "count": count} if unit else {}
|
|
144
136
|
try:
|
|
145
|
-
|
|
137
|
+
read_method = self._read_methods[method]
|
|
138
|
+
_LOGGER.debug(
|
|
139
|
+
"Reading %s registers from %s with method %s from device %s.",
|
|
140
|
+
count,
|
|
141
|
+
address,
|
|
142
|
+
method,
|
|
143
|
+
unit,
|
|
144
|
+
)
|
|
145
|
+
result: ReadInputRegistersResponse = read_method(
|
|
146
146
|
address, **kwargs
|
|
147
147
|
)
|
|
148
|
-
except ModbusException as exception_error:
|
|
148
|
+
except (ModbusException, struct.error) as exception_error:
|
|
149
149
|
_LOGGER.error(exception_error)
|
|
150
150
|
return None
|
|
151
151
|
if not hasattr(result, REGISTERS):
|
|
@@ -53,7 +53,7 @@ class ModbusHelper:
|
|
|
53
53
|
f"Checking connection {self._device_address}, address {address}."
|
|
54
54
|
)
|
|
55
55
|
count = 1 if value_type == "S_WORD" or value_type == "U_WORD" else 2
|
|
56
|
-
value = await self._modbus.
|
|
56
|
+
value = await self._modbus.read_registers(
|
|
57
57
|
unit=self._device_address,
|
|
58
58
|
address=address,
|
|
59
59
|
count=count,
|
|
@@ -180,7 +180,7 @@ async def async_run_modbus_get(
|
|
|
180
180
|
parity=parity,
|
|
181
181
|
)
|
|
182
182
|
count = 1 if value_type == "S_WORD" or value_type == "U_WORD" else 2
|
|
183
|
-
value = await _modbus.
|
|
183
|
+
value = await _modbus.read_registers(
|
|
184
184
|
unit=device_address,
|
|
185
185
|
address=register_address,
|
|
186
186
|
count=count,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model": "orno-or-we-517",
|
|
3
|
+
"registers_base": [
|
|
4
|
+
{
|
|
5
|
+
"base": 14,
|
|
6
|
+
"length": 6,
|
|
7
|
+
"register_type": "holding",
|
|
8
|
+
"registers": [
|
|
9
|
+
{
|
|
10
|
+
"name": "Voltage_L1",
|
|
11
|
+
"address": 14,
|
|
12
|
+
"unit_of_measurement": "V",
|
|
13
|
+
"state_class": "measurement",
|
|
14
|
+
"device_class": "voltage",
|
|
15
|
+
"value_type": "FP32"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Voltage_L2",
|
|
19
|
+
"address": 16,
|
|
20
|
+
"unit_of_measurement": "V",
|
|
21
|
+
"state_class": "measurement",
|
|
22
|
+
"device_class": "voltage",
|
|
23
|
+
"value_type": "FP32"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "Voltage_L3",
|
|
27
|
+
"address": 18,
|
|
28
|
+
"unit_of_measurement": "V",
|
|
29
|
+
"state_class": "measurement",
|
|
30
|
+
"device_class": "voltage",
|
|
31
|
+
"value_type": "FP32"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -122,10 +122,13 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
|
|
|
122
122
|
register_method = first_register_base.get("register_type", "input")
|
|
123
123
|
# Let's try fetch register 2 times in case something wrong with initial packet.
|
|
124
124
|
for _ in [0, 1]:
|
|
125
|
-
register = await self._modbus.
|
|
125
|
+
register = await self._modbus.read_and_decode(
|
|
126
126
|
unit=self._address,
|
|
127
127
|
address=first_register_base[REGISTERS][0][ADDRESS],
|
|
128
128
|
method=register_method,
|
|
129
|
+
payload_type=first_register_base[REGISTERS][0].get(
|
|
130
|
+
"value_type", "FP32"
|
|
131
|
+
),
|
|
129
132
|
)
|
|
130
133
|
if register is not None:
|
|
131
134
|
self._discovery_sent = (
|
|
@@ -144,7 +147,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
|
|
|
144
147
|
update_interval = self._update_interval.total_in_seconds
|
|
145
148
|
await self.check_availability()
|
|
146
149
|
for data in self._db[REGISTERS_BASE]:
|
|
147
|
-
values = await self._modbus.
|
|
150
|
+
values = await self._modbus.read_registers(
|
|
148
151
|
unit=self._address,
|
|
149
152
|
address=data[BASE],
|
|
150
153
|
count=data[LENGTH],
|
|
@@ -432,6 +432,12 @@ output_group:
|
|
|
432
432
|
required: True
|
|
433
433
|
meta:
|
|
434
434
|
label: List of outputs.
|
|
435
|
+
all_on_behaviour:
|
|
436
|
+
type: boolean
|
|
437
|
+
required: True
|
|
438
|
+
default: False
|
|
439
|
+
meta:
|
|
440
|
+
label: Behaviour if set true toggle when all outputs are on, otherwise if any is on then group is on.
|
|
435
441
|
output_type:
|
|
436
442
|
type: string
|
|
437
443
|
required: True
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""INA219 Black sensor."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
import logging
|
|
@@ -10,24 +11,24 @@ from boneio.helper.sensor.ina_219_smbus import INA219_I2C
|
|
|
10
11
|
|
|
11
12
|
_LOGGER = logging.getLogger(__name__)
|
|
12
13
|
|
|
13
|
-
unit_converter = {
|
|
14
|
-
"current": "A",
|
|
15
|
-
"power": "W",
|
|
16
|
-
"voltage": "V"
|
|
17
|
-
}
|
|
14
|
+
unit_converter = {"current": "A", "power": "W", "voltage": "V"}
|
|
18
15
|
|
|
19
16
|
|
|
20
17
|
class INA219Sensor(BasicMqtt, Filter):
|
|
21
18
|
"""Represent singel value from INA219 as sensor."""
|
|
22
19
|
|
|
23
|
-
def __init__(
|
|
20
|
+
def __init__(
|
|
21
|
+
self, device_class: str, filters: list, state: float | None, **kwargs
|
|
22
|
+
) -> None:
|
|
24
23
|
super().__init__(topic_type=SENSOR, **kwargs)
|
|
25
24
|
self._unit_of_measurement = unit_converter[device_class]
|
|
26
25
|
self._device_class = device_class
|
|
27
26
|
self._filters = filters
|
|
28
27
|
self._raw_state = state
|
|
29
28
|
self._state = (
|
|
30
|
-
self._apply_filters(value=self._raw_state)
|
|
29
|
+
self._apply_filters(value=self._raw_state)
|
|
30
|
+
if self._raw_state
|
|
31
|
+
else None
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
@property
|
|
@@ -41,18 +42,22 @@ class INA219Sensor(BasicMqtt, Filter):
|
|
|
41
42
|
@property
|
|
42
43
|
def state(self) -> float | None:
|
|
43
44
|
return self._state
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
@property
|
|
46
47
|
def device_class(self) -> str:
|
|
47
48
|
return self._device_class
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
@property
|
|
50
51
|
def unit_of_measurement(self) -> str:
|
|
51
52
|
return self._unit_of_measurement
|
|
52
53
|
|
|
53
54
|
def update(self, time: datetime) -> None:
|
|
54
55
|
"""Fetch temperature periodically and send to MQTT."""
|
|
55
|
-
_state =
|
|
56
|
+
_state = (
|
|
57
|
+
self._apply_filters(value=self._raw_state)
|
|
58
|
+
if self._raw_state
|
|
59
|
+
else None
|
|
60
|
+
)
|
|
56
61
|
if not _state:
|
|
57
62
|
return
|
|
58
63
|
self._state = _state
|
|
@@ -65,7 +70,9 @@ class INA219Sensor(BasicMqtt, Filter):
|
|
|
65
70
|
class INA219(AsyncUpdater, Filter):
|
|
66
71
|
"""Represent INA219 sensors."""
|
|
67
72
|
|
|
68
|
-
def __init__(
|
|
73
|
+
def __init__(
|
|
74
|
+
self, address: int, id: str, sensors: list[dict] = [], **kwargs
|
|
75
|
+
) -> None:
|
|
69
76
|
"""Setup GPIO ADC Sensor"""
|
|
70
77
|
self._loop = asyncio.get_event_loop()
|
|
71
78
|
self._ina_219 = INA219_I2C(address=address)
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"model": "orno-or-we-517",
|
|
3
|
-
"registers_base": [
|
|
4
|
-
{
|
|
5
|
-
"base": 14,
|
|
6
|
-
"length": 4,
|
|
7
|
-
"register_type": "holding",
|
|
8
|
-
"registers": [
|
|
9
|
-
{
|
|
10
|
-
"name": "Napiecie_L1",
|
|
11
|
-
"address": 14,
|
|
12
|
-
"unit_of_measurement": "V",
|
|
13
|
-
"state_class": "measurement",
|
|
14
|
-
"device_class": "voltage",
|
|
15
|
-
"return_type": "float32"
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|