diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 8db09cdb8da0266cdba1568c7c8e3ae2804116e7..6eae9e13030f3991adad212ab44079aa2cc98f01 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -325,6 +325,14 @@ class ConfigEntries: unloaded = await entry.async_unload(self.hass) + device_registry = await \ + self.hass.helpers.device_registry.async_get_registry() + device_registry.async_clear_config_entry(entry_id) + + entity_registry = await \ + self.hass.helpers.entity_registry.async_get_registry() + entity_registry.async_clear_config_entry(entry_id) + return { 'require_restart': not unloaded } diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 504448b948df3dd218868c0aa9d13abbb2439511..e6ff45af2fe05f7611ce3a94113e0c7d547888b0 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -45,7 +45,7 @@ class DeviceRegistry: self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) @callback - def async_get_device(self, identifiers: str, connections: tuple): + def async_get_device(self, identifiers: set, connections: set): """Check if device is registered.""" for device in self.devices.values(): if any(iden in device.identifiers for iden in identifiers) or \ @@ -127,6 +127,14 @@ class DeviceRegistry: return data + @callback + def async_clear_config_entry(self, config_entry): + """Clear config entry from registry entries.""" + for device in self.devices.values(): + if config_entry in device.config_entries: + device.config_entries.remove(config_entry) + self.async_schedule_save() + @bind_hass async def async_get_registry(hass) -> DeviceRegistry: diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 804ee4235d08870f36391885d33908653c12e5e2..da3645a96fe86466610f8bc002cb6560a477bb4b 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -31,7 +31,7 @@ STORAGE_VERSION = 1 STORAGE_KEY = 'core.entity_registry' -@attr.s(slots=True, frozen=True) +@attr.s(slots=True) class RegistryEntry: """Entity Registry Entry.""" @@ -250,6 +250,14 @@ class EntityRegistry: return data + @callback + def async_clear_config_entry(self, config_entry): + """Clear config entry from registry entries.""" + for entry in self.entities.values(): + if config_entry == entry.config_entry_id: + entry.config_entry_id = None + self.async_schedule_save() + @bind_hass async def async_get_registry(hass) -> EntityRegistry: diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index 84ad54f7b829bc76bf9eb29473674afefe6e9787..a9132529bc3b07e1e9b54f9e873b64cb97469f4a 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -138,3 +138,30 @@ async def test_loading_from_storage(hass, hass_storage): manufacturer='manufacturer', model='model') assert entry.id == 'abcdefghijklm' assert isinstance(entry.config_entries, set) + + +async def test_removing_config_entries(registry): + """Make sure we do not get duplicate entries.""" + entry = registry.async_get_or_create( + config_entry='123', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + entry2 = registry.async_get_or_create( + config_entry='456', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + entry3 = registry.async_get_or_create( + config_entry='123', + connections={('ethernet', '34:56:78:90:AB:CD:EF:12')}, + identifiers={('bridgeid', '4567')}, + manufacturer='manufacturer', model='model') + + assert len(registry.devices) == 2 + assert entry is entry2 + assert entry is not entry3 + assert entry.config_entries == {'123', '456'} + registry.async_clear_config_entry('123') + assert entry.config_entries == {'456'} + assert entry3.config_entries == set() diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index d0c088a6f6971bed005f4a9b3d543e4756801222..bb28287ddd81ec217fcf15e4056a39ee4f4d9e24 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -186,6 +186,15 @@ async def test_updating_config_entry_id(registry): assert entry2.config_entry_id == 'mock-id-2' +async def test_removing_config_entry_id(registry): + """Test that we update config entry id in registry.""" + entry = registry.async_get_or_create( + 'light', 'hue', '5678', config_entry_id='mock-id-1') + assert entry.config_entry_id == 'mock-id-1' + registry.async_clear_config_entry('mock-id-1') + assert entry.config_entry_id is None + + async def test_migration(hass): """Test migration from old data to new.""" old_conf = {