diff --git a/homeassistant/components/airvisual_pro/__init__.py b/homeassistant/components/airvisual_pro/__init__.py index b745dea1d94..b146651b6e6 100644 --- a/homeassistant/components/airvisual_pro/__init__.py +++ b/homeassistant/components/airvisual_pro/__init__.py @@ -21,7 +21,7 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, Platform, ) -from homeassistant.core import Event, HomeAssistant, callback +from homeassistant.core import Event, HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers.entity import DeviceInfo, EntityDescription from homeassistant.helpers.update_coordinator import ( @@ -136,19 +136,3 @@ class AirVisualProEntity(CoordinatorEntity): hw_version=self.coordinator.data["status"]["system_version"], sw_version=self.coordinator.data["status"]["app_version"], ) - - @callback - def _async_update_from_latest_data(self) -> None: - """Update the entity's underlying data.""" - raise NotImplementedError - - @callback - def _handle_coordinator_update(self) -> None: - """Respond to a DataUpdateCoordinator update.""" - self._async_update_from_latest_data() - self.async_write_ha_state() - - async def async_added_to_hass(self) -> None: - """Handle entity which will be added.""" - await super().async_added_to_hass() - self._async_update_from_latest_data() diff --git a/homeassistant/components/airvisual_pro/sensor.py b/homeassistant/components/airvisual_pro/sensor.py index 9fb15c7ac74..11c315be45c 100644 --- a/homeassistant/components/airvisual_pro/sensor.py +++ b/homeassistant/components/airvisual_pro/sensor.py @@ -1,6 +1,8 @@ """Support for AirVisual Pro sensors.""" from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass from typing import Any from homeassistant.components.sensor import ( @@ -23,78 +25,93 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import AirVisualProData, AirVisualProEntity from .const import DOMAIN -SENSOR_KIND_AQI = "air_quality_index" -SENSOR_KIND_BATTERY_LEVEL = "battery_level" -SENSOR_KIND_CO2 = "carbon_dioxide" -SENSOR_KIND_HUMIDITY = "humidity" -SENSOR_KIND_PM_0_1 = "particulate_matter_0_1" -SENSOR_KIND_PM_1_0 = "particulate_matter_1_0" -SENSOR_KIND_PM_2_5 = "particulate_matter_2_5" -SENSOR_KIND_SENSOR_LIFE = "sensor_life" -SENSOR_KIND_TEMPERATURE = "temperature" -SENSOR_KIND_VOC = "voc" + +@dataclass +class AirVisualProMeasurementKeyMixin: + """Define an entity description mixin to include a measurement key.""" + + value_fn: Callable[[dict[str, Any], dict[str, Any], dict[str, Any]], float | int] + + +@dataclass +class AirVisualProMeasurementDescription( + SensorEntityDescription, AirVisualProMeasurementKeyMixin +): + """Describe an AirVisual Pro sensor.""" + SENSOR_DESCRIPTIONS = ( - SensorEntityDescription( - key=SENSOR_KIND_AQI, + AirVisualProMeasurementDescription( + key="air_quality_index", name="Air quality index", device_class=SensorDeviceClass.AQI, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements[ + async_get_aqi_locale(settings) + ], ), - SensorEntityDescription( - key=SENSOR_KIND_BATTERY_LEVEL, + AirVisualProMeasurementDescription( + key="battery_level", name="Battery", device_class=SensorDeviceClass.BATTERY, entity_category=EntityCategory.DIAGNOSTIC, native_unit_of_measurement=PERCENTAGE, + value_fn=lambda settings, status, measurements: status["battery"], ), - SensorEntityDescription( - key=SENSOR_KIND_CO2, + AirVisualProMeasurementDescription( + key="carbon_dioxide", name="C02", device_class=SensorDeviceClass.CO2, native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["co2"], ), - SensorEntityDescription( - key=SENSOR_KIND_HUMIDITY, + AirVisualProMeasurementDescription( + key="humidity", name="Humidity", device_class=SensorDeviceClass.HUMIDITY, native_unit_of_measurement=PERCENTAGE, + value_fn=lambda settings, status, measurements: measurements["humidity"], ), - SensorEntityDescription( - key=SENSOR_KIND_PM_0_1, + AirVisualProMeasurementDescription( + key="particulate_matter_0_1", name="PM 0.1", device_class=SensorDeviceClass.PM1, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["pm0_1"], ), - SensorEntityDescription( - key=SENSOR_KIND_PM_1_0, + AirVisualProMeasurementDescription( + key="particulate_matter_1_0", name="PM 1.0", device_class=SensorDeviceClass.PM10, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["pm1_0"], ), - SensorEntityDescription( - key=SENSOR_KIND_PM_2_5, + AirVisualProMeasurementDescription( + key="particulate_matter_2_5", name="PM 2.5", device_class=SensorDeviceClass.PM25, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["pm2_5"], ), - SensorEntityDescription( - key=SENSOR_KIND_TEMPERATURE, + AirVisualProMeasurementDescription( + key="temperature", name="Temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["temperature_C"], ), - SensorEntityDescription( - key=SENSOR_KIND_VOC, + AirVisualProMeasurementDescription( + key="voc", name="VOC", device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda settings, status, measurements: measurements["voc"], ), ) @@ -124,40 +141,13 @@ class AirVisualProSensor(AirVisualProEntity, SensorEntity): _attr_has_entity_name = True - MEASUREMENTS_KEY_TO_VALUE = { - SENSOR_KIND_CO2: "co2", - SENSOR_KIND_HUMIDITY: "humidity", - SENSOR_KIND_PM_0_1: "pm0_1", - SENSOR_KIND_PM_1_0: "pm1_0", - SENSOR_KIND_PM_2_5: "pm2_5", - SENSOR_KIND_TEMPERATURE: "temperature_C", - SENSOR_KIND_VOC: "voc", - } + entity_description: AirVisualProMeasurementDescription @property - def measurements(self) -> dict[str, Any]: - """Define measurements data.""" - return self.coordinator.data["measurements"] - - @property - def settings(self) -> dict[str, Any]: - """Define settings data.""" - return self.coordinator.data["settings"] - - @property - def status(self) -> dict[str, Any]: - """Define status data.""" - return self.coordinator.data["status"] - - @callback - def _async_update_from_latest_data(self) -> None: - """Update the entity from the latest data.""" - if self.entity_description.key == SENSOR_KIND_AQI: - locale = async_get_aqi_locale(self.settings) - self._attr_native_value = self.measurements[locale] - elif self.entity_description.key == SENSOR_KIND_BATTERY_LEVEL: - self._attr_native_value = self.status["battery"] - else: - self._attr_native_value = self.measurements[ - self.MEASUREMENTS_KEY_TO_VALUE[self.entity_description.key] - ] + def native_value(self) -> float | int: + """Return the sensor value.""" + return self.entity_description.value_fn( + self.coordinator.data["settings"], + self.coordinator.data["status"], + self.coordinator.data["measurements"], + )