mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Reolink fix device migration (#145443)
This commit is contained in:
parent
528a509479
commit
fc2fe32f34
@ -364,90 +364,88 @@ def migrate_entity_ids(
|
|||||||
devices = dr.async_entries_for_config_entry(device_reg, config_entry_id)
|
devices = dr.async_entries_for_config_entry(device_reg, config_entry_id)
|
||||||
ch_device_ids = {}
|
ch_device_ids = {}
|
||||||
for device in devices:
|
for device in devices:
|
||||||
for dev_id in device.identifiers:
|
(device_uid, ch, is_chime) = get_device_uid_and_ch(device, host)
|
||||||
(device_uid, ch, is_chime) = get_device_uid_and_ch(dev_id, host)
|
|
||||||
if not device_uid:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if host.api.supported(None, "UID") and device_uid[0] != host.unique_id:
|
if host.api.supported(None, "UID") and device_uid[0] != host.unique_id:
|
||||||
if ch is None:
|
if ch is None:
|
||||||
new_device_id = f"{host.unique_id}"
|
new_device_id = f"{host.unique_id}"
|
||||||
else:
|
else:
|
||||||
new_device_id = f"{host.unique_id}_{device_uid[1]}"
|
new_device_id = f"{host.unique_id}_{device_uid[1]}"
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Updating Reolink device UID from %s to %s",
|
"Updating Reolink device UID from %s to %s",
|
||||||
device_uid,
|
device_uid,
|
||||||
new_device_id,
|
new_device_id,
|
||||||
)
|
)
|
||||||
new_identifiers = {(DOMAIN, new_device_id)}
|
new_identifiers = {(DOMAIN, new_device_id)}
|
||||||
device_reg.async_update_device(
|
device_reg.async_update_device(device.id, new_identifiers=new_identifiers)
|
||||||
device.id, new_identifiers=new_identifiers
|
|
||||||
)
|
|
||||||
|
|
||||||
if ch is None or is_chime:
|
# Check for wrongfully combined entities in one device
|
||||||
continue # Do not consider the NVR itself or chimes
|
# Can be removed in HA 2025.12
|
||||||
|
new_identifiers = device.identifiers.copy()
|
||||||
# Check for wrongfully combined host with NVR entities in one device
|
remove_ids = False
|
||||||
# Can be removed in HA 2025.12
|
if (DOMAIN, host.unique_id) in device.identifiers:
|
||||||
if (DOMAIN, host.unique_id) in device.identifiers:
|
remove_ids = True # NVR/Hub in identifiers, keep that one, remove others
|
||||||
new_identifiers = device.identifiers.copy()
|
for old_id in device.identifiers:
|
||||||
for old_id in device.identifiers:
|
(old_device_uid, old_ch, old_is_chime) = get_device_uid_and_ch(old_id, host)
|
||||||
if old_id[0] == DOMAIN and old_id[1] != host.unique_id:
|
if (
|
||||||
new_identifiers.remove(old_id)
|
not old_device_uid
|
||||||
_LOGGER.debug(
|
or old_device_uid[0] != host.unique_id
|
||||||
"Updating Reolink device identifiers from %s to %s",
|
or old_id[1] == host.unique_id
|
||||||
device.identifiers,
|
|
||||||
new_identifiers,
|
|
||||||
)
|
|
||||||
device_reg.async_update_device(
|
|
||||||
device.id, new_identifiers=new_identifiers
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Check for wrongfully added MAC of the NVR/Hub to the camera
|
|
||||||
# Can be removed in HA 2025.12
|
|
||||||
host_connnection = (CONNECTION_NETWORK_MAC, host.api.mac_address)
|
|
||||||
if host_connnection in device.connections:
|
|
||||||
new_connections = device.connections.copy()
|
|
||||||
new_connections.remove(host_connnection)
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Updating Reolink device connections from %s to %s",
|
|
||||||
device.connections,
|
|
||||||
new_connections,
|
|
||||||
)
|
|
||||||
device_reg.async_update_device(
|
|
||||||
device.id, new_connections=new_connections
|
|
||||||
)
|
|
||||||
|
|
||||||
ch_device_ids[device.id] = ch
|
|
||||||
if host.api.supported(ch, "UID") and device_uid[1] != host.api.camera_uid(
|
|
||||||
ch
|
|
||||||
):
|
):
|
||||||
if host.api.supported(None, "UID"):
|
continue
|
||||||
new_device_id = f"{host.unique_id}_{host.api.camera_uid(ch)}"
|
if remove_ids:
|
||||||
else:
|
new_identifiers.remove(old_id)
|
||||||
new_device_id = f"{device_uid[0]}_{host.api.camera_uid(ch)}"
|
remove_ids = True # after the first identifier, remove the others
|
||||||
_LOGGER.debug(
|
if new_identifiers != device.identifiers:
|
||||||
"Updating Reolink device UID from %s to %s",
|
_LOGGER.debug(
|
||||||
device_uid,
|
"Updating Reolink device identifiers from %s to %s",
|
||||||
|
device.identifiers,
|
||||||
|
new_identifiers,
|
||||||
|
)
|
||||||
|
device_reg.async_update_device(device.id, new_identifiers=new_identifiers)
|
||||||
|
break
|
||||||
|
|
||||||
|
if ch is None or is_chime:
|
||||||
|
continue # Do not consider the NVR itself or chimes
|
||||||
|
|
||||||
|
# Check for wrongfully added MAC of the NVR/Hub to the camera
|
||||||
|
# Can be removed in HA 2025.12
|
||||||
|
host_connnection = (CONNECTION_NETWORK_MAC, host.api.mac_address)
|
||||||
|
if host_connnection in device.connections:
|
||||||
|
new_connections = device.connections.copy()
|
||||||
|
new_connections.remove(host_connnection)
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Updating Reolink device connections from %s to %s",
|
||||||
|
device.connections,
|
||||||
|
new_connections,
|
||||||
|
)
|
||||||
|
device_reg.async_update_device(device.id, new_connections=new_connections)
|
||||||
|
|
||||||
|
ch_device_ids[device.id] = ch
|
||||||
|
if host.api.supported(ch, "UID") and device_uid[1] != host.api.camera_uid(ch):
|
||||||
|
if host.api.supported(None, "UID"):
|
||||||
|
new_device_id = f"{host.unique_id}_{host.api.camera_uid(ch)}"
|
||||||
|
else:
|
||||||
|
new_device_id = f"{device_uid[0]}_{host.api.camera_uid(ch)}"
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Updating Reolink device UID from %s to %s",
|
||||||
|
device_uid,
|
||||||
|
new_device_id,
|
||||||
|
)
|
||||||
|
new_identifiers = {(DOMAIN, new_device_id)}
|
||||||
|
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,
|
new_device_id,
|
||||||
|
device_uid,
|
||||||
)
|
)
|
||||||
new_identifiers = {(DOMAIN, new_device_id)}
|
device_reg.async_remove_device(device.id)
|
||||||
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)
|
entity_reg = er.async_get(hass)
|
||||||
entities = er.async_entries_for_config_entry(entity_reg, config_entry_id)
|
entities = er.async_entries_for_config_entry(entity_reg, config_entry_id)
|
||||||
|
@ -724,6 +724,57 @@ async def test_cleanup_combined_with_NVR(
|
|||||||
reolink_connect.baichuan.mac_address.return_value = TEST_MAC_CAM
|
reolink_connect.baichuan.mac_address.return_value = TEST_MAC_CAM
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cleanup_hub_and_direct_connection(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
reolink_connect: MagicMock,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test cleanup of the device registry if IPC camera device was connected directly and through the hub/NVR."""
|
||||||
|
reolink_connect.channels = [0]
|
||||||
|
entity_id = f"{TEST_UID}_{TEST_UID_CAM}_record_audio"
|
||||||
|
dev_id = f"{TEST_UID}_{TEST_UID_CAM}"
|
||||||
|
domain = Platform.SWITCH
|
||||||
|
start_identifiers = {
|
||||||
|
(DOMAIN, dev_id), # IPC camera through hub
|
||||||
|
(DOMAIN, TEST_UID_CAM), # directly connected IPC camera
|
||||||
|
("OTHER_INTEGRATION", "SOME_ID"),
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_entry = device_registry.async_get_or_create(
|
||||||
|
identifiers=start_identifiers,
|
||||||
|
connections={(CONNECTION_NETWORK_MAC, TEST_MAC_CAM)},
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
disabled_by=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
entity_registry.async_get_or_create(
|
||||||
|
domain=domain,
|
||||||
|
platform=DOMAIN,
|
||||||
|
unique_id=entity_id,
|
||||||
|
config_entry=config_entry,
|
||||||
|
suggested_object_id=entity_id,
|
||||||
|
disabled_by=None,
|
||||||
|
device_id=dev_entry.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entity_registry.async_get_entity_id(domain, DOMAIN, entity_id)
|
||||||
|
device = device_registry.async_get_device(identifiers={(DOMAIN, dev_id)})
|
||||||
|
assert device
|
||||||
|
assert device.identifiers == start_identifiers
|
||||||
|
|
||||||
|
# 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, entity_id)
|
||||||
|
device = device_registry.async_get_device(identifiers={(DOMAIN, dev_id)})
|
||||||
|
assert device
|
||||||
|
assert device.identifiers == start_identifiers
|
||||||
|
|
||||||
|
|
||||||
async def test_no_repair_issue(
|
async def test_no_repair_issue(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, issue_registry: ir.IssueRegistry
|
hass: HomeAssistant, config_entry: MockConfigEntry, issue_registry: ir.IssueRegistry
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user