Add config and diagnostic entities (#57528)

* Add config entity concept

* Rename is_config_entity to entity_category

* Add test

* Add 'diagnostic' entity category
This commit is contained in:
Erik Montnemery 2021-10-14 10:04:26 +02:00 committed by GitHub
parent 24509503bb
commit 4b3d423767
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 69 additions and 14 deletions

View File

@ -177,6 +177,7 @@ def _entry_dict(entry):
"name": entry.name,
"icon": entry.icon,
"platform": entry.platform,
"entity_category": entry.entity_category,
}

View File

@ -704,3 +704,6 @@ CLOUD_NEVER_EXPOSED_ENTITIES: Final[list[str]] = ["group.all_locks"]
# The ID of the Home Assistant Cast App
CAST_APP_ID_HOMEASSISTANT: Final = "B12CE3CA"
ENTITY_CATEGORY_CONFIG: Final = "config"
ENTITY_CATEGORY_DIAGNOSTIC: Final = "diagnostic"

View File

@ -11,7 +11,7 @@ import logging
import math
import sys
from timeit import default_timer as timer
from typing import Any, TypedDict, final
from typing import Any, Literal, TypedDict, final
from homeassistant.config import DATA_CUSTOMIZE
from homeassistant.const import (
@ -180,6 +180,7 @@ class EntityDescription:
key: str
device_class: str | None = None
entity_category: Literal["config", "diagnostic"] | None = None
entity_registry_enabled_default: bool = True
force_update: bool = False
icon: str | None = None
@ -238,6 +239,7 @@ class Entity(ABC):
_attr_context_recent_time: timedelta = timedelta(seconds=5)
_attr_device_class: str | None
_attr_device_info: DeviceInfo | None = None
_attr_entity_category: str | None
_attr_entity_picture: str | None = None
_attr_entity_registry_enabled_default: bool
_attr_extra_state_attributes: MutableMapping[str, Any]
@ -404,6 +406,15 @@ class Entity(ABC):
"""Return the attribution."""
return self._attr_attribution
@property
def entity_category(self) -> str | None:
"""Return the category of the entity, if any."""
if hasattr(self, "_attr_entity_category"):
return self._attr_entity_category
if hasattr(self, "entity_description"):
return self.entity_description.entity_category
return None
# DO NOT OVERWRITE
# These properties and methods are either managed by Home Assistant or they
# are used to perform a very specific function. Overwriting these may

View File

@ -501,6 +501,7 @@ class EntityPlatform:
unit_of_measurement=entity.unit_of_measurement,
original_name=entity.name,
original_icon=entity.icon,
entity_category=entity.entity_category,
)
entity.registry_entry = entry

View File

@ -106,6 +106,7 @@ class RegistryEntry:
# As set by integration
original_name: str | None = attr.ib(default=None)
original_icon: str | None = attr.ib(default=None)
entity_category: str | None = attr.ib(default=None)
domain: str = attr.ib(init=False, repr=False)
@domain.default
@ -256,6 +257,7 @@ class EntityRegistry:
unit_of_measurement: str | None = None,
original_name: str | None = None,
original_icon: str | None = None,
entity_category: str | None = None,
) -> RegistryEntry:
"""Get entity. Create if it doesn't exist."""
config_entry_id = None
@ -276,6 +278,7 @@ class EntityRegistry:
unit_of_measurement=unit_of_measurement or UNDEFINED,
original_name=original_name or UNDEFINED,
original_icon=original_icon or UNDEFINED,
entity_category=entity_category or UNDEFINED,
# When we changed our slugify algorithm, we invalidated some
# stored entity IDs with either a __ or ending in _.
# Fix introduced in 0.86 (Jan 23, 2019). Next line can be
@ -310,6 +313,7 @@ class EntityRegistry:
unit_of_measurement=unit_of_measurement,
original_name=original_name,
original_icon=original_icon,
entity_category=entity_category,
)
self._register_entry(entity)
_LOGGER.info("Registered new %s.%s entity: %s", domain, platform, entity_id)
@ -418,6 +422,7 @@ class EntityRegistry:
unit_of_measurement: str | None | UndefinedType = UNDEFINED,
original_name: str | None | UndefinedType = UNDEFINED,
original_icon: str | None | UndefinedType = UNDEFINED,
entity_category: str | None | UndefinedType = UNDEFINED,
) -> RegistryEntry:
"""Private facing update properties method."""
old = self.entities[entity_id]
@ -438,6 +443,7 @@ class EntityRegistry:
("unit_of_measurement", unit_of_measurement),
("original_name", original_name),
("original_icon", original_icon),
("entity_category", entity_category),
):
if value is not UNDEFINED and value != getattr(old, attr_name):
new_values[attr_name] = value
@ -523,6 +529,7 @@ class EntityRegistry:
unit_of_measurement=entity.get("unit_of_measurement"),
original_name=entity.get("original_name"),
original_icon=entity.get("original_icon"),
entity_category=entity.get("entity_category"),
)
self.entities = entities
@ -555,6 +562,7 @@ class EntityRegistry:
"unit_of_measurement": entry.unit_of_measurement,
"original_name": entry.original_name,
"original_icon": entry.original_icon,
"entity_category": entry.entity_category,
}
for entry in self.entities.values()
]

View File

@ -1,6 +1,4 @@
"""Test entity_registry API."""
from collections import OrderedDict
import pytest
from homeassistant.components.config import entity_registry
@ -31,18 +29,22 @@ def device_registry(hass):
async def test_list_entities(hass, client):
"""Test list entries."""
entities = OrderedDict()
entities["test_domain.name"] = RegistryEntry(
entity_id="test_domain.name",
unique_id="1234",
platform="test_platform",
name="Hello World",
mock_registry(
hass,
{
"test_domain.name": RegistryEntry(
entity_id="test_domain.name",
unique_id="1234",
platform="test_platform",
name="Hello World",
),
"test_domain.no_name": RegistryEntry(
entity_id="test_domain.no_name",
unique_id="6789",
platform="test_platform",
),
},
)
entities["test_domain.no_name"] = RegistryEntry(
entity_id="test_domain.no_name", unique_id="6789", platform="test_platform"
)
mock_registry(hass, entities)
await client.send_json({"id": 5, "type": "config/entity_registry/list"})
msg = await client.receive_json()
@ -57,6 +59,7 @@ async def test_list_entities(hass, client):
"name": "Hello World",
"icon": None,
"platform": "test_platform",
"entity_category": None,
},
{
"config_entry_id": None,
@ -67,6 +70,7 @@ async def test_list_entities(hass, client):
"name": None,
"icon": None,
"platform": "test_platform",
"entity_category": None,
},
]
@ -108,6 +112,7 @@ async def test_get_entity(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
}
await client.send_json(
@ -132,6 +137,7 @@ async def test_get_entity(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "6789",
"entity_category": None,
}
@ -187,6 +193,7 @@ async def test_update_entity(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
}
}
@ -235,6 +242,7 @@ async def test_update_entity(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
},
"reload_delay": 30,
}
@ -289,6 +297,7 @@ async def test_update_entity_require_restart(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
},
"require_restart": True,
}
@ -390,6 +399,7 @@ async def test_update_entity_no_changes(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
}
}
@ -470,6 +480,7 @@ async def test_update_entity_id(hass, client):
"original_icon": None,
"capabilities": None,
"unique_id": "1234",
"entity_category": None,
}
}

View File

@ -809,3 +809,23 @@ async def test_attribution_attribute(hass):
state = hass.states.get(mock_entity.entity_id)
assert state.attributes.get(ATTR_ATTRIBUTION) == "Home Assistant"
async def test_entity_category_property(hass):
"""Test entity category property."""
mock_entity1 = entity.Entity()
mock_entity1.hass = hass
mock_entity1.entity_description = entity.EntityDescription(
key="abc", entity_category="ignore_me"
)
mock_entity1.entity_id = "hello.world"
mock_entity1._attr_entity_category = "config"
assert mock_entity1.entity_category == "config"
mock_entity2 = entity.Entity()
mock_entity2.hass = hass
mock_entity2.entity_description = entity.EntityDescription(
key="abc", entity_category="config"
)
mock_entity2.entity_id = "hello.world"
assert mock_entity2.entity_category == "config"