boneIO 1.3.0.dev16__py3-none-any.whl → 1.3.0.dev18__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/bonecli.py +4 -1
- boneio/components/cover/cover.py +17 -9
- boneio/components/cover/time_based.py +21 -6
- boneio/core/config/config_helper.py +8 -9
- boneio/core/config/yaml_util.py +266 -225
- boneio/core/discovery.py +86 -77
- boneio/core/manager/covers.py +139 -98
- boneio/core/manager/display.py +12 -2
- boneio/core/manager/inputs.py +172 -182
- boneio/core/manager/manager.py +39 -2
- boneio/core/manager/modbus.py +2 -2
- boneio/core/manager/outputs.py +2 -2
- boneio/core/manager/remote.py +205 -235
- boneio/core/manager/sensors.py +288 -236
- boneio/core/manager/update.py +38 -1
- boneio/core/messaging/__init__.py +9 -1
- boneio/core/messaging/composite.py +85 -0
- boneio/core/messaging/lox.py +221 -0
- boneio/core/messaging/loxone.py +181 -0
- boneio/core/messaging/mqtt.py +3 -0
- boneio/core/remote/__init__.py +1 -1
- boneio/core/remote/base.py +21 -8
- boneio/core/remote/mqtt.py +14 -2
- boneio/core/state/manager.py +12 -2
- boneio/core/system/host_data.py +17 -0
- boneio/hardware/display/oled.py +77 -80
- boneio/integration/homeassistant.py +9 -0
- boneio/integration/lox_template.py +243 -0
- boneio/migrations/__init__.py +10 -0
- boneio/migrations/actions.py +230 -0
- boneio/migrations/assets/MANIFEST.sha256 +19 -0
- boneio/migrations/assets/docker/daemon.json +7 -0
- boneio/migrations/assets/docker/nodered/docker-compose.yaml +30 -0
- boneio/migrations/assets/docker/nodered/nginx/default.conf +50 -0
- boneio/migrations/assets/docker/nodered/node-red/settings.js +5 -0
- boneio/migrations/assets/journald/journald.conf +6 -0
- boneio/migrations/assets/mosquitto/boneio.conf +2 -0
- boneio/migrations/assets/sudoers/boneio +15 -0
- boneio/migrations/assets/systemd/boneio-oled-boot.service +17 -0
- boneio/migrations/assets/systemd/boneio.service +15 -0
- boneio/migrations/assets/systemd/set-hostname-once.service +12 -0
- boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +10 -0
- boneio/migrations/assets/usr-sbin/oled_boot_splash.py +257 -0
- boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +18 -0
- boneio/migrations/assets/usr-sbin/oled_msg.py +110 -0
- boneio/migrations/assets/usr-sbin/oled_msg.sh +17 -0
- boneio/migrations/bootstrap/boneio-migrate +389 -0
- boneio/migrations/bootstrap/install-helper.sh +43 -0
- boneio/migrations/bootstrap/sudoers-migrate +2 -0
- boneio/migrations/runner.py +469 -0
- boneio/migrations/versions/__init__.py +1 -0
- boneio/migrations/versions/v1_3_0_baseline.py +168 -0
- boneio/migrations/versions/v1_3_0dev18_fix_oled_boot.py +75 -0
- boneio/modbus/client.py +116 -2
- boneio/modbus/coordinator.py +7 -0
- boneio/models/events.py +17 -1
- boneio/runner.py +92 -67
- boneio/schema/remote_devices.yaml +8 -8
- boneio/schema/schema.yaml +39 -0
- boneio/version.py +1 -1
- boneio/webui/app.py +4 -0
- boneio/webui/frontend-dist/assets/ConfigEditor-vyhv5yQV.js +1 -0
- boneio/webui/frontend-dist/assets/{aiConfig-DCT969oj.js → aiConfig-LL3nlemJ.js} +2 -2
- boneio/webui/frontend-dist/assets/{aiWizardPrompt-Dpts0jpN.js → aiWizardPrompt-CmumVq54.js} +1 -1
- boneio/webui/frontend-dist/assets/index-D7hfuu2N.css +2 -0
- boneio/webui/frontend-dist/assets/index-D97SbEW0.js +44 -0
- boneio/webui/frontend-dist/assets/useTranslation-DxGR4SjZ.js +13 -0
- boneio/webui/frontend-dist/index.html +4 -4
- boneio/webui/frontend-dist/schema/config.schema.json +80 -0
- boneio/webui/frontend-dist/schema/lox_udp.schema.json +64 -0
- boneio/webui/frontend-dist/schema/mqtt.schema.json +22 -0
- boneio/webui/frontend-dist/sw.js +1 -1
- boneio/webui/routes/__init__.py +2 -0
- boneio/webui/routes/config.py +379 -306
- boneio/webui/routes/migrations.py +187 -0
- boneio/webui/routes/modbus.py +69 -4
- boneio/webui/schema/config.schema.json +80 -0
- boneio/webui/schema/lox_udp.schema.json +64 -0
- boneio/webui/schema/mqtt.schema.json +22 -0
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/METADATA +1 -1
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/RECORD +85 -53
- boneio/webui/frontend-dist/assets/ConfigEditor-BA-Cp1Kt.js +0 -1
- boneio/webui/frontend-dist/assets/index-BPw0PLPj.js +0 -39
- boneio/webui/frontend-dist/assets/index-CCPsr7-u.css +0 -2
- boneio/webui/frontend-dist/assets/useTranslation-Cdm82kxW.js +0 -13
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/WHEEL +0 -0
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/entry_points.txt +0 -0
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/licenses/LICENSE +0 -0
- {boneio-1.3.0.dev16.dist-info → boneio-1.3.0.dev18.dist-info}/top_level.txt +0 -0
boneio/bonecli.py
CHANGED
|
@@ -240,13 +240,16 @@ def run(
|
|
|
240
240
|
|
|
241
241
|
try:
|
|
242
242
|
_t1 = _time.monotonic()
|
|
243
|
-
_config = load_config_from_file(
|
|
243
|
+
_config = load_config_from_file(
|
|
244
|
+
config_file=config, progress_callback=draw_status,
|
|
245
|
+
)
|
|
244
246
|
_LOGGER.debug("[STARTUP TIMING] load_config_from_file: %.2fs", _time.monotonic() - _t1)
|
|
245
247
|
if not _config:
|
|
246
248
|
_LOGGER.error("Config not loaded. Exiting.")
|
|
247
249
|
draw_config_error("Config file is empty or missing")
|
|
248
250
|
return 1
|
|
249
251
|
configure_logger(log_config=_config.get("logger") or {}, debug=debug)
|
|
252
|
+
draw_status("Importing modules...")
|
|
250
253
|
# Granular timing of runner sub-imports to find the bottleneck
|
|
251
254
|
_t_a = _time.monotonic()
|
|
252
255
|
from boneio.const import ACTION
|
boneio/components/cover/cover.py
CHANGED
|
@@ -187,13 +187,17 @@ class BaseCover(BaseCoverABC, BasicMqtt):
|
|
|
187
187
|
|
|
188
188
|
self._event_bus.add_sigterm_listener(self.on_exit)
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
self._loop.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
try:
|
|
191
|
+
self._loop.call_soon_threadsafe(
|
|
192
|
+
self._loop.call_later,
|
|
193
|
+
0.5,
|
|
194
|
+
self.send_state,
|
|
195
|
+
self.state,
|
|
196
|
+
self.json_position
|
|
197
|
+
)
|
|
198
|
+
except RuntimeError:
|
|
199
|
+
# Event loop is closed (e.g. during tests)
|
|
200
|
+
pass
|
|
197
201
|
|
|
198
202
|
async def on_exit(self) -> None:
|
|
199
203
|
"""Stop on exit."""
|
|
@@ -206,8 +210,12 @@ class BaseCover(BaseCoverABC, BasicMqtt):
|
|
|
206
210
|
self._open_relay.turn_off()
|
|
207
211
|
self._close_relay.turn_off()
|
|
208
212
|
# Send relay states to WebSocket (not MQTT - that's handled by output_type check)
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
try:
|
|
214
|
+
asyncio.create_task(self._open_relay.async_send_state())
|
|
215
|
+
asyncio.create_task(self._close_relay.async_send_state())
|
|
216
|
+
except RuntimeError:
|
|
217
|
+
# Event loop is closed (e.g. during tests or shutdown)
|
|
218
|
+
pass
|
|
211
219
|
if self._current_operation in (OPENING, CLOSING):
|
|
212
220
|
self._last_operation = self._current_operation
|
|
213
221
|
self._current_operation = IDLE
|
|
@@ -43,7 +43,7 @@ class TimeBasedCover(BaseCover):
|
|
|
43
43
|
|
|
44
44
|
def _move_cover(self, direction: str, duration: float, target_position: int | None = None):
|
|
45
45
|
"""Run in sepearate thread.
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
Args:
|
|
48
48
|
direction: Direction of movement (OPEN or CLOSE)
|
|
49
49
|
duration: Full time for 0-100% movement in milliseconds
|
|
@@ -60,7 +60,10 @@ class TimeBasedCover(BaseCover):
|
|
|
60
60
|
|
|
61
61
|
if total_steps == 0 or duration == 0:
|
|
62
62
|
self._current_operation = IDLE
|
|
63
|
-
|
|
63
|
+
try:
|
|
64
|
+
self._loop.call_soon_threadsafe(lambda: self.send_state(self.state, self.json_position))
|
|
65
|
+
except RuntimeError:
|
|
66
|
+
pass
|
|
64
67
|
return
|
|
65
68
|
|
|
66
69
|
# Calculate actual duration based on remaining distance
|
|
@@ -69,7 +72,10 @@ class TimeBasedCover(BaseCover):
|
|
|
69
72
|
|
|
70
73
|
relay.turn_on()
|
|
71
74
|
# Send relay state to WebSocket (not MQTT - that's handled by output_type check)
|
|
72
|
-
|
|
75
|
+
try:
|
|
76
|
+
self._loop.call_soon_threadsafe(lambda r=relay: asyncio.ensure_future(r.async_send_state()))
|
|
77
|
+
except RuntimeError:
|
|
78
|
+
pass
|
|
73
79
|
start_time = time.monotonic()
|
|
74
80
|
|
|
75
81
|
while not self._stop_event.is_set():
|
|
@@ -84,7 +90,10 @@ class TimeBasedCover(BaseCover):
|
|
|
84
90
|
|
|
85
91
|
self._last_timestamp = current_time # Użyj pobranego czasu
|
|
86
92
|
if current_time - self._last_update_time >= 1:
|
|
87
|
-
|
|
93
|
+
try:
|
|
94
|
+
self._loop.call_soon_threadsafe(lambda: self.send_state(self.state, self.json_position))
|
|
95
|
+
except RuntimeError:
|
|
96
|
+
break
|
|
88
97
|
self._last_update_time = current_time
|
|
89
98
|
|
|
90
99
|
if target_position is not None:
|
|
@@ -98,9 +107,15 @@ class TimeBasedCover(BaseCover):
|
|
|
98
107
|
time.sleep(0.05) # Małe opóźnienie, aby nie blokować CPU
|
|
99
108
|
relay.turn_off()
|
|
100
109
|
# Send relay state to WebSocket (not MQTT - that's handled by output_type check)
|
|
101
|
-
|
|
110
|
+
try:
|
|
111
|
+
self._loop.call_soon_threadsafe(lambda r=relay: asyncio.ensure_future(r.async_send_state()))
|
|
112
|
+
except RuntimeError:
|
|
113
|
+
pass
|
|
102
114
|
self._current_operation = IDLE
|
|
103
|
-
|
|
115
|
+
try:
|
|
116
|
+
self._loop.call_soon_threadsafe(lambda: self.send_state_and_save(self.json_position))
|
|
117
|
+
except RuntimeError:
|
|
118
|
+
pass
|
|
104
119
|
self._last_update_time = time.monotonic() # Upewnij się, że aktualizacja jest wysłana na końcu ruchu
|
|
105
120
|
|
|
106
121
|
async def run_cover(self, current_operation: str, target_position: int | None = None) -> None:
|
|
@@ -386,8 +386,14 @@ class ConfigHelper:
|
|
|
386
386
|
def reload_config(self) -> dict[str, Any]:
|
|
387
387
|
"""Reload configuration from file and update cache.
|
|
388
388
|
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
Loads config from file using load_config_from_file() which tries the
|
|
390
|
+
disk cache first (~0.5s) and falls back to full Cerberus validation
|
|
391
|
+
(~20s) on cache miss. This method does NOT wait for any background
|
|
392
|
+
cache rebuild — it's independent.
|
|
393
|
+
|
|
394
|
+
NOTE: This method may take up to ~20s on BeagleBone if disk cache
|
|
395
|
+
is not available. Callers should run it via asyncio.to_thread() to
|
|
396
|
+
avoid blocking the event loop.
|
|
391
397
|
|
|
392
398
|
Returns:
|
|
393
399
|
dict: Reloaded configuration dictionary
|
|
@@ -395,13 +401,6 @@ class ConfigHelper:
|
|
|
395
401
|
Raises:
|
|
396
402
|
ValueError: If config_file_path is not set
|
|
397
403
|
"""
|
|
398
|
-
# Wait for background cache rebuild (started after config save)
|
|
399
|
-
try:
|
|
400
|
-
from boneio.webui.routes.config import wait_for_config_cache
|
|
401
|
-
wait_for_config_cache(timeout=30.0)
|
|
402
|
-
except ImportError:
|
|
403
|
-
pass # Web module not available (e.g., during tests)
|
|
404
|
-
|
|
405
404
|
_LOGGER.info("Reloading config from file: %s", self._config_file_path)
|
|
406
405
|
return self.get_config(force_reload=True)
|
|
407
406
|
|