Просмотр исходного кода

Migrate entity ids to use device_class when unnamed.

Some older entity ids will be in the entity registry with just the
platform, but if they are marked with a device_class, the id will now
use that.  The registered entities need to be migrated to match the
new ids to avoid leaving zombie entities in the registry, and losing
any user customisations of name, icon etc.  It may also help with
finding the right entity in automations etc, but I am not sure so will
still list the possiblity that automations will need updating in
breaking changes.

Issue #871
Jason Rumney 2 лет назад
Родитель
Сommit
3b77686990

+ 44 - 0
custom_components/tuya_local/__init__.py

@@ -224,6 +224,50 @@ async def async_migrate_entry(hass, entry: ConfigEntry):
         await async_migrate_entries(hass, entry.entry_id, update_unique_id12)
         entry.version = 12
 
+    if entry.version <= 12:
+        # Migrate unique ids of existing entities to new format taking into
+        # account device_class if name is missing.
+        device_id = entry.unique_id
+        conf_file = get_config(entry.data[CONF_TYPE])
+        if conf_file is None:
+            _LOGGER.error(
+                NOT_FOUND,
+                entry.data[CONF_TYPE],
+            )
+            return False
+
+        @callback
+        def update_unique_id13(entity_entry):
+            """Update the unique id of an entity entry."""
+            old_id = entity_entry.unique_id
+            platform = entity_entry.entity_id.split(".", 1)[0]
+            # if unique_id ends with platform name, then this may have
+            # changed with the addition of device_class.
+            if old_id.endswith(platform):
+                e = conf_file.primary_entity
+                if e.entity != platform or e.name:
+                    for e in conf_file.secondary_entities():
+                        if e.entity == platform and not e.name:
+                            break
+                if e.entity == platform and not e.name:
+                    new_id = e.unique_id(device_id)
+                    if new_id != old_id:
+                        _LOGGER.info(
+                            "Migrating %s unique_id %s to %s",
+                            e.entity,
+                            old_id,
+                            new_id,
+                        )
+                        return {
+                            "new_unique_id": entity_entry.unique_id.replace(
+                                old_id,
+                                new_id,
+                            )
+                        }
+
+        await async_migrate_entries(hass, entry.entry_id, update_unique_id13)
+        entry.version = 13
+
     return True
 
 

+ 1 - 1
custom_components/tuya_local/config_flow.py

@@ -25,7 +25,7 @@ _LOGGER = logging.getLogger(__name__)
 
 
 class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
-    VERSION = 12
+    VERSION = 13
     CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
     device = None
     data = {}

+ 6 - 6
tests/test_config_flow.py

@@ -484,7 +484,7 @@ async def test_flow_choose_entities_creates_config_entry(hass, bypass_setup):
             },
         )
         expected = {
-            "version": 12,
+            "version": 13,
             "context": {"source": "choose_entities"},
             "type": "create_entry",
             "flow_id": ANY,
@@ -512,7 +512,7 @@ async def test_options_flow_init(hass):
     """Test config flow options."""
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=12,
+        version=13,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -551,7 +551,7 @@ async def test_options_flow_modifies_config(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=12,
+        version=13,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -601,7 +601,7 @@ async def test_options_flow_fails_when_connection_fails(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=12,
+        version=13,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -641,7 +641,7 @@ async def test_options_flow_fails_when_config_is_missing(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=12,
+        version=13,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -669,7 +669,7 @@ async def test_async_setup_entry_for_switch(mock_device, hass):
     """Test setting up based on a config entry.  Repeats test_init_entry."""
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=12,
+        version=13,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",

+ 21 - 0
util/catalog.py

@@ -0,0 +1,21 @@
+#!/usr/bin/python3
+"""Build a catalog of supported devices/entities
+
+This script was created to check for entity ids that change between versions.
+The script needs to be run on the version before a potential id changing
+modification, then again after to compare the two outputs.
+"""
+import sys
+
+from custom_components.tuya_local.helpers.device_config import available_configs, TuyaDeviceConfig
+
+def main() -> int:
+    print("Catalog================")
+    for config in available_configs():
+        device = TuyaDeviceConfig(config)
+        print(f"{config}: {device.primary_entity.config_id}")
+        for entity in device.secondary_entities():
+            print(f"{config}: {entity.config_id}")
+
+if __name__ == "__main__":
+    sys.exit(main())