-
-
Notifications
You must be signed in to change notification settings - Fork 28.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subscribe to device registry changes from entities #93601
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -40,7 +40,10 @@ | |||||||||||
|
||||||||||||
from . import device_registry as dr, entity_registry as er | ||||||||||||
from .device_registry import DeviceEntryType | ||||||||||||
from .event import async_track_entity_registry_updated_event | ||||||||||||
from .event import ( | ||||||||||||
async_track_device_registry_updated_event, | ||||||||||||
async_track_entity_registry_updated_event, | ||||||||||||
) | ||||||||||||
from .typing import StateType | ||||||||||||
|
||||||||||||
if TYPE_CHECKING: | ||||||||||||
|
@@ -265,6 +268,8 @@ | |||||||||||
# Hold list for functions to call on remove. | ||||||||||||
_on_remove: list[CALLBACK_TYPE] | None = None | ||||||||||||
|
||||||||||||
_unsub_device_updates: CALLBACK_TYPE | None = None | ||||||||||||
|
||||||||||||
# Context | ||||||||||||
_context: Context | None = None | ||||||||||||
_context_set: datetime | None = None | ||||||||||||
|
@@ -318,17 +323,50 @@ | |||||||||||
return self.entity_description.has_entity_name | ||||||||||||
return False | ||||||||||||
|
||||||||||||
def _uses_device_name(self) -> bool: | ||||||||||||
"""Return if this entity does not have its own name.""" | ||||||||||||
|
||||||||||||
if not self.has_entity_name: | ||||||||||||
return False | ||||||||||||
if hasattr(self, "_attr_name"): | ||||||||||||
if not self._attr_name: | ||||||||||||
return True | ||||||||||||
return False | ||||||||||||
|
||||||||||||
if name_translation_key := self._name_translation_key(): | ||||||||||||
assert self.platform | ||||||||||||
if name_translation_key in self.platform.entity_translations: | ||||||||||||
return False | ||||||||||||
|
||||||||||||
if hasattr(self, "entity_description"): | ||||||||||||
if not self.entity_description.name: | ||||||||||||
return True | ||||||||||||
return False | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
||||||||||||
if not self.name: | ||||||||||||
return True | ||||||||||||
|
||||||||||||
return False | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
||||||||||||
def _name_translation_key(self) -> str | None: | ||||||||||||
"""Return translation key for entity name.""" | ||||||||||||
if self.translation_key is None: | ||||||||||||
return None | ||||||||||||
assert self.platform | ||||||||||||
return ( | ||||||||||||
f"component.{self.platform.platform_name}.entity.{self.platform.domain}" | ||||||||||||
f".{self.translation_key}.name" | ||||||||||||
) | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this change? should we cache it? |
||||||||||||
|
||||||||||||
@property | ||||||||||||
def name(self) -> str | None: | ||||||||||||
"""Return the name of the entity.""" | ||||||||||||
if hasattr(self, "_attr_name"): | ||||||||||||
return self._attr_name | ||||||||||||
if self.translation_key is not None and self.has_entity_name: | ||||||||||||
if self.has_entity_name and ( | ||||||||||||
name_translation_key := self._name_translation_key() | ||||||||||||
): | ||||||||||||
assert self.platform | ||||||||||||
name_translation_key = ( | ||||||||||||
f"component.{self.platform.platform_name}.entity.{self.platform.domain}" | ||||||||||||
f".{self.translation_key}.name" | ||||||||||||
) | ||||||||||||
if name_translation_key in self.platform.entity_translations: | ||||||||||||
name: str = self.platform.entity_translations[name_translation_key] | ||||||||||||
return name | ||||||||||||
|
@@ -926,6 +964,7 @@ | |||||||||||
self.hass, self.entity_id, self._async_registry_updated | ||||||||||||
) | ||||||||||||
) | ||||||||||||
self._async_subscribe_device_updates() | ||||||||||||
|
||||||||||||
async def async_internal_will_remove_from_hass(self) -> None: | ||||||||||||
"""Run when entity will be removed from hass. | ||||||||||||
|
@@ -946,6 +985,9 @@ | |||||||||||
if data["action"] != "update": | ||||||||||||
return | ||||||||||||
|
||||||||||||
if "device_id" in data["changes"]: | ||||||||||||
self._async_subscribe_device_updates() | ||||||||||||
|
||||||||||||
ent_reg = er.async_get(self.hass) | ||||||||||||
old = self.registry_entry | ||||||||||||
self.registry_entry = ent_reg.async_get(data["entity_id"]) | ||||||||||||
|
@@ -967,6 +1009,52 @@ | |||||||||||
self.entity_id = self.registry_entry.entity_id | ||||||||||||
await self.platform.async_add_entities([self]) | ||||||||||||
|
||||||||||||
@callback | ||||||||||||
def _async_unsubscribe_device_updates(self) -> None: | ||||||||||||
"""Unsubscribe from device registry updates.""" | ||||||||||||
if not self._unsub_device_updates: | ||||||||||||
return | ||||||||||||
self._unsub_device_updates() | ||||||||||||
self._unsub_device_updates = None | ||||||||||||
|
||||||||||||
@callback | ||||||||||||
def _async_subscribe_device_updates(self) -> None: | ||||||||||||
"""Subscribe to device registry updates.""" | ||||||||||||
assert self.registry_entry | ||||||||||||
|
||||||||||||
self._async_unsubscribe_device_updates() | ||||||||||||
|
||||||||||||
if (device_id := self.registry_entry.device_id) is None: | ||||||||||||
return | ||||||||||||
|
||||||||||||
if not self._uses_device_name(): | ||||||||||||
return | ||||||||||||
|
||||||||||||
@callback | ||||||||||||
def async_device_registry_updated(event: Event) -> None: | ||||||||||||
"""Handle device registry update.""" | ||||||||||||
data = event.data | ||||||||||||
|
||||||||||||
if data["action"] != "update": | ||||||||||||
return | ||||||||||||
|
||||||||||||
if "name" not in data["changes"] and "name_by_user" not in data["changes"]: | ||||||||||||
return | ||||||||||||
|
||||||||||||
self.async_write_ha_state() | ||||||||||||
|
||||||||||||
self._unsub_device_updates = async_track_device_registry_updated_event( | ||||||||||||
self.hass, | ||||||||||||
device_id, | ||||||||||||
async_device_registry_updated, | ||||||||||||
) | ||||||||||||
if ( | ||||||||||||
self._on_remove | ||||||||||||
and self._async_unsubscribe_device_updates in self._on_remove | ||||||||||||
): | ||||||||||||
return | ||||||||||||
self.async_on_remove(self._async_unsubscribe_device_updates) | ||||||||||||
|
||||||||||||
def __repr__(self) -> str: | ||||||||||||
"""Return the representation.""" | ||||||||||||
return f"<entity {self.entity_id}={self._stringify_state(self.available)}>" | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.