Use UID instead of MAC or channel for unique_ID in Reolink (#119744)
This commit is contained in:
parent
d6be733287
commit
8b4a5042bb
8 changed files with 213 additions and 28 deletions
|
@ -15,6 +15,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DOMAIN
|
||||
|
@ -141,8 +142,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||
firmware_coordinator=firmware_coordinator,
|
||||
)
|
||||
|
||||
cleanup_disconnected_cams(hass, config_entry.entry_id, host)
|
||||
# first migrate and then cleanup, otherwise entities lost
|
||||
migrate_entity_ids(hass, config_entry.entry_id, host)
|
||||
cleanup_disconnected_cams(hass, config_entry.entry_id, host)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
||||
|
||||
|
@ -173,6 +175,24 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
|||
return unload_ok
|
||||
|
||||
|
||||
def get_device_uid_and_ch(
|
||||
device: dr.DeviceEntry, host: ReolinkHost
|
||||
) -> tuple[list[str], int | None]:
|
||||
"""Get the channel and the split device_uid from a reolink DeviceEntry."""
|
||||
device_uid = [
|
||||
dev_id[1].split("_") for dev_id in device.identifiers if dev_id[0] == DOMAIN
|
||||
][0]
|
||||
|
||||
if len(device_uid) < 2:
|
||||
# NVR itself
|
||||
ch = None
|
||||
elif device_uid[1].startswith("ch") and len(device_uid[1]) <= 5:
|
||||
ch = int(device_uid[1][2:])
|
||||
else:
|
||||
ch = host.api.channel_for_uid(device_uid[1])
|
||||
return (device_uid, ch)
|
||||
|
||||
|
||||
def cleanup_disconnected_cams(
|
||||
hass: HomeAssistant, config_entry_id: str, host: ReolinkHost
|
||||
) -> None:
|
||||
|
@ -183,17 +203,10 @@ def cleanup_disconnected_cams(
|
|||
device_reg = dr.async_get(hass)
|
||||
devices = dr.async_entries_for_config_entry(device_reg, config_entry_id)
|
||||
for device in devices:
|
||||
device_id = [
|
||||
dev_id[1].split("_ch")
|
||||
for dev_id in device.identifiers
|
||||
if dev_id[0] == DOMAIN
|
||||
][0]
|
||||
(device_uid, ch) = get_device_uid_and_ch(device, host)
|
||||
if ch is None:
|
||||
continue # Do not consider the NVR itself
|
||||
|
||||
if len(device_id) < 2:
|
||||
# Do not consider the NVR itself
|
||||
continue
|
||||
|
||||
ch = int(device_id[1])
|
||||
ch_model = host.api.camera_model(ch)
|
||||
remove = False
|
||||
if ch not in host.api.channels:
|
||||
|
@ -225,11 +238,54 @@ def migrate_entity_ids(
|
|||
hass: HomeAssistant, config_entry_id: str, host: ReolinkHost
|
||||
) -> None:
|
||||
"""Migrate entity IDs if needed."""
|
||||
device_reg = dr.async_get(hass)
|
||||
devices = dr.async_entries_for_config_entry(device_reg, config_entry_id)
|
||||
ch_device_ids = {}
|
||||
for device in devices:
|
||||
(device_uid, ch) = get_device_uid_and_ch(device, host)
|
||||
|
||||
if host.api.supported(None, "UID") and device_uid[0] != host.unique_id:
|
||||
if ch is None:
|
||||
new_device_id = f"{host.unique_id}"
|
||||
else:
|
||||
new_device_id = f"{host.unique_id}_{device_uid[1]}"
|
||||
new_identifiers = {(DOMAIN, new_device_id)}
|
||||
device_reg.async_update_device(device.id, new_identifiers=new_identifiers)
|
||||
|
||||
if ch is None:
|
||||
continue # Do not consider the NVR itself
|
||||
|
||||
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)}"
|
||||
new_identifiers = {(DOMAIN, new_device_id)}
|
||||
device_reg.async_update_device(device.id, new_identifiers=new_identifiers)
|
||||
|
||||
entity_reg = er.async_get(hass)
|
||||
entities = er.async_entries_for_config_entry(entity_reg, config_entry_id)
|
||||
for entity in entities:
|
||||
# Can be removed in HA 2025.1.0
|
||||
if entity.domain == "update" and entity.unique_id == host.unique_id:
|
||||
if entity.domain == "update" and entity.unique_id in [
|
||||
host.unique_id,
|
||||
format_mac(host.api.mac_address),
|
||||
]:
|
||||
entity_reg.async_update_entity(
|
||||
entity.entity_id, new_unique_id=f"{host.unique_id}_firmware"
|
||||
)
|
||||
continue
|
||||
|
||||
if host.api.supported(None, "UID") and not entity.unique_id.startswith(
|
||||
host.unique_id
|
||||
):
|
||||
new_id = f"{host.unique_id}_{entity.unique_id.split("_", 1)[1]}"
|
||||
entity_reg.async_update_entity(entity.entity_id, new_unique_id=new_id)
|
||||
|
||||
if entity.device_id in ch_device_ids:
|
||||
ch = ch_device_ids[entity.device_id]
|
||||
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue