1 """Provide a registry to track entity IDs.
3 The Entity Registry keeps a registry of entities. Entities are uniquely
4 identified by their domain, platform and a unique id provided by that platform.
6 The Entity Registry will persist itself 10 seconds after a new entity is
7 registered. Registering a new entity while a timer is in progress resets the
11 from __future__
import annotations
13 from collections
import defaultdict
14 from collections.abc
import Callable, Container, Hashable, KeysView, Mapping
15 from datetime
import datetime, timedelta
16 from enum
import StrEnum
19 from typing
import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict
22 import voluptuous
as vol
29 ATTR_SUPPORTED_FEATURES,
30 ATTR_UNIT_OF_MEASUREMENT,
31 EVENT_HOMEASSISTANT_START,
32 EVENT_HOMEASSISTANT_STOP,
33 MAX_LENGTH_STATE_DOMAIN,
34 MAX_LENGTH_STATE_ENTITY_ID,
56 from .
import device_registry
as dr, storage
57 from .device_registry
import (
58 EVENT_DEVICE_REGISTRY_UPDATED,
59 EventDeviceRegistryUpdatedData,
61 from .json
import JSON_DUMP, find_paths_unserializable_data, json_bytes, json_fragment
62 from .registry
import BaseRegistry, BaseRegistryItems, RegistryIndexType
63 from .singleton
import singleton
64 from .typing
import UNDEFINED, UndefinedType
68 from propcache
import cached_property
as under_cached_property
72 from propcache
import under_cached_property
74 DATA_REGISTRY: HassKey[EntityRegistry] =
HassKey(
"entity_registry")
75 EVENT_ENTITY_REGISTRY_UPDATED: EventType[EventEntityRegistryUpdatedData] =
EventType(
76 "entity_registry_updated"
79 _LOGGER = logging.getLogger(__name__)
81 STORAGE_VERSION_MAJOR = 1
82 STORAGE_VERSION_MINOR = 15
83 STORAGE_KEY =
"core.entity_registry"
85 CLEANUP_INTERVAL = 3600 * 24
86 ORPHANED_ENTITY_KEEP_SECONDS = 3600 * 24 * 30
88 ENTITY_CATEGORY_VALUE_TO_INDEX: dict[EntityCategory |
None, int] = {
91 for idx, val
in enumerate(EntityCategory)
93 ENTITY_CATEGORY_INDEX_TO_VALUE =
dict(enumerate(EntityCategory))
97 ENTITY_DESCRIBING_ATTRIBUTES = {
103 "supported_features",
104 "unit_of_measurement",
109 """What disabled a registry entry."""
111 CONFIG_ENTRY =
"config_entry"
114 INTEGRATION =
"integration"
119 """What hid a registry entry."""
121 INTEGRATION =
"integration"
126 """EventEntityRegistryUpdated data for action type 'create' and 'remove'."""
128 action: Literal[
"create",
"remove"]
133 """EventEntityRegistryUpdated data for action type 'update'."""
135 action: Literal[
"update"]
137 changes: dict[str, Any]
138 old_entity_id: NotRequired[str]
141 type EventEntityRegistryUpdatedData = (
142 _EventEntityRegistryUpdatedData_CreateRemove
143 | _EventEntityRegistryUpdatedData_Update
147 type EntityOptionsType = Mapping[str, Mapping[str, Any]]
148 type ReadOnlyEntityOptionsType = ReadOnlyDict[str, ReadOnlyDict[str, Any]]
150 DISPLAY_DICT_OPTIONAL = (
152 (
"ai",
"area_id",
False),
153 (
"lb",
"labels",
True),
154 (
"di",
"device_id",
False),
155 (
"ic",
"icon",
False),
156 (
"tk",
"translation_key",
False),
161 data: EntityOptionsType |
None,
162 ) -> ReadOnlyEntityOptionsType:
163 """Protect entity options from being modified."""
169 @attr.s(frozen=True, slots=True)
171 """Entity Registry Entry."""
173 entity_id: str = attr.ib()
174 unique_id: str = attr.ib()
175 platform: str = attr.ib()
176 previous_unique_id: str |
None = attr.ib(default=
None)
177 aliases: set[str] = attr.ib(factory=set)
178 area_id: str |
None = attr.ib(default=
None)
179 categories: dict[str, str] = attr.ib(factory=dict)
180 capabilities: Mapping[str, Any] |
None = attr.ib(default=
None)
181 config_entry_id: str |
None = attr.ib(default=
None)
182 created_at: datetime = attr.ib(factory=utcnow)
183 device_class: str |
None = attr.ib(default=
None)
184 device_id: str |
None = attr.ib(default=
None)
185 domain: str = attr.ib(init=
False, repr=
False)
186 disabled_by: RegistryEntryDisabler |
None = attr.ib(default=
None)
187 entity_category: EntityCategory |
None = attr.ib(default=
None)
188 hidden_by: RegistryEntryHider |
None = attr.ib(default=
None)
189 icon: str |
None = attr.ib(default=
None)
192 converter=attr.converters.default_if_none(factory=uuid_util.random_uuid_hex),
194 has_entity_name: bool = attr.ib(default=
False)
195 labels: set[str] = attr.ib(factory=set)
196 modified_at: datetime = attr.ib(factory=utcnow)
197 name: str |
None = attr.ib(default=
None)
198 options: ReadOnlyEntityOptionsType = attr.ib(
199 default=
None, converter=_protect_entity_options
202 original_device_class: str |
None = attr.ib(default=
None)
203 original_icon: str |
None = attr.ib(default=
None)
204 original_name: str |
None = attr.ib(default=
None)
205 supported_features: int = attr.ib(default=0)
206 translation_key: str |
None = attr.ib(default=
None)
207 unit_of_measurement: str |
None = attr.ib(default=
None)
208 _cache: dict[str, Any] = attr.ib(factory=dict, eq=
False, init=
False)
212 """Compute domain value."""
217 """Return if entry is disabled."""
218 return self.disabled_by
is not None
222 """Return if entry is hidden."""
223 return self.hidden_by
is not None
227 """Return a partial dict representation of the entry.
229 This version only includes what's needed for display.
230 Returns None if there's no data needed for display.
232 display_dict: dict[str, Any] = {
"ei": self.entity_id,
"pl": self.platform}
233 for key, attr_name, convert_list
in DISPLAY_DICT_OPTIONAL:
234 if (attr_val := getattr(self, attr_name))
is not None:
238 display_dict[key] =
list(attr_val)
if convert_list
else attr_val
239 if (category := self.entity_category)
is not None:
240 display_dict[
"ec"] = ENTITY_CATEGORY_VALUE_TO_INDEX[category]
241 if self.hidden_by
is not None:
242 display_dict[
"hb"] =
True
243 if self.has_entity_name:
244 display_dict[
"hn"] =
True
245 name = self.name
or self.original_name
247 display_dict[
"en"] = name
248 if self.
domaindomain ==
"sensor" and (sensor_options := self.options.
get(
"sensor")):
249 if (precision := sensor_options.get(
"display_precision"))
is not None or (
250 precision := sensor_options.get(
"suggested_display_precision")
252 display_dict[
"dp"] = precision
255 @under_cached_property
257 """Return a cached partial JSON representation of the entry.
259 This version only includes what's needed for display.
263 json_repr: bytes |
None =
json_bytes(dict_repr)
if dict_repr
else None
264 except (ValueError, TypeError):
266 "Unable to serialize entry %s to JSON. Bad data found at %s",
275 @under_cached_property
277 """Return a partial dict representation of the entry."""
282 "area_id": self.area_id,
283 "categories": self.categories,
284 "config_entry_id": self.config_entry_id,
285 "created_at": self.created_at.timestamp(),
286 "device_id": self.device_id,
287 "disabled_by": self.disabled_by,
288 "entity_category": self.entity_category,
289 "entity_id": self.entity_id,
290 "has_entity_name": self.has_entity_name,
291 "hidden_by": self.hidden_by,
294 "labels":
list(self.labels),
295 "modified_at": self.modified_at.timestamp(),
297 "options": self.options,
298 "original_name": self.original_name,
299 "platform": self.platform,
300 "translation_key": self.translation_key,
301 "unique_id": self.unique_id,
304 @under_cached_property
306 """Return a extended dict representation of the entry."""
312 "aliases":
list(self.aliases),
313 "capabilities": self.capabilities,
314 "device_class": self.device_class,
315 "original_device_class": self.original_device_class,
316 "original_icon": self.original_icon,
319 @under_cached_property
321 """Return a cached partial JSON representation of the entry."""
325 except (ValueError, TypeError):
327 "Unable to serialize entry %s to JSON. Bad data found at %s",
335 @under_cached_property
337 """Return a json fragment for storage."""
341 "aliases":
list(self.aliases),
342 "area_id": self.area_id,
343 "categories": self.categories,
344 "capabilities": self.capabilities,
345 "config_entry_id": self.config_entry_id,
346 "created_at": self.created_at,
347 "device_class": self.device_class,
348 "device_id": self.device_id,
349 "disabled_by": self.disabled_by,
350 "entity_category": self.entity_category,
351 "entity_id": self.entity_id,
352 "hidden_by": self.hidden_by,
355 "has_entity_name": self.has_entity_name,
356 "labels":
list(self.labels),
357 "modified_at": self.modified_at,
359 "options": self.options,
360 "original_device_class": self.original_device_class,
361 "original_icon": self.original_icon,
362 "original_name": self.original_name,
363 "platform": self.platform,
364 "supported_features": self.supported_features,
365 "translation_key": self.translation_key,
366 "unique_id": self.unique_id,
367 "previous_unique_id": self.previous_unique_id,
368 "unit_of_measurement": self.unit_of_measurement,
375 """Write the unavailable state to the state machine."""
376 attrs: dict[str, Any] = {ATTR_RESTORED:
True}
378 if self.capabilities
is not None:
379 attrs.update(self.capabilities)
381 device_class = self.device_class
or self.original_device_class
382 if device_class
is not None:
383 attrs[ATTR_DEVICE_CLASS] = device_class
385 icon = self.icon
or self.original_icon
387 attrs[ATTR_ICON] = icon
389 name = self.name
or self.original_name
391 attrs[ATTR_FRIENDLY_NAME] = name
393 if self.supported_features
is not None:
394 attrs[ATTR_SUPPORTED_FEATURES] = self.supported_features
396 if self.unit_of_measurement
is not None:
397 attrs[ATTR_UNIT_OF_MEASUREMENT] = self.unit_of_measurement
399 hass.states.async_set(self.entity_id, STATE_UNAVAILABLE, attrs)
402 @attr.s(frozen=True, slots=True)
404 """Deleted Entity Registry Entry."""
406 entity_id: str = attr.ib()
407 unique_id: str = attr.ib()
408 platform: str = attr.ib()
409 config_entry_id: str |
None = attr.ib()
410 domain: str = attr.ib(init=
False, repr=
False)
412 orphaned_timestamp: float |
None = attr.ib()
413 created_at: datetime = attr.ib(factory=utcnow)
414 modified_at: datetime = attr.ib(factory=utcnow)
415 _cache: dict[str, Any] = attr.ib(factory=dict, eq=
False, init=
False)
419 """Compute domain value."""
422 @under_cached_property
424 """Return a json fragment for storage."""
428 "config_entry_id": self.config_entry_id,
429 "created_at": self.created_at,
430 "entity_id": self.entity_id,
432 "modified_at": self.modified_at,
433 "orphaned_timestamp": self.orphaned_timestamp,
434 "platform": self.platform,
435 "unique_id": self.unique_id,
442 """Store entity registry data."""
446 old_major_version: int,
447 old_minor_version: int,
448 old_data: dict[str, list[dict[str, Any]]],
450 """Migrate to the new version."""
452 if old_major_version == 1:
453 if old_minor_version < 2:
455 for entity
in data[
"entities"]:
457 entity.setdefault(
"area_id",
None)
458 entity.setdefault(
"capabilities", {})
459 entity.setdefault(
"config_entry_id",
None)
460 entity.setdefault(
"device_class",
None)
461 entity.setdefault(
"device_id",
None)
462 entity.setdefault(
"disabled_by",
None)
463 entity.setdefault(
"entity_category",
None)
464 entity.setdefault(
"icon",
None)
465 entity.setdefault(
"name",
None)
466 entity.setdefault(
"original_icon",
None)
467 entity.setdefault(
"original_name",
None)
468 entity.setdefault(
"supported_features", 0)
469 entity.setdefault(
"unit_of_measurement",
None)
471 if old_minor_version < 3:
473 for entity
in data[
"entities"]:
475 entity[
"original_device_class"] = entity[
"device_class"]
476 entity[
"device_class"] =
None
478 if old_minor_version < 4:
480 for entity
in data[
"entities"]:
481 entity[
"id"] = uuid_util.random_uuid_hex()
483 if old_minor_version < 5:
485 for entity
in data[
"entities"]:
486 entity[
"options"] = {}
488 if old_minor_version < 6:
490 for entity
in data[
"entities"]:
491 entity[
"hidden_by"] =
None
493 if old_minor_version < 7:
495 for entity
in data[
"entities"]:
496 entity[
"has_entity_name"] =
False
498 if old_minor_version < 8:
501 for entity
in data[
"entities"]:
503 if domain
in [Platform.BINARY_SENSOR, Platform.COVER]:
505 entity[
"device_class"] =
None
507 if old_minor_version < 9:
509 for entity
in data[
"entities"]:
510 entity[
"translation_key"] =
None
512 if old_minor_version < 10:
514 for entity
in data[
"entities"]:
515 entity[
"aliases"] = []
517 if old_minor_version < 11:
519 data[
"deleted_entities"] = data.get(
"deleted_entities", [])
521 if old_minor_version < 12:
523 for entity
in data[
"entities"]:
524 entity[
"previous_unique_id"] =
None
526 if old_minor_version < 13:
528 for entity
in data[
"entities"]:
529 entity[
"labels"] = []
531 if old_minor_version < 14:
533 for entity
in data[
"entities"]:
534 entity[
"categories"] = {}
536 if old_minor_version < 15:
539 for entity
in data[
"entities"]:
540 entity[
"created_at"] = entity[
"modified_at"] = created_at
541 for entity
in data[
"deleted_entities"]:
542 entity[
"created_at"] = entity[
"modified_at"] = created_at
544 if old_major_version > 1:
545 raise NotImplementedError
550 """Container for entity registry items, maps entity_id -> entry.
552 Maintains six additional indexes:
554 - (domain, platform, unique_id) -> entity_id
555 - config_entry_id -> dict[key, True]
556 - device_id -> dict[key, True]
557 - area_id -> dict[key, True]
558 - label -> dict[key, True]
562 """Initialize the container."""
564 self._entry_ids: dict[str, RegistryEntry] = {}
565 self._index: dict[tuple[str, str, str], str] = {}
566 self._config_entry_id_index: RegistryIndexType = defaultdict(dict)
567 self._device_id_index: RegistryIndexType = defaultdict(dict)
568 self._area_id_index: RegistryIndexType = defaultdict(dict)
569 self._labels_index: RegistryIndexType = defaultdict(dict)
572 """Index an entry."""
573 self._entry_ids[entry.id] = entry
574 self._index[(entry.domain, entry.platform, entry.unique_id)] = entry.entity_id
577 if (config_entry_id := entry.config_entry_id)
is not None:
578 self._config_entry_id_index[config_entry_id][key] =
True
579 if (device_id := entry.device_id)
is not None:
580 self._device_id_index[device_id][key] =
True
581 if (area_id := entry.area_id)
is not None:
582 self._area_id_index[area_id][key] =
True
583 for label
in entry.labels:
584 self._labels_index[label][key] =
True
587 self, key: str, replacement_entry: RegistryEntry |
None =
None
589 """Unindex an entry."""
590 entry = self.data[key]
591 del self._entry_ids[entry.id]
592 del self._index[(entry.domain, entry.platform, entry.unique_id)]
593 if config_entry_id := entry.config_entry_id:
594 self.
_unindex_entry_value_unindex_entry_value(key, config_entry_id, self._config_entry_id_index)
595 if device_id := entry.device_id:
597 if area_id := entry.area_id:
599 if labels := entry.labels:
604 """Return device ids."""
605 return self._device_id_index.keys()
608 """Get entity_id from (domain, platform, unique_id)."""
609 return self._index.
get(key)
612 """Get entry from id."""
613 return self._entry_ids.
get(key)
616 self, device_id: str, include_disabled_entities: bool =
False
617 ) -> list[RegistryEntry]:
618 """Get entries for device."""
622 for key
in self._device_id_index.
get(device_id, ())
623 if not (entry := data[key]).disabled_by
or include_disabled_entities
627 self, config_entry_id: str
628 ) -> list[RegistryEntry]:
629 """Get entries for config entry."""
632 data[key]
for key
in self._config_entry_id_index.
get(config_entry_id, ())
636 """Get entries for area."""
638 return [data[key]
for key
in self._area_id_index.
get(area_id, ())]
641 """Get entries for label."""
643 return [data[key]
for key
in self._labels_index.
get(label, ())]
651 disabled_by: RegistryEntryDisabler |
None | UndefinedType =
None,
652 entity_category: EntityCategory |
None | UndefinedType =
None,
653 hidden_by: RegistryEntryHider |
None | UndefinedType =
None,
654 report_non_string_unique_id: bool =
True,
655 unique_id: str | Hashable | UndefinedType | Any,
657 """Validate entity registry item."""
658 if unique_id
is not UNDEFINED
and not isinstance(unique_id, Hashable):
659 raise TypeError(f
"unique_id must be a string, got {unique_id}")
661 report_non_string_unique_id
662 and unique_id
is not UNDEFINED
663 and not isinstance(unique_id, str)
668 (
"'%s' from integration %s has a non string unique_id" " '%s', please %s"),
676 and disabled_by
is not UNDEFINED
677 and not isinstance(disabled_by, RegistryEntryDisabler)
680 f
"disabled_by must be a RegistryEntryDisabler value, got {disabled_by}"
684 and entity_category
is not UNDEFINED
685 and not isinstance(entity_category, EntityCategory)
688 f
"entity_category must be a valid EntityCategory instance, got {entity_category}"
692 and hidden_by
is not UNDEFINED
693 and not isinstance(hidden_by, RegistryEntryHider)
696 f
"hidden_by must be a RegistryEntryHider value, got {hidden_by}"
701 """Class to hold a registry of entities."""
703 deleted_entities: dict[tuple[str, str, str], DeletedRegistryEntry]
704 entities: EntityRegistryItems
705 _entities_data: dict[str, RegistryEntry]
708 """Initialize the registry."""
712 STORAGE_VERSION_MAJOR,
715 minor_version=STORAGE_VERSION_MINOR,
717 self.
hasshass.bus.async_listen(
718 EVENT_DEVICE_REGISTRY_UPDATED,
724 """Check if an entity_id is currently registered."""
725 return entity_id
in self.
entitiesentities
728 def async_get(self, entity_id_or_uuid: str) -> RegistryEntry |
None:
729 """Get EntityEntry for an entity_id or entity entry id.
731 We retrieve the RegistryEntry from the underlying dict to avoid
732 the overhead of the UserDict __getitem__.
740 self, domain: str, platform: str, unique_id: str
742 """Check if an entity_id is currently registered."""
743 return self.
entitiesentities.get_entity_id((domain, platform, unique_id))
747 """Return known device ids."""
751 self, entity_id: str, known_object_ids: Container[str] |
None
753 """Return True if the entity_id is available.
755 An entity_id is available if:
756 - It's not registered
757 - It's not known by the entity component adding the entity
758 - It's not in the state machine
760 Note that an entity_id which belongs to a deleted entity is considered
763 if known_object_ids
is None:
764 known_object_ids = {}
767 entity_id
not in self.
entitiesentities
768 and entity_id
not in known_object_ids
769 and self.
hasshass.states.async_available(entity_id)
776 suggested_object_id: str,
777 known_object_ids: Container[str] |
None =
None,
779 """Generate an entity ID that does not conflict.
781 Conflicts checked against registered and currently existing entities.
783 preferred_string = f
"{domain}.{slugify(suggested_object_id)}"
785 if len(domain) > MAX_LENGTH_STATE_DOMAIN:
788 test_string = preferred_string[:MAX_LENGTH_STATE_ENTITY_ID]
789 if known_object_ids
is None:
790 known_object_ids = set()
795 len_suffix = len(
str(tries)) + 1
797 f
"{preferred_string[:MAX_LENGTH_STATE_ENTITY_ID-len_suffix]}_{tries}"
810 known_object_ids: Container[str] |
None =
None,
811 suggested_object_id: str |
None =
None,
813 disabled_by: RegistryEntryDisabler |
None =
None,
814 hidden_by: RegistryEntryHider |
None =
None,
816 get_initial_options: Callable[[], EntityOptionsType |
None] |
None =
None,
818 capabilities: Mapping[str, Any] |
None | UndefinedType = UNDEFINED,
819 config_entry: ConfigEntry |
None | UndefinedType = UNDEFINED,
820 device_id: str |
None | UndefinedType = UNDEFINED,
821 entity_category: EntityCategory | UndefinedType |
None = UNDEFINED,
822 has_entity_name: bool | UndefinedType = UNDEFINED,
823 original_device_class: str |
None | UndefinedType = UNDEFINED,
824 original_icon: str |
None | UndefinedType = UNDEFINED,
825 original_name: str |
None | UndefinedType = UNDEFINED,
826 supported_features: int |
None | UndefinedType = UNDEFINED,
827 translation_key: str |
None | UndefinedType = UNDEFINED,
828 unit_of_measurement: str |
None | UndefinedType = UNDEFINED,
830 """Get entity. Create if it doesn't exist."""
831 config_entry_id: str |
None | UndefinedType = UNDEFINED
833 config_entry_id =
None
834 elif config_entry
is not UNDEFINED:
835 config_entry_id = config_entry.entry_id
837 supported_features = supported_features
or 0
844 capabilities=capabilities,
845 config_entry_id=config_entry_id,
847 entity_category=entity_category,
848 has_entity_name=has_entity_name,
849 original_device_class=original_device_class,
850 original_icon=original_icon,
851 original_name=original_name,
852 supported_features=supported_features,
853 translation_key=translation_key,
854 unit_of_measurement=unit_of_measurement,
857 self.
hasshass.verify_event_loop_thread(
"entity_registry.async_get_or_create")
862 disabled_by=disabled_by,
863 entity_category=entity_category,
868 entity_registry_id: str |
None =
None
870 deleted_entity = self.
deleted_entitiesdeleted_entities.pop((domain, platform, unique_id),
None)
871 if deleted_entity
is not None:
873 entity_registry_id = deleted_entity.id
874 created_at = deleted_entity.created_at
878 suggested_object_id
or f
"{platform}_{unique_id}",
885 and config_entry
is not UNDEFINED
886 and config_entry.pref_disable_new_entities
888 disabled_by = RegistryEntryDisabler.INTEGRATION
890 def none_if_undefined[_T](value: _T | UndefinedType) -> _T |
None:
891 """Return None if value is UNDEFINED, otherwise return value."""
892 return None if value
is UNDEFINED
else value
894 initial_options = get_initial_options()
if get_initial_options
else None
897 capabilities=none_if_undefined(capabilities),
898 config_entry_id=none_if_undefined(config_entry_id),
899 created_at=created_at,
900 device_id=none_if_undefined(device_id),
901 disabled_by=disabled_by,
902 entity_category=none_if_undefined(entity_category),
905 has_entity_name=none_if_undefined(has_entity_name)
or False,
906 id=entity_registry_id,
907 options=initial_options,
908 original_device_class=none_if_undefined(original_device_class),
909 original_icon=none_if_undefined(original_icon),
910 original_name=none_if_undefined(original_name),
912 supported_features=none_if_undefined(supported_features)
or 0,
913 translation_key=none_if_undefined(translation_key),
915 unit_of_measurement=none_if_undefined(unit_of_measurement),
917 self.
entitiesentities[entity_id] = entry
918 _LOGGER.info(
"Registered new %s.%s entity: %s", domain, platform, entity_id)
919 self.async_schedule_save()
921 self.
hasshass.bus.async_fire_internal(
922 EVENT_ENTITY_REGISTRY_UPDATED,
924 action=
"create", entity_id=entity_id
932 """Remove an entity from registry."""
933 self.
hasshass.verify_event_loop_thread(
"entity_registry.async_remove")
934 entity = self.
entitiesentities.pop(entity_id)
935 config_entry_id = entity.config_entry_id
936 key = (entity.domain, entity.platform, entity.unique_id)
938 orphaned_timestamp =
None if config_entry_id
else time.time()
940 config_entry_id=config_entry_id,
941 created_at=entity.created_at,
944 orphaned_timestamp=orphaned_timestamp,
945 platform=entity.platform,
946 unique_id=entity.unique_id,
948 self.
hasshass.bus.async_fire_internal(
949 EVENT_ENTITY_REGISTRY_UPDATED,
951 action=
"remove", entity_id=entity_id
954 self.async_schedule_save()
958 self, event: Event[EventDeviceRegistryUpdatedData]
960 """Handle the removal or update of a device.
962 Remove entities from the registry that are associated to a device when
963 the device is removed.
965 Disable entities in the registry that are associated to a device when
966 the device is disabled.
968 if event.data[
"action"] ==
"remove":
970 self, event.data[
"device_id"], include_disabled_entities=
True
972 for entity
in entities:
976 if event.data[
"action"] !=
"update":
980 device_registry = dr.async_get(self.
hasshass)
981 device = device_registry.async_get(event.data[
"device_id"])
991 self, event.data[
"device_id"], include_disabled_entities=
True
993 for entity
in entities:
995 entity.config_entry_id
is not None
996 and entity.config_entry_id
not in device.config_entries
1001 if not device.disabled:
1003 self, event.data[
"device_id"], include_disabled_entities=
True
1005 for entity
in entities:
1006 if entity.disabled_by
is not RegistryEntryDisabler.DEVICE:
1013 if device.disabled_by
is dr.DeviceEntryDisabler.CONFIG_ENTRY:
1018 for entity
in entities:
1020 entity.entity_id, disabled_by=RegistryEntryDisabler.DEVICE
1028 aliases: set[str] | UndefinedType = UNDEFINED,
1029 area_id: str |
None | UndefinedType = UNDEFINED,
1030 categories: dict[str, str] | UndefinedType = UNDEFINED,
1031 capabilities: Mapping[str, Any] |
None | UndefinedType = UNDEFINED,
1032 config_entry_id: str |
None | UndefinedType = UNDEFINED,
1033 device_class: str |
None | UndefinedType = UNDEFINED,
1034 device_id: str |
None | UndefinedType = UNDEFINED,
1035 disabled_by: RegistryEntryDisabler |
None | UndefinedType = UNDEFINED,
1036 entity_category: EntityCategory |
None | UndefinedType = UNDEFINED,
1037 hidden_by: RegistryEntryHider |
None | UndefinedType = UNDEFINED,
1038 icon: str |
None | UndefinedType = UNDEFINED,
1039 has_entity_name: bool | UndefinedType = UNDEFINED,
1040 labels: set[str] | UndefinedType = UNDEFINED,
1041 name: str |
None | UndefinedType = UNDEFINED,
1042 new_entity_id: str | UndefinedType = UNDEFINED,
1043 new_unique_id: str | UndefinedType = UNDEFINED,
1044 options: EntityOptionsType | UndefinedType = UNDEFINED,
1045 original_device_class: str |
None | UndefinedType = UNDEFINED,
1046 original_icon: str |
None | UndefinedType = UNDEFINED,
1047 original_name: str |
None | UndefinedType = UNDEFINED,
1048 platform: str |
None | UndefinedType = UNDEFINED,
1049 supported_features: int | UndefinedType = UNDEFINED,
1050 translation_key: str |
None | UndefinedType = UNDEFINED,
1051 unit_of_measurement: str |
None | UndefinedType = UNDEFINED,
1053 """Private facing update properties method."""
1054 old = self.
entitiesentities[entity_id]
1056 new_values: dict[str, Any] = {}
1057 old_values: dict[str, Any] = {}
1059 for attr_name, value
in (
1060 (
"aliases", aliases),
1061 (
"area_id", area_id),
1062 (
"categories", categories),
1063 (
"capabilities", capabilities),
1064 (
"config_entry_id", config_entry_id),
1065 (
"device_class", device_class),
1066 (
"device_id", device_id),
1067 (
"disabled_by", disabled_by),
1068 (
"entity_category", entity_category),
1069 (
"hidden_by", hidden_by),
1071 (
"has_entity_name", has_entity_name),
1074 (
"options", options),
1075 (
"original_device_class", original_device_class),
1076 (
"original_icon", original_icon),
1077 (
"original_name", original_name),
1078 (
"platform", platform),
1079 (
"supported_features", supported_features),
1080 (
"translation_key", translation_key),
1081 (
"unit_of_measurement", unit_of_measurement),
1083 if value
is not UNDEFINED
and value != getattr(old, attr_name):
1084 new_values[attr_name] = value
1085 old_values[attr_name] = getattr(old, attr_name)
1088 if new_values
or new_unique_id
is not UNDEFINED:
1093 disabled_by=disabled_by,
1094 entity_category=entity_category,
1095 hidden_by=hidden_by,
1096 unique_id=new_unique_id,
1099 if new_entity_id
is not UNDEFINED
and new_entity_id != old.entity_id:
1101 raise ValueError(
"Entity with this ID is already registered")
1104 raise ValueError(
"Invalid entity ID")
1107 raise ValueError(
"New entity ID should be same domain")
1109 self.
entitiesentities.pop(entity_id)
1110 entity_id = new_values[
"entity_id"] = new_entity_id
1111 old_values[
"entity_id"] = old.entity_id
1113 if new_unique_id
is not UNDEFINED:
1115 old.domain, old.platform, new_unique_id
1117 if conflict_entity_id:
1119 f
"Unique id '{new_unique_id}' is already in use by "
1120 f
"'{conflict_entity_id}'"
1122 new_values[
"unique_id"] = new_unique_id
1123 old_values[
"unique_id"] = old.unique_id
1124 new_values[
"previous_unique_id"] = old.unique_id
1129 new_values[
"modified_at"] =
utcnow()
1131 self.
hasshass.verify_event_loop_thread(
"entity_registry.async_update_entity")
1133 new = self.
entitiesentities[entity_id] = attr.evolve(old, **new_values)
1135 self.async_schedule_save()
1137 data: _EventEntityRegistryUpdatedData_Update = {
1139 "entity_id": entity_id,
1140 "changes": old_values,
1143 if old.entity_id != entity_id:
1144 data[
"old_entity_id"] = old.entity_id
1146 self.
hasshass.bus.async_fire_internal(EVENT_ENTITY_REGISTRY_UPDATED, data)
1155 aliases: set[str] | UndefinedType = UNDEFINED,
1156 area_id: str |
None | UndefinedType = UNDEFINED,
1157 categories: dict[str, str] | UndefinedType = UNDEFINED,
1158 capabilities: Mapping[str, Any] |
None | UndefinedType = UNDEFINED,
1159 config_entry_id: str |
None | UndefinedType = UNDEFINED,
1160 device_class: str |
None | UndefinedType = UNDEFINED,
1161 device_id: str |
None | UndefinedType = UNDEFINED,
1162 disabled_by: RegistryEntryDisabler |
None | UndefinedType = UNDEFINED,
1163 entity_category: EntityCategory |
None | UndefinedType = UNDEFINED,
1164 hidden_by: RegistryEntryHider |
None | UndefinedType = UNDEFINED,
1165 icon: str |
None | UndefinedType = UNDEFINED,
1166 has_entity_name: bool | UndefinedType = UNDEFINED,
1167 labels: set[str] | UndefinedType = UNDEFINED,
1168 name: str |
None | UndefinedType = UNDEFINED,
1169 new_entity_id: str | UndefinedType = UNDEFINED,
1170 new_unique_id: str | UndefinedType = UNDEFINED,
1171 original_device_class: str |
None | UndefinedType = UNDEFINED,
1172 original_icon: str |
None | UndefinedType = UNDEFINED,
1173 original_name: str |
None | UndefinedType = UNDEFINED,
1174 supported_features: int | UndefinedType = UNDEFINED,
1175 translation_key: str |
None | UndefinedType = UNDEFINED,
1176 unit_of_measurement: str |
None | UndefinedType = UNDEFINED,
1178 """Update properties of an entity."""
1183 categories=categories,
1184 capabilities=capabilities,
1185 config_entry_id=config_entry_id,
1186 device_class=device_class,
1187 device_id=device_id,
1188 disabled_by=disabled_by,
1189 entity_category=entity_category,
1190 hidden_by=hidden_by,
1192 has_entity_name=has_entity_name,
1195 new_entity_id=new_entity_id,
1196 new_unique_id=new_unique_id,
1197 original_device_class=original_device_class,
1198 original_icon=original_icon,
1199 original_name=original_name,
1200 supported_features=supported_features,
1201 translation_key=translation_key,
1202 unit_of_measurement=unit_of_measurement,
1211 new_config_entry_id: str | UndefinedType = UNDEFINED,
1212 new_unique_id: str | UndefinedType = UNDEFINED,
1213 new_device_id: str |
None | UndefinedType = UNDEFINED,
1215 """Update entity platform.
1217 This should only be used when an entity needs to be migrated between
1221 state := self.
hasshass.states.get(entity_id)
1222 )
is not None and state.state != STATE_UNKNOWN:
1223 raise ValueError(
"Only entities that haven't been loaded can be migrated")
1225 old = self.
entitiesentities[entity_id]
1226 if new_config_entry_id == UNDEFINED
and old.config_entry_id
is not None:
1228 f
"new_config_entry_id required because {entity_id} is already linked "
1234 new_unique_id=new_unique_id,
1235 config_entry_id=new_config_entry_id,
1236 device_id=new_device_id,
1237 platform=new_platform,
1242 self, entity_id: str, domain: str, options: Mapping[str, Any] |
None
1244 """Update entity options for a domain.
1246 If the domain options are set to None, they will be removed.
1248 old = self.
entitiesentities[entity_id]
1249 new_options: dict[str, Mapping] = {
1250 key: value
for key, value
in old.options.items()
if key != domain
1252 if options
is not None:
1253 new_options[domain] = options
1257 """Load the entity registry."""
1263 deleted_entities: dict[tuple[str, str, str], DeletedRegistryEntry] = {}
1265 if data
is not None:
1266 for entity
in data[
"entities"]:
1273 report_non_string_unique_id=
False,
1274 unique_id=entity[
"unique_id"],
1276 except (TypeError, ValueError)
as err:
1278 self.
hasshass, integration_domain=entity[
"platform"]
1282 "Entity registry entry '%s' from integration %s could not "
1283 "be loaded: '%s', please %s"
1285 entity[
"entity_id"],
1293 aliases=set(entity[
"aliases"]),
1294 area_id=entity[
"area_id"],
1295 categories=entity[
"categories"],
1296 capabilities=entity[
"capabilities"],
1297 config_entry_id=entity[
"config_entry_id"],
1298 created_at=datetime.fromisoformat(entity[
"created_at"]),
1299 device_class=entity[
"device_class"],
1300 device_id=entity[
"device_id"],
1302 if entity[
"disabled_by"]
1305 if entity[
"entity_category"]
1307 entity_id=entity[
"entity_id"],
1309 if entity[
"hidden_by"]
1311 icon=entity[
"icon"],
1313 has_entity_name=entity[
"has_entity_name"],
1314 labels=set(entity[
"labels"]),
1315 modified_at=datetime.fromisoformat(entity[
"modified_at"]),
1316 name=entity[
"name"],
1317 options=entity[
"options"],
1318 original_device_class=entity[
"original_device_class"],
1319 original_icon=entity[
"original_icon"],
1320 original_name=entity[
"original_name"],
1321 platform=entity[
"platform"],
1322 supported_features=entity[
"supported_features"],
1323 translation_key=entity[
"translation_key"],
1324 unique_id=entity[
"unique_id"],
1325 previous_unique_id=entity[
"previous_unique_id"],
1326 unit_of_measurement=entity[
"unit_of_measurement"],
1328 for entity
in data[
"deleted_entities"]:
1335 report_non_string_unique_id=
False,
1336 unique_id=entity[
"unique_id"],
1338 except (TypeError, ValueError):
1343 entity[
"unique_id"],
1346 config_entry_id=entity[
"config_entry_id"],
1347 created_at=datetime.fromisoformat(entity[
"created_at"]),
1348 entity_id=entity[
"entity_id"],
1350 modified_at=datetime.fromisoformat(entity[
"modified_at"]),
1351 orphaned_timestamp=entity[
"orphaned_timestamp"],
1352 platform=entity[
"platform"],
1353 unique_id=entity[
"unique_id"],
1362 """Return data of entity registry to store in a file."""
1364 "entities": [entry.as_storage_fragment
for entry
in self.
entitiesentities.values()],
1365 "deleted_entities": [
1366 entry.as_storage_fragment
for entry
in self.
deleted_entitiesdeleted_entities.values()
1372 """Clear category id from registry entries."""
1373 for entity_id, entry
in self.
entitiesentities.items():
1375 existing_category_id := entry.categories.get(scope)
1376 )
and category_id == existing_category_id:
1377 categories = entry.categories.copy()
1378 del categories[scope]
1383 """Clear label from registry entries."""
1384 for entry
in self.
entitiesentities.get_entries_for_label(label_id):
1385 self.
async_update_entityasync_update_entity(entry.entity_id, labels=entry.labels - {label_id})
1389 """Clear config entry from registry entries."""
1390 now_time = time.time()
1393 for entry
in self.
entitiesentities.get_entries_for_config_entry_id(config_entry_id)
1397 if config_entry_id != deleted_entity.config_entry_id:
1401 deleted_entity, orphaned_timestamp=now_time, config_entry_id=
None
1403 self.async_schedule_save()
1407 """Purge expired orphaned entities from the registry.
1409 We need to purge these periodically to avoid the database
1410 growing without bound.
1412 now_time = time.time()
1414 if (orphaned_timestamp := deleted_entity.orphaned_timestamp)
is None:
1417 if orphaned_timestamp + ORPHANED_ENTITY_KEEP_SECONDS < now_time:
1419 self.async_schedule_save()
1423 """Clear area id from registry entries."""
1424 for entry
in self.
entitiesentities.get_entries_for_area_id(area_id):
1429 @singleton(DATA_REGISTRY)
1431 """Get entity registry."""
1436 """Load entity registry."""
1437 assert DATA_REGISTRY
not in hass.data
1443 registry: EntityRegistry, device_id: str, include_disabled_entities: bool =
False
1444 ) -> list[RegistryEntry]:
1445 """Return entries that match a device."""
1446 return registry.entities.get_entries_for_device_id(
1447 device_id, include_disabled_entities
1453 registry: EntityRegistry, area_id: str
1454 ) -> list[RegistryEntry]:
1455 """Return entries that match an area."""
1456 return registry.entities.get_entries_for_area_id(area_id)
1461 registry: EntityRegistry, label_id: str
1462 ) -> list[RegistryEntry]:
1463 """Return entries that match a label."""
1464 return registry.entities.get_entries_for_label(label_id)
1469 registry: EntityRegistry, scope: str, category_id: str
1470 ) -> list[RegistryEntry]:
1471 """Return entries that match a category in a scope."""
1474 for entry
in registry.entities.values()
1476 (existing_category_id := entry.categories.get(scope))
1477 and category_id == existing_category_id
1484 registry: EntityRegistry, config_entry_id: str
1485 ) -> list[RegistryEntry]:
1486 """Return entries that match a config entry."""
1487 return registry.entities.get_entries_for_config_entry_id(config_entry_id)
1492 registry: EntityRegistry, config_entry: ConfigEntry
1494 """Handle a config entry being disabled or enabled.
1496 Disable entities in the registry that are associated with a config entry when
1497 the config entry is disabled, enable entities in the registry that are associated
1498 with a config entry when the config entry is enabled and the entities are marked
1499 DISABLED_CONFIG_ENTRY.
1504 if not config_entry.disabled_by:
1505 for entity
in entities:
1506 if entity.disabled_by
is not RegistryEntryDisabler.CONFIG_ENTRY:
1508 registry.async_update_entity(entity.entity_id, disabled_by=
None)
1511 for entity
in entities:
1515 registry.async_update_entity(
1516 entity.entity_id, disabled_by=RegistryEntryDisabler.CONFIG_ENTRY
1522 """Clean up device registry when entities removed."""
1524 from .
import category_registry
as cr, event, label_registry
as lr
1527 def _removed_from_registry_filter(
1528 event_data: lr.EventLabelRegistryUpdatedData
1529 | cr.EventCategoryRegistryUpdatedData,
1531 """Filter all except for the remove action from registry events."""
1532 return event_data[
"action"] ==
"remove"
1535 def _handle_label_registry_update(event: lr.EventLabelRegistryUpdated) ->
None:
1536 """Update entity that have a label that has been removed."""
1537 registry.async_clear_label_id(event.data[
"label_id"])
1539 hass.bus.async_listen(
1540 event_type=lr.EVENT_LABEL_REGISTRY_UPDATED,
1541 event_filter=_removed_from_registry_filter,
1542 listener=_handle_label_registry_update,
1546 def _handle_category_registry_update(
1547 event: cr.EventCategoryRegistryUpdated,
1549 """Update entity that have a category that has been removed."""
1550 registry.async_clear_category_id(event.data[
"scope"], event.data[
"category_id"])
1552 hass.bus.async_listen(
1553 event_type=cr.EVENT_CATEGORY_REGISTRY_UPDATED,
1554 event_filter=_removed_from_registry_filter,
1555 listener=_handle_category_registry_update,
1559 def cleanup(_: datetime) ->
None:
1560 """Clean up entity registry."""
1563 registry.async_purge_expired_orphaned_entities()
1565 cancel = event.async_track_time_interval(
1566 hass, cleanup,
timedelta(seconds=CLEANUP_INTERVAL)
1570 def _on_homeassistant_stop(event: Event) ->
None:
1571 """Cancel cleanup."""
1574 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _on_homeassistant_stop)
1579 """Set up the entity restore mechanism."""
1582 def cleanup_restored_states_filter(event_data: Mapping[str, Any]) -> bool:
1583 """Clean up restored states filter."""
1584 return bool(event_data[
"action"] ==
"remove")
1587 def cleanup_restored_states(event: Event[EventEntityRegistryUpdatedData]) ->
None:
1588 """Clean up restored states."""
1589 state = hass.states.get(event.data[
"entity_id"])
1591 if state
is None or not state.attributes.get(ATTR_RESTORED):
1594 hass.states.async_remove(event.data[
"entity_id"], context=event.context)
1596 hass.bus.async_listen(
1597 EVENT_ENTITY_REGISTRY_UPDATED,
1598 cleanup_restored_states,
1599 event_filter=cleanup_restored_states_filter,
1606 def _write_unavailable_states(_: Event) ->
None:
1607 """Make sure state machine contains entry for each registered entity."""
1608 existing = set(hass.states.async_entity_ids())
1610 for entry
in registry.entities.values():
1611 if entry.entity_id
in existing
or entry.disabled:
1614 entry.write_unavailable_state(hass)
1616 hass.bus.async_listen(EVENT_HOMEASSISTANT_START, _write_unavailable_states)
1620 hass: HomeAssistant,
1621 config_entry_id: str,
1622 entry_callback: Callable[[RegistryEntry], dict[str, Any] |
None],
1624 """Migrate entity registry entries which belong to a config entry.
1626 Can be used as a migrator of unique_ids or to update other entity registry data.
1627 Can also be used to remove duplicated entity registry entries.
1630 entities = ent_reg.entities
1631 for entry
in entities.get_entries_for_config_entry_id(config_entry_id):
1633 entities.get_entry(entry.id)
1634 and (updates := entry_callback(entry))
is not None
1636 ent_reg.async_update_entity(entry.entity_id, **updates)
1641 """Validate and resolve an entity id or UUID to an entity id.
1643 Raises vol.Invalid if the entity or UUID is invalid, or if the UUID is not
1644 associated with an entity registry item.
1647 return entity_id_or_uuid
1648 if (entry := registry.entities.get_entry(entity_id_or_uuid))
is None:
1649 raise vol.Invalid(f
"Unknown entity registry entry {entity_id_or_uuid}")
1650 return entry.entity_id
1655 registry: EntityRegistry, entity_id_or_uuid: str
1657 """Validate and resolve an entity id or UUID to an entity id.
1659 Returns None if the entity or UUID is invalid, or if the UUID is not
1660 associated with an entity registry item.
1663 return entity_id_or_uuid
1664 if (entry := registry.entities.get_entry(entity_id_or_uuid))
is None:
1666 return entry.entity_id
1671 registry: EntityRegistry, entity_ids_or_uuids: list[str]
1673 """Validate and resolve a list of entity ids or UUIDs to a list of entity ids.
1675 Returns a list with UUID resolved to entity_ids.
1676 Raises vol.Invalid if any item is invalid, or if any a UUID is not associated with
1677 an entity registry item.
json_fragment as_storage_fragment(self)
str _domain_default(self)
RegistryEntry|None get_entry(self, str key)
KeysView[str] get_device_ids(self)
list[RegistryEntry] get_entries_for_device_id(self, str device_id, bool include_disabled_entities=False)
list[RegistryEntry] get_entries_for_label(self, str label)
None _index_entry(self, str key, RegistryEntry entry)
None _unindex_entry(self, str key, RegistryEntry|None replacement_entry=None)
list[RegistryEntry] get_entries_for_config_entry_id(self, str config_entry_id)
str|None get_entity_id(self, tuple[str, str, str] key)
list[RegistryEntry] get_entries_for_area_id(self, str area_id)
dict _async_migrate_func(self, int old_major_version, int old_minor_version, dict[str, list[dict[str, Any]]] old_data)
RegistryEntry async_update_entity_options(self, str entity_id, str domain, Mapping[str, Any]|None options)
None __init__(self, HomeAssistant hass)
RegistryEntry|None async_get(self, str entity_id_or_uuid)
None async_purge_expired_orphaned_entities(self)
None async_clear_config_entry(self, str config_entry_id)
None async_remove(self, str entity_id)
None async_clear_label_id(self, str label_id)
str async_generate_entity_id(self, str domain, str suggested_object_id, Container[str]|None known_object_ids=None)
RegistryEntry async_get_or_create(self, str domain, str platform, str unique_id, *Container[str]|None known_object_ids=None, str|None suggested_object_id=None, RegistryEntryDisabler|None disabled_by=None, RegistryEntryHider|None hidden_by=None, Callable[[], EntityOptionsType|None]|None get_initial_options=None, Mapping[str, Any]|None|UndefinedType capabilities=UNDEFINED, ConfigEntry|None|UndefinedType config_entry=UNDEFINED, str|None|UndefinedType device_id=UNDEFINED, EntityCategory|UndefinedType|None entity_category=UNDEFINED, bool|UndefinedType has_entity_name=UNDEFINED, str|None|UndefinedType original_device_class=UNDEFINED, str|None|UndefinedType original_icon=UNDEFINED, str|None|UndefinedType original_name=UNDEFINED, int|None|UndefinedType supported_features=UNDEFINED, str|None|UndefinedType translation_key=UNDEFINED, str|None|UndefinedType unit_of_measurement=UNDEFINED)
bool async_is_registered(self, str entity_id)
list[str] async_device_ids(self)
dict[str, Any] _data_to_save(self)
None async_clear_area_id(self, str area_id)
None async_device_modified(self, Event[EventDeviceRegistryUpdatedData] event)
RegistryEntry async_update_entity_platform(self, str entity_id, str new_platform, *str|UndefinedType new_config_entry_id=UNDEFINED, str|UndefinedType new_unique_id=UNDEFINED, str|None|UndefinedType new_device_id=UNDEFINED)
RegistryEntry _async_update_entity(self, str entity_id, *set[str]|UndefinedType aliases=UNDEFINED, str|None|UndefinedType area_id=UNDEFINED, dict[str, str]|UndefinedType categories=UNDEFINED, Mapping[str, Any]|None|UndefinedType capabilities=UNDEFINED, str|None|UndefinedType config_entry_id=UNDEFINED, str|None|UndefinedType device_class=UNDEFINED, str|None|UndefinedType device_id=UNDEFINED, RegistryEntryDisabler|None|UndefinedType disabled_by=UNDEFINED, EntityCategory|None|UndefinedType entity_category=UNDEFINED, RegistryEntryHider|None|UndefinedType hidden_by=UNDEFINED, str|None|UndefinedType icon=UNDEFINED, bool|UndefinedType has_entity_name=UNDEFINED, set[str]|UndefinedType labels=UNDEFINED, str|None|UndefinedType name=UNDEFINED, str|UndefinedType new_entity_id=UNDEFINED, str|UndefinedType new_unique_id=UNDEFINED, EntityOptionsType|UndefinedType options=UNDEFINED, str|None|UndefinedType original_device_class=UNDEFINED, str|None|UndefinedType original_icon=UNDEFINED, str|None|UndefinedType original_name=UNDEFINED, str|None|UndefinedType platform=UNDEFINED, int|UndefinedType supported_features=UNDEFINED, str|None|UndefinedType translation_key=UNDEFINED, str|None|UndefinedType unit_of_measurement=UNDEFINED)
bool _entity_id_available(self, str entity_id, Container[str]|None known_object_ids)
None async_clear_category_id(self, str scope, str category_id)
str|None async_get_entity_id(self, str domain, str platform, str unique_id)
RegistryEntry async_update_entity(self, str entity_id, *set[str]|UndefinedType aliases=UNDEFINED, str|None|UndefinedType area_id=UNDEFINED, dict[str, str]|UndefinedType categories=UNDEFINED, Mapping[str, Any]|None|UndefinedType capabilities=UNDEFINED, str|None|UndefinedType config_entry_id=UNDEFINED, str|None|UndefinedType device_class=UNDEFINED, str|None|UndefinedType device_id=UNDEFINED, RegistryEntryDisabler|None|UndefinedType disabled_by=UNDEFINED, EntityCategory|None|UndefinedType entity_category=UNDEFINED, RegistryEntryHider|None|UndefinedType hidden_by=UNDEFINED, str|None|UndefinedType icon=UNDEFINED, bool|UndefinedType has_entity_name=UNDEFINED, set[str]|UndefinedType labels=UNDEFINED, str|None|UndefinedType name=UNDEFINED, str|UndefinedType new_entity_id=UNDEFINED, str|UndefinedType new_unique_id=UNDEFINED, str|None|UndefinedType original_device_class=UNDEFINED, str|None|UndefinedType original_icon=UNDEFINED, str|None|UndefinedType original_name=UNDEFINED, int|UndefinedType supported_features=UNDEFINED, str|None|UndefinedType translation_key=UNDEFINED, str|None|UndefinedType unit_of_measurement=UNDEFINED)
bytes|None partial_json_repr(self)
dict[str, Any] as_partial_dict(self)
dict[str, Any]|None _as_display_dict(self)
dict[str, Any] extended_dict(self)
json_fragment as_storage_fragment(self)
bytes|None display_json_repr(self)
None write_unavailable_state(self, HomeAssistant hass)
str _domain_default(self)
None _unindex_entry_value(self, str key, str value, RegistryIndexType index)
config_entries.ConfigEntry|None get_entry(HomeAssistant hass, websocket_api.ActiveConnection connection, str entry_id, int msg_id)
web.Response get(self, web.Request request, str config_key)
bool valid_entity_id(str entity_id)
tuple[str, str] split_entity_id(str entity_id)
None async_config_entry_disabled_by_changed(EntityRegistry registry, ConfigEntry config_entry)
list[RegistryEntry] async_entries_for_device(EntityRegistry registry, str device_id, bool include_disabled_entities=False)
str async_validate_entity_id(EntityRegistry registry, str entity_id_or_uuid)
None async_load(HomeAssistant hass)
str|None async_resolve_entity_id(EntityRegistry registry, str entity_id_or_uuid)
None _validate_item(HomeAssistant hass, str domain, str platform, *RegistryEntryDisabler|None|UndefinedType disabled_by=None, EntityCategory|None|UndefinedType entity_category=None, RegistryEntryHider|None|UndefinedType hidden_by=None, bool report_non_string_unique_id=True, str|Hashable|UndefinedType|Any unique_id)
None async_migrate_entries(HomeAssistant hass, str config_entry_id, Callable[[RegistryEntry], dict[str, Any]|None] entry_callback)
EntityRegistry async_get(HomeAssistant hass)
list[RegistryEntry] async_entries_for_category(EntityRegistry registry, str scope, str category_id)
list[RegistryEntry] async_entries_for_config_entry(EntityRegistry registry, str config_entry_id)
None _async_setup_cleanup(HomeAssistant hass, EntityRegistry registry)
None _async_setup_entity_restore(HomeAssistant hass, EntityRegistry registry)
list[str] async_validate_entity_ids(EntityRegistry registry, list[str] entity_ids_or_uuids)
list[RegistryEntry] async_entries_for_area(EntityRegistry registry, str area_id)
list[RegistryEntry] async_entries_for_label(EntityRegistry registry, str label_id)
ReadOnlyEntityOptionsType _protect_entity_options(EntityOptionsType|None data)
dict[str, Any] find_paths_unserializable_data(Any bad_data, *Callable[[Any], str] dump=json.dumps)
str async_suggest_report_issue(HomeAssistant|None hass, *Integration|None integration=None, str|None integration_domain=None, str|None module=None)
str format_unserializable_data(dict[str, Any] data)