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

Config flow: migrate unique_id of entities to include platform.

When a device contains two entities of different types with the same
name,  an ERROR is logged about duplicate unique IDs, but things seem
to still work, as the config_id is different.  Probably customizing
these entities through the UI will not work however.

If we include the entity platorm in the unique_id, we can eliminate
these duplicates.

Issue #455
Jason Rumney 3 лет назад
Родитель
Сommit
31802d4c6a

+ 39 - 0
custom_components/tuya_local/__init__.py

@@ -165,6 +165,45 @@ async def async_migrate_entry(hass, entry: ConfigEntry):
         entry.options = {}
         entry.version = 11
 
+    if entry.version <= 11:
+        # Migrate unique ids of existing entities to new format
+        device_id = entry.unique_id
+        conf_file = get_config(entry.data[CONF_TYPE])
+        if conf_file is None:
+            _LOGGER.error(f"Configuration file for {entry.data[CONF_TYPE]} not found.")
+            return False
+
+        @callback
+        def update_unique_id(entity_entry):
+            """Update the unique id of an entity entry."""
+            old_id = entity_entry.unique_id
+            e = conf_file.primary_entity
+            if e.name:
+                expect_id = f"{device_id}-{e.name}"
+            else:
+                expect_id = device_id
+            if e.entity != entity_entry.platform or expect_id != old_id:
+                for e in conf_file.secondary_entities():
+                    if e.name:
+                        expect_id = f"{device_id}-{e.name}"
+                    else:
+                        expect_id = device_id
+                    if e.entity == entity_entry.platform and expect_id == old_id:
+                        break
+
+            if e.entity == entity_entry.platform and expect_id == old_id:
+                new_id = e.unique_id(device_id)
+                if new_id != old_id:
+                    _LOGGER.info(
+                        f"Migrating {e.entity} unique_id {old_id} to {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_id)
+        entry.version = 12
+
     return True
 
 

+ 1 - 1
custom_components/tuya_local/config_flow.py

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

+ 1 - 5
custom_components/tuya_local/helpers/device_config.py

@@ -185,11 +185,7 @@ class TuyaEntityConfig:
 
     def unique_id(self, device_uid):
         """Return a suitable unique_id for this entity."""
-        own_name = self.name
-        if own_name:
-            return f"{device_uid}-{slugify(own_name)}"
-        else:
-            return device_uid
+        return f"{device_uid}-{slugify(self.config_id)}"
 
     @property
     def entity_category(self):

+ 6 - 6
tests/test_config_flow.py

@@ -458,7 +458,7 @@ async def test_flow_choose_entities_creates_config_entry(hass, bypass_setup):
             },
         )
         expected = {
-            "version": 11,
+            "version": 12,
             "context": {"source": "choose_entities"},
             "type": "create_entry",
             "flow_id": ANY,
@@ -485,7 +485,7 @@ async def test_options_flow_init(hass):
     """Test config flow options."""
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=11,
+        version=12,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -523,7 +523,7 @@ async def test_options_flow_modifies_config(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=11,
+        version=12,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -570,7 +570,7 @@ async def test_options_flow_fails_when_connection_fails(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=11,
+        version=12,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -609,7 +609,7 @@ async def test_options_flow_fails_when_config_is_missing(mock_test, hass):
 
     config_entry = MockConfigEntry(
         domain=DOMAIN,
-        version=11,
+        version=12,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",
@@ -637,7 +637,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=11,
+        version=12,
         unique_id="uniqueid",
         data={
             CONF_DEVICE_ID: "deviceid",