Use SensorEntityDescription in GIOS integration (#53581)

This commit is contained in:
Maciej Bieniek 2021-07-28 08:21:00 +02:00 committed by GitHub
parent b7f1f2330a
commit 9b67605b8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 77 deletions

View File

@ -4,10 +4,10 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Final from typing import Final
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT
from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
from .model import SensorDescription from .model import GiosSensorEntityDescription
ATTRIBUTION: Final = "Data provided by GIOŚ" ATTRIBUTION: Final = "Data provided by GIOŚ"
@ -22,9 +22,6 @@ API_TIMEOUT: Final = 30
ATTR_INDEX: Final = "index" ATTR_INDEX: Final = "index"
ATTR_STATION: Final = "station" ATTR_STATION: Final = "station"
ATTR_UNIT: Final = "unit"
ATTR_VALUE: Final = "value"
ATTR_STATION_NAME: Final = "station_name"
ATTR_C6H6: Final = "c6h6" ATTR_C6H6: Final = "c6h6"
ATTR_CO: Final = "co" ATTR_CO: Final = "co"
@ -35,41 +32,52 @@ ATTR_PM25: Final = "pm25"
ATTR_SO2: Final = "so2" ATTR_SO2: Final = "so2"
ATTR_AQI: Final = "aqi" ATTR_AQI: Final = "aqi"
SENSOR_TYPES: Final[dict[str, SensorDescription]] = { SENSOR_TYPES: Final[tuple[GiosSensorEntityDescription, ...]] = (
ATTR_AQI: {}, GiosSensorEntityDescription(
ATTR_C6H6: { key=ATTR_AQI,
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, name="AQI",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, value=None,
ATTR_VALUE: round, ),
}, GiosSensorEntityDescription(
ATTR_CO: { key=ATTR_C6H6,
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, name="C6H6",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_VALUE: round, state_class=STATE_CLASS_MEASUREMENT,
}, ),
ATTR_NO2: { GiosSensorEntityDescription(
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, key=ATTR_CO,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, name="CO",
ATTR_VALUE: round, unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
}, state_class=STATE_CLASS_MEASUREMENT,
ATTR_O3: { ),
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, GiosSensorEntityDescription(
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, key=ATTR_NO2,
ATTR_VALUE: round, name="NO2",
}, unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_PM10: { state_class=STATE_CLASS_MEASUREMENT,
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ),
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, GiosSensorEntityDescription(
ATTR_VALUE: round, key=ATTR_O3,
}, name="O3",
ATTR_PM25: { unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=STATE_CLASS_MEASUREMENT,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, ),
ATTR_VALUE: round, GiosSensorEntityDescription(
}, key=ATTR_PM10,
ATTR_SO2: { name="PM10",
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
ATTR_VALUE: round, ),
}, GiosSensorEntityDescription(
} key=ATTR_PM25,
name="PM2.5",
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
GiosSensorEntityDescription(
key=ATTR_SO2,
name="SO2",
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
)

View File

@ -1,12 +1,14 @@
"""Type definitions for GIOS integration.""" """Type definitions for GIOS integration."""
from __future__ import annotations from __future__ import annotations
from typing import Callable, TypedDict from dataclasses import dataclass
from typing import Callable
from homeassistant.components.sensor import SensorEntityDescription
class SensorDescription(TypedDict, total=False): @dataclass
"""Sensor description class.""" class GiosSensorEntityDescription(SensorEntityDescription):
"""Class describing GIOS sensor entities."""
unit: str value: Callable | None = round
state_class: str
value: Callable

View File

@ -4,11 +4,7 @@ from __future__ import annotations
import logging import logging
from typing import Any, cast from typing import Any, cast
from homeassistant.components.sensor import ( from homeassistant.components.sensor import DOMAIN as PLATFORM, SensorEntity
ATTR_STATE_CLASS,
DOMAIN as PLATFORM,
SensorEntity,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_NAME, CONF_NAME from homeassistant.const import ATTR_ATTRIBUTION, ATTR_NAME, CONF_NAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -23,14 +19,13 @@ from .const import (
ATTR_INDEX, ATTR_INDEX,
ATTR_PM25, ATTR_PM25,
ATTR_STATION, ATTR_STATION,
ATTR_UNIT,
ATTR_VALUE,
ATTRIBUTION, ATTRIBUTION,
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
MANUFACTURER, MANUFACTURER,
SENSOR_TYPES, SENSOR_TYPES,
) )
from .model import GiosSensorEntityDescription
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -61,13 +56,13 @@ async def async_setup_entry(
sensors: list[GiosSensor | GiosAqiSensor] = [] sensors: list[GiosSensor | GiosAqiSensor] = []
for sensor in SENSOR_TYPES: for description in SENSOR_TYPES:
if getattr(coordinator.data, sensor) is None: if getattr(coordinator.data, description.key) is None:
continue continue
if sensor == ATTR_AQI: if description.key == ATTR_AQI:
sensors.append(GiosAqiSensor(name, sensor, coordinator)) sensors.append(GiosAqiSensor(name, coordinator, description))
else: else:
sensors.append(GiosSensor(name, sensor, coordinator)) sensors.append(GiosSensor(name, coordinator, description))
async_add_entities(sensors) async_add_entities(sensors)
@ -75,13 +70,16 @@ class GiosSensor(CoordinatorEntity, SensorEntity):
"""Define an GIOS sensor.""" """Define an GIOS sensor."""
coordinator: GiosDataUpdateCoordinator coordinator: GiosDataUpdateCoordinator
entity_description: GiosSensorEntityDescription
def __init__( def __init__(
self, name: str, sensor_type: str, coordinator: GiosDataUpdateCoordinator self,
name: str,
coordinator: GiosDataUpdateCoordinator,
description: GiosSensorEntityDescription,
) -> None: ) -> None:
"""Initialize.""" """Initialize."""
super().__init__(coordinator) super().__init__(coordinator)
self._description = SENSOR_TYPES[sensor_type]
self._attr_device_info = { self._attr_device_info = {
"identifiers": {(DOMAIN, str(coordinator.gios.station_id))}, "identifiers": {(DOMAIN, str(coordinator.gios.station_id))},
"name": DEFAULT_NAME, "name": DEFAULT_NAME,
@ -89,33 +87,31 @@ class GiosSensor(CoordinatorEntity, SensorEntity):
"entry_type": "service", "entry_type": "service",
} }
self._attr_icon = "mdi:blur" self._attr_icon = "mdi:blur"
if sensor_type == ATTR_PM25: self._attr_name = f"{name} {description.name}"
self._attr_name = f"{name} PM2.5" self._attr_unique_id = f"{coordinator.gios.station_id}-{description.key}"
else:
self._attr_name = f"{name} {sensor_type.upper()}"
self._attr_state_class = self._description.get(ATTR_STATE_CLASS)
self._attr_unique_id = f"{coordinator.gios.station_id}-{sensor_type}"
self._attr_unit_of_measurement = self._description.get(ATTR_UNIT)
self._sensor_type = sensor_type
self._attrs: dict[str, Any] = { self._attrs: dict[str, Any] = {
ATTR_ATTRIBUTION: ATTRIBUTION, ATTR_ATTRIBUTION: ATTRIBUTION,
ATTR_STATION: self.coordinator.gios.station_name, ATTR_STATION: self.coordinator.gios.station_name,
} }
self.entity_description = description
@property @property
def extra_state_attributes(self) -> dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes.""" """Return the state attributes."""
self._attrs[ATTR_NAME] = getattr(self.coordinator.data, self._sensor_type).name self._attrs[ATTR_NAME] = getattr(
self.coordinator.data, self.entity_description.key
).name
self._attrs[ATTR_INDEX] = getattr( self._attrs[ATTR_INDEX] = getattr(
self.coordinator.data, self._sensor_type self.coordinator.data, self.entity_description.key
).index ).index
return self._attrs return self._attrs
@property @property
def state(self) -> StateType: def state(self) -> StateType:
"""Return the state.""" """Return the state."""
state = getattr(self.coordinator.data, self._sensor_type).value state = getattr(self.coordinator.data, self.entity_description.key).value
return cast(StateType, self._description[ATTR_VALUE](state)) assert self.entity_description.value is not None
return cast(StateType, self.entity_description.value(state))
class GiosAqiSensor(GiosSensor): class GiosAqiSensor(GiosSensor):
@ -124,10 +120,14 @@ class GiosAqiSensor(GiosSensor):
@property @property
def state(self) -> StateType: def state(self) -> StateType:
"""Return the state.""" """Return the state."""
return cast(StateType, getattr(self.coordinator.data, self._sensor_type).value) return cast(
StateType, getattr(self.coordinator.data, self.entity_description.key).value
)
@property @property
def available(self) -> bool: def available(self) -> bool:
"""Return if entity is available.""" """Return if entity is available."""
available = super().available available = super().available
return available and bool(getattr(self.coordinator.data, self._sensor_type)) return available and bool(
getattr(self.coordinator.data, self.entity_description.key)
)