🗑️ Remove stale devices when they disappear from Comwatt #17

Merged
mat merged 1 commit from fix/22-remove-stale into main 2026-04-25 15:18:42 +00:00
Owner

Summary

Closes MateoGreil/homeassistant-comwatt#22.

When a device is deleted on the Comwatt side, its entities and the device itself currently stay in HA's registries forever. This PR adds a prune pass that runs after async_config_entry_first_refresh succeeds: walk the entity registry and device registry for this config entry and drop anything whose unique_id / identifier is no longer present in the fresh topology snapshot.

The prune only runs at setup (HA startup and integration reload), so a transient API hiccup during normal polling can never accidentally remove a real device — the first-refresh has to succeed, which means the topology we compare against is reliable.

Device removal uses async_update_device(remove_config_entry_id=...) so HA removes the device only if no other integration still references it.

Test plan

  • New test_setup_prunes_stale_entities_and_devices in test_init.py: seeds a stale device + entity, runs setup with an API response that doesn't mention them, asserts they've been removed.
  • pytest tests/ — 25 passed.
  • Hands-on: on your HA, add a device in Comwatt app, reload the integration, confirm the new entities appear. Then remove that device from the Comwatt app, reload the integration, confirm the entity and device disappear from Settings → Devices & services → Comwatt.
## Summary Closes [MateoGreil/homeassistant-comwatt#22](https://github.com/MateoGreil/homeassistant-comwatt/issues/22). When a device is deleted on the Comwatt side, its entities and the device itself currently stay in HA's registries forever. This PR adds a prune pass that runs after `async_config_entry_first_refresh` succeeds: walk the entity registry and device registry for this config entry and drop anything whose unique_id / identifier is no longer present in the fresh topology snapshot. The prune only runs at setup (HA startup and integration reload), so a transient API hiccup during normal polling can never accidentally remove a real device — the first-refresh has to succeed, which means the topology we compare against is reliable. Device removal uses `async_update_device(remove_config_entry_id=...)` so HA removes the device only if no other integration still references it. ## Test plan - [x] New `test_setup_prunes_stale_entities_and_devices` in `test_init.py`: seeds a stale device + entity, runs setup with an API response that doesn't mention them, asserts they've been removed. - [x] `pytest tests/` — 25 passed. - [ ] Hands-on: on your HA, add a device in Comwatt app, reload the integration, confirm the new entities appear. Then remove that device from the Comwatt app, reload the integration, confirm the entity and device disappear from Settings → Devices & services → Comwatt.
🗑️ Remove stale devices when they disappear from Comwatt
All checks were successful
Validate / validate-hacs (push) Has been skipped
Validate / validate-hassfest (push) Has been skipped
Validate / lint-ruff (push) Successful in 7s
Validate / test-pytest (push) Successful in 1m45s
Validate / type-check-mypy (push) Successful in 1m48s
Validate / validate-hacs (pull_request) Has been skipped
Validate / validate-hassfest (pull_request) Has been skipped
Validate / lint-ruff (pull_request) Successful in 7s
Validate / test-pytest (pull_request) Successful in 1m45s
Validate / type-check-mypy (pull_request) Successful in 1m49s
2015af572d
Closes #22.

When a device is deleted on the Comwatt side, its entities and the
device itself stay in HA's registries forever — there is no user-facing
way to clean them up short of removing and re-adding the whole
integration. Now, after each `async_config_entry_first_refresh`
succeeds, walk the entity and device registries for this config entry
and drop anything whose unique_id / identifier is no longer present in
the fresh topology snapshot.

Done only at setup (including integration reload) rather than on every
poll, so a transient API hiccup during normal operation can never prune
a legitimate device — the pre-flight refresh has to succeed before we
even look at the registries.

Device pruning uses `async_update_device(remove_config_entry_id=...)`
so HA removes the device only if no other integrations still reference
it, which is the safe idiom.
mat force-pushed fix/22-remove-stale from 2015af572d
All checks were successful
Validate / validate-hacs (push) Has been skipped
Validate / validate-hassfest (push) Has been skipped
Validate / lint-ruff (push) Successful in 7s
Validate / test-pytest (push) Successful in 1m45s
Validate / type-check-mypy (push) Successful in 1m48s
Validate / validate-hacs (pull_request) Has been skipped
Validate / validate-hassfest (pull_request) Has been skipped
Validate / lint-ruff (pull_request) Successful in 7s
Validate / test-pytest (pull_request) Successful in 1m45s
Validate / type-check-mypy (pull_request) Successful in 1m49s
to 1fd4f52e68
All checks were successful
Validate / validate-hacs (pull_request) Has been skipped
Validate / validate-hassfest (pull_request) Has been skipped
Validate / lint-ruff (pull_request) Successful in 7s
Validate / test-pytest (pull_request) Successful in 1m45s
Validate / type-check-mypy (pull_request) Successful in 1m49s
Validate / validate-hacs (push) Has been skipped
Validate / validate-hassfest (push) Has been skipped
Validate / lint-ruff (push) Successful in 7s
Validate / test-pytest (push) Successful in 1m45s
Validate / type-check-mypy (push) Successful in 1m48s
2026-04-24 21:53:00 +00:00
Compare
mat merged commit cefed8b2ef into main 2026-04-25 15:18:42 +00:00
mat deleted branch fix/22-remove-stale 2026-04-25 15:18:42 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
mat/homeassistant-comwatt!17
No description provided.