diff --git a/homeassistant/components/generic/__init__.py b/homeassistant/components/generic/__init__.py index f243f1639b3..cb669d8b906 100644 --- a/homeassistant/components/generic/__init__.py +++ b/homeassistant/components/generic/__init__.py @@ -1,8 +1,12 @@ """The generic component.""" +from __future__ import annotations + +from typing import Any from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import entity_registry as er DOMAIN = "generic" PLATFORMS = [Platform.CAMERA] @@ -13,9 +17,25 @@ async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> Non await hass.config_entries.async_reload(entry.entry_id) +async def _async_migrate_unique_ids(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Migrate entities to the new unique id.""" + + @callback + def _async_migrator(entity_entry: er.RegistryEntry) -> dict[str, Any] | None: + if entity_entry.unique_id == entry.entry_id: + # Already correct, nothing to do + return None + # There is only one entity, and its unique id + # should always be the same as the config entry entry_id + return {"new_unique_id": entry.entry_id} + + await er.async_migrate_entries(hass, entry.entry_id, _async_migrator) + + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up generic IP camera from a config entry.""" + await _async_migrate_unique_ids(hass, entry) hass.config_entries.async_setup_platforms(entry, PLATFORMS) entry.async_on_unload(entry.add_update_listener(_async_update_listener)) diff --git a/homeassistant/components/generic/camera.py b/homeassistant/components/generic/camera.py index e83cb0df0aa..d20032e2607 100644 --- a/homeassistant/components/generic/camera.py +++ b/homeassistant/components/generic/camera.py @@ -109,7 +109,7 @@ async def async_setup_entry( """Set up a generic IP Camera.""" async_add_entities( - [GenericCamera(hass, entry.options, entry.unique_id, entry.title)] + [GenericCamera(hass, entry.options, entry.entry_id, entry.title)] ) diff --git a/homeassistant/components/generic/config_flow.py b/homeassistant/components/generic/config_flow.py index 3d15069bca8..4298b473681 100644 --- a/homeassistant/components/generic/config_flow.py +++ b/homeassistant/components/generic/config_flow.py @@ -274,7 +274,6 @@ class GenericIPCamConfigFlow(ConfigFlow, domain=DOMAIN): # is always jpeg user_input[CONF_CONTENT_TYPE] = "image/jpeg" - await self.async_set_unique_id(self.flow_id) return self.async_create_entry( title=name, data={}, options=user_input ) @@ -302,7 +301,6 @@ class GenericIPCamConfigFlow(ConfigFlow, domain=DOMAIN): import_config[CONF_LIMIT_REFETCH_TO_URL_CHANGE] = False still_format = import_config.get(CONF_CONTENT_TYPE, "image/jpeg") import_config[CONF_CONTENT_TYPE] = still_format - await self.async_set_unique_id(self.flow_id) return self.async_create_entry(title=name, data={}, options=import_config) diff --git a/tests/components/generic/test_config_flow.py b/tests/components/generic/test_config_flow.py index 3caa1aa7adf..f5411ed3ea0 100644 --- a/tests/components/generic/test_config_flow.py +++ b/tests/components/generic/test_config_flow.py @@ -28,6 +28,7 @@ from homeassistant.const import ( CONF_VERIFY_SSL, HTTP_BASIC_AUTHENTICATION, ) +from homeassistant.helpers import entity_registry from tests.common import MockConfigEntry @@ -577,3 +578,36 @@ async def test_reload_on_title_change(hass) -> None: await hass.async_block_till_done() assert hass.states.get("camera.my_title").attributes["friendly_name"] == "New Title" + + +async def test_migrate_existing_ids(hass) -> None: + """Test that existing ids are migrated for issue #70568.""" + + registry = entity_registry.async_get(hass) + + test_data = TESTDATA_OPTIONS.copy() + test_data[CONF_CONTENT_TYPE] = "image/png" + old_unique_id = "54321" + entity_id = "camera.sample_camera" + + mock_entry = MockConfigEntry( + domain=DOMAIN, unique_id=old_unique_id, options=test_data, title="My Title" + ) + new_unique_id = mock_entry.entry_id + mock_entry.add_to_hass(hass) + + entity_entry = registry.async_get_or_create( + "camera", + DOMAIN, + old_unique_id, + suggested_object_id="sample camera", + config_entry=mock_entry, + ) + assert entity_entry.entity_id == entity_id + assert entity_entry.unique_id == old_unique_id + + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() + + entity_entry = registry.async_get(entity_id) + assert entity_entry.unique_id == new_unique_id