Add SensorEntityDescription class (#53357)
This commit is contained in:
parent
88cffc86bb
commit
ee452d415d
6 changed files with 293 additions and 247 deletions
|
@ -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,
|
||||
),
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue