Add aliases to entity registry items (#84239)

This commit is contained in:
Erik Montnemery 2022-12-20 12:10:46 +01:00 committed by GitHub
parent 8ca92254b6
commit 1f3da9cf1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 3 deletions

View file

@ -102,6 +102,7 @@ def websocket_get_entity(
vol.Required("type"): "config/entity_registry/update", vol.Required("type"): "config/entity_registry/update",
vol.Required("entity_id"): cv.entity_id, vol.Required("entity_id"): cv.entity_id,
# If passed in, we update value. Passing None will remove old value. # 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("area_id"): vol.Any(str, None),
vol.Optional("device_class"): vol.Any(str, None), vol.Optional("device_class"): vol.Any(str, None),
vol.Optional("icon"): vol.Any(str, None), vol.Optional("icon"): vol.Any(str, None),
@ -160,6 +161,10 @@ def websocket_update_entity(
if key in msg: if key in msg:
changes[key] = msg[key] 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: if "disabled_by" in msg and msg["disabled_by"] is None:
# Don't allow enabling an entity of a disabled device # Don't allow enabling an entity of a disabled device
if entity_entry.device_id: 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]: def _entry_ext_dict(entry: er.RegistryEntry) -> dict[str, Any]:
"""Convert entry to API format.""" """Convert entry to API format."""
data = _entry_dict(entry) data = _entry_dict(entry)
data["aliases"] = entry.aliases
data["capabilities"] = entry.capabilities data["capabilities"] = entry.capabilities
data["device_class"] = entry.device_class data["device_class"] = entry.device_class
data["options"] = entry.options data["options"] = entry.options

View file

@ -61,7 +61,7 @@ SAVE_DELAY = 10
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
STORAGE_VERSION_MAJOR = 1 STORAGE_VERSION_MAJOR = 1
STORAGE_VERSION_MINOR = 9 STORAGE_VERSION_MINOR = 10
STORAGE_KEY = "core.entity_registry" STORAGE_KEY = "core.entity_registry"
# Attributes relevant to describing entity # Attributes relevant to describing entity
@ -104,6 +104,7 @@ class RegistryEntry:
entity_id: str = attr.ib() entity_id: str = attr.ib()
unique_id: str = attr.ib() unique_id: str = attr.ib()
platform: str = attr.ib() platform: str = attr.ib()
aliases: set[str] = attr.ib(factory=set)
area_id: str | None = attr.ib(default=None) area_id: str | None = attr.ib(default=None)
capabilities: Mapping[str, Any] | None = attr.ib(default=None) capabilities: Mapping[str, Any] | None = attr.ib(default=None)
config_entry_id: str | 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"]: for entity in data["entities"]:
entity["translation_key"] = None 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: if old_major_version > 1:
raise NotImplementedError raise NotImplementedError
return data return data
@ -590,6 +596,7 @@ class EntityRegistry:
self, self,
entity_id: str, entity_id: str,
*, *,
aliases: set[str] | UndefinedType = UNDEFINED,
area_id: str | None | UndefinedType = UNDEFINED, area_id: str | None | UndefinedType = UNDEFINED,
capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED, capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED,
config_entry_id: str | 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") raise ValueError("entity_category must be a valid EntityCategory instance")
for attr_name, value in ( for attr_name, value in (
("aliases", aliases),
("area_id", area_id), ("area_id", area_id),
("capabilities", capabilities), ("capabilities", capabilities),
("config_entry_id", config_entry_id), ("config_entry_id", config_entry_id),
@ -716,6 +724,7 @@ class EntityRegistry:
self, self,
entity_id: str, entity_id: str,
*, *,
aliases: set[str] | UndefinedType = UNDEFINED,
area_id: str | None | UndefinedType = UNDEFINED, area_id: str | None | UndefinedType = UNDEFINED,
capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED, capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED,
config_entry_id: str | None | UndefinedType = UNDEFINED, config_entry_id: str | None | UndefinedType = UNDEFINED,
@ -739,6 +748,7 @@ class EntityRegistry:
"""Update properties of an entity.""" """Update properties of an entity."""
return self._async_update_entity( return self._async_update_entity(
entity_id, entity_id,
aliases=aliases,
area_id=area_id, area_id=area_id,
capabilities=capabilities, capabilities=capabilities,
config_entry_id=config_entry_id, config_entry_id=config_entry_id,
@ -821,6 +831,7 @@ class EntityRegistry:
entity["entity_category"] = None entity["entity_category"] = None
entities[entity["entity_id"]] = RegistryEntry( entities[entity["entity_id"]] = RegistryEntry(
aliases=set(entity["aliases"]),
area_id=entity["area_id"], area_id=entity["area_id"],
capabilities=entity["capabilities"], capabilities=entity["capabilities"],
config_entry_id=entity["config_entry_id"], config_entry_id=entity["config_entry_id"],
@ -865,6 +876,7 @@ class EntityRegistry:
data["entities"] = [ data["entities"] = [
{ {
"aliases": list(entry.aliases),
"area_id": entry.area_id, "area_id": entry.area_id,
"capabilities": entry.capabilities, "capabilities": entry.capabilities,
"config_entry_id": entry.config_entry_id, "config_entry_id": entry.config_entry_id,

View file

@ -24,6 +24,7 @@ pytest-socket==0.5.1
pytest-test-groups==1.0.3 pytest-test-groups==1.0.3
pytest-sugar==0.9.5 pytest-sugar==0.9.5
pytest-timeout==2.1.0 pytest-timeout==2.1.0
pytest-unordered==0.5.2
pytest-xdist==2.5.0 pytest-xdist==2.5.0
pytest==7.2.0 pytest==7.2.0
requests_mock==1.10.0 requests_mock==1.10.0

View file

@ -1,5 +1,6 @@
"""Test entity_registry API.""" """Test entity_registry API."""
import pytest import pytest
from pytest_unordered import unordered
from homeassistant.components.config import entity_registry from homeassistant.components.config import entity_registry
from homeassistant.const import ATTR_ICON from homeassistant.const import ATTR_ICON
@ -159,6 +160,7 @@ async def test_get_entity(hass, client):
msg = await client.receive_json() msg = await client.receive_json()
assert msg["result"] == { assert msg["result"] == {
"aliases": [],
"area_id": None, "area_id": None,
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -191,6 +193,7 @@ async def test_get_entity(hass, client):
msg = await client.receive_json() msg = await client.receive_json()
assert msg["result"] == { assert msg["result"] == {
"aliases": [],
"area_id": None, "area_id": None,
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -244,6 +247,7 @@ async def test_update_entity(hass, client):
"id": 6, "id": 6,
"type": "config/entity_registry/update", "type": "config/entity_registry/update",
"entity_id": "test_domain.world", "entity_id": "test_domain.world",
"aliases": ["alias_1", "alias_2"],
"area_id": "mock-area-id", "area_id": "mock-area-id",
"device_class": "custom_device_class", "device_class": "custom_device_class",
"hidden_by": "user", # We exchange strings over the WS API, not enums "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"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": unordered(["alias_1", "alias_2"]),
"area_id": "mock-area-id", "area_id": "mock-area-id",
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -330,6 +335,7 @@ async def test_update_entity(hass, client):
assert msg["result"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": unordered(["alias_1", "alias_2"]),
"area_id": "mock-area-id", "area_id": "mock-area-id",
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -369,6 +375,7 @@ async def test_update_entity(hass, client):
assert msg["result"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": unordered(["alias_1", "alias_2"]),
"area_id": "mock-area-id", "area_id": "mock-area-id",
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -420,6 +427,7 @@ async def test_update_entity_require_restart(hass, client):
assert msg["result"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": [],
"area_id": None, "area_id": None,
"capabilities": None, "capabilities": None,
"config_entry_id": config_entry.entry_id, "config_entry_id": config_entry.entry_id,
@ -527,6 +535,7 @@ async def test_update_entity_no_changes(hass, client):
assert msg["result"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": [],
"area_id": None, "area_id": None,
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,
@ -615,6 +624,7 @@ async def test_update_entity_id(hass, client):
assert msg["result"] == { assert msg["result"] == {
"entity_entry": { "entity_entry": {
"aliases": [],
"area_id": None, "area_id": None,
"capabilities": None, "capabilities": None,
"config_entry_id": None, "config_entry_id": None,

View file

@ -136,6 +136,7 @@ def test_get_or_create_updates_data(registry):
"light.hue_5678", "light.hue_5678",
"5678", "5678",
"hue", "hue",
aliases=set(),
area_id=None, area_id=None,
capabilities={"new-max": 150}, capabilities={"new-max": 150},
config_entry_id=new_config_entry.entry_id, config_entry_id=new_config_entry.entry_id,
@ -179,6 +180,7 @@ def test_get_or_create_updates_data(registry):
"light.hue_5678", "light.hue_5678",
"5678", "5678",
"hue", "hue",
aliases=set(),
area_id=None, area_id=None,
capabilities=None, capabilities=None,
config_entry_id=None, config_entry_id=None,
@ -253,6 +255,7 @@ async def test_loading_saving_data(hass, registry):
) )
registry.async_update_entity( registry.async_update_entity(
orig_entry2.entity_id, orig_entry2.entity_id,
aliases={"initial_alias_1", "initial_alias_2"},
area_id="mock-area-id", area_id="mock-area-id",
device_class="user-class", device_class="user-class",
name="User Name", name="User Name",
@ -663,9 +666,10 @@ async def test_update_entity(registry):
) )
for attr_name, new_value in ( for attr_name, new_value in (
("name", "new name"), ("aliases", {"alias_1", "alias_2"}),
("icon", "new icon"),
("disabled_by", er.RegistryEntryDisabler.USER), ("disabled_by", er.RegistryEntryDisabler.USER),
("icon", "new icon"),
("name", "new name"),
): ):
changes = {attr_name: new_value} changes = {attr_name: new_value}
updated_entry = registry.async_update_entity(entry.entity_id, **changes) updated_entry = registry.async_update_entity(entry.entity_id, **changes)