boneIO 1.3.0.dev17__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/components/cover/cover.py +17 -9
- boneio/components/cover/time_based.py +21 -6
- boneio/core/config/config_helper.py +8 -9
- boneio/core/discovery.py +86 -77
- boneio/core/manager/covers.py +139 -98
- boneio/core/manager/display.py +1 -1
- boneio/core/manager/inputs.py +172 -182
- boneio/core/manager/manager.py +36 -2
- boneio/core/manager/modbus.py +2 -2
- boneio/core/manager/outputs.py +2 -2
- boneio/core/manager/remote.py +20 -4
- boneio/core/manager/sensors.py +6 -6
- boneio/core/manager/update.py +38 -1
- boneio/core/remote/base.py +18 -5
- boneio/core/remote/mqtt.py +14 -2
- boneio/core/state/manager.py +12 -2
- boneio/hardware/display/oled.py +77 -80
- boneio/integration/lox_template.py +1 -1
- 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/runner.py +3 -3
- 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/sw.js +1 -1
- boneio/webui/routes/__init__.py +2 -0
- boneio/webui/routes/config.py +59 -43
- boneio/webui/routes/migrations.py +187 -0
- boneio/webui/routes/modbus.py +69 -4
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/METADATA +1 -1
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/RECORD +66 -40
- boneio/webui/frontend-dist/assets/ConfigEditor-QHQCOrq6.js +0 -1
- boneio/webui/frontend-dist/assets/index-BvmO3gdL.css +0 -2
- boneio/webui/frontend-dist/assets/index-Dzdilk6s.js +0 -44
- boneio/webui/frontend-dist/assets/useTranslation-DjBDGbAU.js +0 -13
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/WHEEL +0 -0
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/entry_points.txt +0 -0
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/licenses/LICENSE +0 -0
- {boneio-1.3.0.dev17.dist-info → boneio-1.3.0.dev18.dist-info}/top_level.txt +0 -0
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
|
|
boneio/core/discovery.py
CHANGED
|
@@ -18,10 +18,10 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
18
18
|
|
|
19
19
|
class BlackDiscoveryPublisher:
|
|
20
20
|
"""Publishes BoneIO Black device discovery information to MQTT.
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
This is NOT Home Assistant discovery - it's for autodiscovery
|
|
23
23
|
of neighboring BoneIO Black devices.
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
Discovery is split into separate topics for efficiency:
|
|
26
26
|
- discovery/device - Device info (id, name, serial, firmware)
|
|
27
27
|
- discovery/outputs - Available outputs
|
|
@@ -29,13 +29,13 @@ class BlackDiscoveryPublisher:
|
|
|
29
29
|
- discovery/inputs - Available inputs
|
|
30
30
|
- discovery/sensors - Available sensors
|
|
31
31
|
- discovery/modbus - Available modbus devices
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
All topics are published with retain=True.
|
|
34
34
|
"""
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
def __init__(self, manager: Manager, message_bus: MessageBus) -> None:
|
|
37
37
|
"""Initialize discovery publisher.
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
Args:
|
|
40
40
|
manager: Manager instance
|
|
41
41
|
message_bus: Message bus for MQTT communication
|
|
@@ -43,10 +43,10 @@ class BlackDiscoveryPublisher:
|
|
|
43
43
|
self._manager = manager
|
|
44
44
|
self._message_bus = message_bus
|
|
45
45
|
self._base_topic = f"{manager._config_helper.topic_prefix}/discovery"
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
def _publish(self, subtopic: str, payload: Any) -> None:
|
|
48
48
|
"""Publish payload to discovery subtopic with retain.
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
Args:
|
|
51
51
|
subtopic: Subtopic name (e.g., "device", "outputs")
|
|
52
52
|
payload: Payload to publish (will be JSON encoded)
|
|
@@ -55,11 +55,11 @@ class BlackDiscoveryPublisher:
|
|
|
55
55
|
payload_json = json.dumps(payload)
|
|
56
56
|
self._message_bus.send_message(topic=topic, payload=payload_json, retain=True)
|
|
57
57
|
_LOGGER.debug("Published discovery/%s: %s", subtopic, payload_json)
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
def _build_device_info(self) -> dict[str, Any]:
|
|
60
60
|
"""Build device information payload."""
|
|
61
61
|
from boneio.version import __version__
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
config_helper = self._manager._config_helper
|
|
64
64
|
device_info = {
|
|
65
65
|
"id": config_helper._serial_no or "unknown",
|
|
@@ -72,104 +72,116 @@ class BlackDiscoveryPublisher:
|
|
|
72
72
|
if config_helper._network_info:
|
|
73
73
|
device_info["ip"] = config_helper._network_info.get("ip", "")
|
|
74
74
|
return device_info
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
def _build_outputs(self) -> list[dict[str, Any]]:
|
|
77
77
|
"""Build outputs list (excludes cover outputs - those are in discovery/covers)."""
|
|
78
78
|
outputs = []
|
|
79
|
-
if hasattr(self._manager,
|
|
79
|
+
if hasattr(self._manager, "outputs") and self._manager.outputs:
|
|
80
80
|
for output_id, output in self._manager.outputs._outputs.items():
|
|
81
81
|
# Skip cover outputs - they are published in discovery/covers
|
|
82
|
-
output_type = getattr(output,
|
|
83
|
-
if output_type ==
|
|
82
|
+
output_type = getattr(output, "output_type", None)
|
|
83
|
+
if output_type == "cover":
|
|
84
84
|
continue
|
|
85
85
|
output_info = {
|
|
86
86
|
"id": output_id,
|
|
87
|
-
"name": getattr(output,
|
|
87
|
+
"name": getattr(output, "name", output_id),
|
|
88
88
|
}
|
|
89
89
|
if output_type:
|
|
90
90
|
output_info["type"] = output_type
|
|
91
91
|
outputs.append(output_info)
|
|
92
92
|
return outputs
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
def _build_covers(self) -> list[dict[str, Any]]:
|
|
95
|
-
"""Build covers list."""
|
|
95
|
+
"""Build covers list with tilt support info."""
|
|
96
96
|
covers = []
|
|
97
|
-
if hasattr(self._manager,
|
|
97
|
+
if hasattr(self._manager, "covers") and self._manager.covers:
|
|
98
98
|
for cover_id, cover in self._manager.covers._covers.items():
|
|
99
|
-
|
|
99
|
+
cover_info: dict[str, Any] = {
|
|
100
100
|
"id": cover_id,
|
|
101
|
-
"name": getattr(cover,
|
|
102
|
-
|
|
101
|
+
"name": getattr(cover, "name", cover_id),
|
|
102
|
+
"kind": getattr(cover, "kind", "time"),
|
|
103
|
+
"supports_tilt": getattr(cover, "kind", "time") == "venetian",
|
|
104
|
+
}
|
|
105
|
+
covers.append(cover_info)
|
|
103
106
|
return covers
|
|
104
|
-
|
|
107
|
+
|
|
105
108
|
def _build_inputs(self) -> list[dict[str, Any]]:
|
|
106
109
|
"""Build inputs list."""
|
|
107
110
|
inputs = []
|
|
108
|
-
if hasattr(self._manager,
|
|
111
|
+
if hasattr(self._manager, "inputs") and self._manager.inputs:
|
|
109
112
|
for input_id, input_device in self._manager.inputs._inputs.items():
|
|
110
|
-
inputs.append(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
inputs.append(
|
|
114
|
+
{
|
|
115
|
+
"id": input_id,
|
|
116
|
+
"name": getattr(input_device, "name", input_id),
|
|
117
|
+
}
|
|
118
|
+
)
|
|
114
119
|
return inputs
|
|
115
|
-
|
|
120
|
+
|
|
116
121
|
def _build_sensors(self) -> list[dict[str, Any]]:
|
|
117
122
|
"""Build sensors list."""
|
|
118
123
|
sensors = []
|
|
119
|
-
if hasattr(self._manager,
|
|
120
|
-
if hasattr(self._manager.sensors,
|
|
124
|
+
if hasattr(self._manager, "sensors") and self._manager.sensors:
|
|
125
|
+
if hasattr(self._manager.sensors, "_dallas_sensors"):
|
|
121
126
|
for sensor in self._manager.sensors._dallas_sensors:
|
|
122
|
-
sensors.append(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
sensors.append(
|
|
128
|
+
{
|
|
129
|
+
"id": sensor.id,
|
|
130
|
+
"name": sensor.name,
|
|
131
|
+
"type": "temperature",
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
if hasattr(self._manager.sensors, "_adc_sensors"):
|
|
128
135
|
for sensor in self._manager.sensors._adc_sensors:
|
|
129
|
-
sensors.append(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
sensors.append(
|
|
137
|
+
{
|
|
138
|
+
"id": sensor.id,
|
|
139
|
+
"name": sensor.name,
|
|
140
|
+
"type": "adc",
|
|
141
|
+
}
|
|
142
|
+
)
|
|
134
143
|
return sensors
|
|
135
|
-
|
|
144
|
+
|
|
136
145
|
def _build_modbus(self) -> list[dict[str, Any]]:
|
|
137
146
|
"""Build modbus devices list."""
|
|
138
147
|
modbus_devices = []
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
if (
|
|
149
|
+
hasattr(self._manager, "modbus")
|
|
150
|
+
and self._manager.modbus
|
|
151
|
+
and hasattr(self._manager.modbus, "_modbus_coordinators")
|
|
152
|
+
):
|
|
153
|
+
for device_id, device in self._manager.modbus._modbus_coordinators.items():
|
|
154
|
+
device_info = {
|
|
155
|
+
"id": device_id,
|
|
156
|
+
"name": getattr(device, "name", device_id),
|
|
157
|
+
}
|
|
158
|
+
if hasattr(device, "model"):
|
|
159
|
+
device_info["model"] = device.model
|
|
160
|
+
modbus_devices.append(device_info)
|
|
149
161
|
return modbus_devices
|
|
150
|
-
|
|
162
|
+
|
|
151
163
|
# Public methods for publishing individual sections
|
|
152
|
-
|
|
164
|
+
|
|
153
165
|
def publish_device(self) -> None:
|
|
154
166
|
"""Publish device info to discovery/device."""
|
|
155
167
|
self._publish("device", self._build_device_info())
|
|
156
|
-
|
|
168
|
+
|
|
157
169
|
def publish_outputs(self) -> None:
|
|
158
170
|
"""Publish outputs list to discovery/outputs."""
|
|
159
171
|
self._publish("outputs", self._build_outputs())
|
|
160
|
-
|
|
172
|
+
|
|
161
173
|
def publish_covers(self) -> None:
|
|
162
174
|
"""Publish covers list to discovery/covers."""
|
|
163
175
|
self._publish("covers", self._build_covers())
|
|
164
|
-
|
|
176
|
+
|
|
165
177
|
def publish_inputs(self) -> None:
|
|
166
178
|
"""Publish inputs list to discovery/inputs."""
|
|
167
179
|
self._publish("inputs", self._build_inputs())
|
|
168
|
-
|
|
180
|
+
|
|
169
181
|
def publish_sensors(self) -> None:
|
|
170
182
|
"""Publish sensors list to discovery/sensors."""
|
|
171
183
|
self._publish("sensors", self._build_sensors())
|
|
172
|
-
|
|
184
|
+
|
|
173
185
|
def publish_modbus(self) -> None:
|
|
174
186
|
"""Publish modbus devices list to discovery/modbus."""
|
|
175
187
|
self._publish("modbus", self._build_modbus())
|
|
@@ -177,13 +189,15 @@ class BlackDiscoveryPublisher:
|
|
|
177
189
|
def _build_irrigation(self) -> list[dict[str, Any]]:
|
|
178
190
|
"""Build irrigation controllers list."""
|
|
179
191
|
controllers = []
|
|
180
|
-
if hasattr(self._manager,
|
|
192
|
+
if hasattr(self._manager, "irrigation") and self._manager.irrigation:
|
|
181
193
|
for ctrl_id, ctrl in self._manager.irrigation._controllers.items():
|
|
182
|
-
controllers.append(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
controllers.append(
|
|
195
|
+
{
|
|
196
|
+
"id": ctrl_id,
|
|
197
|
+
"name": ctrl.name,
|
|
198
|
+
"zones": [{"id": z.id, "name": z.name} for z in ctrl.zones],
|
|
199
|
+
}
|
|
200
|
+
)
|
|
187
201
|
return controllers
|
|
188
202
|
|
|
189
203
|
def publish_irrigation(self) -> None:
|
|
@@ -192,7 +206,7 @@ class BlackDiscoveryPublisher:
|
|
|
192
206
|
|
|
193
207
|
async def publish_discovery(self) -> None:
|
|
194
208
|
"""Publish all discovery sections.
|
|
195
|
-
|
|
209
|
+
|
|
196
210
|
Publishes to:
|
|
197
211
|
- boneio/{device_id}/discovery/device
|
|
198
212
|
- boneio/{device_id}/discovery/outputs
|
|
@@ -201,24 +215,20 @@ class BlackDiscoveryPublisher:
|
|
|
201
215
|
- boneio/{device_id}/discovery/sensors
|
|
202
216
|
- boneio/{device_id}/discovery/modbus
|
|
203
217
|
- boneio/{device_id}/discovery/irrigation
|
|
204
|
-
|
|
218
|
+
|
|
205
219
|
All with retain=True.
|
|
206
|
-
|
|
220
|
+
|
|
207
221
|
Does nothing if send_boneio_autodiscovery is disabled in config.
|
|
208
222
|
"""
|
|
209
223
|
# Check if autodiscovery publishing is enabled
|
|
210
224
|
if not self._manager._config_helper.send_boneio_autodiscovery:
|
|
211
225
|
_LOGGER.debug("BoneIO autodiscovery publishing is disabled")
|
|
212
226
|
return
|
|
213
|
-
|
|
227
|
+
|
|
214
228
|
try:
|
|
215
229
|
device_info = self._build_device_info()
|
|
216
|
-
_LOGGER.info(
|
|
217
|
-
|
|
218
|
-
device_info["id"],
|
|
219
|
-
self._base_topic
|
|
220
|
-
)
|
|
221
|
-
|
|
230
|
+
_LOGGER.info("Publishing discovery for device '%s' to '%s/*'", device_info["id"], self._base_topic)
|
|
231
|
+
|
|
222
232
|
self.publish_device()
|
|
223
233
|
self.publish_outputs()
|
|
224
234
|
self.publish_covers()
|
|
@@ -226,9 +236,8 @@ class BlackDiscoveryPublisher:
|
|
|
226
236
|
self.publish_sensors()
|
|
227
237
|
self.publish_modbus()
|
|
228
238
|
self.publish_irrigation()
|
|
229
|
-
|
|
239
|
+
|
|
230
240
|
_LOGGER.info("Discovery published successfully")
|
|
231
|
-
|
|
241
|
+
|
|
232
242
|
except Exception as e:
|
|
233
243
|
_LOGGER.error("Failed to publish discovery: %s", e, exc_info=True)
|
|
234
|
-
|