Subscribe to device registry changes from entities (#93601)

* Subscribe to device registry changes from entities

* Use async_track_device_registry_updated_event

* Fix unsubscribe

* Fix logic, add tests
This commit is contained in:
Erik Montnemery 2023-05-31 11:01:55 +02:00 committed by GitHub
parent 204215e0f2
commit 59c6220b7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 138 additions and 1 deletions

View file

@ -40,7 +40,10 @@ from homeassistant.util import dt as dt_util, ensure_unique_string, slugify
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 @@ class Entity(ABC):
# 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
@ -926,6 +931,7 @@ class Entity(ABC):
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 +952,9 @@ class Entity(ABC):
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 +976,51 @@ class Entity(ABC):
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.has_entity_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 (
not self._on_remove
or self._async_unsubscribe_device_updates not in self._on_remove
):
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)}>"