fix(topology): ask for bus topology when adding a gateway, prune whole duplicate devices (#524) - #525
Conversation
…e duplicate devices (OpenWebNet-HA#524) A gateway added next to a configured one was set up as a standalone primary: its startup sweep discovered every device the other gateway already had. Once it was made a follower, only the duplicate actuators were pruned, leaving their lock / unlock / calibrate buttons unavailable on devices without an actuator. - Config flow: when another IP gateway is configured, a bus_topology step asks standalone or shared before the entry exists. Shared creates the entry as secondary / standby of the chosen gateway (role and delegated WHOs suggested from both models) and promotes a standalone primary to shared primary. - Pruning a follower's duplicate now also removes its companion buttons and the device once empty; button setup cleans up orphans left by earlier versions (only when the primary has the actuator). - topology: split the follower delegation out of infer_shared_bus_topology; recommend_follower keeps the configured gateway as primary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Testing this PR: one line from the Home Assistant terminal@anotherjulien, you can try this on your F454 + MH202 without a release or HACS. From the Terminal & SSH add-on: curl -fsSL https://github.com/GreenGrassBlueOcean/MyHOME/releases/download/pr-525-test/install.sh | bashIt backs up your current integration to What's in it (pre-release
The full MyHOME suite passes against that OWNd (2617 tests). Important We urgently need an OWNd release. What to check:
Roll back: rm -rf /config/custom_components/myhome && cp -a /config/myhome_backup/<the backup dir> /config/custom_components/myhome && ha core restartThe restored manifest pins |
|
Thanks for the neat package 🙂 So:
If the F454 is standalone, it is correctly switched to principal on a shared bus On my way to perform the tests in #524 ! |
|
Quick note: if I add it through the config flow as a secondary with delegated WHO2, the cover devices still appear under the F454. |
…gateway anotherjulien found it on OpenWebNet-HA#525: after a follower's duplicate covers are pruned in favour of the primary, its device-level "Calibrate all covers" button stayed present and looked available even though this gateway has nothing left to calibrate. `available` now also requires at least one cover entity of this config entry, matching what `async_press` already checks. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for both — pushed a fix for the first, and the second is expected behaviour. 1. "Calibrate all covers" button unavailable-but-present: fixed in 2. Covers "still appear under the F454" with WHO 2 delegated to the MH202: this is existing #453 behaviour, not something #525 changes. Delegation only decides who discovers new devices going forward — it never moves devices a gateway already owns. Your F454 discovered those covers when it was still standalone, long before the MH202 was configured; delegating WHO 2 to the MH202 afterwards doesn't retroactively transfer them. Concretely: the MH202 does try to create them from the bus, but |
Updated test build — same one-liner@anotherjulien, curl -fsSL https://github.com/GreenGrassBlueOcean/MyHOME/releases/download/pr-525-test/install.sh | bashBacks up your current integration first, then restarts Home Assistant. Release is MyHOME @ What's new to check:
Nothing else changed — A (the topology step) and the rest of B (device/button pruning) are exactly what you already confirmed working. No need to redo those unless you want to. Rollback is the same as before: rm -rf /config/custom_components/myhome && cp -a /config/myhome_backup/<the backup dir> /config/custom_components/myhome && ha core restart |
4463e23
into
OpenWebNet-HA:v2-phase1-architecture
Fixes #524 (split out of #523).
Problem
Adding a second gateway on a bus that a configured gateway already serves:
*#2*0##returns 11 cover addresses (11#4#02,85,12–16,18,19,21,22behind#4#02). That's 11 cover devices plus 33 buttons before the user can do anything.PlatformDiscovery.restore()prunes the duplicate actuators (Two gateways in one installation? Help us support shared buses (MH200N + MH201, MHS1 + LN4890, …) #453). It left their lock / unlock / calibrate buttons registered, andbutton.pyno longer rebuilds them, so they stay behind as unavailable orphans on a device without its actuator. This is what @anotherjulien saw.Changes
A. Topology in the initial config flow. When another IP gateway is configured (not a follower, not USB/serial), a new
bus_topologystep runs before the entry is created:bus_topology: standalonestored.recommend_follower(), which keeps the configured gateway as primary because it already owns the devices. For example, an MH202 next to a MyHomeServer1 takes WHO 16+22; next to an F454 it becomes a standby.validate_shared_bus_topology(), and any matching shared-bus repair issue is dismissed.B. Prune whole devices, not just the entity.
discovery.prune_entity()removes the entity together with its-disable/-enable/-calibratebuttons, then the device once nothing is left on it.restore()now uses it.prune_orphaned_companions()runs at follower button setup. It removes buttons left behind by earlier versions, but only when this gateway no longer has the actuator and the primary does. Buttons of an actuator a user deleted are left alone.availablenow also requires at least one cover entity on this config entry (found live by @anotherjulien on fix(topology): ask for bus topology when adding a gateway, prune whole duplicate devices (#524) #525, fixed ind2e2fa32).topology.infer_shared_bus_topology()now shares its follower-delegation logic (_follower_delegation) withrecommend_follower(). Its behaviour is unchanged.Strings: new step and errors in
strings.json/en.json, with nl/fr/it translations.How it works
A. Adding a gateway (config flow)
B. Follower setup: removing duplicates without leaving orphans
Either platform may set up first. If the buttons are rebuilt before
restore()prunes their actuator, removing the registry entries takes the live button entities down too.C. Holding back discovery on an unconfirmed entry: feasibility
As proposed ("hold discovery while topology is unconfirmed and other gateways exist"): feasible, but I don't recommend it.
PlatformDiscovery._discovers()andinitial_discovery()onCONF_BUS_TOPOLOGY in entry.options.bus_topologystored. The only unconfirmed entries left are ones created by earlier versions, where the duplicates already exist.Better variant: detect instead of hold, to prefill A's answer.
During the
bus_topologystep, the new gateway would send a few point status requests (*#1*<addr>##) for addresses the configured gateway already has entities for. It would then listen on that gateway'smyhome_message_<mac>signal for the replies for about 2 s. Hearing them means same bus, so Shared is preselected.It is read-only (status requests only) and runs while both gateways are connected.
The existing TX→RX echo detector (
_correlate_shared_bus_traffic) can't do this job. It needs 3 command echoes within 5 min, which a quiet plant may never produce, and commands change state, so they can't be used as a probe.Confirmed on a real bus, live: same-bus replies do cross, but only in one direction. @anotherjulien tested this on his F454 + MH202 (#524), sending point status requests (light
*#1*33##, cover*#2*31##) from each gateway while tracing both, plus*#2*99##(a nonexistent address) as a control:*#2*99##(nonexistent) → either side?The MH202→F454 misses aren't a capture gap: in that exact window the F454's trace caught one unrelated bus frame (proving its monitor was live), just never a reply to anything the MH202 sent. So this is a real, repeatable asymmetry on that bus — not a trace-capture artifact — and the control frame rules out a false "same bus" from either direction.
What this means for the probe: my original sketch ("new gateway sends, existing gateway listens") is exactly the direction that failed on this plant. The reliable direction is the other way round: the already-configured gateway sends, the new gateway listens. That's slightly more work than the original estimate, since the new gateway only has a short test connection during onboarding, not a running event listener yet — it needs a temporary monitor session for those couple of seconds:
Next step: a follow-up PR once A/B have settled, roughly 150 lines plus tests (the extra size over my original estimate is the temporary monitor session). Whether this asymmetry is specific to Julien's plant (a bus coupler, a firmware difference in how the two models arbitrate the bus) or general to F454+MH202 pairs is still open; it doesn't block the design above either way, since only the working direction is needed.
Tests
tests/test_shared_bus_onboarding.py(15 tests):Full suite (WSL, core 2026.9.2): 2618 passed, 100.0 % coverage. Ruff and
verify_ha_standards.pypass.mypy-ratchetpasses in CI. Locally, the newer WSL core reports 8 strict errors in code this PR doesn't touch; the two this PR introduced are fixed.V2 Architecture: New entities implement
handle_event()and do not manually subscribe viaasync_dispatcher_connect. (No new entities.)🤖 Generated with Claude Code