diff --git a/homeassistant/components/nina/config_flow.py b/homeassistant/components/nina/config_flow.py index e6ebedb42082..6844db9c437e 100644 --- a/homeassistant/components/nina/config_flow.py +++ b/homeassistant/components/nina/config_flow.py @@ -13,7 +13,11 @@ from homeassistant.config_entries import ( ) from homeassistant.core import callback from homeassistant.data_entry_flow import section -from homeassistant.helpers import config_validation as cv, entity_registry as er +from homeassistant.helpers import ( + config_validation as cv, + device_registry as dr, + entity_registry as er, +) from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import VolDictType @@ -245,6 +249,7 @@ class OptionsFlowHandler(OptionsFlowWithReload): ) await self.remove_unused_entities(user_input) + await self.remove_unused_devices(user_input) self.hass.config_entries.async_update_entry( self.config_entry, data=user_input @@ -264,6 +269,20 @@ class OptionsFlowHandler(OptionsFlowWithReload): errors=errors, ) + async def remove_unused_devices(self, user_input: dict[str, Any]) -> None: + """Remove devices from regions that are not selected.""" + device_registry = dr.async_get(self.hass) + + removed_regions = set(self.data[CONF_REGIONS]) - set(user_input[CONF_REGIONS]) + + for region in removed_regions: + if device := device_registry.async_get_device( + identifiers={(DOMAIN, region)} + ): + device_registry.async_update_device( + device.id, remove_config_entry_id=self.config_entry.entry_id + ) + async def remove_unused_entities(self, user_input: dict[str, Any]) -> None: """Remove entities which are not used anymore.""" entity_registry = er.async_get(self.hass) diff --git a/tests/components/nina/conftest.py b/tests/components/nina/conftest.py index 8113eca50baa..9ccd88383337 100644 --- a/tests/components/nina/conftest.py +++ b/tests/components/nina/conftest.py @@ -14,6 +14,7 @@ from .const import ( DUMMY_CONFIG_ENTRY, DUMMY_CONFIG_ENTRY_AREA_FILTERS, DUMMY_CONFIG_ENTRY_DEFAULT_FILTERS, + DUMMY_CONFIG_ENTRY_MULTIPLE_REGIONS, ) from tests.common import ( @@ -80,6 +81,22 @@ def mock_config_entry_area_filter(hass: HomeAssistant) -> MockConfigEntry: return config_entry +@pytest.fixture +def mock_config_entry_multiple_regions(hass: HomeAssistant) -> MockConfigEntry: + """Provide a common mock config entry with an area filter.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + title="NINA", + data=deepcopy(DUMMY_CONFIG_ENTRY_MULTIPLE_REGIONS), + version=1, + minor_version=3, + ) + + config_entry.add_to_hass(hass) + + return config_entry + + @pytest.fixture def mock_nina_class(nina_region_codes: dict[str, str]) -> Generator[AsyncMock]: """Fixture to mock the NINA class.""" diff --git a/tests/components/nina/const.py b/tests/components/nina/const.py index bdf0f601e1ed..3aaba8b31666 100644 --- a/tests/components/nina/const.py +++ b/tests/components/nina/const.py @@ -55,3 +55,12 @@ DUMMY_CONFIG_ENTRY_AREA_FILTERS: dict[str, Any] = { CONF_AREA_FILTER: ".*nagold.*", }, } + +DUMMY_CONFIG_ENTRY_MULTIPLE_REGIONS: dict[str, Any] = { + CONF_MESSAGE_SLOTS: 5, + CONF_REGIONS: {"083350000000": "Aach, Stadt", "010590000000": "Test, Stadt"}, + CONF_FILTERS: { + CONF_HEADLINE_FILTER: "/(?!)/", + CONF_AREA_FILTER: ".*nagold.*", + }, +} diff --git a/tests/components/nina/test_config_flow.py b/tests/components/nina/test_config_flow.py index 0a2f1801940b..d504d636347c 100644 --- a/tests/components/nina/test_config_flow.py +++ b/tests/components/nina/test_config_flow.py @@ -25,7 +25,7 @@ from homeassistant.components.nina.const import ( from homeassistant.config_entries import SOURCE_USER from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType -from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import device_registry as dr, entity_registry as er from . import setup_platform from .const import DUMMY_USER_INPUT @@ -327,3 +327,52 @@ async def test_options_flow_entity_removal( ) assert len(entries) == new_slot_count * entities_per_slot + + +async def test_options_flow_device_removal( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + mock_config_entry_multiple_regions: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: + """Test if old devices are removed.""" + await setup_platform( + hass, mock_config_entry_multiple_regions, mock_nina_class, nina_warnings + ) + + old_devices = dr.async_entries_for_config_entry( + device_registry, mock_config_entry_multiple_regions.entry_id + ) + + assert len(old_devices) == len( + mock_config_entry_multiple_regions.data.get(CONF_REGIONS, []) + ) + + result = await hass.config_entries.options.async_init( + mock_config_entry_multiple_regions.entry_id + ) + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_MESSAGE_SLOTS: 5, + CONST_REGION_A_TO_D: ["095760000000_0"], + CONST_REGION_E_TO_H: [], + CONST_REGION_I_TO_L: [], + CONST_REGION_M_TO_Q: [], + CONST_REGION_R_TO_U: [], + CONST_REGION_V_TO_Z: [], + CONF_FILTERS: {}, + }, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + devices = dr.async_entries_for_config_entry( + device_registry, mock_config_entry_multiple_regions.entry_id + ) + + assert not any( + old_device.id in (device.id for device in devices) for old_device in old_devices + )