Small speed up to entity state calculation (#121273)

This commit is contained in:
J. Nick Koston 2024-07-05 01:56:20 -05:00 committed by GitHub
parent adee8094e7
commit cdb2ec4231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -263,8 +263,6 @@ class CalculatedState:
attributes: dict[str, Any] attributes: dict[str, Any]
# Capability attributes returned by the capability_attributes property # Capability attributes returned by the capability_attributes property
capability_attributes: Mapping[str, Any] | None capability_attributes: Mapping[str, Any] | None
# Attributes which may be overridden by the entity registry
shadowed_attributes: Mapping[str, Any]
class CachedProperties(type): class CachedProperties(type):
@ -1042,18 +1040,20 @@ class Entity(
@callback @callback
def _async_calculate_state(self) -> CalculatedState: def _async_calculate_state(self) -> CalculatedState:
"""Calculate state string and attribute mapping.""" """Calculate state string and attribute mapping."""
return CalculatedState(*self.__async_calculate_state()) state, attr, capabilities, _, _ = self.__async_calculate_state()
return CalculatedState(state, attr, capabilities)
def __async_calculate_state( def __async_calculate_state(
self, self,
) -> tuple[str, dict[str, Any], Mapping[str, Any] | None, Mapping[str, Any]]: ) -> tuple[str, dict[str, Any], Mapping[str, Any] | None, str | None, int | None]:
"""Calculate state string and attribute mapping. """Calculate state string and attribute mapping.
Returns a tuple (state, attr, capability_attr, shadowed_attr). Returns a tuple:
state - the stringified state state - the stringified state
attr - the attribute dictionary attr - the attribute dictionary
capability_attr - a mapping with capability attributes capability_attr - a mapping with capability attributes
shadowed_attr - a mapping with attributes which may be overridden original_device_class - the device class which may be overridden
supported_features - the supported features
This method is called when writing the state to avoid the overhead of creating This method is called when writing the state to avoid the overhead of creating
a dataclass object. a dataclass object.
@ -1062,7 +1062,6 @@ class Entity(
capability_attr = self.capability_attributes capability_attr = self.capability_attributes
attr = capability_attr.copy() if capability_attr else {} attr = capability_attr.copy() if capability_attr else {}
shadowed_attr = {}
available = self.available # only call self.available once per update cycle available = self.available # only call self.available once per update cycle
state = self._stringify_state(available) state = self._stringify_state(available)
@ -1081,30 +1080,27 @@ class Entity(
if (attribution := self.attribution) is not None: if (attribution := self.attribution) is not None:
attr[ATTR_ATTRIBUTION] = attribution attr[ATTR_ATTRIBUTION] = attribution
shadowed_attr[ATTR_DEVICE_CLASS] = self.device_class original_device_class = self.device_class
if ( if (
device_class := (entry and entry.device_class) device_class := (entry and entry.device_class) or original_device_class
or shadowed_attr[ATTR_DEVICE_CLASS]
) is not None: ) is not None:
attr[ATTR_DEVICE_CLASS] = str(device_class) attr[ATTR_DEVICE_CLASS] = str(device_class)
if (entity_picture := self.entity_picture) is not None: if (entity_picture := self.entity_picture) is not None:
attr[ATTR_ENTITY_PICTURE] = entity_picture attr[ATTR_ENTITY_PICTURE] = entity_picture
shadowed_attr[ATTR_ICON] = self.icon if (icon := (entry and entry.icon) or self.icon) is not None:
if (icon := (entry and entry.icon) or shadowed_attr[ATTR_ICON]) is not None:
attr[ATTR_ICON] = icon attr[ATTR_ICON] = icon
shadowed_attr[ATTR_FRIENDLY_NAME] = self._friendly_name_internal()
if ( if (
name := (entry and entry.name) or shadowed_attr[ATTR_FRIENDLY_NAME] name := (entry and entry.name) or self._friendly_name_internal()
) is not None: ) is not None:
attr[ATTR_FRIENDLY_NAME] = name attr[ATTR_FRIENDLY_NAME] = name
if (supported_features := self.supported_features) is not None: if (supported_features := self.supported_features) is not None:
attr[ATTR_SUPPORTED_FEATURES] = supported_features attr[ATTR_SUPPORTED_FEATURES] = supported_features
return (state, attr, capability_attr, shadowed_attr) return (state, attr, capability_attr, original_device_class, supported_features)
@callback @callback
def _async_write_ha_state(self) -> None: def _async_write_ha_state(self) -> None:
@ -1130,14 +1126,15 @@ class Entity(
return return
state_calculate_start = timer() state_calculate_start = timer()
state, attr, capabilities, shadowed_attr = self.__async_calculate_state() state, attr, capabilities, original_device_class, supported_features = (
self.__async_calculate_state()
)
time_now = timer() time_now = timer()
if entry: if entry:
# Make sure capabilities in the entity registry are up to date. Capabilities # Make sure capabilities in the entity registry are up to date. Capabilities
# include capability attributes, device class and supported features # include capability attributes, device class and supported features
original_device_class: str | None = shadowed_attr[ATTR_DEVICE_CLASS] supported_features = supported_features or 0
supported_features: int = attr.get(ATTR_SUPPORTED_FEATURES) or 0
if ( if (
capabilities != entry.capabilities capabilities != entry.capabilities
or original_device_class != entry.original_device_class or original_device_class != entry.original_device_class