From d6dc738a124a7255dc07b3e2aca81950076f63e8 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Tue, 20 Jun 2023 22:24:51 +0200 Subject: [PATCH] Add entity translations for AirNow (#94175) * Add entity translations for AirNow * Restore keys * Restore keys --- homeassistant/components/airnow/const.py | 2 - homeassistant/components/airnow/sensor.py | 86 ++++++++++++++------ homeassistant/components/airnow/strings.json | 13 +++ 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/airnow/const.py b/homeassistant/components/airnow/const.py index 67a9289efc5..34b1f4392bc 100644 --- a/homeassistant/components/airnow/const.py +++ b/homeassistant/components/airnow/const.py @@ -17,5 +17,3 @@ ATTR_API_STATION_LATITUDE = "Latitude" ATTR_API_STATION_LONGITUDE = "Longitude" DEFAULT_NAME = "AirNow" DOMAIN = "airnow" -SENSOR_AQI_ATTR_DESCR = "description" -SENSOR_AQI_ATTR_LEVEL = "level" diff --git a/homeassistant/components/airnow/sensor.py b/homeassistant/components/airnow/sensor.py index decec74ee47..31bb3d793a1 100644 --- a/homeassistant/components/airnow/sensor.py +++ b/homeassistant/components/airnow/sensor.py @@ -1,6 +1,10 @@ """Support for the AirNow sensor service.""" from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass +from typing import Any + from homeassistant.components.sensor import ( SensorEntity, SensorEntityDescription, @@ -12,7 +16,10 @@ from homeassistant.const import ( CONCENTRATION_PARTS_PER_MILLION, ) from homeassistant.core import HomeAssistant +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 AirNowDataUpdateCoordinator @@ -22,36 +29,61 @@ from .const import ( ATTR_API_AQI_LEVEL, ATTR_API_O3, ATTR_API_PM25, + DEFAULT_NAME, DOMAIN, - SENSOR_AQI_ATTR_DESCR, - SENSOR_AQI_ATTR_LEVEL, ) ATTRIBUTION = "Data provided by AirNow" PARALLEL_UPDATES = 1 -SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( - SensorEntityDescription( +ATTR_DESCR = "description" +ATTR_LEVEL = "level" + + +@dataclass +class AirNowEntityDescriptionMixin: + """Mixin for required keys.""" + + value_fn: Callable[[Any], StateType] + extra_state_attributes_fn: Callable[[Any], dict[str, str]] | None + + +@dataclass +class AirNowEntityDescription(SensorEntityDescription, AirNowEntityDescriptionMixin): + """Describes Airnow sensor entity.""" + + +SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = ( + AirNowEntityDescription( key=ATTR_API_AQI, + translation_key="aqi", icon="mdi:blur", - name=ATTR_API_AQI, native_unit_of_measurement="aqi", state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda data: data.get(ATTR_API_AQI), + extra_state_attributes_fn=lambda data: { + ATTR_DESCR: data[ATTR_API_AQI_DESCRIPTION], + ATTR_LEVEL: data[ATTR_API_AQI_LEVEL], + }, ), - SensorEntityDescription( + AirNowEntityDescription( key=ATTR_API_PM25, + translation_key="pm25", icon="mdi:blur", - name=ATTR_API_PM25, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda data: data.get(ATTR_API_PM25), + extra_state_attributes_fn=None, ), - SensorEntityDescription( + AirNowEntityDescription( key=ATTR_API_O3, + translation_key="o3", icon="mdi:blur", - name=ATTR_API_O3, native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda data: data.get(ATTR_API_O3), + extra_state_attributes_fn=None, ), ) @@ -73,38 +105,38 @@ class AirNowSensor(CoordinatorEntity[AirNowDataUpdateCoordinator], SensorEntity) """Define an AirNow sensor.""" _attr_attribution = ATTRIBUTION + _attr_has_entity_name = True + + entity_description: AirNowEntityDescription def __init__( self, coordinator: AirNowDataUpdateCoordinator, - description: SensorEntityDescription, + description: AirNowEntityDescription, ) -> None: """Initialize.""" super().__init__(coordinator) self.entity_description = description - self._state = None - self._attrs: dict[str, str] = {} - self._attr_name = f"AirNow {description.name}" self._attr_unique_id = ( f"{coordinator.latitude}-{coordinator.longitude}-{description.key.lower()}" ) + self._attr_device_info = DeviceInfo( + entry_type=DeviceEntryType.SERVICE, + identifiers={(DOMAIN, self._attr_unique_id)}, + manufacturer=DEFAULT_NAME, + name=DEFAULT_NAME, + ) @property - def native_value(self): + def native_value(self) -> StateType: """Return the state.""" - self._state = self.coordinator.data.get(self.entity_description.key) - - return self._state + return self.entity_description.value_fn(self.coordinator.data) @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, str] | None: """Return the state attributes.""" - if self.entity_description.key == ATTR_API_AQI: - self._attrs[SENSOR_AQI_ATTR_DESCR] = self.coordinator.data[ - ATTR_API_AQI_DESCRIPTION - ] - self._attrs[SENSOR_AQI_ATTR_LEVEL] = self.coordinator.data[ - ATTR_API_AQI_LEVEL - ] - - return self._attrs + if self.entity_description.extra_state_attributes_fn: + return self.entity_description.extra_state_attributes_fn( + self.coordinator.data + ) + return None diff --git a/homeassistant/components/airnow/strings.json b/homeassistant/components/airnow/strings.json index 0e86c4531dc..ff1ba6481c8 100644 --- a/homeassistant/components/airnow/strings.json +++ b/homeassistant/components/airnow/strings.json @@ -20,5 +20,18 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "entity": { + "sensor": { + "aqi": { + "name": "[%key:component::sensor::entity_component::aqi::name%]" + }, + "pm25": { + "name": "[%key:component::sensor::entity_component::pm25::name%]" + }, + "o3": { + "name": "[%key:component::sensor::entity_component::ozone::name%]" + } + } } }