Use EntityStateAttribute enum in helpers (#175836)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
epenet
2026-07-07 13:32:55 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent db0d5da9b3
commit a3c58649d8
7 changed files with 41 additions and 36 deletions
+5 -3
View File
@@ -7,7 +7,7 @@ from dataclasses import dataclass, field
from datetime import datetime
from typing import TYPE_CHECKING, Any, Literal, TypedDict, override
from homeassistant.const import ATTR_DEVICE_CLASS
from homeassistant.const import EntityStateAttribute
from homeassistant.core import HomeAssistant, callback
from homeassistant.util.dt import utc_from_timestamp, utcnow
from homeassistant.util.event_type import EventType
@@ -581,7 +581,8 @@ def _validate_temperature_entity(hass: HomeAssistant, entity_id: str) -> None:
if (
state.domain != "sensor"
or state.attributes.get(ATTR_DEVICE_CLASS) != SensorDeviceClass.TEMPERATURE
or state.attributes.get(EntityStateAttribute.DEVICE_CLASS)
!= SensorDeviceClass.TEMPERATURE
):
raise ValueError(f"Entity {entity_id} is not a temperature sensor")
@@ -595,6 +596,7 @@ def _validate_humidity_entity(hass: HomeAssistant, entity_id: str) -> None:
if (
state.domain != "sensor"
or state.attributes.get(ATTR_DEVICE_CLASS) != SensorDeviceClass.HUMIDITY
or state.attributes.get(EntityStateAttribute.DEVICE_CLASS)
!= SensorDeviceClass.HUMIDITY
):
raise ValueError(f"Entity {entity_id} is not a humidity sensor")
+7 -8
View File
@@ -31,8 +31,6 @@ from typing import (
import voluptuous as vol
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_UNIT_OF_MEASUREMENT,
CONF_ABOVE,
CONF_AFTER,
CONF_ATTRIBUTE,
@@ -56,6 +54,7 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
STATE_UNKNOWN,
WEEKDAYS,
EntityStateAttribute,
)
from homeassistant.core import HomeAssistant, State, callback, split_entity_id
from homeassistant.exceptions import (
@@ -989,7 +988,7 @@ class EntityNumericalConditionBase(EntityConditionBase):
# Entity not found
return None
if not self._is_valid_unit(
entity_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
entity_state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
):
# Entity unit does not match the expected unit
return None
@@ -1007,7 +1006,7 @@ class EntityNumericalConditionBase(EntityConditionBase):
domain_spec = self._domain_specs[entity_state.domain]
if domain_spec.value_source is None:
if not self._is_valid_unit(
entity_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
entity_state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
):
return None
return entity_state.state
@@ -1095,7 +1094,7 @@ class EntityNumericalConditionWithUnitBase(EntityNumericalConditionBase):
def _get_entity_unit(self, entity_state: State) -> str | None:
"""Get the unit of an entity from its state."""
return entity_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
return entity_state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
@override
def _get_threshold_value(self, threshold: ThresholdConfig | None) -> float | None:
@@ -1121,7 +1120,7 @@ class EntityNumericalConditionWithUnitBase(EntityNumericalConditionBase):
try:
return self._unit_converter.convert(
value,
entity_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT),
entity_state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT),
self._base_unit,
)
except HomeAssistantError:
@@ -1851,7 +1850,7 @@ def time(
):
after = datetime.strptime(after_entity.state, "%H:%M:%S").time()
elif (
after_entity.attributes.get(ATTR_DEVICE_CLASS)
after_entity.attributes.get(EntityStateAttribute.DEVICE_CLASS)
in (SensorDeviceClass.TIMESTAMP, SensorDeviceClass.UPTIME)
) and after_entity.state not in (
STATE_UNAVAILABLE,
@@ -1881,7 +1880,7 @@ def time(
except ValueError:
return False
elif (
before_entity.attributes.get(ATTR_DEVICE_CLASS)
before_entity.attributes.get(EntityStateAttribute.DEVICE_CLASS)
in (SensorDeviceClass.TIMESTAMP, SensorDeviceClass.UPTIME)
) and before_entity.state not in (
STATE_UNAVAILABLE,
+6 -8
View File
@@ -14,11 +14,7 @@ from propcache.api import cached_property
import voluptuous as vol
from homeassistant.components.homeassistant.exposed_entities import async_should_expose
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
)
from homeassistant.const import ATTR_ENTITY_ID, EntityStateAttribute
from homeassistant.core import Context, HomeAssistant, State, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.hass_dict import HassKey
@@ -455,7 +451,9 @@ def _filter_by_features(
yield candidate
continue
supported_features = candidate.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
supported_features = candidate.state.attributes.get(
EntityStateAttribute.SUPPORTED_FEATURES, 0
)
if (supported_features & features) == features:
yield candidate
@@ -474,7 +472,7 @@ def _filter_by_device_classes(
yield candidate
continue
device_class = candidate.state.attributes.get(ATTR_DEVICE_CLASS)
device_class = candidate.state.attributes.get(EntityStateAttribute.DEVICE_CLASS)
if device_class and (device_class in device_classes):
yield candidate
@@ -811,7 +809,7 @@ def async_match_states(
@callback
def async_test_feature(state: State, feature: int, feature_name: str) -> None:
"""Test if state supports a feature."""
if state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) & feature == 0:
if state.attributes.get(EntityStateAttribute.SUPPORTED_FEATURES, 0) & feature == 0:
raise IntentHandleError(f"Entity {state.name} does not support {feature_name}")
+5 -1
View File
@@ -30,6 +30,7 @@ from homeassistant.const import (
ATTR_SERVICE,
EVENT_HOMEASSISTANT_CLOSE,
EVENT_SERVICE_REMOVED,
EntityStateAttribute,
)
from homeassistant.core import Context, Event, HomeAssistant, callback, split_entity_id
from homeassistant.exceptions import HomeAssistantError
@@ -731,7 +732,10 @@ def _get_exposed_entities(
info["state"] = async_rounded_state(hass, state.entity_id, state)
# Convert timestamp device_class states from UTC to local time
if state.attributes.get("device_class") == "timestamp" and state.state:
if (
state.attributes.get(EntityStateAttribute.DEVICE_CLASS) == "timestamp"
and state.state
):
if (parsed_utc := dt_util.parse_datetime(state.state)) is not None:
info["state"] = dt_util.as_local(parsed_utc).isoformat()
+6 -4
View File
@@ -9,7 +9,7 @@ from typing import Any, override
from lru import LRU
from propcache.api import under_cached_property
from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, STATE_UNKNOWN
from homeassistant.const import STATE_UNKNOWN, EntityStateAttribute
from homeassistant.core import (
Context,
HomeAssistant,
@@ -182,7 +182,7 @@ class StateTranslated:
state_value = state.state
domain = state.domain
device_class = state.attributes.get("device_class")
device_class = state.attributes.get(EntityStateAttribute.DEVICE_CLASS)
entry = er.async_get(self._hass).async_get(entity_id)
platform = None if entry is None else entry.platform
translation_key = None if entry is None else entry.translation_key
@@ -219,7 +219,7 @@ class StateAttrTranslated:
return attr_value
domain = state.domain
device_class = state.attributes.get("device_class")
device_class = state.attributes.get(EntityStateAttribute.DEVICE_CLASS)
entry = er.async_get(self._hass).async_get(entity_id)
platform = None if entry is None else entry.platform
translation_key = None if entry is None else entry.translation_key
@@ -413,7 +413,9 @@ class TemplateStateBase(State):
state = async_rounded_state(self._hass, self._entity_id, self._state)
else:
state = self._state.state
if with_unit and (unit := self._state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)):
if with_unit and (
unit := self._state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
):
return f"{state} {unit}"
return state
+8 -6
View File
@@ -26,7 +26,6 @@ import voluptuous as vol
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_UNIT_OF_MEASUREMENT,
CONF_ALIAS,
CONF_DEVICE_ID,
CONF_ENABLED,
@@ -42,6 +41,7 @@ from homeassistant.const import (
CONF_ZONE,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
EntityStateAttribute,
)
from homeassistant.core import (
CALLBACK_TYPE,
@@ -856,7 +856,7 @@ class EntityNumericalStateTriggerBase(EntityTriggerBase):
entity_id=threshold.entity,
)
return None
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
unit = state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
if not self._is_valid_unit(unit):
# Entity unit does not match the expected unit
report_not_triggered(
@@ -882,7 +882,9 @@ class EntityNumericalStateTriggerBase(EntityTriggerBase):
domain_spec = self._domain_specs[state.domain]
raw_value: Any
if domain_spec.value_source is None:
if not self._is_valid_unit(state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)):
if not self._is_valid_unit(
state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
):
return None
raw_value = state.state
else:
@@ -907,7 +909,7 @@ class EntityNumericalStateTriggerBase(EntityTriggerBase):
domain_spec = self._domain_specs[state.domain]
raw_value: Any
if domain_spec.value_source is None:
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
unit = state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
if not self._is_valid_unit(unit):
report_not_triggered(
"entity_unit_not_supported",
@@ -984,7 +986,7 @@ class EntityNumericalStateTriggerWithUnitBase(EntityNumericalStateTriggerBase):
def _get_entity_unit(self, state: State) -> str | None:
"""Get the unit of an entity from its state."""
return state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
return state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
@override
def _report_tracked_value_problem(
@@ -1050,7 +1052,7 @@ class EntityNumericalStateTriggerWithUnitBase(EntityNumericalStateTriggerBase):
)
return None
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
unit = state.attributes.get(EntityStateAttribute.UNIT_OF_MEASUREMENT)
try:
return self._unit_converter.convert(value, unit, self._base_unit)
except HomeAssistantError:
@@ -18,14 +18,12 @@ from homeassistant.components.sensor.helpers import ( # pylint: disable=home-as
async_parse_date_datetime,
)
from homeassistant.const import (
ATTR_ENTITY_PICTURE,
ATTR_FRIENDLY_NAME,
ATTR_ICON,
CONF_DEVICE_CLASS,
CONF_ICON,
CONF_NAME,
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
EntityStateAttribute,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import TemplateError
@@ -48,9 +46,9 @@ CONF_ATTRIBUTES = "attributes"
CONF_PICTURE = "picture"
CONF_TO_ATTRIBUTE = {
CONF_ICON: ATTR_ICON,
CONF_NAME: ATTR_FRIENDLY_NAME,
CONF_PICTURE: ATTR_ENTITY_PICTURE,
CONF_ICON: EntityStateAttribute.ICON,
CONF_NAME: EntityStateAttribute.FRIENDLY_NAME,
CONF_PICTURE: EntityStateAttribute.ENTITY_PICTURE,
}
TEMPLATE_ENTITY_BASE_SCHEMA = vol.Schema(