From eebc338c3b1eb518d23e3795e4690e1f6c466f8d Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Sun, 29 Jan 2023 11:44:23 +0100 Subject: [PATCH] Support `native_precision` in Airly integration (#86843) * Use native_precision * Refactor extra_state_attributes --- homeassistant/components/airly/sensor.py | 118 ++++++++++------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/homeassistant/components/airly/sensor.py b/homeassistant/components/airly/sensor.py index c85db155a55..a591d5f538f 100644 --- a/homeassistant/components/airly/sensor.py +++ b/homeassistant/components/airly/sensor.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass -from typing import Any, cast +from typing import Any from homeassistant.components.sensor import ( SensorDeviceClass, @@ -19,11 +19,10 @@ from homeassistant.const import ( UnitOfPressure, UnitOfTemperature, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity from . import AirlyDataUpdateCoordinator @@ -62,7 +61,7 @@ PARALLEL_UPDATES = 1 class AirlySensorEntityDescription(SensorEntityDescription): """Class describing Airly sensor entities.""" - value: Callable = round + attrs: Callable[[dict[str, Any]], dict[str, Any]] = lambda data: {} SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = ( @@ -70,12 +69,19 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = ( key=ATTR_API_CAQI, icon="mdi:air-filter", name=ATTR_API_CAQI, + native_precision=0, native_unit_of_measurement="CAQI", + attrs=lambda data: { + ATTR_LEVEL: data[ATTR_API_CAQI_LEVEL], + ATTR_ADVICE: data[ATTR_API_ADVICE], + ATTR_DESCRIPTION: data[ATTR_API_CAQI_DESCRIPTION], + }, ), AirlySensorEntityDescription( key=ATTR_API_PM1, device_class=SensorDeviceClass.PM1, name=ATTR_API_PM1, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, ), @@ -83,28 +89,39 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = ( key=ATTR_API_PM25, device_class=SensorDeviceClass.PM25, name="PM2.5", + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_PM25}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_PM25}_{SUFFIX_PERCENT}"]), + }, ), AirlySensorEntityDescription( key=ATTR_API_PM10, device_class=SensorDeviceClass.PM10, name=ATTR_API_PM10, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_PM10}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_PM10}_{SUFFIX_PERCENT}"]), + }, ), AirlySensorEntityDescription( key=ATTR_API_HUMIDITY, device_class=SensorDeviceClass.HUMIDITY, name=ATTR_API_HUMIDITY.capitalize(), + native_precision=1, native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, - value=lambda value: round(value, 1), ), AirlySensorEntityDescription( key=ATTR_API_PRESSURE, device_class=SensorDeviceClass.PRESSURE, name=ATTR_API_PRESSURE.capitalize(), + native_precision=0, native_unit_of_measurement=UnitOfPressure.HPA, state_class=SensorStateClass.MEASUREMENT, ), @@ -112,36 +129,56 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = ( key=ATTR_API_TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE, name=ATTR_API_TEMPERATURE.capitalize(), + native_precision=1, native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, - value=lambda value: round(value, 1), ), AirlySensorEntityDescription( key=ATTR_API_CO, name=ATTR_API_CO, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_CO}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_CO}_{SUFFIX_PERCENT}"]), + }, ), AirlySensorEntityDescription( key=ATTR_API_NO2, device_class=SensorDeviceClass.NITROGEN_DIOXIDE, name=ATTR_API_NO2, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_NO2}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_NO2}_{SUFFIX_PERCENT}"]), + }, ), AirlySensorEntityDescription( key=ATTR_API_SO2, device_class=SensorDeviceClass.SULPHUR_DIOXIDE, name=ATTR_API_SO2, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_SO2}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_SO2}_{SUFFIX_PERCENT}"]), + }, ), AirlySensorEntityDescription( key=ATTR_API_O3, device_class=SensorDeviceClass.OZONE, name=ATTR_API_O3, + native_precision=0, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + attrs=lambda data: { + ATTR_LIMIT: data[f"{ATTR_API_O3}_{SUFFIX_LIMIT}"], + ATTR_PERCENT: round(data[f"{ATTR_API_O3}_{SUFFIX_PERCENT}"]), + }, ), ) @@ -190,64 +227,15 @@ class AirlySensor(CoordinatorEntity[AirlyDataUpdateCoordinator], SensorEntity): self._attr_unique_id = ( f"{coordinator.latitude}-{coordinator.longitude}-{description.key}".lower() ) - self._attrs: dict[str, Any] = {} + self._attr_native_value = coordinator.data[description.key] + self._attr_extra_state_attributes = description.attrs(coordinator.data) self.entity_description = description - @property - def native_value(self) -> StateType: - """Return the state.""" - state = self.coordinator.data[self.entity_description.key] - return cast(StateType, self.entity_description.value(state)) - - @property - def extra_state_attributes(self) -> dict[str, Any]: - """Return the state attributes.""" - if self.entity_description.key == ATTR_API_CAQI: - self._attrs[ATTR_LEVEL] = self.coordinator.data[ATTR_API_CAQI_LEVEL] - self._attrs[ATTR_ADVICE] = self.coordinator.data[ATTR_API_ADVICE] - self._attrs[ATTR_DESCRIPTION] = self.coordinator.data[ - ATTR_API_CAQI_DESCRIPTION - ] - if self.entity_description.key == ATTR_API_PM25: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_PM25}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_PM25}_{SUFFIX_PERCENT}"] - ) - if self.entity_description.key == ATTR_API_PM10: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_PM10}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_PM10}_{SUFFIX_PERCENT}"] - ) - if self.entity_description.key == ATTR_API_CO: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_CO}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_CO}_{SUFFIX_PERCENT}"] - ) - if self.entity_description.key == ATTR_API_NO2: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_NO2}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_NO2}_{SUFFIX_PERCENT}"] - ) - if self.entity_description.key == ATTR_API_SO2: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_SO2}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_SO2}_{SUFFIX_PERCENT}"] - ) - if self.entity_description.key == ATTR_API_O3: - self._attrs[ATTR_LIMIT] = self.coordinator.data[ - f"{ATTR_API_O3}_{SUFFIX_LIMIT}" - ] - self._attrs[ATTR_PERCENT] = round( - self.coordinator.data[f"{ATTR_API_O3}_{SUFFIX_PERCENT}"] - ) - return self._attrs + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self._attr_native_value = self.coordinator.data[self.entity_description.key] + self._attr_extra_state_attributes = self.entity_description.attrs( + self.coordinator.data + ) + self.async_write_ha_state()