From dd8de14cc57b3217c24061413d3130750c9765a3 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Benecke Date: Fri, 5 Apr 2024 15:28:33 +0200 Subject: [PATCH] Update `person` to use `_attr_*` and thus cached properties (#114590) * Update `person` to use `_attr_*` and thus cached properties * Make func * Just use attribute * Move to init --- homeassistant/components/person/__init__.py | 90 ++++++++++----------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/homeassistant/components/person/__init__.py b/homeassistant/components/person/__init__.py index 82b3b5ef7bd..cf4059dcc6b 100644 --- a/homeassistant/components/person/__init__.py +++ b/homeassistant/components/person/__init__.py @@ -402,7 +402,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True -class Person(collection.CollectionEntity, RestoreEntity): +class Person( + collection.CollectionEntity, + RestoreEntity, +): """Represent a tracked person.""" _entity_component_unrecorded_attributes = frozenset({ATTR_DEVICE_TRACKERS}) @@ -417,8 +420,18 @@ class Person(collection.CollectionEntity, RestoreEntity): self._longitude: float | None = None self._gps_accuracy: float | None = None self._source: str | None = None - self._state: str | None = None self._unsub_track_device: Callable[[], None] | None = None + self._attr_state: str | None = None + self.device_trackers: list[str] = [] + + self._attr_unique_id = config[CONF_ID] + self._set_attrs_from_config() + + def _set_attrs_from_config(self) -> None: + """Set attributes from config.""" + self._attr_name = self._config[CONF_NAME] + self._attr_entity_picture = self._config.get(CONF_PICTURE) + self.device_trackers = self._config[CONF_DEVICE_TRACKERS] @classmethod def from_storage(cls, config: ConfigType) -> Self: @@ -434,48 +447,6 @@ class Person(collection.CollectionEntity, RestoreEntity): person.editable = False return person - @property - def name(self) -> str: - """Return the name of the entity.""" - return self._config[CONF_NAME] - - @property - def entity_picture(self) -> str | None: - """Return entity picture.""" - return self._config.get(CONF_PICTURE) - - @property - def state(self) -> str | None: - """Return the state of the person.""" - return self._state - - @property - def extra_state_attributes(self) -> dict[str, Any]: - """Return the state attributes of the person.""" - data: dict[str, Any] = {ATTR_EDITABLE: self.editable, ATTR_ID: self.unique_id} - if self._latitude is not None: - data[ATTR_LATITUDE] = self._latitude - if self._longitude is not None: - data[ATTR_LONGITUDE] = self._longitude - if self._gps_accuracy is not None: - data[ATTR_GPS_ACCURACY] = self._gps_accuracy - if self._source is not None: - data[ATTR_SOURCE] = self._source - if (user_id := self._config.get(CONF_USER_ID)) is not None: - data[ATTR_USER_ID] = user_id - data[ATTR_DEVICE_TRACKERS] = self.device_trackers - return data - - @property - def unique_id(self) -> str: - """Return a unique ID for the person.""" - return self._config[CONF_ID] - - @property - def device_trackers(self) -> list[str]: - """Return the device trackers for the person.""" - return self._config[CONF_DEVICE_TRACKERS] - async def async_added_to_hass(self) -> None: """Register device trackers.""" await super().async_added_to_hass() @@ -495,6 +466,9 @@ class Person(collection.CollectionEntity, RestoreEntity): self.hass.bus.async_listen_once( EVENT_HOMEASSISTANT_START, _async_person_start_hass ) + # Update extra state attributes now + # as there are attributes that can already be set + self._update_extra_state_attributes() async def async_update_config(self, config: ConfigType) -> None: """Handle when the config is updated.""" @@ -504,6 +478,7 @@ class Person(collection.CollectionEntity, RestoreEntity): def _async_update_config(self, config: ConfigType) -> None: """Handle when the config is updated.""" self._config = config + self._set_attrs_from_config() if self._unsub_track_device is not None: self._unsub_track_device() @@ -550,12 +525,13 @@ class Person(collection.CollectionEntity, RestoreEntity): if latest: self._parse_source_state(latest) else: - self._state = None + self._attr_state = None self._source = None self._latitude = None self._longitude = None self._gps_accuracy = None + self._update_extra_state_attributes() self.async_write_ha_state() @callback @@ -564,12 +540,34 @@ class Person(collection.CollectionEntity, RestoreEntity): This is a device tracker state or the restored person state. """ - self._state = state.state + self._attr_state = state.state self._source = state.entity_id self._latitude = state.attributes.get(ATTR_LATITUDE) self._longitude = state.attributes.get(ATTR_LONGITUDE) self._gps_accuracy = state.attributes.get(ATTR_GPS_ACCURACY) + @callback + def _update_extra_state_attributes(self) -> None: + """Update extra state attributes.""" + data: dict[str, Any] = { + ATTR_EDITABLE: self.editable, + ATTR_ID: self.unique_id, + ATTR_DEVICE_TRACKERS: self.device_trackers, + } + + if self._latitude is not None: + data[ATTR_LATITUDE] = self._latitude + if self._longitude is not None: + data[ATTR_LONGITUDE] = self._longitude + if self._gps_accuracy is not None: + data[ATTR_GPS_ACCURACY] = self._gps_accuracy + if self._source is not None: + data[ATTR_SOURCE] = self._source + if (user_id := self._config.get(CONF_USER_ID)) is not None: + data[ATTR_USER_ID] = user_id + + self._attr_extra_state_attributes = data + @websocket_api.websocket_command({vol.Required(CONF_TYPE): "person/list"}) def ws_list_person(