From c6157d55208017a03cc209e950e51776ac146be8 Mon Sep 17 00:00:00 2001 From: Franck Nijhof <git@frenck.dev> Date: Fri, 29 Oct 2021 06:08:59 +0200 Subject: [PATCH] Migrate Tuya unique IDs for switches & lights (#58631) --- homeassistant/components/tuya/__init__.py | 85 ++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index bcc5c9dc79c..4f34d3c31bf 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -14,9 +14,11 @@ from tuya_iot import ( TuyaOpenMQ, ) +from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.dispatcher import dispatcher_send from .const import ( @@ -33,6 +35,7 @@ from .const import ( PLATFORMS, TUYA_DISCOVERY_NEW, TUYA_HA_SIGNAL_UPDATE_ENTITY, + DPCode, ) _LOGGER = logging.getLogger(__name__) @@ -115,6 +118,9 @@ async def _init_tuya_sdk(hass: HomeAssistant, entry: ConfigEntry) -> bool: await hass.async_add_executor_job(home_manager.update_device_cache) await cleanup_device_registry(hass, device_manager) + # Migrate old unique_ids to the new format + async_migrate_entities_unique_ids(hass, entry, device_manager) + # Register known device IDs device_registry = dr.async_get(hass) for device in device_manager.device_map.values(): @@ -143,6 +149,83 @@ async def cleanup_device_registry( break +@callback +def async_migrate_entities_unique_ids( + hass: HomeAssistant, config_entry: ConfigEntry, device_manager: TuyaDeviceManager +) -> None: + """Migrate unique_ids in the entity registry to the new format.""" + entity_registry = er.async_get(hass) + registry_entries = er.async_entries_for_config_entry( + entity_registry, config_entry.entry_id + ) + light_entries = { + entry.unique_id: entry + for entry in registry_entries + if entry.domain == LIGHT_DOMAIN + } + switch_entries = { + entry.unique_id: entry + for entry in registry_entries + if entry.domain == SWITCH_DOMAIN + } + + for device in device_manager.device_map.values(): + # Old lights where in `tuya.{device_id}` format, now the DPCode is added. + # + # If the device is a previously supported light category and still has + # the old format for the unique ID, migrate it to the new format. + # + # Previously only devices providing the SWITCH_LED DPCode were supported, + # thus this can be added to those existing IDs. + # + # `tuya.{device_id}` -> `tuya.{device_id}{SWITCH_LED}` + if ( + device.category in ("dc", "dd", "dj", "fs", "fwl", "jsq", "xdd", "xxj") + and (entry := light_entries.get(f"tuya.{device.id}")) + and f"tuya.{device.id}{DPCode.SWITCH_LED}" not in light_entries + ): + entity_registry.async_update_entity( + entry.entity_id, new_unique_id=f"tuya.{device.id}{DPCode.SWITCH_LED}" + ) + + # Old switches has different formats for the unique ID, but is mappable. + # + # If the device is a previously supported switch category and still has + # the old format for the unique ID, migrate it to the new format. + # + # `tuya.{device_id}` -> `tuya.{device_id}{SWITCH}` + # `tuya.{device_id}_1` -> `tuya.{device_id}{SWITCH_1}` + # ... + # `tuya.{device_id}_6` -> `tuya.{device_id}{SWITCH_6}` + # `tuya.{device_id}_usb1` -> `tuya.{device_id}{SWITCH_USB1}` + # ... + # `tuya.{device_id}_usb6` -> `tuya.{device_id}{SWITCH_USB6}` + # + # In all other cases, the unique ID is not changed. + if device.category in ("bh", "cwysj", "cz", "dlq", "kg", "kj", "pc", "xxj"): + for postfix, dpcode in ( + ("", DPCode.SWITCH), + ("_1", DPCode.SWITCH_1), + ("_2", DPCode.SWITCH_2), + ("_3", DPCode.SWITCH_3), + ("_4", DPCode.SWITCH_4), + ("_5", DPCode.SWITCH_5), + ("_6", DPCode.SWITCH_6), + ("_usb1", DPCode.SWITCH_USB1), + ("_usb2", DPCode.SWITCH_USB2), + ("_usb3", DPCode.SWITCH_USB3), + ("_usb4", DPCode.SWITCH_USB4), + ("_usb5", DPCode.SWITCH_USB5), + ("_usb6", DPCode.SWITCH_USB6), + ): + if ( + entry := switch_entries.get(f"tuya.{device.id}{postfix}") + ) and f"tuya.{device.id}{dpcode}" not in switch_entries: + entity_registry.async_update_entity( + entry.entity_id, new_unique_id=f"tuya.{device.id}{dpcode}" + ) + + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unloading the Tuya platforms.""" unload = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) -- GitLab