From ea1539ee5051dc714abb38b50341a59fc0dea9d5 Mon Sep 17 00:00:00 2001 From: Donald Clark Jackson Date: Sat, 3 Oct 2026 22:54:08 -0700 Subject: [PATCH] docs(examples): correct stale claims in examples/README.md and example docstrings - utility-meter: the spec path moved to devices/utility-meter.md (written against v0.3, unchanged on the wire); tick() is an unimplemented stub, so say so instead of "simulates measurement updates"; usage shows the required --broker-config; the adapter adds eight capability nodes, not four. - examples/README.md: --config/EBUS_BROKER_CFG applies to four examples, not all (utility-meter uses -b/--broker-config, simple-span-controller builds its own); the throwaway-broker recipe used `mosquitto -c <(...)`, which mosquitto 2.x refuses; --check logs the root and its direct children. - ha-discovery-bridge: drop an internal tracker ID from the docstring. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T32pvgqCzp1qCz7K5gS9Wm --- examples/README.md | 10 ++++++---- examples/ha-discovery-bridge | 2 +- examples/simple-tree-device | 4 +++- examples/utility-meter | 21 ++++++++++++--------- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/examples/README.md b/examples/README.md index 5bd002f..7a1a17e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,7 +14,7 @@ Basic Homie device that publishes sensor data (temperature, humidity, air pressu ### simple-tree-device -A parent/child device TREE over one MQTT connection: a root `distribution-enclosure` (`panel-1`) with circuit and BESS children and a MID grandchild, all sharing the root's single connection. It shows building the tree inside one `with root.state_transition():` (so the root publishes one INIT->READY for the whole tree, not one per child), a settable property on a child whose `/set` routes back over the shared connection, and the per-device topics each tree node publishes under. Reach for this over `simple-device` when you need to model a device that contains sub-devices. `--check` builds the tree, logs its structure, and exits (it works even with the broker down, since connect is asynchronous). +A parent/child device TREE over one MQTT connection: a root `distribution-enclosure` (`panel-1`) with circuit and BESS children and a MID grandchild, all sharing the root's single connection. It shows building the tree inside one `with root.state_transition():` (so the root publishes one INIT->READY for the whole tree, not one per child), a settable property on a child whose `/set` routes back over the shared connection, and the per-device topics each tree node publishes under. Reach for this over `simple-device` when you need to model a device that contains sub-devices. `--check` builds the tree, logs the root and its direct children, and exits (it works even with the broker down, since connect is asynchronous). ```bash ./simple-tree-device --config /path/to/broker-cfg.json @@ -23,7 +23,7 @@ A parent/child device TREE over one MQTT connection: a root `distribution-enclos ### utility-meter -Publishes a single eBus utility-meter device (`energy.ebus.device.utility-meter`, per the Electrification Bus `data-models/utility-meter.md`, v0.3) with the data model's capabilities: the required `info` / `meter` / `status` plus the optional `grid` / `doe` / `price` / `demand` / `power-quality` a meter publishes when it has the signal. The `doe` and `price` capabilities are `json` properties (`doe/import-limit`/`export-limit`, `price/import-price`/`export-price`), each a JSON array of time-windowed objects that advertises its schema as a `$format` JSONSchema; enum properties advertise their allowed values via `$format`. A local HTTP endpoint stands in for the utility's out-of-band backhaul for runtime doe/price updates, validating each posted body against the property's `$format` before publish (install the `validation` extra to enable it: `pip install 'ebus-sdk[validation]'`). +Publishes a single eBus utility-meter device (`energy.ebus.device.utility-meter`, per the Electrification Bus `devices/utility-meter.md`, written against v0.3 of that data model) with the data model's capabilities: the required `info` / `meter` / `status` plus the optional `grid` / `doe` / `price` / `demand` / `power-quality` a meter publishes when it has the signal. The `doe` and `price` capabilities are `json` properties (`doe/import-limit`/`export-limit`, `price/import-price`/`export-price`), each a JSON array of time-windowed objects that advertises its schema as a `$format` JSONSchema; enum properties advertise their allowed values via `$format`. A local HTTP endpoint stands in for the utility's out-of-band backhaul for runtime doe/price updates, validating each posted body against the property's `$format` before publish (install the `validation` extra to enable it: `pip install 'ebus-sdk[validation]'`). ```bash ./utility-meter --config ./utility-meter-cfg.example.json --broker-config /path/to/broker-cfg.json @@ -105,15 +105,17 @@ Bridges eBus/Homie devices to Home Assistant MQTT discovery (the reverse of the ./ha-discovery-bridge --keep-running # leave it up for a real HA to consume ``` -No broker handy? A throwaway local one works: `mosquitto -c <(printf 'listener 1883 127.0.0.1\nallow_anonymous true\n')`, then run with no `--config`. +No broker handy? A throwaway local one works: `printf 'listener 1883 127.0.0.1\nallow_anonymous true\n' > /tmp/mosquitto.conf && mosquitto -c /tmp/mosquitto.conf`, then run with no `--config`. (mosquitto 2.x refuses a process-substitution path such as `-c <(...)`.) ## Configuration -All examples accept broker configuration via: +`simple-device`, `simple-tree-device`, `simple-controller`, and `ha-discovery-bridge` accept broker configuration via: 1. **Command line**: `--config /path/to/broker-cfg.json` 2. **Environment variable**: `EBUS_BROKER_CFG=/path/to/broker-cfg.json` +`utility-meter` takes the broker config as `-b` / `--broker-config` (its `--config` is the meter config), also defaulting to `EBUS_BROKER_CFG`. `simple-span-controller` builds its own config from the panel serial number, password, and mDNS. + ### Broker Config Format ```json diff --git a/examples/ha-discovery-bridge b/examples/ha-discovery-bridge index 2c7a315..ab6ce9a 100755 --- a/examples/ha-discovery-bridge +++ b/examples/ha-discovery-bridge @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Bridge eBus/Homie devices to Home Assistant MQTT discovery (SDK-dn4). +"""Bridge eBus/Homie devices to Home Assistant MQTT discovery. End-to-end demonstration and self-check for `ebus_sdk.ha.HaDiscoveryBridge`, against a REAL broker but WITHOUT needing a running Home Assistant. It: diff --git a/examples/simple-tree-device b/examples/simple-tree-device index 0491ff3..4547388 100755 --- a/examples/simple-tree-device +++ b/examples/simple-tree-device @@ -124,7 +124,9 @@ def build_tree(mqtt_cfg: dict, logger: logging.Logger) -> homie.Device: def main() -> None: parser = argparse.ArgumentParser(description="Example parent/child Homie device tree") parser.add_argument("-c", "--config", help="Path to broker config JSON (or set EBUS_BROKER_CFG env var)") - parser.add_argument("--check", action="store_true", help="Build the tree, log its structure, and exit") + parser.add_argument( + "--check", action="store_true", help="Build the tree, log the root and its direct children, and exit" + ) args = parser.parse_args() config_file = args.config or os.environ.get("EBUS_BROKER_CFG") diff --git a/examples/utility-meter b/examples/utility-meter index 9d85e81..4e7b894 100755 --- a/examples/utility-meter +++ b/examples/utility-meter @@ -3,8 +3,9 @@ utility-meter — eBus utility-meter publisher reference implementation. Publishes a single eBus utility-meter device -(`energy.ebus.device.utility-meter`, per `data-models/utility-meter.md` -in the Electrification Bus specification, v0.3) to an MQTT broker, exposing +(`energy.ebus.device.utility-meter`, per `devices/utility-meter.md` in the +Electrification Bus specification, written against v0.3 of that data model) +to an MQTT broker, exposing the data model's capabilities: the required `info`, `meter`, and `status`, plus the optional `grid`, `doe`, `price`, `demand`, and `power-quality` a meter publishes when it has the signal. The `doe` and `price` json properties @@ -38,7 +39,7 @@ Meter measurements (`meter/active-power`, etc.) are synthesised from a config file — this is a publisher reference, not a metrology device. Usage: - ./utility-meter --config /path/to/meter-cfg.json + ./utility-meter --config /path/to/meter-cfg.json --broker-config /path/to/broker-cfg.json See `utility-meter-cfg.example.json` for the config schema. """ @@ -70,7 +71,7 @@ DEFAULT_BROKER_CFG_ENV = "EBUS_BROKER_CFG" # eBus utility-meter device type per the data model. DEVICE_TYPE = "energy.ebus.device.utility-meter" -# Capability node types (the eBus utility-meter data model, v0.3: three MUST +# Capability node types (devices/utility-meter.md, v0.3: three MUST # capabilities plus five optional ones a meter publishes when it has the signal). CAPABILITY_INFO = "energy.ebus.capability.info" CAPABILITY_METER = "energy.ebus.capability.meter" @@ -156,9 +157,10 @@ class UtilityMeter: Knows nothing about MQTT — the adapter below translates this state to Homie/eBus topics. - Values change via `set_doe_*` methods (driven by the HTTP DOE endpoint) - and via `tick()` (driven by a periodic thread that simulates meter - measurement updates). Subscribers register callbacks via + Values change via `set_doe_*` methods (driven by the HTTP DOE endpoint). + A periodic thread also calls `tick()`, which is an unimplemented stub, so + meter measurements stay at their configured values. Subscribers register + callbacks via `add_property_on_change_callback`. """ @@ -433,7 +435,8 @@ class UtilityMeterAdapter: Translates a UtilityMeter to a Homie 5 device on the eBus broker. Creates one root device of type `energy.ebus.device.utility-meter` with - four capability nodes (`info`, `meter`, `status`, `doe`). Each Homie + eight capability nodes (`info`, `meter`, `status`, `grid`, `doe`, `price`, + `demand`, `power-quality`). Each Homie property is mirrored from the corresponding UtilityMeter property via a callback. """ @@ -778,7 +781,7 @@ def main(): "--tick-interval", type=float, default=5.0, - help="Synthetic-update interval seconds (default: 5.0).", + help="Interval in seconds for tick(), currently an unimplemented stub (default: 5.0).", ) args = parser.parse_args()