From 1f3da9cf1adc8d2cba1489f094c7c3e4fda1ea6d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 20 Dec 2022 12:10:46 +0100 Subject: [PATCH] Add aliases to entity registry items (#84239) --- homeassistant/components/config/entity_registry.py | 6 ++++++ homeassistant/helpers/entity_registry.py | 14 +++++++++++++- requirements_test.txt | 1 + tests/components/config/test_entity_registry.py | 10 ++++++++++ tests/helpers/test_entity_registry.py | 8 ++++++-- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/config/entity_registry.py b/homeassistant/components/config/entity_registry.py index 5602a48c0a1..dffb44c8153 100644 --- a/homeassistant/components/config/entity_registry.py +++ b/homeassistant/components/config/entity_registry.py @@ -102,6 +102,7 @@ def websocket_get_entity( vol.Required("type"): "config/entity_registry/update", vol.Required("entity_id"): cv.entity_id, # If passed in, we update value. Passing None will remove old value. + vol.Optional("aliases"): list, vol.Optional("area_id"): vol.Any(str, None), vol.Optional("device_class"): vol.Any(str, None), vol.Optional("icon"): vol.Any(str, None), @@ -160,6 +161,10 @@ def websocket_update_entity( if key in msg: changes[key] = msg[key] + if "aliases" in msg: + # Convert aliases to a set + changes["aliases"] = set(msg["aliases"]) + if "disabled_by" in msg and msg["disabled_by"] is None: # Don't allow enabling an entity of a disabled device if entity_entry.device_id: @@ -265,6 +270,7 @@ def _entry_dict(entry: er.RegistryEntry) -> dict[str, Any]: def _entry_ext_dict(entry: er.RegistryEntry) -> dict[str, Any]: """Convert entry to API format.""" data = _entry_dict(entry) + data["aliases"] = entry.aliases data["capabilities"] = entry.capabilities data["device_class"] = entry.device_class data["options"] = entry.options diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 2325ccca786..ce4bed377e8 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -61,7 +61,7 @@ SAVE_DELAY = 10 _LOGGER = logging.getLogger(__name__) STORAGE_VERSION_MAJOR = 1 -STORAGE_VERSION_MINOR = 9 +STORAGE_VERSION_MINOR = 10 STORAGE_KEY = "core.entity_registry" # Attributes relevant to describing entity @@ -104,6 +104,7 @@ class RegistryEntry: entity_id: str = attr.ib() unique_id: str = attr.ib() platform: str = attr.ib() + aliases: set[str] = attr.ib(factory=set) area_id: str | None = attr.ib(default=None) capabilities: Mapping[str, Any] | None = attr.ib(default=None) config_entry_id: str | None = attr.ib(default=None) @@ -242,6 +243,11 @@ class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]): for entity in data["entities"]: entity["translation_key"] = None + if old_major_version == 1 and old_minor_version < 10: + # Version 1.10 adds aliases + for entity in data["entities"]: + entity["aliases"] = [] + if old_major_version > 1: raise NotImplementedError return data @@ -590,6 +596,7 @@ class EntityRegistry: self, entity_id: str, *, + aliases: set[str] | UndefinedType = UNDEFINED, area_id: str | None | UndefinedType = UNDEFINED, capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED, config_entry_id: str | None | UndefinedType = UNDEFINED, @@ -641,6 +648,7 @@ class EntityRegistry: raise ValueError("entity_category must be a valid EntityCategory instance") for attr_name, value in ( + ("aliases", aliases), ("area_id", area_id), ("capabilities", capabilities), ("config_entry_id", config_entry_id), @@ -716,6 +724,7 @@ class EntityRegistry: self, entity_id: str, *, + aliases: set[str] | UndefinedType = UNDEFINED, area_id: str | None | UndefinedType = UNDEFINED, capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED, config_entry_id: str | None | UndefinedType = UNDEFINED, @@ -739,6 +748,7 @@ class EntityRegistry: """Update properties of an entity.""" return self._async_update_entity( entity_id, + aliases=aliases, area_id=area_id, capabilities=capabilities, config_entry_id=config_entry_id, @@ -821,6 +831,7 @@ class EntityRegistry: entity["entity_category"] = None entities[entity["entity_id"]] = RegistryEntry( + aliases=set(entity["aliases"]), area_id=entity["area_id"], capabilities=entity["capabilities"], config_entry_id=entity["config_entry_id"], @@ -865,6 +876,7 @@ class EntityRegistry: data["entities"] = [ { + "aliases": list(entry.aliases), "area_id": entry.area_id, "capabilities": entry.capabilities, "config_entry_id": entry.config_entry_id, diff --git a/requirements_test.txt b/requirements_test.txt index 2cad4a13aa0..179a98f96f1 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -24,6 +24,7 @@ pytest-socket==0.5.1 pytest-test-groups==1.0.3 pytest-sugar==0.9.5 pytest-timeout==2.1.0 +pytest-unordered==0.5.2 pytest-xdist==2.5.0 pytest==7.2.0 requests_mock==1.10.0 diff --git a/tests/components/config/test_entity_registry.py b/tests/components/config/test_entity_registry.py index 88fdd988dd5..9caa9cbf3f2 100644 --- a/tests/components/config/test_entity_registry.py +++ b/tests/components/config/test_entity_registry.py @@ -1,5 +1,6 @@ """Test entity_registry API.""" import pytest +from pytest_unordered import unordered from homeassistant.components.config import entity_registry from homeassistant.const import ATTR_ICON @@ -159,6 +160,7 @@ async def test_get_entity(hass, client): msg = await client.receive_json() assert msg["result"] == { + "aliases": [], "area_id": None, "capabilities": None, "config_entry_id": None, @@ -191,6 +193,7 @@ async def test_get_entity(hass, client): msg = await client.receive_json() assert msg["result"] == { + "aliases": [], "area_id": None, "capabilities": None, "config_entry_id": None, @@ -244,6 +247,7 @@ async def test_update_entity(hass, client): "id": 6, "type": "config/entity_registry/update", "entity_id": "test_domain.world", + "aliases": ["alias_1", "alias_2"], "area_id": "mock-area-id", "device_class": "custom_device_class", "hidden_by": "user", # We exchange strings over the WS API, not enums @@ -256,6 +260,7 @@ async def test_update_entity(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": unordered(["alias_1", "alias_2"]), "area_id": "mock-area-id", "capabilities": None, "config_entry_id": None, @@ -330,6 +335,7 @@ async def test_update_entity(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": unordered(["alias_1", "alias_2"]), "area_id": "mock-area-id", "capabilities": None, "config_entry_id": None, @@ -369,6 +375,7 @@ async def test_update_entity(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": unordered(["alias_1", "alias_2"]), "area_id": "mock-area-id", "capabilities": None, "config_entry_id": None, @@ -420,6 +427,7 @@ async def test_update_entity_require_restart(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": [], "area_id": None, "capabilities": None, "config_entry_id": config_entry.entry_id, @@ -527,6 +535,7 @@ async def test_update_entity_no_changes(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": [], "area_id": None, "capabilities": None, "config_entry_id": None, @@ -615,6 +624,7 @@ async def test_update_entity_id(hass, client): assert msg["result"] == { "entity_entry": { + "aliases": [], "area_id": None, "capabilities": None, "config_entry_id": None, diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index 6db1b59b2c0..b8e66255c48 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -136,6 +136,7 @@ def test_get_or_create_updates_data(registry): "light.hue_5678", "5678", "hue", + aliases=set(), area_id=None, capabilities={"new-max": 150}, config_entry_id=new_config_entry.entry_id, @@ -179,6 +180,7 @@ def test_get_or_create_updates_data(registry): "light.hue_5678", "5678", "hue", + aliases=set(), area_id=None, capabilities=None, config_entry_id=None, @@ -253,6 +255,7 @@ async def test_loading_saving_data(hass, registry): ) registry.async_update_entity( orig_entry2.entity_id, + aliases={"initial_alias_1", "initial_alias_2"}, area_id="mock-area-id", device_class="user-class", name="User Name", @@ -663,9 +666,10 @@ async def test_update_entity(registry): ) for attr_name, new_value in ( - ("name", "new name"), - ("icon", "new icon"), + ("aliases", {"alias_1", "alias_2"}), ("disabled_by", er.RegistryEntryDisabler.USER), + ("icon", "new icon"), + ("name", "new name"), ): changes = {attr_name: new_value} updated_entry = registry.async_update_entity(entry.entity_id, **changes)