Repository navigation
Optional cleanup of discovery configs for removed packs (2.3.0) - #27
Merged
Merged
Conversation
Home Assistant learns about entities from retained MQTT discovery messages, which survive on the broker until someone clears them. 2.1.1 added per-entity removals, but they are emitted per BmsRunner, so a pack dropped from bms_ids has no runner and keeps ~100 dead entities in Home Assistant, re-processed on every start. Changing bms_name_prefix orphans every pack the same way. New opt-in option `clean_orphaned_discovery` (default false). On startup the bridge reads the retained configs under its discovery prefix and clears those whose device id is ours (`<bms_name_prefix>_<id>_device_*`) for an id no longer in bms_ids. Every cleared topic is logged. Design: - `mqtt.orphan_removals()` decides what gets deleted. Pure and unit-tested: foreign integrations, another bridge's discovery prefix, unknown components and malformed device ids are all left alone, as are the packs still being polled. - `app._clean_orphaned_discovery()` does the broker conversation only, under the existing no-cover pragma for MQTT glue. - It runs before the /set subscriptions: aiomqtt hands out one shared message queue, so draining it while command topics were subscribed could swallow a user's write. Until we subscribe, none can arrive. Off by default because two bridges can share one broker, where a pack this instance does not poll may legitimately belong to the other. Add-on version 2.3.0. Closes #25 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Retained MQTT discovery messages outlive the bridge. 2.1.1 added per-entity removals, but they are emitted per
BmsRunner— so a pack dropped frombms_idshas no runner, and its ~100 entities stay in Home Assistant as dead, unavailable entries that are re-processed on every restart. Changingbms_name_prefixorphans every pack the same way.What changes
New option, off by default:
On startup the bridge reads the retained configs under its own
discovery_prefix, and clears those whose device id matches<bms_name_prefix>_<slave id>_device_*for a slave id no longer inbms_ids. Each cleared topic is logged, plus a summary.Design
The decision and the I/O are split, because this repo gates at 100 % branch coverage and
run()is excluded as top-level glue. Putting the logic inside the MQTT loop would have made the part that decides what to delete untestable.mqtt.orphan_removals(topics, *, settings)— pure, unit-tested. Leaves alone: packs still polled, other integrations, another jkbms2mqtt under a different discovery prefix, unknown components, malformed device ids, and already-cleared (empty) configs.app._clean_orphaned_discovery()— subscribe, collect, publish, log. Under the existing# pragma: no cover - MQTT glue.Ordering matters.
aiomqtthands out a single shared message queue (MessagesIteratoroverClient._queue), so draining it while the/settopics were subscribed could swallow a user's write. The cleanup therefore runs before those subscriptions, when no command can exist yet. Ending the collect window withwait_foris safe:Queue.get()doesn't drop an item when cancelled.Why opt-in. Two bridges can share one broker. A pack this instance doesn't poll may legitimately belong to the other one, and clearing its configs would delete that instance's entities.
Test plan
orphan_removals(removed pack cleared; configured packs untouched; foreign integration, foreign prefix, unknown component, malformed ids all ignored; empty broker; renders as an empty retained payload)false, present inconfig.yamloptions + schema, round-trips intoSettingsruff,mypy,pytest— 572 passed, 100 % branch coveragebms_ids, confirm the log lists the cleared topics and the entities disappear from Home Assistantdiscovery_prefixis untouchedCloses #25
🤖 Generated with Claude Code