diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index f9cd751a81e..e986cc302ae 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -218,6 +218,9 @@ def _async_fix_device_id( for device_entry in device_entries: unique_id = str(next(iter(device_entry.identifiers))[1]) device_entry_map[unique_id] = device_entry + if unique_id.startswith(mac_address): + # Already in the correct format + continue if (suffix := unique_id.removeprefix(str(serial_number))) != unique_id: migrations[unique_id] = f"{mac_address}{suffix}" diff --git a/tests/components/rainbird/test_init.py b/tests/components/rainbird/test_init.py index 01e0c4458e4..520f8578c6e 100644 --- a/tests/components/rainbird/test_init.py +++ b/tests/components/rainbird/test_init.py @@ -449,3 +449,75 @@ async def test_fix_duplicate_device_ids( assert device_entry.identifiers == {(DOMAIN, MAC_ADDRESS_UNIQUE_ID)} assert device_entry.name_by_user == expected_device_name assert device_entry.disabled_by == expected_disabled_by + + +async def test_reload_migration_with_leading_zero_mac( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test migration and reload of a device with a mac address with a leading zero.""" + mac_address = "01:02:03:04:05:06" + mac_address_unique_id = dr.format_mac(mac_address) + serial_number = "0" + + # Setup the config entry to be in a pre-migrated state + config_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=serial_number, + data={ + "host": "127.0.0.1", + "password": "password", + CONF_MAC: mac_address, + "serial_number": serial_number, + }, + ) + config_entry.add_to_hass(hass) + + # Create a device and entity with the old unique id format + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + identifiers={(DOMAIN, f"{serial_number}-1")}, + ) + entity_entry = entity_registry.async_get_or_create( + "switch", + DOMAIN, + f"{serial_number}-1-zone1", + suggested_object_id="zone1", + config_entry=config_entry, + device_id=device_entry.id, + ) + + # Setup the integration, which will migrate the unique ids + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + # Verify the device and entity were migrated to the new format + migrated_device_entry = device_registry.async_get_device( + identifiers={(DOMAIN, f"{mac_address_unique_id}-1")} + ) + assert migrated_device_entry is not None + migrated_entity_entry = entity_registry.async_get(entity_entry.entity_id) + assert migrated_entity_entry is not None + assert migrated_entity_entry.unique_id == f"{mac_address_unique_id}-1-zone1" + + # Reload the integration + await hass.config_entries.async_reload(config_entry.entry_id) + await hass.async_block_till_done() + + # Verify the device and entity still have the correct identifiers and were not duplicated + reloaded_device_entry = device_registry.async_get(migrated_device_entry.id) + assert reloaded_device_entry is not None + assert reloaded_device_entry.identifiers == {(DOMAIN, f"{mac_address_unique_id}-1")} + reloaded_entity_entry = entity_registry.async_get(entity_entry.entity_id) + assert reloaded_entity_entry is not None + assert reloaded_entity_entry.unique_id == f"{mac_address_unique_id}-1-zone1" + + assert ( + len(dr.async_entries_for_config_entry(device_registry, config_entry.entry_id)) + == 1 + ) + assert ( + len(er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)) + == 1 + )