Add SensorEntityDescription class (#53357)

This commit is contained in:
Franck Nijhof 2021-07-26 22:00:43 +02:00 committed by GitHub
parent 88cffc86bb
commit ee452d415d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 293 additions and 247 deletions

View file

@ -5,12 +5,11 @@ from datetime import timedelta
import logging
from typing import Final
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntityDescription,
)
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_CUBIC_METER,
@ -18,13 +17,10 @@ from homeassistant.const import (
DEVICE_CLASS_CO,
)
from .models import AmbeeSensor
DOMAIN: Final = "ambee"
LOGGER = logging.getLogger(__package__)
SCAN_INTERVAL = timedelta(hours=1)
ATTR_ENABLED_BY_DEFAULT: Final = "enabled_by_default"
ATTR_ENTRY_TYPE: Final = "entry_type"
ENTRY_TYPE_SERVICE: Final = "service"
@ -38,175 +34,202 @@ SERVICES: dict[str, str] = {
SERVICE_POLLEN: "Pollen",
}
SENSORS: dict[str, dict[str, AmbeeSensor]] = {
SERVICE_AIR_QUALITY: {
"particulate_matter_2_5": {
ATTR_NAME: "Particulate Matter < 2.5 μm",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"particulate_matter_10": {
ATTR_NAME: "Particulate Matter < 10 μm",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"sulphur_dioxide": {
ATTR_NAME: "Sulphur Dioxide (SO2)",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"nitrogen_dioxide": {
ATTR_NAME: "Nitrogen Dioxide (NO2)",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"ozone": {
ATTR_NAME: "Ozone",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"carbon_monoxide": {
ATTR_NAME: "Carbon Monoxide (CO)",
ATTR_DEVICE_CLASS: DEVICE_CLASS_CO,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_MILLION,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
"air_quality_index": {
ATTR_NAME: "Air Quality Index (AQI)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
},
SERVICE_POLLEN: {
"grass": {
ATTR_NAME: "Grass Pollen",
ATTR_ICON: "mdi:grass",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
},
"tree": {
ATTR_NAME: "Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
},
"weed": {
ATTR_NAME: "Weed Pollen",
ATTR_ICON: "mdi:sprout",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
},
"grass_risk": {
ATTR_NAME: "Grass Pollen Risk",
ATTR_ICON: "mdi:grass",
ATTR_DEVICE_CLASS: DEVICE_CLASS_AMBEE_RISK,
},
"tree_risk": {
ATTR_NAME: "Tree Pollen Risk",
ATTR_ICON: "mdi:tree",
ATTR_DEVICE_CLASS: DEVICE_CLASS_AMBEE_RISK,
},
"weed_risk": {
ATTR_NAME: "Weed Pollen Risk",
ATTR_ICON: "mdi:sprout",
ATTR_DEVICE_CLASS: DEVICE_CLASS_AMBEE_RISK,
},
"grass_poaceae": {
ATTR_NAME: "Poaceae Grass Pollen",
ATTR_ICON: "mdi:grass",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_alder": {
ATTR_NAME: "Alder Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_birch": {
ATTR_NAME: "Birch Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_cypress": {
ATTR_NAME: "Cypress Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_elm": {
ATTR_NAME: "Elm Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_hazel": {
ATTR_NAME: "Hazel Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_oak": {
ATTR_NAME: "Oak Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_pine": {
ATTR_NAME: "Pine Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_plane": {
ATTR_NAME: "Plane Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"tree_poplar": {
ATTR_NAME: "Poplar Tree Pollen",
ATTR_ICON: "mdi:tree",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"weed_chenopod": {
ATTR_NAME: "Chenopod Weed Pollen",
ATTR_ICON: "mdi:sprout",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"weed_mugwort": {
ATTR_NAME: "Mugwort Weed Pollen",
ATTR_ICON: "mdi:sprout",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"weed_nettle": {
ATTR_NAME: "Nettle Weed Pollen",
ATTR_ICON: "mdi:sprout",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
"weed_ragweed": {
ATTR_NAME: "Ragweed Weed Pollen",
ATTR_ICON: "mdi:sprout",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_CUBIC_METER,
ATTR_ENABLED_BY_DEFAULT: False,
},
},
SENSORS: dict[str, list[SensorEntityDescription]] = {
SERVICE_AIR_QUALITY: [
SensorEntityDescription(
key="particulate_matter_2_5",
name="Particulate Matter < 2.5 μm",
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="particulate_matter_10",
name="Particulate Matter < 10 μm",
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="sulphur_dioxide",
name="Sulphur Dioxide (SO2)",
unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="nitrogen_dioxide",
name="Nitrogen Dioxide (NO2)",
unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="ozone",
name="Ozone",
unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="carbon_monoxide",
name="Carbon Monoxide (CO)",
device_class=DEVICE_CLASS_CO,
unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="air_quality_index",
name="Air Quality Index (AQI)",
state_class=STATE_CLASS_MEASUREMENT,
),
],
SERVICE_POLLEN: [
SensorEntityDescription(
key="grass",
name="Grass Pollen",
icon="mdi:grass",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
),
SensorEntityDescription(
key="tree",
name="Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
),
SensorEntityDescription(
key="weed",
name="Weed Pollen",
icon="mdi:sprout",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
),
SensorEntityDescription(
key="grass_risk",
name="Grass Pollen Risk",
icon="mdi:grass",
device_class=DEVICE_CLASS_AMBEE_RISK,
),
SensorEntityDescription(
key="tree_risk",
name="Tree Pollen Risk",
icon="mdi:tree",
device_class=DEVICE_CLASS_AMBEE_RISK,
),
SensorEntityDescription(
key="weed_risk",
name="Weed Pollen Risk",
icon="mdi:sprout",
device_class=DEVICE_CLASS_AMBEE_RISK,
),
SensorEntityDescription(
key="grass_poaceae",
name="Poaceae Grass Pollen",
icon="mdi:grass",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_alder",
name="Alder Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_birch",
name="Birch Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_cypress",
name="Cypress Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_elm",
name="Elm Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_hazel",
name="Hazel Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_oak",
name="Oak Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_pine",
name="Pine Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_plane",
name="Plane Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="tree_poplar",
name="Poplar Tree Pollen",
icon="mdi:tree",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="weed_chenopod",
name="Chenopod Weed Pollen",
icon="mdi:sprout",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="weed_mugwort",
name="Mugwort Weed Pollen",
icon="mdi:sprout",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="weed_nettle",
name="Nettle Weed Pollen",
icon="mdi:sprout",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
SensorEntityDescription(
key="weed_ragweed",
name="Ragweed Weed Pollen",
icon="mdi:sprout",
state_class=STATE_CLASS_MEASUREMENT,
unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False,
),
],
}

View file

@ -1,15 +0,0 @@
"""Models helper class for the Ambee integration."""
from __future__ import annotations
from typing import TypedDict
class AmbeeSensor(TypedDict, total=False):
"""Represent an Ambee Sensor."""
device_class: str
enabled_by_default: bool
icon: str
name: str
state_class: str
unit_of_measurement: str

View file

@ -2,19 +2,12 @@
from __future__ import annotations
from homeassistant.components.sensor import (
ATTR_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_IDENTIFIERS,
ATTR_MANUFACTURER,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
)
from homeassistant.const import ATTR_IDENTIFIERS, ATTR_MANUFACTURER, ATTR_NAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
@ -23,15 +16,7 @@ from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator,
)
from .const import (
ATTR_ENABLED_BY_DEFAULT,
ATTR_ENTRY_TYPE,
DOMAIN,
ENTRY_TYPE_SERVICE,
SENSORS,
SERVICES,
)
from .models import AmbeeSensor
from .const import ATTR_ENTRY_TYPE, DOMAIN, ENTRY_TYPE_SERVICE, SENSORS, SERVICES
async def async_setup_entry(
@ -44,13 +29,12 @@ async def async_setup_entry(
AmbeeSensorEntity(
coordinator=hass.data[DOMAIN][entry.entry_id][service_key],
entry_id=entry.entry_id,
sensor_key=sensor_key,
sensor=sensor,
description=description,
service_key=service_key,
service=SERVICES[service_key],
)
for service_key, service_sensors in SENSORS.items()
for sensor_key, sensor in service_sensors.items()
for description in service_sensors
)
@ -62,26 +46,17 @@ class AmbeeSensorEntity(CoordinatorEntity, SensorEntity):
*,
coordinator: DataUpdateCoordinator,
entry_id: str,
sensor_key: str,
sensor: AmbeeSensor,
description: SensorEntityDescription,
service_key: str,
service: str,
) -> None:
"""Initialize Ambee sensor."""
super().__init__(coordinator=coordinator)
self._sensor_key = sensor_key
self._service_key = service_key
self.entity_id = f"{SENSOR_DOMAIN}.{service_key}_{sensor_key}"
self._attr_device_class = sensor.get(ATTR_DEVICE_CLASS)
self._attr_entity_registry_enabled_default = sensor.get(
ATTR_ENABLED_BY_DEFAULT, True
)
self._attr_icon = sensor.get(ATTR_ICON)
self._attr_name = sensor.get(ATTR_NAME)
self._attr_state_class = sensor.get(ATTR_STATE_CLASS)
self._attr_unique_id = f"{entry_id}_{service_key}_{sensor_key}"
self._attr_unit_of_measurement = sensor.get(ATTR_UNIT_OF_MEASUREMENT)
self.entity_id = f"{SENSOR_DOMAIN}.{service_key}_{description.key}"
self.entity_description = description
self._attr_unique_id = f"{entry_id}_{service_key}_{description.key}"
self._attr_device_info = {
ATTR_IDENTIFIERS: {(DOMAIN, f"{entry_id}_{service_key}")},
@ -93,7 +68,7 @@ class AmbeeSensorEntity(CoordinatorEntity, SensorEntity):
@property
def state(self) -> StateType:
"""Return the state of the sensor."""
value = getattr(self.coordinator.data, self._sensor_key)
value = getattr(self.coordinator.data, self.entity_description.key)
if isinstance(value, str):
return value.lower()
return value # type: ignore[no-any-return]

View file

@ -2,6 +2,7 @@
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import dataclass
from datetime import datetime, timedelta
import logging
from typing import Any, Final, cast, final
@ -31,7 +32,7 @@ from homeassistant.helpers.config_validation import ( # noqa: F401
PLATFORM_SCHEMA,
PLATFORM_SCHEMA_BASE,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import ConfigType
@ -95,21 +96,38 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return await component.async_unload_entry(entry)
@dataclass
class SensorEntityDescription(EntityDescription):
"""An class that describes sensor entities."""
state_class: str | None = None
last_reset: datetime | None = None
class SensorEntity(Entity):
"""Base class for sensor entities."""
_attr_state_class: str | None = None
_attr_last_reset: datetime | None = None
entity_description: SensorEntityDescription
_attr_state_class: str | None
_attr_last_reset: datetime | None
@property
def state_class(self) -> str | None:
"""Return the state class of this entity, from STATE_CLASSES, if any."""
if hasattr(self, "_attr_state_class"):
return self._attr_state_class
if hasattr(self, "entity_description"):
return self.entity_description.state_class
return None
@property
def last_reset(self) -> datetime | None:
"""Return the time when the sensor was last reset, if any."""
if hasattr(self, "_attr_last_reset"):
return self._attr_last_reset
if hasattr(self, "entity_description"):
return self.entity_description.last_reset
return None
@property
def capability_attributes(self) -> Mapping[str, Any] | None:

View file

@ -112,6 +112,9 @@ class _TemplateAttribute:
class TemplateEntity(Entity):
"""Entity that uses templates to calculate attributes."""
_attr_available = True
_attr_entity_picture = None
_attr_icon = None
_attr_should_poll = False
def __init__(
@ -128,7 +131,6 @@ class TemplateEntity(Entity):
self._attribute_templates = attribute_templates
self._attr_extra_state_attributes = {}
self._availability_template = availability_template
self._attr_available = True
self._icon_template = icon_template
self._entity_picture_template = entity_picture_template
self._self_ref_update_count = 0

View file

@ -4,6 +4,7 @@ from __future__ import annotations
from abc import ABC
import asyncio
from collections.abc import Awaitable, Iterable, Mapping, MutableMapping
from dataclasses import dataclass
from datetime import datetime, timedelta
import functools as ft
import logging
@ -178,6 +179,21 @@ class DeviceInfo(TypedDict, total=False):
default_model: str
@dataclass
class EntityDescription:
"""An class that describes Home Assistant entities."""
# This is the key identifier for this entity
key: str
device_class: str | None = None
entity_registry_enabled_default: bool = True
force_update: bool = False
icon: str | None = None
name: str | None = None
unit_of_measurement: str | None = None
class Entity(ABC):
"""An abstract class for Home Assistant entities."""
@ -194,6 +210,9 @@ class Entity(ABC):
# Owning platform instance. Will be set by EntityPlatform
platform: EntityPlatform | None = None
# Entity description instance for this Entity
entity_description: EntityDescription
# If we reported if this entity was slow
_slow_reported = False
@ -223,19 +242,19 @@ class Entity(ABC):
_attr_assumed_state: bool = False
_attr_available: bool = True
_attr_context_recent_time: timedelta = timedelta(seconds=5)
_attr_device_class: str | None = None
_attr_device_class: str | None
_attr_device_info: DeviceInfo | None = None
_attr_entity_picture: str | None = None
_attr_entity_registry_enabled_default: bool = True
_attr_entity_registry_enabled_default: bool
_attr_extra_state_attributes: MutableMapping[str, Any] | None = None
_attr_force_update: bool = False
_attr_icon: str | None = None
_attr_name: str | None = None
_attr_force_update: bool
_attr_icon: str | None
_attr_name: str | None
_attr_should_poll: bool = True
_attr_state: StateType = STATE_UNKNOWN
_attr_supported_features: int | None = None
_attr_unique_id: str | None = None
_attr_unit_of_measurement: str | None = None
_attr_unit_of_measurement: str | None
@property
def should_poll(self) -> bool:
@ -253,7 +272,11 @@ class Entity(ABC):
@property
def name(self) -> str | None:
"""Return the name of the entity."""
if hasattr(self, "_attr_name"):
return self._attr_name
if hasattr(self, "entity_description"):
return self.entity_description.name
return None
@property
def state(self) -> StateType:
@ -309,17 +332,29 @@ class Entity(ABC):
@property
def device_class(self) -> str | None:
"""Return the class of this device, from component DEVICE_CLASSES."""
if hasattr(self, "_attr_device_class"):
return self._attr_device_class
if hasattr(self, "entity_description"):
return self.entity_description.device_class
return None
@property
def unit_of_measurement(self) -> str | None:
"""Return the unit of measurement of this entity, if any."""
if hasattr(self, "_attr_unit_of_measurement"):
return self._attr_unit_of_measurement
if hasattr(self, "entity_description"):
return self.entity_description.unit_of_measurement
return None
@property
def icon(self) -> str | None:
"""Return the icon to use in the frontend, if any."""
if hasattr(self, "_attr_icon"):
return self._attr_icon
if hasattr(self, "entity_description"):
return self.entity_description.icon
return None
@property
def entity_picture(self) -> str | None:
@ -343,7 +378,11 @@ class Entity(ABC):
If True, a state change will be triggered anytime the state property is
updated, not just when the value changes.
"""
if hasattr(self, "_attr_force_update"):
return self._attr_force_update
if hasattr(self, "entity_description"):
return self.entity_description.force_update
return False
@property
def supported_features(self) -> int | None:
@ -358,7 +397,11 @@ class Entity(ABC):
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
if hasattr(self, "_attr_entity_registry_enabled_default"):
return self._attr_entity_registry_enabled_default
if hasattr(self, "entity_description"):
return self.entity_description.entity_registry_enabled_default
return True
# DO NOT OVERWRITE
# These properties and methods are either managed by Home Assistant or they