You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: add CHANGELOG, document parent/child trees in README
Start a CHANGELOG.md (Keep-a-Changelog format) anchored at 0.2.0.
Entry documents the breaking changes — Device constructor signature,
removed ID-based parent/child mutators, refresh_all_nodes rename —
alongside the additive features: tree navigation, effective-state
computation, delete protocol, reconnect cascade. Brief 0.1.7 and
0.1.2 entries reference git for pre-changelog history.
README gains a "Device Trees" Quick Start section showing the
parent= constructor pattern, batched state_transition, and 3-level
depth. Controller Role section gains a hierarchy/effective-state
example. Module Structure no longer mentions the removed mqtt.py
(extracted to ebus-mqtt-client at 56ad978). homie.py contents list
adds the new public surface: HOMIE_EFFECTIVE_STATE_TABLE,
DiscoveredDevice hierarchy fields, Controller tree-nav methods.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All notable changes to `ebus-sdk` are recorded here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases earlier than 0.2.0 predate this file — see `git log` and the corresponding `v0.1.x` tags for details.
4
+
5
+
## [Unreleased]
6
+
7
+
## [0.2.0] — 2026-06-11
8
+
9
+
The 0.2.0 release introduces first-class parent/child device trees on both the device (publisher) and controller (consumer) sides of the SDK. A panel-style root device can now own dozens of child devices that share a single MQTT connection and a single Last Will, and controllers can navigate the resulting tree and compute effective state per the Homie 5 spec without re-implementing the rules per consumer.
10
+
11
+
### Added
12
+
13
+
-`Device(parent=<Device>)` constructor argument for building child devices. The child borrows the root's MQTT connection — there is exactly one `MqttClient` per tree and exactly one Last Will registered, on the root's `$state` topic.
14
+
-`Device.root()`, `Device.parent()`, `Device.children()` — live references that walk the tree. `root_id()` / `parent_id()` accessors are now derived from these. Trees may be arbitrary depth (e.g. panel → BESS child → MID grandchild).
15
+
-`Device.delete()` — runs the Homie remove-child protocol (clear retained `$state` / `$description` / property values, detach from parent, re-publish parent's description). Recursive on roots: leaves-first teardown of the whole subtree.
16
+
-`Device.refresh_tree()` — recursive republish of description + nodes + state for every device under this one. Called automatically by `on_connect()` on broker reconnect so the entire tree's retained-state is re-established.
17
+
-`DiscoveredDevice.root_id`, `parent_id`, `children_ids`, `is_root` — hierarchy fields derived from `$description`.
-`Controller.get_effective_state(device_id)` and the public `HOMIE_EFFECTIVE_STATE_TABLE` module constant — implement the Homie 5 state-precedence rule. When a root is `init` / `disconnected` / `sleeping` / `lost`, every descendant is effectively the same state without each descendant needing to republish.
20
+
21
+
### Changed
22
+
23
+
-**BREAKING** — `Device` constructor signature. The previous string-ID args `root_id=`, `parent_id=`, and `children_ids=` are removed; use `parent=<Device>` instead. Pure root-device usage (`Device(id, name, type, mqtt_cfg, ...)`) is unchanged and source-compatible.
24
+
- The `Device._end_state_transition()` → broker sequence now emits exactly one `$state=init` and one `$state=ready` regardless of nesting depth (state transitions are reentrant via an internal depth counter). Previously a nested `with device.state_transition(): with device.state_transition(): ...` emitted a spurious extra INIT/READY cycle from the outer `__exit__`, forcing every controller in the wild to resync unnecessarily.
25
+
-`add_node()` and other structural mutations inside `with parent.state_transition(): ...` now collapse into a single parent `$state=init` → `$description` → `$state=ready` cycle for the whole batch. Building a panel with 32 circuit children produces one observable parent transition, not 32.
26
+
-`Device.publish()`, `delete_all_from_mqtt()`, `clear_retained_topic()`, and the `Property` → `Node` → `Device` publish chain all route through `Device.get_mqtt_client()`, which ascends to `root().mqttc`. There is no behavioral change for root devices; child devices now publish their topics through the root's connection automatically.
27
+
28
+
### Removed
29
+
30
+
-**BREAKING** — `Device.add_child(child_id)`. Children are added by constructing them with `parent=<Device>`; the `_children` list is maintained automatically.
31
+
-**BREAKING** — `Device.remove_child(child_id)`. Use `child_device.delete()` instead — it runs the full Homie remove-child protocol rather than just popping an ID from a list.
32
+
-**BREAKING** — `Device.set_parent(parent_id)` and `Device.unset_parent()`. Homie does not support reparenting at the wire level; destroy and reconstruct instead.
33
+
-**BREAKING** — `Device.refresh_all_nodes()`. Renamed to `refresh_tree()` to reflect that it now walks descendants. The old name was misleading: it always published `$description` and `$state` in addition to nodes.
34
+
35
+
### Fixed
36
+
37
+
- Recursive `Device.delete()` no longer emits gratuitous `$state=init` / `$state=ready` publishes on dying intermediate devices while the cascade is in progress.
38
+
- Broker reconnect now republishes every device in the tree (description, nodes, property values, state), not just the root.
39
+
40
+
## [0.1.7] — 2025
41
+
42
+
### Fixed
43
+
44
+
- Added `setup.py` shim for legacy setuptools toolchains that can't read `pyproject.toml`-only packages.
45
+
46
+
## [0.1.2] — 2025
47
+
48
+
Initial public release on PyPI. See `git log v0.1.2` for the surface that shipped.
Copy file name to clipboardExpand all lines: README.md
+48-10Lines changed: 48 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -46,6 +46,30 @@ device.start_mqtt_client()
46
46
temp.set_value(23.5)
47
47
```
48
48
49
+
### Device Trees (parent / child)
50
+
51
+
Build a tree of devices that share a single MQTT connection. The root device owns the connection (and the Last Will), every child borrows it via the `parent=` constructor arg, and `$description``root` / `parent` / `children` fields are kept in sync automatically. The tree can be any depth.
# Remove a child at runtime (runs the Homie remove-child protocol)
68
+
panel.children()[0].delete()
69
+
```
70
+
71
+
Children may have children of their own. A single Last Will registered on the root marks the entire tree `lost` if the publisher process dies — controllers compute effective state per the Homie 5 precedence table (see [`HOMIE_EFFECTIVE_STATE_TABLE`](src/ebus_sdk/homie.py)).
-**Unit** - Common units: `DEGREE_CELSIUS`, `PERCENT`, `WATT`, `KILOWATT_HOUR`, etc.
90
128
91
-
### mqtt.py
92
-
93
-
-**MqttClient** - Wrapper around paho-mqtt with automatic reconnection, TLS support, and subscription management
94
-
95
129
### property.py
96
130
97
131
Application-level property abstractions for bridging application state to Homie:
@@ -110,6 +144,10 @@ See [`examples/README.md`](examples/README.md) for example scripts demonstrating
110
144
- Python 3.10+
111
145
- paho-mqtt >= 1.6.1
112
146
147
+
## Releases
148
+
149
+
See [CHANGELOG.md](CHANGELOG.md). 0.2.0 introduces parent/child device trees and contains breaking changes to the `Device` constructor — see the changelog entry before upgrading from 0.1.x.
150
+
113
151
## Contributing
114
152
115
153
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to file Discussions, Issues, and pull requests. Pure MQTT-transport changes (TLS, auth, paho upgrades) belong in [`ebus-mqtt-client`](https://github.com/electrification-bus/ebus-mqtt-client), not here. Normative behavior tracks the [Electrification Bus specification](https://github.com/electrification-bus/specification).
0 commit comments