mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Cleanup stale devices on incomfort integration startup (#136566)
This commit is contained in:
parent
7133eec185
commit
3e0f6562c7
@ -7,12 +7,12 @@ from incomfortclient import InvalidGateway, InvalidHeaterList
|
|||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .coordinator import InComfortDataCoordinator, async_connect_gateway
|
from .coordinator import InComfortData, InComfortDataCoordinator, async_connect_gateway
|
||||||
from .errors import InComfortTimeout, InComfortUnknownError, NoHeaters, NotFound
|
from .errors import InComfortTimeout, InComfortUnknownError, NoHeaters, NotFound
|
||||||
|
|
||||||
PLATFORMS = (
|
PLATFORMS = (
|
||||||
@ -27,6 +27,43 @@ INTEGRATION_TITLE = "Intergas InComfort/Intouch Lan2RF gateway"
|
|||||||
type InComfortConfigEntry = ConfigEntry[InComfortDataCoordinator]
|
type InComfortConfigEntry = ConfigEntry[InComfortDataCoordinator]
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_cleanup_stale_devices(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: InComfortConfigEntry,
|
||||||
|
data: InComfortData,
|
||||||
|
gateway_device: dr.DeviceEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Cleanup stale heater devices and climates."""
|
||||||
|
heater_serial_numbers = {heater.serial_no for heater in data.heaters}
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
device_entries = device_registry.devices.get_devices_for_config_entry_id(
|
||||||
|
entry.entry_id
|
||||||
|
)
|
||||||
|
stale_heater_serial_numbers: list[str] = [
|
||||||
|
device_entry.serial_number
|
||||||
|
for device_entry in device_entries
|
||||||
|
if device_entry.id != gateway_device.id
|
||||||
|
and device_entry.serial_number is not None
|
||||||
|
and device_entry.serial_number not in heater_serial_numbers
|
||||||
|
]
|
||||||
|
if not stale_heater_serial_numbers:
|
||||||
|
return
|
||||||
|
cleanup_devices: list[str] = []
|
||||||
|
# Find stale heater and climate devices
|
||||||
|
for serial_number in stale_heater_serial_numbers:
|
||||||
|
cleanup_list = [f"{serial_number}_{index}" for index in range(1, 4)]
|
||||||
|
cleanup_list.append(serial_number)
|
||||||
|
cleanup_identifiers = [{(DOMAIN, cleanup_id)} for cleanup_id in cleanup_list]
|
||||||
|
cleanup_devices.extend(
|
||||||
|
device_entry.id
|
||||||
|
for device_entry in device_entries
|
||||||
|
if device_entry.identifiers in cleanup_identifiers
|
||||||
|
)
|
||||||
|
for device_id in cleanup_devices:
|
||||||
|
device_registry.async_remove_device(device_id)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: InComfortConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: InComfortConfigEntry) -> bool:
|
||||||
"""Set up a config entry."""
|
"""Set up a config entry."""
|
||||||
try:
|
try:
|
||||||
@ -46,7 +83,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: InComfortConfigEntry) ->
|
|||||||
|
|
||||||
# Register discovered gateway device
|
# Register discovered gateway device
|
||||||
device_registry = dr.async_get(hass)
|
device_registry = dr.async_get(hass)
|
||||||
device_registry.async_get_or_create(
|
gateway_device = device_registry.async_get_or_create(
|
||||||
config_entry_id=entry.entry_id,
|
config_entry_id=entry.entry_id,
|
||||||
identifiers={(DOMAIN, entry.entry_id)},
|
identifiers={(DOMAIN, entry.entry_id)},
|
||||||
connections={(dr.CONNECTION_NETWORK_MAC, entry.unique_id)}
|
connections={(dr.CONNECTION_NETWORK_MAC, entry.unique_id)}
|
||||||
@ -55,6 +92,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: InComfortConfigEntry) ->
|
|||||||
manufacturer="Intergas",
|
manufacturer="Intergas",
|
||||||
name="RFGateway",
|
name="RFGateway",
|
||||||
)
|
)
|
||||||
|
async_cleanup_stale_devices(hass, entry, data, gateway_device)
|
||||||
coordinator = InComfortDataCoordinator(hass, data, entry.entry_id)
|
coordinator = InComfortDataCoordinator(hass, data, entry.entry_id)
|
||||||
entry.runtime_data = coordinator
|
entry.runtime_data = coordinator
|
||||||
await coordinator.async_config_entry_first_refresh()
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Tests for Intergas InComfort integration."""
|
"""Tests for Intergas InComfort integration."""
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
from aiohttp import ClientResponseError, RequestInfo
|
from aiohttp import ClientResponseError, RequestInfo
|
||||||
@ -8,13 +9,17 @@ from freezegun.api import FrozenDateTimeFactory
|
|||||||
from incomfortclient import InvalidGateway, InvalidHeaterList
|
from incomfortclient import InvalidGateway, InvalidHeaterList
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.incomfort import DOMAIN
|
||||||
from homeassistant.components.incomfort.coordinator import UPDATE_INTERVAL
|
from homeassistant.components.incomfort.coordinator import UPDATE_INTERVAL
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
from homeassistant.helpers.device_registry import DeviceRegistry
|
||||||
|
|
||||||
from tests.common import async_fire_time_changed
|
from .conftest import MOCK_HEATER_STATUS
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
@ -22,13 +27,62 @@ async def test_setup_platforms(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_incomfort: MagicMock,
|
mock_incomfort: MagicMock,
|
||||||
entity_registry: er.EntityRegistry,
|
entity_registry: er.EntityRegistry,
|
||||||
mock_config_entry: ConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the incomfort integration is set up correctly."""
|
"""Test the incomfort integration is set up correctly."""
|
||||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
assert mock_config_entry.state is ConfigEntryState.LOADED
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"mock_heater_status", [MOCK_HEATER_STATUS | {"serial_no": "c01d00c0ffee"}]
|
||||||
|
)
|
||||||
|
async def test_stale_devices_cleanup(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_registry: DeviceRegistry,
|
||||||
|
mock_incomfort: MagicMock,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_heater_status: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Test the incomfort integration is cleaning up stale devices."""
|
||||||
|
# Setup an old heater with serial_no c01d00c0ffee
|
||||||
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||||
|
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
||||||
|
old_entries = device_registry.devices.get_devices_for_config_entry_id(
|
||||||
|
mock_config_entry.entry_id
|
||||||
|
)
|
||||||
|
assert len(old_entries) == 3
|
||||||
|
old_heater = device_registry.async_get_device({(DOMAIN, "c01d00c0ffee")})
|
||||||
|
assert old_heater is not None
|
||||||
|
assert old_heater.serial_number == "c01d00c0ffee"
|
||||||
|
old_climate = device_registry.async_get_device({(DOMAIN, "c01d00c0ffee_1")})
|
||||||
|
assert old_heater is not None
|
||||||
|
old_climate = device_registry.async_get_device({(DOMAIN, "c01d00c0ffee_1")})
|
||||||
|
assert old_climate is not None
|
||||||
|
|
||||||
|
mock_heater_status["serial_no"] = "c0ffeec0ffee"
|
||||||
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
new_entries = device_registry.devices.get_devices_for_config_entry_id(
|
||||||
|
mock_config_entry.entry_id
|
||||||
|
)
|
||||||
|
assert len(new_entries) == 3
|
||||||
|
new_heater = device_registry.async_get_device({(DOMAIN, "c0ffeec0ffee")})
|
||||||
|
assert new_heater is not None
|
||||||
|
assert new_heater.serial_number == "c0ffeec0ffee"
|
||||||
|
new_climate = device_registry.async_get_device({(DOMAIN, "c0ffeec0ffee_1")})
|
||||||
|
assert new_climate is not None
|
||||||
|
|
||||||
|
old_heater = device_registry.async_get_device({(DOMAIN, "c01d00c0ffee")})
|
||||||
|
assert old_heater is None
|
||||||
|
old_climate = device_registry.async_get_device({(DOMAIN, "c01d00c0ffee_1")})
|
||||||
|
assert old_climate is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_coordinator_updates(
|
async def test_coordinator_updates(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user