Victron GX stale devices (#168706)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Tomer
2026-04-23 22:06:13 +02:00
committed by GitHub
co-authored by Copilot Joost Lekkerkerker
parent 0122b2811a
commit 1cd34e8477
4 changed files with 65 additions and 1 deletions
@@ -6,6 +6,7 @@ import logging
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers import device_registry as dr
from .hub import Hub, VictronGxConfigEntry
@@ -65,3 +66,13 @@ async def async_unload_entry(hass: HomeAssistant, entry: VictronGxConfigEntry) -
hub.unregister_all_new_metric_callbacks()
return unload_ok
async def async_remove_config_entry_device(
hass: HomeAssistant,
config_entry: VictronGxConfigEntry,
device_entry: dr.DeviceEntry,
) -> bool:
"""Remove a device from the config entry if the device is no longer known."""
hub: Hub = config_entry.runtime_data
return not hub.is_device_connected(device_entry.identifiers)
@@ -142,6 +142,15 @@ class Hub:
device_info["via_device"] = (DOMAIN, f"{installation_id}_system_0")
return device_info
def is_device_connected(self, device_identifiers: set[tuple[str, str]]) -> bool:
"""Check if a device is currently known to the hub."""
known_devices = self._hub.devices
return any(
identifier[1].removeprefix(f"{self._hub.installation_id}_") in known_devices
for identifier in device_identifiers
if identifier[0] == DOMAIN
)
def get_diagnostics_data(self) -> dict[str, Any]:
"""Return diagnostics data for the hub's device and entity tree."""
return {
@@ -64,7 +64,7 @@ rules:
Not relevant.
reconfiguration-flow: todo
repair-issues: todo
stale-devices: todo
stale-devices: done
# Platinum
async-dependency: done
+44
View File
@@ -9,10 +9,14 @@ from victron_mqtt import (
Hub as VictronVenusHub,
MetricKind,
)
from victron_mqtt.testing import finalize_injection, inject_message
from homeassistant.components.victron_gx import async_remove_config_entry_device
from homeassistant.components.victron_gx.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from .const import MOCK_INSTALLATION_ID
@@ -210,3 +214,43 @@ async def test_hub_stop_disconnect_error(
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
async def test_remove_config_entry_device(
hass: HomeAssistant,
init_integration: tuple[VictronVenusHub, MockConfigEntry],
device_registry: dr.DeviceRegistry,
) -> None:
"""Test removing a device from the config entry."""
victron_hub, mock_config_entry = init_integration
# A device that was never discovered should be removable
device_entry = device_registry.async_get_or_create(
config_entry_id=mock_config_entry.entry_id,
identifiers={(DOMAIN, f"{MOCK_INSTALLATION_ID}_test_device")},
)
result = await async_remove_config_entry_device(
hass, mock_config_entry, device_entry
)
assert result is True
# Inject a sensor to make battery_0 a known device
await inject_message(
victron_hub,
f"N/{MOCK_INSTALLATION_ID}/battery/0/Dc/0/Current",
'{"value": 10.5}',
)
await finalize_injection(victron_hub)
await hass.async_block_till_done()
# A device that is currently connected should NOT be removable
connected_device = device_registry.async_get_or_create(
config_entry_id=mock_config_entry.entry_id,
identifiers={(DOMAIN, f"{MOCK_INSTALLATION_ID}_battery_0")},
)
result = await async_remove_config_entry_device(
hass, mock_config_entry, connected_device
)
assert result is False