boneIO 0.5.0.dev1__tar.gz → 0.5.0.dev3__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.5.0.dev1 → boneIO-0.5.0.dev3}/PKG-INFO +1 -1
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/const.py +1 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/cover.py +15 -14
- boneIO-0.5.0.dev3/boneio/helper/filter.py +26 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/loader.py +7 -4
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/stats.py +24 -4
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/manager.py +14 -11
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/oled.py +19 -6
- boneIO-0.5.0.dev3/boneio/schema/filters.yaml +11 -0
- boneIO-0.5.0.dev3/boneio/schema/filters_adc.yaml +12 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/schema/schema.yaml +26 -50
- boneIO-0.5.0.dev3/boneio/schema/update_interval.yaml +10 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/adc.py +9 -3
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/temp/__init__.py +15 -3
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/temp/dallas.py +9 -1
- boneIO-0.5.0.dev3/boneio/version.py +2 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/pyproject.toml +1 -1
- boneIO-0.5.0.dev1/boneio/version.py +0 -2
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/LICENSE +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/README.md +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/bonecli.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/adc.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/config.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/cover.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/input.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/output24x16A.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/example_config/output32x5A.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/fonts/danube__.ttf +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/async_updater.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/config.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/events.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/exceptions.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/gpio.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/ha_discovery.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/logger.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/mqtt.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/oled.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/onewire/W1ThermSensor.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/onewire/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/onewire/ds2482.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/onewire/onewire.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/queue.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/state_manager.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/timeperiod.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/util.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/helper/yaml_util.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/input/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/input/gpio.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/modbus.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/mqtt_client.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/relay/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/relay/basic.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/relay/gpio.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/relay/mcp.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/runner.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/schema/actions.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/schema/actions_sensor.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/schema/actions_switch.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/gpio.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/modbus/__init__.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/modbus/sdm120.json +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/modbus/sdm630.json +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/modbus/sofar.json +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/temp/lm75.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/boneio/sensor/temp/mcp9808.py +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/tests/32_5_config.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/tests/bandit.yaml +0 -0
- {boneIO-0.5.0.dev1 → boneIO-0.5.0.dev3}/tests/relay_32_5.py +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Cover module."""
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
from typing import Callable
|
|
@@ -108,24 +109,24 @@ class Cover(BasicMqtt):
|
|
|
108
109
|
self._stop_cover(on_exit=True)
|
|
109
110
|
|
|
110
111
|
@property
|
|
111
|
-
def cover_state(self):
|
|
112
|
+
def cover_state(self) -> CLOSED | OPEN:
|
|
112
113
|
"""Current state of cover."""
|
|
113
114
|
return CLOSED if self._closed else OPEN
|
|
114
115
|
|
|
115
|
-
def stop(self):
|
|
116
|
+
def stop(self) -> None:
|
|
116
117
|
"""Public Stop cover graceful."""
|
|
117
118
|
_LOGGER.info("Stopping cover %s.", self._id)
|
|
118
119
|
if self._current_operation != IDLE:
|
|
119
120
|
self._stop_cover(on_exit=False)
|
|
120
121
|
|
|
121
|
-
def send_state(self):
|
|
122
|
+
def send_state(self) -> None:
|
|
122
123
|
"""Send state of cover to mqtt."""
|
|
123
124
|
self._send_message(topic=f"{self._send_topic}/state", payload=self.cover_state)
|
|
124
125
|
pos = round(self._position, 0)
|
|
125
126
|
self._send_message(topic=f"{self._send_topic}/pos", payload=str(pos))
|
|
126
127
|
self._state_save(position=pos)
|
|
127
128
|
|
|
128
|
-
def _stop_cover(self, on_exit=False):
|
|
129
|
+
def _stop_cover(self, on_exit=False) -> None:
|
|
129
130
|
"""Stop cover."""
|
|
130
131
|
self._open.relay.turn_off()
|
|
131
132
|
self._close.relay.turn_off()
|
|
@@ -138,11 +139,11 @@ class Cover(BasicMqtt):
|
|
|
138
139
|
self._current_operation = IDLE
|
|
139
140
|
|
|
140
141
|
@property
|
|
141
|
-
def current_cover_position(self):
|
|
142
|
+
def current_cover_position(self) -> int:
|
|
142
143
|
"""Return the current position of the cover."""
|
|
143
144
|
return round(self._position, 0)
|
|
144
145
|
|
|
145
|
-
def listen_cover(self, *args):
|
|
146
|
+
def listen_cover(self, *args) -> None:
|
|
146
147
|
"""Listen for change in cover."""
|
|
147
148
|
if self._current_operation == IDLE:
|
|
148
149
|
return
|
|
@@ -178,7 +179,7 @@ class Cover(BasicMqtt):
|
|
|
178
179
|
|
|
179
180
|
self._closed = self.current_cover_position <= 0
|
|
180
181
|
|
|
181
|
-
async def close_cover(self):
|
|
182
|
+
async def close_cover(self) -> None:
|
|
182
183
|
"""Close cover."""
|
|
183
184
|
if self._position == 0:
|
|
184
185
|
return
|
|
@@ -193,7 +194,7 @@ class Cover(BasicMqtt):
|
|
|
193
194
|
current_operation=CLOSING,
|
|
194
195
|
)
|
|
195
196
|
|
|
196
|
-
async def open_cover(self):
|
|
197
|
+
async def open_cover(self) -> None:
|
|
197
198
|
"""Open cover."""
|
|
198
199
|
if self._position == 100:
|
|
199
200
|
return
|
|
@@ -208,7 +209,7 @@ class Cover(BasicMqtt):
|
|
|
208
209
|
current_operation=OPENING,
|
|
209
210
|
)
|
|
210
211
|
|
|
211
|
-
async def set_cover_position(self, position: int):
|
|
212
|
+
async def set_cover_position(self, position: int) -> None:
|
|
212
213
|
"""Move cover to a specific position."""
|
|
213
214
|
set_position = round(position, -1)
|
|
214
215
|
if self._position == position or set_position == self._set_position:
|
|
@@ -228,29 +229,29 @@ class Cover(BasicMqtt):
|
|
|
228
229
|
current_operation=current_operation,
|
|
229
230
|
)
|
|
230
231
|
|
|
231
|
-
def open(self):
|
|
232
|
+
def open(self) -> None:
|
|
232
233
|
_LOGGER.debug("Opening cover %s.", self._id)
|
|
233
234
|
asyncio.create_task(self.open_cover())
|
|
234
235
|
|
|
235
|
-
def close(self):
|
|
236
|
+
def close(self) -> None:
|
|
236
237
|
_LOGGER.debug("Closing cover %s.", self._id)
|
|
237
238
|
asyncio.create_task(self.close_cover())
|
|
238
239
|
|
|
239
|
-
def toggle(self):
|
|
240
|
+
def toggle(self) -> None:
|
|
240
241
|
_LOGGER.debug("Toggle cover %s from input.", self._id)
|
|
241
242
|
if self.cover_state == CLOSED:
|
|
242
243
|
self.close()
|
|
243
244
|
else:
|
|
244
245
|
self.open()
|
|
245
246
|
|
|
246
|
-
def toggle_open(self):
|
|
247
|
+
def toggle_open(self) -> None:
|
|
247
248
|
_LOGGER.debug("Toggle open cover %s from input.", self._id)
|
|
248
249
|
if self._current_operation != IDLE:
|
|
249
250
|
self.stop()
|
|
250
251
|
else:
|
|
251
252
|
self.open()
|
|
252
253
|
|
|
253
|
-
def toggle_close(self):
|
|
254
|
+
def toggle_close(self) -> None:
|
|
254
255
|
_LOGGER.debug("Toggle close cover %s from input.", self._id)
|
|
255
256
|
if self._current_operation != IDLE:
|
|
256
257
|
self.stop()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Filter class to adjust sensor values."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
FILTERS = {
|
|
6
|
+
"offset": lambda x, y: x + y,
|
|
7
|
+
"round": lambda x, y: round(x, y),
|
|
8
|
+
"multiply": lambda x, y: x * y,
|
|
9
|
+
"filter_out": lambda x, y: None if x == y else x,
|
|
10
|
+
"filter_out_greater": lambda x, y: None if x > y else x,
|
|
11
|
+
"filter_out_lower": lambda x, y: None if x < y else x,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Filter:
|
|
16
|
+
_filters = []
|
|
17
|
+
|
|
18
|
+
def _apply_filters(self, value: float) -> float | None:
|
|
19
|
+
for filter in self._filters:
|
|
20
|
+
for k, v in filter.items():
|
|
21
|
+
if k not in FILTERS:
|
|
22
|
+
break
|
|
23
|
+
value = FILTERS[k](value, v)
|
|
24
|
+
if value is None:
|
|
25
|
+
return None
|
|
26
|
+
return value
|
|
@@ -13,6 +13,7 @@ from boneio.const import (
|
|
|
13
13
|
BINARY_SENSOR,
|
|
14
14
|
COVER,
|
|
15
15
|
DEVICE_CLASS,
|
|
16
|
+
FILTERS,
|
|
16
17
|
GPIO,
|
|
17
18
|
ID,
|
|
18
19
|
INIT_SLEEP,
|
|
@@ -107,7 +108,7 @@ def create_temp_sensor(
|
|
|
107
108
|
topic_prefix: str,
|
|
108
109
|
sensor_type: str,
|
|
109
110
|
i2cbusio: I2C,
|
|
110
|
-
|
|
111
|
+
config: dict = {},
|
|
111
112
|
):
|
|
112
113
|
"""Create LM sensor in manager."""
|
|
113
114
|
if sensor_type == LM75:
|
|
@@ -116,17 +117,18 @@ def create_temp_sensor(
|
|
|
116
117
|
from boneio.sensor import MCP9808Sensor as TempSensor
|
|
117
118
|
else:
|
|
118
119
|
return
|
|
119
|
-
name =
|
|
120
|
+
name = config.get(ID)
|
|
120
121
|
id = name.replace(" ", "")
|
|
121
122
|
try:
|
|
122
123
|
temp_sensor = TempSensor(
|
|
123
124
|
id=id,
|
|
124
125
|
name=name,
|
|
125
126
|
i2c=i2cbusio,
|
|
126
|
-
address=
|
|
127
|
+
address=config[ADDRESS],
|
|
127
128
|
send_message=manager.send_message,
|
|
128
129
|
topic_prefix=topic_prefix,
|
|
129
|
-
update_interval=
|
|
130
|
+
update_interval=config.get(UPDATE_INTERVAL, TimePeriod(seconds=60)),
|
|
131
|
+
filters=config.get(FILTERS, []),
|
|
130
132
|
)
|
|
131
133
|
manager.send_ha_autodiscovery(
|
|
132
134
|
id=id,
|
|
@@ -393,6 +395,7 @@ def create_dallas_sensor(
|
|
|
393
395
|
name=name,
|
|
394
396
|
update_interval=config.get(UPDATE_INTERVAL, TimePeriod(seconds=60)),
|
|
395
397
|
send_message=manager.send_message,
|
|
398
|
+
filters=config.get(FILTERS, []),
|
|
396
399
|
**kwargs,
|
|
397
400
|
)
|
|
398
401
|
if config.get(SHOW_HA, True):
|
|
@@ -4,7 +4,8 @@ from datetime import datetime
|
|
|
4
4
|
import socket
|
|
5
5
|
import time
|
|
6
6
|
from math import floor
|
|
7
|
-
from typing import Callable
|
|
7
|
+
from typing import Callable, List
|
|
8
|
+
from functools import partial
|
|
8
9
|
|
|
9
10
|
import psutil
|
|
10
11
|
|
|
@@ -117,19 +118,32 @@ def get_uptime():
|
|
|
117
118
|
class HostSensor(AsyncUpdater):
|
|
118
119
|
"""Host sensor."""
|
|
119
120
|
|
|
120
|
-
def __init__(
|
|
121
|
+
def __init__(
|
|
122
|
+
self,
|
|
123
|
+
update_function: Callable,
|
|
124
|
+
manager_callback: Callable,
|
|
125
|
+
static_data: dict,
|
|
126
|
+
id: str,
|
|
127
|
+
type: str,
|
|
128
|
+
**kwargs,
|
|
129
|
+
) -> None:
|
|
121
130
|
self._update_function = update_function
|
|
122
131
|
self._static_data = static_data
|
|
123
132
|
self._state = None
|
|
133
|
+
self._type = type
|
|
134
|
+
self._manager_callback = manager_callback
|
|
135
|
+
self._loop = asyncio.get_event_loop()
|
|
136
|
+
self.id = id
|
|
124
137
|
super().__init__(**kwargs)
|
|
125
138
|
|
|
126
139
|
async def async_update(self, time: datetime) -> None:
|
|
127
140
|
self._state = self._update_function()
|
|
141
|
+
self._loop.call_soon_threadsafe(partial(self._manager_callback, self._type))
|
|
128
142
|
|
|
129
143
|
@property
|
|
130
144
|
def state(self) -> dict:
|
|
131
145
|
if self._static_data:
|
|
132
|
-
return {**self._static_data,
|
|
146
|
+
return {**self._static_data, self._type: self._state}
|
|
133
147
|
return self._state
|
|
134
148
|
|
|
135
149
|
|
|
@@ -144,6 +158,7 @@ class HostData:
|
|
|
144
158
|
callback: Callable,
|
|
145
159
|
temp_sensor: Callable[[LM75Sensor, MCP9808Sensor], None],
|
|
146
160
|
manager: Manager,
|
|
161
|
+
enabled_screens: List[str],
|
|
147
162
|
) -> None:
|
|
148
163
|
"""Initialize HostData."""
|
|
149
164
|
self._hostname = socket.gethostname()
|
|
@@ -160,10 +175,15 @@ class HostData:
|
|
|
160
175
|
},
|
|
161
176
|
}
|
|
162
177
|
for k, _v in host_stats.items():
|
|
163
|
-
|
|
178
|
+
if k not in enabled_screens:
|
|
179
|
+
continue
|
|
180
|
+
self.data[k] = HostSensor(
|
|
164
181
|
update_function=_v["f"],
|
|
165
182
|
static_data=_v.get("static"),
|
|
166
183
|
manager=manager,
|
|
184
|
+
manager_callback=callback,
|
|
185
|
+
id=f"{k}_hoststats",
|
|
186
|
+
type=k,
|
|
167
187
|
update_interval=_v["update_interval"],
|
|
168
188
|
)
|
|
169
189
|
self._temp_sensor = temp_sensor
|
|
@@ -204,8 +204,11 @@ class Manager:
|
|
|
204
204
|
if oled.get("enabled", False):
|
|
205
205
|
from boneio.oled import Oled
|
|
206
206
|
|
|
207
|
+
screens = oled.get("screens")
|
|
208
|
+
|
|
207
209
|
self._host_data = HostData(
|
|
208
210
|
manager=self,
|
|
211
|
+
enabled_screens=screens,
|
|
209
212
|
output=self.grouped_outputs,
|
|
210
213
|
temp_sensor=self._temp_sensors[0] if self._temp_sensors else None,
|
|
211
214
|
callback=self._host_data_callback,
|
|
@@ -213,12 +216,13 @@ class Manager:
|
|
|
213
216
|
try:
|
|
214
217
|
self._oled = Oled(
|
|
215
218
|
host_data=self._host_data,
|
|
219
|
+
screen_order=screens,
|
|
216
220
|
output_groups=list(self.grouped_outputs),
|
|
217
221
|
sleep_timeout=oled.get("screensaver_timeout", 60),
|
|
218
222
|
)
|
|
219
223
|
except (GPIOInputException, I2CError) as err:
|
|
220
224
|
_LOGGER.error("Can't configure OLED display. %s", err)
|
|
221
|
-
|
|
225
|
+
self.prepare_ha_buttons()
|
|
222
226
|
|
|
223
227
|
_LOGGER.info("BoneIO manager is ready.")
|
|
224
228
|
|
|
@@ -320,7 +324,7 @@ class Manager:
|
|
|
320
324
|
manager=self,
|
|
321
325
|
topic_prefix=self._config_helper.topic_prefix,
|
|
322
326
|
sensor_type=sensor_type,
|
|
323
|
-
|
|
327
|
+
config=temp_def,
|
|
324
328
|
i2cbusio=self._i2cbusio,
|
|
325
329
|
)
|
|
326
330
|
if temp_sensor:
|
|
@@ -371,11 +375,11 @@ class Manager:
|
|
|
371
375
|
"""Retrieve asyncio tasks to run."""
|
|
372
376
|
return self._tasks
|
|
373
377
|
|
|
374
|
-
def
|
|
375
|
-
"""Prepare buttons for reload."""
|
|
378
|
+
def prepare_ha_buttons(self) -> None:
|
|
379
|
+
"""Prepare HA buttons for reload."""
|
|
376
380
|
self.send_ha_autodiscovery(
|
|
377
381
|
id="Logger",
|
|
378
|
-
name="Logger",
|
|
382
|
+
name="Logger reload",
|
|
379
383
|
ha_type=BUTTON,
|
|
380
384
|
availability_msg_func=ha_button_availabilty_message,
|
|
381
385
|
)
|
|
@@ -438,7 +442,7 @@ class Manager:
|
|
|
438
442
|
self._config_helper.add_autodiscovery_msg(topic=topic, payload=payload)
|
|
439
443
|
self.send_message(topic=topic, payload=payload, retain=True)
|
|
440
444
|
|
|
441
|
-
def resend_autodiscovery(self):
|
|
445
|
+
def resend_autodiscovery(self) -> None:
|
|
442
446
|
for msg in self._config_helper.autodiscovery_msgs:
|
|
443
447
|
self.send_message(**msg, retain=True)
|
|
444
448
|
|
|
@@ -500,11 +504,10 @@ class Manager:
|
|
|
500
504
|
_LOGGER.warn(
|
|
501
505
|
"Positon cannot be set. Not number between 0-100. %s", message
|
|
502
506
|
)
|
|
503
|
-
elif msg_type == BUTTON:
|
|
504
|
-
if device_id == "logger" and
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
self._logger_reload()
|
|
507
|
+
elif msg_type == BUTTON and command == "set":
|
|
508
|
+
if device_id == "logger" and message == "reload":
|
|
509
|
+
_LOGGER.info("Reloading logger configuration.")
|
|
510
|
+
self._logger_reload()
|
|
508
511
|
|
|
509
512
|
@property
|
|
510
513
|
def output(self) -> dict:
|
|
@@ -28,7 +28,7 @@ fontSmall = make_font("DejaVuSans.ttf", 9)
|
|
|
28
28
|
fontExtraSmall = make_font("DejaVuSans.ttf", 7)
|
|
29
29
|
danube = make_font("danube__.ttf", 15, local=True)
|
|
30
30
|
|
|
31
|
-
screen_order = [UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP]
|
|
31
|
+
# screen_order = [UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP]
|
|
32
32
|
|
|
33
33
|
STANDARD_ROWS = [17, 32, 47]
|
|
34
34
|
UPTIME_ROWS = list(range(22, 60, 10))
|
|
@@ -40,19 +40,32 @@ class Oled:
|
|
|
40
40
|
"""Oled display class."""
|
|
41
41
|
|
|
42
42
|
def __init__(
|
|
43
|
-
self,
|
|
43
|
+
self,
|
|
44
|
+
host_data: HostData,
|
|
45
|
+
output_groups: List[str],
|
|
46
|
+
sleep_timeout: TimePeriod,
|
|
47
|
+
screen_order: List[str],
|
|
44
48
|
) -> None:
|
|
45
49
|
"""Initialize OLED screen."""
|
|
46
50
|
self._loop = asyncio.get_running_loop()
|
|
47
|
-
self.
|
|
48
|
-
|
|
51
|
+
self._output_groups = None
|
|
52
|
+
try:
|
|
53
|
+
_ind_screen = screen_order.index("outputs")
|
|
54
|
+
if not output_groups:
|
|
55
|
+
_LOGGER.debug("No outputs configured. Omitting in screen.")
|
|
56
|
+
screen_order.pop(_ind_screen)
|
|
57
|
+
screen_order[_ind_screen:_ind_screen] = output_groups
|
|
58
|
+
self._output_groups = output_groups
|
|
59
|
+
except ValueError:
|
|
60
|
+
pass
|
|
61
|
+
self._screen_order = cycle(screen_order)
|
|
49
62
|
self._current_screen = next(self._screen_order)
|
|
50
63
|
self._host_data = host_data
|
|
51
64
|
self._sleep = False
|
|
52
65
|
self._sleep_handle = None
|
|
53
66
|
self._sleep_timeout = sleep_timeout
|
|
54
67
|
setup_input(pin=OLED_PIN, pull_mode="gpio_pu")
|
|
55
|
-
edge_detect(pin=OLED_PIN, callback=self._handle_press, bounce=
|
|
68
|
+
edge_detect(pin=OLED_PIN, callback=self._handle_press, bounce=240)
|
|
56
69
|
try:
|
|
57
70
|
serial = i2c(port=2, address=0x3C)
|
|
58
71
|
self._device = sh1106(serial)
|
|
@@ -112,7 +125,7 @@ class Oled:
|
|
|
112
125
|
data = self._host_data.get(self._current_screen)
|
|
113
126
|
if data:
|
|
114
127
|
with canvas(self._device) as draw:
|
|
115
|
-
if self._current_screen in self._output_groups:
|
|
128
|
+
if self._output_groups and self._current_screen in self._output_groups:
|
|
116
129
|
self._draw_output(data, draw)
|
|
117
130
|
elif self._current_screen == UPTIME:
|
|
118
131
|
self._draw_uptime(data, draw)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type: list
|
|
2
|
+
required: False
|
|
3
|
+
schema:
|
|
4
|
+
type: dict
|
|
5
|
+
keysrules:
|
|
6
|
+
type: string
|
|
7
|
+
allowed: ["offset", "round", "multiply", "filter_out", "filter_out_greater", "filter_out_lower"]
|
|
8
|
+
default:
|
|
9
|
+
- round: 2
|
|
10
|
+
meta:
|
|
11
|
+
label: List of filters to apply. Allowed filters visible in allowed section.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type: list
|
|
2
|
+
required: False
|
|
3
|
+
schema:
|
|
4
|
+
type: dict
|
|
5
|
+
keysrules:
|
|
6
|
+
type: string
|
|
7
|
+
allowed: ["offset", "round", "multiply", "filter_out", "filter_out_greater", "filter_out_lower"]
|
|
8
|
+
default:
|
|
9
|
+
- multiply: 1.8
|
|
10
|
+
- round: 2
|
|
11
|
+
meta:
|
|
12
|
+
label: List of filters to apply. Allowed filters visible in allowed section.
|
|
@@ -75,6 +75,18 @@ oled:
|
|
|
75
75
|
default: False
|
|
76
76
|
meta:
|
|
77
77
|
label: Disable builtin screen.
|
|
78
|
+
screens:
|
|
79
|
+
type: list
|
|
80
|
+
required: True
|
|
81
|
+
allowed: ["uptime", "network", "cpu", "disk", "memory", "swap", "outputs"]
|
|
82
|
+
default:
|
|
83
|
+
- uptime
|
|
84
|
+
- network
|
|
85
|
+
- cpu
|
|
86
|
+
- disk
|
|
87
|
+
- memory
|
|
88
|
+
- swap
|
|
89
|
+
- outputs
|
|
78
90
|
screensaver_timeout:
|
|
79
91
|
type:
|
|
80
92
|
- string
|
|
@@ -147,17 +159,8 @@ lm75:
|
|
|
147
159
|
default: 0x48
|
|
148
160
|
meta:
|
|
149
161
|
label: Address of I2C
|
|
150
|
-
update_interval:
|
|
151
|
-
|
|
152
|
-
- string
|
|
153
|
-
- timeperiod
|
|
154
|
-
coerce:
|
|
155
|
-
- str
|
|
156
|
-
- positive_time_period
|
|
157
|
-
required: True
|
|
158
|
-
default: 60s
|
|
159
|
-
meta:
|
|
160
|
-
label: Update interval.
|
|
162
|
+
update_interval: !include update_interval.yaml
|
|
163
|
+
filters: !include filters.yaml
|
|
161
164
|
|
|
162
165
|
|
|
163
166
|
mcp9808:
|
|
@@ -175,17 +178,8 @@ mcp9808:
|
|
|
175
178
|
default: 0x18
|
|
176
179
|
meta:
|
|
177
180
|
label: Address of I2C device
|
|
178
|
-
update_interval:
|
|
179
|
-
|
|
180
|
-
- string
|
|
181
|
-
- timeperiod
|
|
182
|
-
coerce:
|
|
183
|
-
- str
|
|
184
|
-
- positive_time_period
|
|
185
|
-
required: True
|
|
186
|
-
default: 60s
|
|
187
|
-
meta:
|
|
188
|
-
label: Update interval.
|
|
181
|
+
update_interval: !include update_interval.yaml
|
|
182
|
+
filters: !include filters.yaml
|
|
189
183
|
|
|
190
184
|
mcp23017:
|
|
191
185
|
type: list
|
|
@@ -360,17 +354,7 @@ adc:
|
|
|
360
354
|
allowed: ["P9_33", "P9_35", "P9_36", "P9_37", "P9_38", "P9_39", "P9_40"]
|
|
361
355
|
meta:
|
|
362
356
|
label: PIN to use.
|
|
363
|
-
update_interval:
|
|
364
|
-
required: True
|
|
365
|
-
type:
|
|
366
|
-
- string
|
|
367
|
-
- timeperiod
|
|
368
|
-
coerce:
|
|
369
|
-
- str
|
|
370
|
-
- positive_time_period
|
|
371
|
-
default: 60s
|
|
372
|
-
meta:
|
|
373
|
-
label: Update interval.
|
|
357
|
+
update_interval: !include update_interval.yaml
|
|
374
358
|
show_in_ha:
|
|
375
359
|
type: boolean
|
|
376
360
|
required: True
|
|
@@ -483,17 +467,18 @@ sensor:
|
|
|
483
467
|
required: False
|
|
484
468
|
meta:
|
|
485
469
|
label: Id to use in HA if needed. Default to address.
|
|
470
|
+
platform:
|
|
471
|
+
type: string
|
|
472
|
+
required: True
|
|
473
|
+
default: dallas
|
|
474
|
+
allowed: ["dallas"]
|
|
475
|
+
meta:
|
|
476
|
+
label: Platform of sensor to use. Currently only Dallas platform is supported.
|
|
486
477
|
address:
|
|
487
478
|
type: integer
|
|
488
479
|
required: True
|
|
489
480
|
meta:
|
|
490
481
|
label: Address of Dallas device
|
|
491
|
-
via_ds2482:
|
|
492
|
-
type: boolean
|
|
493
|
-
required: True
|
|
494
|
-
default: False
|
|
495
|
-
meta:
|
|
496
|
-
label: Choose if sensor is connected via DS2482 bus.
|
|
497
482
|
bus_id:
|
|
498
483
|
type: string
|
|
499
484
|
required: False
|
|
@@ -505,14 +490,5 @@ sensor:
|
|
|
505
490
|
default: True
|
|
506
491
|
meta:
|
|
507
492
|
label: If you want you can disable discovering this input in HA.
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
- string
|
|
511
|
-
- timeperiod
|
|
512
|
-
coerce:
|
|
513
|
-
- str
|
|
514
|
-
- positive_time_period
|
|
515
|
-
required: True
|
|
516
|
-
default: 60 s
|
|
517
|
-
meta:
|
|
518
|
-
label: Update interval.
|
|
493
|
+
filters: !include filters.yaml
|
|
494
|
+
update_interval: !include update_interval.yaml
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
|
|
5
5
|
from boneio.const import SENSOR
|
|
6
6
|
from boneio.helper import BasicMqtt, AsyncUpdater
|
|
7
|
+
from boneio.helper.filter import Filter
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
import Adafruit_BBIO.ADC as ADC
|
|
@@ -22,23 +23,28 @@ def initialize_adc():
|
|
|
22
23
|
ADC.setup()
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
class GpioADCSensor(BasicMqtt, AsyncUpdater):
|
|
26
|
+
class GpioADCSensor(BasicMqtt, AsyncUpdater, Filter):
|
|
26
27
|
"""Represent Gpio ADC sensor."""
|
|
27
28
|
|
|
28
29
|
def __init__(self, pin: str, **kwargs) -> None:
|
|
29
30
|
"""Setup GPIO ADC Sensor"""
|
|
30
31
|
super().__init__(topic_type=SENSOR, **kwargs)
|
|
31
32
|
self._pin = pin
|
|
33
|
+
self._state = None
|
|
32
34
|
AsyncUpdater.__init__(self, **kwargs)
|
|
33
35
|
_LOGGER.debug("Configured sensor pin %s", self._pin)
|
|
34
36
|
|
|
35
37
|
@property
|
|
36
|
-
def state(self):
|
|
38
|
+
def state(self) -> float:
|
|
37
39
|
"""Give rounded value of temperature."""
|
|
38
|
-
return
|
|
40
|
+
return self._state
|
|
39
41
|
|
|
40
42
|
def update(self, time: datetime) -> None:
|
|
41
43
|
"""Fetch temperature periodically and send to MQTT."""
|
|
44
|
+
_state = self._apply_filters(value=ADC.read(self._pin))
|
|
45
|
+
if not _state:
|
|
46
|
+
return
|
|
47
|
+
self._state = _state
|
|
42
48
|
self._send_message(
|
|
43
49
|
topic=self._send_topic,
|
|
44
50
|
payload=self.state,
|
|
@@ -6,18 +6,27 @@ from datetime import datetime
|
|
|
6
6
|
from boneio.const import SENSOR, STATE, TEMPERATURE
|
|
7
7
|
from boneio.helper import BasicMqtt, AsyncUpdater
|
|
8
8
|
from boneio.helper.exceptions import I2CError
|
|
9
|
+
from boneio.helper.filter import Filter
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
class TempSensor(BasicMqtt, AsyncUpdater):
|
|
12
|
+
class TempSensor(BasicMqtt, AsyncUpdater, Filter):
|
|
12
13
|
"""Represent Temp sensor in BoneIO."""
|
|
13
14
|
|
|
14
15
|
SensorClass = None
|
|
15
16
|
DefaultName = TEMPERATURE
|
|
16
17
|
|
|
17
|
-
def __init__(
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
i2c,
|
|
21
|
+
address: str,
|
|
22
|
+
id: str = DefaultName,
|
|
23
|
+
filters: list = ["round(x, 2)"],
|
|
24
|
+
**kwargs
|
|
25
|
+
):
|
|
18
26
|
"""Initialize Temp class."""
|
|
19
27
|
super().__init__(id=id, topic_type=SENSOR, **kwargs)
|
|
20
28
|
self._loop = asyncio.get_event_loop()
|
|
29
|
+
self._filters = filters
|
|
21
30
|
try:
|
|
22
31
|
self._pct = self.SensorClass(i2c_bus=i2c, address=address)
|
|
23
32
|
self._state: float | None = None
|
|
@@ -32,7 +41,10 @@ class TempSensor(BasicMqtt, AsyncUpdater):
|
|
|
32
41
|
|
|
33
42
|
def update(self, time: datetime) -> None:
|
|
34
43
|
"""Fetch temperature periodically and send to MQTT."""
|
|
35
|
-
|
|
44
|
+
_temp = self._apply_filters(value=self._pct.temperature)
|
|
45
|
+
if not _temp:
|
|
46
|
+
return
|
|
47
|
+
self._state = _temp
|
|
36
48
|
self._send_message(
|
|
37
49
|
topic=self._send_topic,
|
|
38
50
|
payload={STATE: self._state},
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
from datetime import datetime
|
|
6
|
+
from ast import literal_eval
|
|
6
7
|
|
|
7
8
|
from adafruit_ds18x20 import DS18X20
|
|
8
9
|
from w1thermsensor import SensorNotReadyError
|
|
@@ -47,11 +48,13 @@ class DallasSensorW1(TempSensor, AsyncUpdater):
|
|
|
47
48
|
self,
|
|
48
49
|
address: OneWireAddress,
|
|
49
50
|
id: str = DefaultName,
|
|
51
|
+
filters: list = ["round(x, 2)"],
|
|
50
52
|
**kwargs,
|
|
51
53
|
):
|
|
52
54
|
"""Initialize Temp class."""
|
|
53
55
|
self._loop = asyncio.get_event_loop()
|
|
54
56
|
BasicMqtt.__init__(self, id=id, topic_type=SENSOR, **kwargs)
|
|
57
|
+
self._filters = filters
|
|
55
58
|
try:
|
|
56
59
|
self._pct = AsyncBoneIOW1ThermSensor(sensor_id=address)
|
|
57
60
|
except ValueError as err:
|
|
@@ -60,7 +63,12 @@ class DallasSensorW1(TempSensor, AsyncUpdater):
|
|
|
60
63
|
|
|
61
64
|
async def async_update(self, time: datetime) -> None:
|
|
62
65
|
try:
|
|
63
|
-
|
|
66
|
+
_temp = await self._pct.get_temperature()
|
|
67
|
+
_LOGGER.debug("Fetched temperature %s. Applying filters.", _temp)
|
|
68
|
+
_temp = self._apply_filters(value=_temp)
|
|
69
|
+
if not _temp:
|
|
70
|
+
return
|
|
71
|
+
self._state = _temp
|
|
64
72
|
self._send_message(
|
|
65
73
|
topic=self._send_topic,
|
|
66
74
|
payload={STATE: self._state},
|
|
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
|