From 03ca7a90b49b434a4424ba0108e8eb9fe2f80908 Mon Sep 17 00:00:00 2001 From: Donald Clark Jackson Date: Fri, 9 Oct 2026 09:33:57 -0700 Subject: [PATCH] utility-meter: advertise the Homie keys on _ebus._tcp ebus-service-discovery 0.5.1 adds homie_domain, homie_version and homie_roles to the _ebus._tcp TXT when Identity.homie_domain is set (electrification-bus/python-service-discovery#8). The meter passes the domain its Homie device publishes under. The mdns extra requires 0.5.1. The default instance name is the first device id since 0.5.0, so the explicit instance_name is dropped. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T32pvgqCzp1qCz7K5gS9Wm --- CHANGELOG.md | 4 ++++ examples/README.md | 2 +- examples/utility-meter | 24 +++++++++++++++++------- pyproject.toml | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc69b04..42b9a50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to `ebus-sdk` are recorded here. Format follows [Keep a Chan ## [Unreleased] +### Changed + +- `utility-meter` adds `homie_domain`, `homie_version` and `homie_roles` to its `_ebus._tcp` advertisement, from the domain its Homie device publishes under. The `mdns` extra requires `ebus-service-discovery[zeroconf]>=0.5.1`, which added those keys (electrification-bus/python-service-discovery#8). + ## [0.26.0] — 2026-10-09 Adopts [`ebus-service-discovery`](https://github.com/electrification-bus/python-service-discovery) 0.5.0 for mDNS ([#100](https://github.com/electrification-bus/python-sdk/issues/100)); requires ebus-mqtt-client 0.8.0. diff --git a/examples/README.md b/examples/README.md index 5bc9f0c..86b1d7b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -37,7 +37,7 @@ Add `--discover` to find the broker over mDNS, with [`ebus-service-discovery`](h ./utility-meter --config ./utility-meter-cfg.example.json --broker-config /path/to/broker-cfg.json --discover ``` -With the `mdns` extra installed, the meter also advertises `_ebus._tcp` and `_device-info._tcp` (role `device`; manufacturer, model, serial number and firmware version from the config's `info`), as the eBus framework requires of every entity. `--no-advertise` turns this off. On a host with several network interfaces, see [electrification-bus/python-service-discovery#3](https://github.com/electrification-bus/python-service-discovery/issues/3). +With the `mdns` extra installed, the meter also advertises `_ebus._tcp` and `_device-info._tcp` (role `device`; manufacturer, model, serial number and firmware version from the config's `info`; `homie_domain`, `homie_version` and `homie_roles` from its Homie device), as the eBus framework requires of every entity. `--no-advertise` turns this off. On a host with several interfaces on one subnet, the advertisement uses one of them and moves to another if that one goes down (ebus-service-discovery's default `interfaces="one-per-subnet"`). Set a DOE envelope at runtime. The body is a single envelope object or an array of them (the retained schedule); it is set atomically as one `json` value: diff --git a/examples/utility-meter b/examples/utility-meter index e915186..940da71 100755 --- a/examples/utility-meter +++ b/examples/utility-meter @@ -463,6 +463,10 @@ class UtilityMeterAdapter: if self._homie_device is not None: self._homie_device.stop() + def homie_domain(self) -> str: + """The Homie domain the meter publishes under.""" + return self._homie_device.homie_domain() + @staticmethod def load_broker_config(config_file: str) -> Dict[str, Any]: with open(config_file, "r") as fp: @@ -752,8 +756,11 @@ def _discover_broker(mqtt_cfg: Dict[str, Any], timeout: float, log: logging.Logg return None -def _identity_from_info(device_id: str, info: Dict[str, Any]): - """The `_ebus._tcp` / `_device-info._tcp` identity from the meter's `info` config.""" +def _identity_from_info(device_id: str, info: Dict[str, Any], homie_domain: str): + """The `_ebus._tcp` / `_device-info._tcp` identity from the meter's `info` config. + + `homie_domain` adds the `homie_domain`, `homie_version` and `homie_roles` TXT keys. + """ from ebus_service_discovery.ebus import Identity return Identity( @@ -764,10 +771,11 @@ def _identity_from_info(device_id: str, info: Dict[str, Any]): serial_number=str(info.get("serial-number") or device_id), fw_version=str(info["firmware-version"]) if info.get("firmware-version") else None, device_type=DEVICE_TYPE, + homie_domain=homie_domain, ) -def _start_advertiser(device_id: str, info: Dict[str, Any], log: logging.Logger): +def _start_advertiser(device_id: str, info: Dict[str, Any], homie_domain: str, log: logging.Logger): """Advertise `_ebus._tcp` and `_device-info._tcp` (framework.md requirement 6). Returns the running `mdns.Advertiser`, or None when the `mdns` extra is not @@ -779,9 +787,7 @@ def _start_advertiser(device_id: str, info: Dict[str, Any], log: logging.Logger) log.warning("reason=advertiseSkipped,detail=mdns extra not installed (pip install 'ebus-sdk[mdns]')") return None try: - # Named for the device: on macOS the OS already advertises a - # `_device-info._tcp` instance under the host label, the default name. - advertiser = mdns.Advertiser(_identity_from_info(device_id, info), instance_name=device_id).start() + advertiser = mdns.Advertiser(_identity_from_info(device_id, info, homie_domain)).start() except Exception as exc: log.warning("reason=advertiseFailed,error=%s", exc) return None @@ -894,7 +900,11 @@ def main(): ) start_doe_endpoint(meter, args.doe_port) start_tick_thread(meter, args.tick_interval) - advertiser = None if args.no_advertise else _start_advertiser(device_id, meter_cfg.get("info", {}), log) + advertiser = ( + None + if args.no_advertise + else _start_advertiser(device_id, meter_cfg.get("info", {}), adapter.homie_domain(), log) + ) log.info( "reason=utilityMeterReady,deviceId=%s,deviceType=%s", diff --git a/pyproject.toml b/pyproject.toml index 6eced3c..fb4221f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dependencies = [ [project.optional-dependencies] # mDNS broker discovery and _ebus._tcp advertising for the examples, through # ebus-service-discovery (which brings zeroconf). -mdns = ["ebus-service-discovery[zeroconf]>=0.5.0"] +mdns = ["ebus-service-discovery[zeroconf]>=0.5.1"] # Optional: JSONSchema validation of `json`-datatype property `$format`. Absent # it, the SDK still runs and $format validation is gracefully skipped (with a # one-time warning). Kept optional so a constrained build (e.g. Yocto) can omit