Fix Glances integration leaving stale entities for removed devices#169690
Draft
serl wants to merge 2 commits intohome-assistant:devfrom
Draft
Fix Glances integration leaving stale entities for removed devices#169690serl wants to merge 2 commits intohome-assistant:devfrom
serl wants to merge 2 commits intohome-assistant:devfrom
Conversation
Glances created entities once at setup and never removed them. When the underlying object disappeared on the remote host (most commonly Docker bridge networks like veth*/br-* which churn whenever containers are recreated, but also ZFS datasets), the entity stayed registered forever as STATE_UNAVAILABLE. Adapt the iotawatt pattern: on each coordinator update, add entities for new device labels and remove entities (from the entity registry) when their device label disappears from a populated parent type dict. A missing parent type is treated as a transient API gap and leaves the entity unavailable, preserving the existing test_sensor_removed behavior. Closes home-assistant#124563
Contributor
|
Hey there @engrbm87, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Glances integration so sensor entities can track dynamic device lists instead of only being created once at setup. It aims to prevent stale Glances entities from accumulating in Home Assistant when remote interfaces, filesystems, or similar resources disappear.
Changes:
- Refactors Glances sensor setup to add newly discovered entities on coordinator updates instead of only during initial setup.
- Removes dynamic Glances sensor entities from the entity registry when their backing device label disappears from an otherwise present data block.
- Adds sensor tests covering dynamic network-entity removal and creation on subsequent coordinator refreshes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
homeassistant/components/glances/sensor.py |
Adds dynamic entity discovery and auto-removal logic for Glances sensors. |
tests/components/glances/test_sensor.py |
Adds regression tests for dynamic network sensor removal and addition. |
Comment on lines
+305
to
+321
| created: set[tuple[str, str, str]] = set() | ||
|
|
||
| for sensor_type, sensors in coordinator.data.items(): | ||
| if sensor_type in ["fs", "diskio", "sensors", "raid", "gpu", "network"]: | ||
| entities.extend( | ||
| GlancesSensor( | ||
| coordinator, | ||
| sensor_description, | ||
| sensor_label, | ||
| ) | ||
| for sensor_label, params in sensors.items() | ||
| for param in params | ||
| if (sensor_description := SENSOR_TYPES.get((sensor_type, param))) | ||
| ) | ||
| else: | ||
| entities.extend( | ||
| GlancesSensor( | ||
| coordinator, | ||
| sensor_description, | ||
| ) | ||
| for sensor in sensors | ||
| if (sensor_description := SENSOR_TYPES.get((sensor_type, sensor))) | ||
| ) | ||
| @callback | ||
| def _add_new_entities() -> None: | ||
| new_entities: list[GlancesSensor] = [] | ||
| for sensor_type, sensors in coordinator.data.items(): | ||
| if sensor_type in DYNAMIC_TYPES: | ||
| for sensor_label, params in sensors.items(): | ||
| for param in params: | ||
| key = (sensor_type, sensor_label, param) | ||
| if key in created: | ||
| continue | ||
| if ( | ||
| description := SENSOR_TYPES.get((sensor_type, param)) | ||
| ) is None: | ||
| continue | ||
| created.add(key) |
Entities registered before the dynamic-removal behavior (or while Home Assistant was offline) had no live GlancesSensor instance to trigger _handle_coordinator_update, so they remained in the registry as STATE_UNAVAILABLE forever. Add a one-time sweep in async_setup_entry that removes registry entries whose dynamic device label is no longer present in the API response, mirroring the runtime guard: only remove when at least one candidate parent type dict is present and the label is missing from every present parent. Static singleton entries (empty sensor_label) are skipped so they remain unavailable through transient outages, matching the existing test_sensor_removed behavior.
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.
Proposed change
The Glances integration created sensor entities once at setup and never removed them. When the underlying device disappeared on the remote host (most commonly Docker bridge networks like
veth*/br-*, but also ZFS datasets), the entity stayed registered forever asSTATE_UNAVAILABLE. Users in the linked issue reported thousands of dead entities accumulating, breaking dashboards and the entity picker.This PR refactors
homeassistant/components/glances/sensor.pyso entity creation is dynamic, modeled on the canonical pattern used byhomeassistant/components/iotawatt/sensor.py(dynamic add+remove via a coordinator listener pluser.async_removein_handle_coordinator_update):async_setup_entrykeeps acreatedset and registers a coordinator listener that adds entities for new(sensor_type, sensor_label, param)keys appearing incoordinator.data.GlancesSensor._handle_coordinator_updatecallsentity_registry.async_remove(self.entity_id)when the entity's parent type dict is present incoordinator.databut its label is missing — meaning the underlying network/disk was deleted on the host. A missing parent type is still treated as a transient API gap and leaves the entity unavailable, preserving the existingtest_sensor_removedbehavior.Tests added in
tests/components/glances/test_sensor.py:test_dynamic_sensor_auto_removed: wheneth0disappears from thenetworkblock on the next poll, bothtest-eth0-rxandtest-eth0-txare removed from the entity registry, whiletest-lo-rxremains.test_dynamic_sensor_auto_added: when a new interfaceeth1appears on the next poll, the new entity is registered and has a non-unavailable state.Type of change
Additional information
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: