diff --git a/homeassistant/components/tradfri/__init__.py b/homeassistant/components/tradfri/__init__.py index cd6adbc5fef..2de40ab46e6 100644 --- a/homeassistant/components/tradfri/__init__.py +++ b/homeassistant/components/tradfri/__init__.py @@ -21,6 +21,7 @@ from homeassistant.helpers.event import async_track_time_interval from .const import CONF_GATEWAY_ID, CONF_IDENTITY, CONF_KEY, DOMAIN, LOGGER from .coordinator import TradfriDeviceDataUpdateCoordinator +from .migration import migrate_device_identifier from .models import TradfriData PLATFORMS = [ @@ -39,6 +40,9 @@ async def async_setup_entry( entry: ConfigEntry, ) -> bool: """Create a gateway.""" + # Migrate old integer device identifier to string, added in core-2022.7.0. + migrate_device_identifier(hass, entry) + factory = await APIFactory.init( entry.data[CONF_HOST], psk_id=entry.data[CONF_IDENTITY], @@ -151,7 +155,7 @@ def remove_stale_devices( if identifier[0] != DOMAIN: continue - # The device id in the identifier is not copied from integer to string + # The device id in the identifier was not copied from integer to string # when setting entity device info. Copy here to make sure it's a string. _id = str(identifier[1]) diff --git a/homeassistant/components/tradfri/entity.py b/homeassistant/components/tradfri/entity.py index 6d85a54e039..d76958a311a 100644 --- a/homeassistant/components/tradfri/entity.py +++ b/homeassistant/components/tradfri/entity.py @@ -59,7 +59,7 @@ class TradfriBaseEntity(CoordinatorEntity[TradfriDeviceDataUpdateCoordinator]): info = self._device.device_info self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, self._device_id)}, + identifiers={(DOMAIN, str(self._device.id))}, manufacturer=info.manufacturer, model=info.model_number, name=self._device.name, diff --git a/homeassistant/components/tradfri/migration.py b/homeassistant/components/tradfri/migration.py new file mode 100644 index 00000000000..1f70e3942a1 --- /dev/null +++ b/homeassistant/components/tradfri/migration.py @@ -0,0 +1,32 @@ +"""Provide migration tools for the Tradfri integration.""" +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +import homeassistant.helpers.device_registry as dr + +from .const import DOMAIN + + +@callback +def migrate_device_identifier(hass: HomeAssistant, config_entry: ConfigEntry) -> None: + """Migrate device identifier to new format.""" + device_registry = dr.async_get(hass) + device_entries = dr.async_entries_for_config_entry( + device_registry, config_entry.entry_id + ) + + for device_entry in device_entries: + device_identifiers = set(device_entry.identifiers) + + for identifier in device_entry.identifiers: + if identifier[0] == DOMAIN and isinstance( + identifier[1], int # type: ignore[unreachable] + ): + device_identifiers.remove(identifier) # type: ignore[unreachable] + # Copy pytradfri device id to string. + device_identifiers.add((DOMAIN, str(identifier[1]))) + break + + if device_identifiers != device_entry.identifiers: + device_registry.async_update_device( + device_entry.id, new_identifiers=device_identifiers + ) diff --git a/tests/components/tradfri/test_migration.py b/tests/components/tradfri/test_migration.py new file mode 100644 index 00000000000..21e52859cd9 --- /dev/null +++ b/tests/components/tradfri/test_migration.py @@ -0,0 +1,43 @@ +"""Test the tradfri migration tools.""" +from unittest.mock import MagicMock + +from homeassistant.components.tradfri.const import DOMAIN +from homeassistant.core import HomeAssistant +import homeassistant.helpers.device_registry as dr + +from . import GATEWAY_ID + +from tests.common import MockConfigEntry + + +async def test_migrate_device_identifier( + hass: HomeAssistant, mock_api_factory: MagicMock +) -> None: + """Test migrate device identifier.""" + entry = MockConfigEntry( + domain=DOMAIN, + data={ + "host": "mock-host", + "identity": "mock-identity", + "key": "mock-key", + "gateway_id": GATEWAY_ID, + }, + ) + entry.add_to_hass(hass) + device_registry = dr.async_get(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, 1)}, # type: ignore[arg-type] + ) + + assert device_entry.identifiers == {(DOMAIN, 1)} # type: ignore[comparison-overlap] + + # FIXME: We need to mock the pytradfri device on the gateway. + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + migrated_device_entry = device_registry.async_get(device_entry.id) + + assert migrated_device_entry + assert migrated_device_entry.identifiers == {(DOMAIN, "1")}