Reolink fix dev/entity id migration (#130836)

pull/130903/head
starkillerOG 2024-11-18 18:59:17 +01:00 committed by GitHub
parent 039df1070e
commit a379535127
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 138 additions and 2 deletions

View File

@ -326,7 +326,19 @@ def migrate_entity_ids(
else:
new_device_id = f"{device_uid[0]}_{host.api.camera_uid(ch)}"
new_identifiers = {(DOMAIN, new_device_id)}
device_reg.async_update_device(device.id, new_identifiers=new_identifiers)
existing_device = device_reg.async_get_device(identifiers=new_identifiers)
if existing_device is None:
device_reg.async_update_device(
device.id, new_identifiers=new_identifiers
)
else:
_LOGGER.warning(
"Reolink device with uid %s already exists, "
"removing device with uid %s",
new_device_id,
device_uid,
)
device_reg.async_remove_device(device.id)
entity_reg = er.async_get(hass)
entities = er.async_entries_for_config_entry(entity_reg, config_entry_id)
@ -352,4 +364,18 @@ def migrate_entity_ids(
id_parts = entity.unique_id.split("_", 2)
if host.api.supported(ch, "UID") and id_parts[1] != host.api.camera_uid(ch):
new_id = f"{host.unique_id}_{host.api.camera_uid(ch)}_{id_parts[2]}"
entity_reg.async_update_entity(entity.entity_id, new_unique_id=new_id)
existing_entity = entity_reg.async_get_entity_id(
entity.domain, entity.platform, new_id
)
if existing_entity is None:
entity_reg.async_update_entity(
entity.entity_id, new_unique_id=new_id
)
else:
_LOGGER.warning(
"Reolink entity with unique_id %s already exists, "
"removing device with unique_id %s",
new_id,
entity.unique_id,
)
entity_reg.async_remove(entity.entity_id)

View File

@ -469,6 +469,116 @@ async def test_migrate_entity_ids(
assert device_registry.async_get_device(identifiers={(DOMAIN, new_dev_id)})
async def test_migrate_with_already_existing_device(
hass: HomeAssistant,
config_entry: MockConfigEntry,
reolink_connect: MagicMock,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test device ids that need to be migrated while the new ids already exist."""
original_dev_id = f"{TEST_MAC}_ch0"
new_dev_id = f"{TEST_UID}_{TEST_UID_CAM}"
domain = Platform.SWITCH
def mock_supported(ch, capability):
if capability == "UID" and ch is None:
return True
if capability == "UID":
return True
return True
reolink_connect.channels = [0]
reolink_connect.supported = mock_supported
device_registry.async_get_or_create(
identifiers={(DOMAIN, new_dev_id)},
config_entry_id=config_entry.entry_id,
disabled_by=None,
)
device_registry.async_get_or_create(
identifiers={(DOMAIN, original_dev_id)},
config_entry_id=config_entry.entry_id,
disabled_by=None,
)
assert device_registry.async_get_device(identifiers={(DOMAIN, original_dev_id)})
assert device_registry.async_get_device(identifiers={(DOMAIN, new_dev_id)})
# setup CH 0 and host entities/device
with patch("homeassistant.components.reolink.PLATFORMS", [domain]):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert (
device_registry.async_get_device(identifiers={(DOMAIN, original_dev_id)})
is None
)
assert device_registry.async_get_device(identifiers={(DOMAIN, new_dev_id)})
async def test_migrate_with_already_existing_entity(
hass: HomeAssistant,
config_entry: MockConfigEntry,
reolink_connect: MagicMock,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test entity ids that need to be migrated while the new ids already exist."""
original_id = f"{TEST_UID}_0_record_audio"
new_id = f"{TEST_UID}_{TEST_UID_CAM}_record_audio"
dev_id = f"{TEST_UID}_{TEST_UID_CAM}"
domain = Platform.SWITCH
def mock_supported(ch, capability):
if capability == "UID" and ch is None:
return True
if capability == "UID":
return True
return True
reolink_connect.channels = [0]
reolink_connect.supported = mock_supported
dev_entry = device_registry.async_get_or_create(
identifiers={(DOMAIN, dev_id)},
config_entry_id=config_entry.entry_id,
disabled_by=None,
)
entity_registry.async_get_or_create(
domain=domain,
platform=DOMAIN,
unique_id=new_id,
config_entry=config_entry,
suggested_object_id=new_id,
disabled_by=None,
device_id=dev_entry.id,
)
entity_registry.async_get_or_create(
domain=domain,
platform=DOMAIN,
unique_id=original_id,
config_entry=config_entry,
suggested_object_id=original_id,
disabled_by=None,
device_id=dev_entry.id,
)
assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id)
assert entity_registry.async_get_entity_id(domain, DOMAIN, new_id)
# setup CH 0 and host entities/device
with patch("homeassistant.components.reolink.PLATFORMS", [domain]):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert entity_registry.async_get_entity_id(domain, DOMAIN, original_id) is None
assert entity_registry.async_get_entity_id(domain, DOMAIN, new_id)
async def test_no_repair_issue(
hass: HomeAssistant, config_entry: MockConfigEntry, issue_registry: ir.IssueRegistry
) -> None: