From 648e6497181338a8ee4d846ce3b655692a52325a Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Wed, 28 Jul 2021 10:26:14 +0200 Subject: [PATCH] Use SensorEntityDescription in AccuWeather integration (#53604) * Use SensorEntityDescription * Add missing type for entity_description * Use tuples instead of lists * Suggested change --- homeassistant/components/accuweather/const.py | 541 +++++++++--------- homeassistant/components/accuweather/model.py | 18 +- .../components/accuweather/sensor.py | 110 ++-- 3 files changed, 328 insertions(+), 341 deletions(-) diff --git a/homeassistant/components/accuweather/const.py b/homeassistant/components/accuweather/const.py index aea394446ad..5802695afef 100644 --- a/homeassistant/components/accuweather/const.py +++ b/homeassistant/components/accuweather/const.py @@ -3,7 +3,7 @@ from __future__ import annotations 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.components.weather import ( ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLOUDY, @@ -21,8 +21,6 @@ from homeassistant.components.weather import ( ATTR_CONDITION_WINDY, ) from homeassistant.const import ( - ATTR_DEVICE_CLASS, - ATTR_ICON, CONCENTRATION_PARTS_PER_CUBIC_METER, DEVICE_CLASS_TEMPERATURE, LENGTH_FEET, @@ -38,16 +36,12 @@ from homeassistant.const import ( UV_INDEX, ) -from .model import SensorDescription +from .model import AccuWeatherSensorDescription API_IMPERIAL: Final = "Imperial" API_METRIC: Final = "Metric" ATTRIBUTION: Final = "Data provided by AccuWeather" -ATTR_ENABLED: Final = "enabled" ATTR_FORECAST: Final = "forecast" -ATTR_LABEL: Final = "label" -ATTR_UNIT_IMPERIAL: Final = "unit_imperial" -ATTR_UNIT_METRIC: Final = "unit_metric" CONF_FORECAST: Final = "forecast" DOMAIN: Final = "accuweather" MANUFACTURER: Final = "AccuWeather, Inc." @@ -71,276 +65,263 @@ CONDITION_CLASSES: Final[dict[str, list[int]]] = { ATTR_CONDITION_WINDY: [32], } -FORECAST_SENSOR_TYPES: Final[dict[str, SensorDescription]] = { - "CloudCoverDay": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-cloudy", - ATTR_LABEL: "Cloud Cover Day", - ATTR_UNIT_METRIC: PERCENTAGE, - ATTR_UNIT_IMPERIAL: PERCENTAGE, - ATTR_ENABLED: False, - }, - "CloudCoverNight": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-cloudy", - ATTR_LABEL: "Cloud Cover Night", - ATTR_UNIT_METRIC: PERCENTAGE, - ATTR_UNIT_IMPERIAL: PERCENTAGE, - ATTR_ENABLED: False, - }, - "Grass": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:grass", - ATTR_LABEL: "Grass Pollen", - ATTR_UNIT_METRIC: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_UNIT_IMPERIAL: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_ENABLED: False, - }, - "HoursOfSun": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-partly-cloudy", - ATTR_LABEL: "Hours Of Sun", - ATTR_UNIT_METRIC: TIME_HOURS, - ATTR_UNIT_IMPERIAL: TIME_HOURS, - ATTR_ENABLED: True, - }, - "Mold": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:blur", - ATTR_LABEL: "Mold Pollen", - ATTR_UNIT_METRIC: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_UNIT_IMPERIAL: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_ENABLED: False, - }, - "Ozone": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:vector-triangle", - ATTR_LABEL: "Ozone", - ATTR_UNIT_METRIC: None, - ATTR_UNIT_IMPERIAL: None, - ATTR_ENABLED: False, - }, - "Ragweed": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:sprout", - ATTR_LABEL: "Ragweed Pollen", - ATTR_UNIT_METRIC: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_UNIT_IMPERIAL: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_ENABLED: False, - }, - "RealFeelTemperatureMax": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature Max", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: True, - }, - "RealFeelTemperatureMin": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature Min", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: True, - }, - "RealFeelTemperatureShadeMax": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature Shade Max", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - }, - "RealFeelTemperatureShadeMin": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature Shade Min", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - }, - "ThunderstormProbabilityDay": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-lightning", - ATTR_LABEL: "Thunderstorm Probability Day", - ATTR_UNIT_METRIC: PERCENTAGE, - ATTR_UNIT_IMPERIAL: PERCENTAGE, - ATTR_ENABLED: True, - }, - "ThunderstormProbabilityNight": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-lightning", - ATTR_LABEL: "Thunderstorm Probability Night", - ATTR_UNIT_METRIC: PERCENTAGE, - ATTR_UNIT_IMPERIAL: PERCENTAGE, - ATTR_ENABLED: True, - }, - "Tree": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:tree-outline", - ATTR_LABEL: "Tree Pollen", - ATTR_UNIT_METRIC: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_UNIT_IMPERIAL: CONCENTRATION_PARTS_PER_CUBIC_METER, - ATTR_ENABLED: False, - }, - "UVIndex": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-sunny", - ATTR_LABEL: "UV Index", - ATTR_UNIT_METRIC: UV_INDEX, - ATTR_UNIT_IMPERIAL: UV_INDEX, - ATTR_ENABLED: True, - }, - "WindGustDay": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind Gust Day", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: False, - }, - "WindGustNight": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind Gust Night", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: False, - }, - "WindDay": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind Day", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: True, - }, - "WindNight": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind Night", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: True, - }, -} +FORECAST_SENSOR_TYPES: Final[tuple[AccuWeatherSensorDescription, ...]] = ( + AccuWeatherSensorDescription( + key="CloudCoverDay", + icon="mdi:weather-cloudy", + name="Cloud Cover Day", + unit_metric=PERCENTAGE, + unit_imperial=PERCENTAGE, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="CloudCoverNight", + icon="mdi:weather-cloudy", + name="Cloud Cover Night", + unit_metric=PERCENTAGE, + unit_imperial=PERCENTAGE, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="Grass", + icon="mdi:grass", + name="Grass Pollen", + unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER, + unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="HoursOfSun", + icon="mdi:weather-partly-cloudy", + name="Hours Of Sun", + unit_metric=TIME_HOURS, + unit_imperial=TIME_HOURS, + ), + AccuWeatherSensorDescription( + key="Mold", + icon="mdi:blur", + name="Mold Pollen", + unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER, + unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="Ozone", + icon="mdi:vector-triangle", + name="Ozone", + unit_metric=None, + unit_imperial=None, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="Ragweed", + icon="mdi:sprout", + name="Ragweed Pollen", + unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER, + unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperatureMax", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature Max", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperatureMin", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature Min", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperatureShadeMax", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature Shade Max", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperatureShadeMin", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature Shade Min", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="ThunderstormProbabilityDay", + icon="mdi:weather-lightning", + name="Thunderstorm Probability Day", + unit_metric=PERCENTAGE, + unit_imperial=PERCENTAGE, + ), + AccuWeatherSensorDescription( + key="ThunderstormProbabilityNight", + icon="mdi:weather-lightning", + name="Thunderstorm Probability Night", + unit_metric=PERCENTAGE, + unit_imperial=PERCENTAGE, + ), + AccuWeatherSensorDescription( + key="Tree", + icon="mdi:tree-outline", + name="Tree Pollen", + unit_metric=CONCENTRATION_PARTS_PER_CUBIC_METER, + unit_imperial=CONCENTRATION_PARTS_PER_CUBIC_METER, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="UVIndex", + icon="mdi:weather-sunny", + name="UV Index", + unit_metric=UV_INDEX, + unit_imperial=UV_INDEX, + ), + AccuWeatherSensorDescription( + key="WindGustDay", + icon="mdi:weather-windy", + name="Wind Gust Day", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="WindGustNight", + icon="mdi:weather-windy", + name="Wind Gust Night", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + entity_registry_enabled_default=False, + ), + AccuWeatherSensorDescription( + key="WindDay", + icon="mdi:weather-windy", + name="Wind Day", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + ), + AccuWeatherSensorDescription( + key="WindNight", + icon="mdi:weather-windy", + name="Wind Night", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + ), +) -SENSOR_TYPES: Final[dict[str, SensorDescription]] = { - "ApparentTemperature": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "Apparent Temperature", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "Ceiling": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-fog", - ATTR_LABEL: "Cloud Ceiling", - ATTR_UNIT_METRIC: LENGTH_METERS, - ATTR_UNIT_IMPERIAL: LENGTH_FEET, - ATTR_ENABLED: True, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "CloudCover": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-cloudy", - ATTR_LABEL: "Cloud Cover", - ATTR_UNIT_METRIC: PERCENTAGE, - ATTR_UNIT_IMPERIAL: PERCENTAGE, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "DewPoint": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "Dew Point", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "RealFeelTemperature": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: True, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "RealFeelTemperatureShade": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "RealFeel Temperature Shade", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "Precipitation": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-rainy", - ATTR_LABEL: "Precipitation", - ATTR_UNIT_METRIC: LENGTH_MILLIMETERS, - ATTR_UNIT_IMPERIAL: LENGTH_INCHES, - ATTR_ENABLED: True, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "PressureTendency": { - ATTR_DEVICE_CLASS: "accuweather__pressure_tendency", - ATTR_ICON: "mdi:gauge", - ATTR_LABEL: "Pressure Tendency", - ATTR_UNIT_METRIC: None, - ATTR_UNIT_IMPERIAL: None, - ATTR_ENABLED: True, - }, - "UVIndex": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-sunny", - ATTR_LABEL: "UV Index", - ATTR_UNIT_METRIC: UV_INDEX, - ATTR_UNIT_IMPERIAL: UV_INDEX, - ATTR_ENABLED: True, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "WetBulbTemperature": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "Wet Bulb Temperature", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "WindChillTemperature": { - ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, - ATTR_ICON: None, - ATTR_LABEL: "Wind Chill Temperature", - ATTR_UNIT_METRIC: TEMP_CELSIUS, - ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "Wind": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: True, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, - "WindGust": { - ATTR_DEVICE_CLASS: None, - ATTR_ICON: "mdi:weather-windy", - ATTR_LABEL: "Wind Gust", - ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, - ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, - ATTR_ENABLED: False, - ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, - }, -} +SENSOR_TYPES: Final[tuple[AccuWeatherSensorDescription, ...]] = ( + AccuWeatherSensorDescription( + key="ApparentTemperature", + device_class=DEVICE_CLASS_TEMPERATURE, + name="Apparent Temperature", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="Ceiling", + icon="mdi:weather-fog", + name="Cloud Ceiling", + unit_metric=LENGTH_METERS, + unit_imperial=LENGTH_FEET, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="CloudCover", + icon="mdi:weather-cloudy", + name="Cloud Cover", + unit_metric=PERCENTAGE, + unit_imperial=PERCENTAGE, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="DewPoint", + device_class=DEVICE_CLASS_TEMPERATURE, + name="Dew Point", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperature", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="RealFeelTemperatureShade", + device_class=DEVICE_CLASS_TEMPERATURE, + name="RealFeel Temperature Shade", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="Precipitation", + icon="mdi:weather-rainy", + name="Precipitation", + unit_metric=LENGTH_MILLIMETERS, + unit_imperial=LENGTH_INCHES, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="PressureTendency", + device_class="accuweather__pressure_tendency", + icon="mdi:gauge", + name="Pressure Tendency", + unit_metric=None, + unit_imperial=None, + ), + AccuWeatherSensorDescription( + key="UVIndex", + icon="mdi:weather-sunny", + name="UV Index", + unit_metric=UV_INDEX, + unit_imperial=UV_INDEX, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="WetBulbTemperature", + device_class=DEVICE_CLASS_TEMPERATURE, + name="Wet Bulb Temperature", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="WindChillTemperature", + device_class=DEVICE_CLASS_TEMPERATURE, + name="Wind Chill Temperature", + unit_metric=TEMP_CELSIUS, + unit_imperial=TEMP_FAHRENHEIT, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="Wind", + icon="mdi:weather-windy", + name="Wind", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + state_class=STATE_CLASS_MEASUREMENT, + ), + AccuWeatherSensorDescription( + key="WindGust", + icon="mdi:weather-windy", + name="Wind Gust", + unit_metric=SPEED_KILOMETERS_PER_HOUR, + unit_imperial=SPEED_MILES_PER_HOUR, + entity_registry_enabled_default=False, + state_class=STATE_CLASS_MEASUREMENT, + ), +) diff --git a/homeassistant/components/accuweather/model.py b/homeassistant/components/accuweather/model.py index 2127629728b..e74a6d46057 100644 --- a/homeassistant/components/accuweather/model.py +++ b/homeassistant/components/accuweather/model.py @@ -1,16 +1,14 @@ """Type definitions for AccuWeather integration.""" from __future__ import annotations -from typing import TypedDict +from dataclasses import dataclass + +from homeassistant.components.sensor import SensorEntityDescription -class SensorDescription(TypedDict, total=False): - """Sensor description class.""" +@dataclass +class AccuWeatherSensorDescription(SensorEntityDescription): + """Class describing AccuWeather sensor entities.""" - device_class: str | None - icon: str | None - label: str - unit_metric: str | None - unit_imperial: str | None - enabled: bool - state_class: str | None + unit_metric: str | None = None + unit_imperial: str | None = None diff --git a/homeassistant/components/accuweather/sensor.py b/homeassistant/components/accuweather/sensor.py index 3a774afe341..4a5af6054e1 100644 --- a/homeassistant/components/accuweather/sensor.py +++ b/homeassistant/components/accuweather/sensor.py @@ -3,15 +3,9 @@ from __future__ import annotations from typing import Any, cast -from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorEntity +from homeassistant.components.sensor import SensorEntity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ( - ATTR_ATTRIBUTION, - ATTR_DEVICE_CLASS, - ATTR_ICON, - CONF_NAME, - DEVICE_CLASS_TEMPERATURE, -) +from homeassistant.const import ATTR_ATTRIBUTION, CONF_NAME, DEVICE_CLASS_TEMPERATURE from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType @@ -21,11 +15,7 @@ from . import AccuWeatherDataUpdateCoordinator from .const import ( API_IMPERIAL, API_METRIC, - ATTR_ENABLED, ATTR_FORECAST, - ATTR_LABEL, - ATTR_UNIT_IMPERIAL, - ATTR_UNIT_METRIC, ATTRIBUTION, DOMAIN, FORECAST_SENSOR_TYPES, @@ -34,6 +24,7 @@ from .const import ( NAME, SENSOR_TYPES, ) +from .model import AccuWeatherSensorDescription PARALLEL_UPDATES = 1 @@ -47,17 +38,19 @@ async def async_setup_entry( coordinator: AccuWeatherDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] sensors: list[AccuWeatherSensor] = [] - for sensor in SENSOR_TYPES: - sensors.append(AccuWeatherSensor(name, sensor, coordinator)) + for description in SENSOR_TYPES: + sensors.append(AccuWeatherSensor(name, coordinator, description)) if coordinator.forecast: - for sensor in FORECAST_SENSOR_TYPES: + for description in FORECAST_SENSOR_TYPES: for day in range(MAX_FORECAST_DAYS + 1): # Some air quality/allergy sensors are only available for certain # locations. - if sensor in coordinator.data[ATTR_FORECAST][0]: + if description.key in coordinator.data[ATTR_FORECAST][0]: sensors.append( - AccuWeatherSensor(name, sensor, coordinator, forecast_day=day) + AccuWeatherSensor( + name, coordinator, description, forecast_day=day + ) ) async_add_entities(sensors) @@ -67,69 +60,72 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity): """Define an AccuWeather entity.""" coordinator: AccuWeatherDataUpdateCoordinator + entity_description: AccuWeatherSensorDescription def __init__( self, name: str, - kind: str, coordinator: AccuWeatherDataUpdateCoordinator, + description: AccuWeatherSensorDescription, forecast_day: int | None = None, ) -> None: """Initialize.""" super().__init__(coordinator) - self._sensor_data = _get_sensor_data(coordinator.data, forecast_day, kind) - if forecast_day is None: - self._description = SENSOR_TYPES[kind] - else: - self._description = FORECAST_SENSOR_TYPES[kind] - self._unit_system = API_METRIC if coordinator.is_metric else API_IMPERIAL - self.kind = kind + self.entity_description = description + self._sensor_data = _get_sensor_data( + coordinator.data, forecast_day, description.key + ) self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION} - self.forecast_day = forecast_day - self._attr_state_class = self._description.get(ATTR_STATE_CLASS) - self._attr_icon = self._description[ATTR_ICON] - self._attr_device_class = self._description[ATTR_DEVICE_CLASS] - self._attr_entity_registry_enabled_default = self._description[ATTR_ENABLED] - if self.forecast_day is not None: - self._attr_name = f"{name} {self._description[ATTR_LABEL]} {forecast_day}d" + if forecast_day is not None: + self._attr_name = f"{name} {description.name} {forecast_day}d" self._attr_unique_id = ( - f"{coordinator.location_key}-{kind}-{forecast_day}".lower() + f"{coordinator.location_key}-{description.key}-{forecast_day}".lower() ) else: - self._attr_name = f"{name} {self._description[ATTR_LABEL]}" - self._attr_unique_id = f"{coordinator.location_key}-{kind}".lower() + self._attr_name = f"{name} {description.name}" + self._attr_unique_id = ( + f"{coordinator.location_key}-{description.key}".lower() + ) if coordinator.is_metric: - self._attr_unit_of_measurement = self._description[ATTR_UNIT_METRIC] + self._unit_system = API_METRIC + self._attr_unit_of_measurement = description.unit_metric else: - self._attr_unit_of_measurement = self._description[ATTR_UNIT_IMPERIAL] + self._unit_system = API_IMPERIAL + self._attr_unit_of_measurement = description.unit_imperial self._attr_device_info = { "identifiers": {(DOMAIN, coordinator.location_key)}, "name": NAME, "manufacturer": MANUFACTURER, "entry_type": "service", } + self.forecast_day = forecast_day @property def state(self) -> StateType: """Return the state.""" if self.forecast_day is not None: - if self._description["device_class"] == DEVICE_CLASS_TEMPERATURE: + if self.entity_description.device_class == DEVICE_CLASS_TEMPERATURE: return cast(float, self._sensor_data["Value"]) - if self.kind == "UVIndex": + if self.entity_description.key == "UVIndex": return cast(int, self._sensor_data["Value"]) - if self.kind in ["Grass", "Mold", "Ragweed", "Tree", "Ozone"]: + if self.entity_description.key in ("Grass", "Mold", "Ragweed", "Tree", "Ozone"): return cast(int, self._sensor_data["Value"]) - if self.kind == "Ceiling": + if self.entity_description.key == "Ceiling": return round(self._sensor_data[self._unit_system]["Value"]) - if self.kind == "PressureTendency": + if self.entity_description.key == "PressureTendency": return cast(str, self._sensor_data["LocalizedText"].lower()) - if self._description["device_class"] == DEVICE_CLASS_TEMPERATURE: + if self.entity_description.device_class == DEVICE_CLASS_TEMPERATURE: return cast(float, self._sensor_data[self._unit_system]["Value"]) - if self.kind == "Precipitation": + if self.entity_description.key == "Precipitation": return cast(float, self._sensor_data[self._unit_system]["Value"]) - if self.kind in ["Wind", "WindGust"]: + if self.entity_description.key in ("Wind", "WindGust"): return cast(float, self._sensor_data["Speed"][self._unit_system]["Value"]) - if self.kind in ["WindDay", "WindNight", "WindGustDay", "WindGustNight"]: + if self.entity_description.key in ( + "WindDay", + "WindNight", + "WindGustDay", + "WindGustNight", + ): return cast(StateType, self._sensor_data["Speed"]["Value"]) return cast(StateType, self._sensor_data) @@ -137,14 +133,26 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity): def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" if self.forecast_day is not None: - if self.kind in ["WindDay", "WindNight", "WindGustDay", "WindGustNight"]: + if self.entity_description.key in ( + "WindDay", + "WindNight", + "WindGustDay", + "WindGustNight", + ): self._attrs["direction"] = self._sensor_data["Direction"]["English"] - elif self.kind in ["Grass", "Mold", "Ragweed", "Tree", "UVIndex", "Ozone"]: + elif self.entity_description.key in ( + "Grass", + "Mold", + "Ozone", + "Ragweed", + "Tree", + "UVIndex", + ): self._attrs["level"] = self._sensor_data["Category"] return self._attrs - if self.kind == "UVIndex": + if self.entity_description.key == "UVIndex": self._attrs["level"] = self.coordinator.data["UVIndexText"] - elif self.kind == "Precipitation": + elif self.entity_description.key == "Precipitation": self._attrs["type"] = self.coordinator.data["PrecipitationType"] return self._attrs @@ -152,7 +160,7 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity): def _handle_coordinator_update(self) -> None: """Handle data update.""" self._sensor_data = _get_sensor_data( - self.coordinator.data, self.forecast_day, self.kind + self.coordinator.data, self.forecast_day, self.entity_description.key ) self.async_write_ha_state()