From 756f27a64002e17283f771e0a5250fa9c6cadbf0 Mon Sep 17 00:00:00 2001 From: Donald Clark Jackson Date: Thu, 8 Oct 2026 20:32:57 -0700 Subject: [PATCH] utility-meter: wait for the configured broker under ebus-service-discovery 0.5.0 0.5.0's discovery-with-fallback returns the configured broker when the broker it hears is a different one, so the discovery loop fell back on the first browse that heard any broker. Use match_configured() and keep browsing until the configured broker is heard or --discover-timeout ends. Raise the mdns extra's floor to 0.5.0 and correct the README and CHANGELOG description. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T32pvgqCzp1qCz7K5gS9Wm --- CHANGELOG.md | 6 +++--- examples/README.md | 2 +- examples/utility-meter | 15 ++++++++++----- pyproject.toml | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 155578e..16329e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to `ebus-sdk` are recorded here. Format follows [Keep a Chan ## [Unreleased] -Adopts [`ebus-service-discovery`](https://github.com/electrification-bus/python-service-discovery) 0.4.0 for mDNS ([#100](https://github.com/electrification-bus/python-sdk/issues/100)). +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)). ### Added @@ -12,8 +12,8 @@ Adopts [`ebus-service-discovery`](https://github.com/electrification-bus/python- ### Changed -- The `mdns` extra installs `ebus-service-discovery[zeroconf]>=0.4.0` in place of `zeroconf>=0.131.0`. zeroconf still comes with it, as a dependency of that package. -- `utility-meter --discover` finds the broker with `ebus-service-discovery` (`mdns.browse_many()`, `ebus.rank_brokers()`, `ebus.select_broker()`). A plain (non-TLS) broker config now also accepts `_mqtt._tcp`; a TLS config still accepts only `_secure-mqtt._tcp`. `use_tls` follows the discovered service type, and when the config names a `host`, a discovered broker with that host is preferred among several. The fallback to the config's `host` after `--discover-timeout` seconds is unchanged. +- The `mdns` extra installs `ebus-service-discovery[zeroconf]>=0.5.0` in place of `zeroconf>=0.131.0`. zeroconf still comes with it, as a dependency of that package. +- `utility-meter --discover` finds the broker with `ebus-service-discovery` (`mdns.browse_many()`, `ebus.rank_brokers()`, `ebus.match_configured()`). A plain (non-TLS) broker config now also accepts `_mqtt._tcp`; a TLS config still accepts only `_secure-mqtt._tcp`. `use_tls` follows the discovered service type, and when the config names a `host`, only a discovered broker that is that host is used, so another broker never receives the config's credentials. The fallback to the config's `host` after `--discover-timeout` seconds is unchanged. - `simple-span-controller` accepts only the `_secure-mqtt._tcp` advertisement whose SRV target is `span-.local` (it matched a substring of the target before, and also browsed `_mqtt._tcp`), and connects by that host name instead of the first IPv4 address. When this host cannot resolve `.local` names, it connects to the panel's most-preferred advertised address. ## [0.25.0] — 2026-10-08 diff --git a/examples/README.md b/examples/README.md index a0b711a..5bc9f0c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,7 +31,7 @@ Publishes a single eBus utility-meter device (`energy.ebus.device.utility-meter` **Need a broker to run against?** [`broker-quickstart`](https://github.com/electrification-bus/broker-quickstart) brings up a local eBus broker on macOS with one command (`python -m laptop.run`), including the mDNS advertisement that `--discover` (below) resolves. Its `scripts/laptop-bench.sh` runs this simulator against that broker with `--discover`, end to end; see the [laptop quickstart](https://github.com/electrification-bus/broker-quickstart/blob/main/docs/laptop-quickstart.md). -Add `--discover` to find the broker over mDNS, with [`ebus-service-discovery`](https://github.com/electrification-bus/python-service-discovery), instead of using the `host`/`port` in the broker config; the broker config still supplies the TLS material and credentials. A TLS broker config accepts only `_secure-mqtt._tcp`; a plain one accepts `_secure-mqtt._tcp` or `_mqtt._tcp`. When the config also names a `host`, a discovered broker with that host is preferred, and the config's `host` is the fallback after `--discover-timeout` seconds. Needs the `mdns` extra (`pip install 'ebus-sdk[mdns]'`): +Add `--discover` to find the broker over mDNS, with [`ebus-service-discovery`](https://github.com/electrification-bus/python-service-discovery), instead of using the `host`/`port` in the broker config; the broker config still supplies the TLS material and credentials. A TLS broker config accepts only `_secure-mqtt._tcp`; a plain one accepts `_secure-mqtt._tcp` or `_mqtt._tcp`. When the config also names a `host`, only a discovered broker that is that host is used, so another broker never receives the config's credentials, and the config's `host` is the fallback after `--discover-timeout` seconds. When you know where the broker is, leave out `--discover`. Needs the `mdns` extra (`pip install 'ebus-sdk[mdns]'`): ```bash ./utility-meter --config ./utility-meter-cfg.example.json --broker-config /path/to/broker-cfg.json --discover diff --git a/examples/utility-meter b/examples/utility-meter index e431044..e915186 100755 --- a/examples/utility-meter +++ b/examples/utility-meter @@ -714,8 +714,10 @@ def _discover_broker(mqtt_cfg: Dict[str, Any], timeout: float, log: logging.Logg `use_tls` (the host is the advertised `broker` TXT value, the name the broker's certificate covers, else the SRV target), or None when no broker is found within `timeout` seconds. A TLS config accepts only - `_secure-mqtt._tcp`. When the config names a `host`, a discovered broker - with that host is preferred among several. Requires the `mdns` extra. + `_secure-mqtt._tcp`. When the config names a `host`, only a discovered + broker that is that host is used (another broker never receives this + config's credentials); otherwise the first ranked broker. Requires the + `mdns` extra. """ try: from ebus_service_discovery import mdns @@ -723,8 +725,8 @@ def _discover_broker(mqtt_cfg: Dict[str, Any], timeout: float, log: logging.Logg SECURE_MQTT_SERVICE, TCP_BROKER_TYPES, BrokerEndpoint, + match_configured, rank_brokers, - select_broker, ) except ImportError: log.error("discovery needs the 'mdns' extra: pip install 'ebus-sdk[mdns]'") @@ -740,8 +742,11 @@ def _discover_broker(mqtt_cfg: Dict[str, Any], timeout: float, log: logging.Logg while (remaining := deadline - time.monotonic()) > 0: found = mdns.browse_many(accept, min(3.0, remaining), zc) usable = rank_brokers((BrokerEndpoint.from_instance(i) for i in found), accept=accept) - if usable: - return select_broker("discovery-with-fallback", configured, usable).mqtt_cfg(mqtt_cfg) + chosen = usable[0] if configured is None and usable else None + if configured is not None: + chosen = match_configured(configured, usable) + if chosen is not None: + return chosen.mqtt_cfg(mqtt_cfg) finally: zc.close() return None diff --git a/pyproject.toml b/pyproject.toml index 92be5c3..007a2c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,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.4.0"] +mdns = ["ebus-service-discovery[zeroconf]>=0.5.0"] # 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