Skip to content
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

Merged
merged 4 commits into from
May 31, 2023
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 94 additions & 6 deletions homeassistant/helpers/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link
Member

@bdraco bdraco May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not self._attr_name:
return True
return False
return not self._attr_name


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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not self.entity_description.name:
return True
return False
return not self.entity_description.name


if not self.name:
return True

return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not self.name:
return True
return False
return not self.name


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"
)
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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.
Expand All @@ -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"])
Expand All @@ -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

Check warning on line 1055 in homeassistant/helpers/entity.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/helpers/entity.py#L1055

Added line #L1055 was not covered by tests
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)}>"
Expand Down