diff --git a/homeassistant/components/accuweather/const.py b/homeassistant/components/accuweather/const.py index e834feae8d2..aea394446ad 100644 --- a/homeassistant/components/accuweather/const.py +++ b/homeassistant/components/accuweather/const.py @@ -3,6 +3,7 @@ from __future__ import annotations from typing import Final +from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT from homeassistant.components.weather import ( ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLOUDY, @@ -233,6 +234,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: TEMP_CELSIUS, ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, ATTR_ENABLED: False, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, "Ceiling": { ATTR_DEVICE_CLASS: None, @@ -241,6 +243,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: LENGTH_METERS, ATTR_UNIT_IMPERIAL: LENGTH_FEET, ATTR_ENABLED: True, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, "CloudCover": { ATTR_DEVICE_CLASS: None, @@ -249,6 +252,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: PERCENTAGE, ATTR_UNIT_IMPERIAL: PERCENTAGE, ATTR_ENABLED: False, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, "DewPoint": { ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, @@ -257,6 +261,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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, @@ -265,6 +270,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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, @@ -273,6 +279,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: TEMP_CELSIUS, ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, ATTR_ENABLED: False, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, "Precipitation": { ATTR_DEVICE_CLASS: None, @@ -281,6 +288,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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", @@ -297,6 +305,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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, @@ -305,6 +314,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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, @@ -313,6 +323,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: TEMP_CELSIUS, ATTR_UNIT_IMPERIAL: TEMP_FAHRENHEIT, ATTR_ENABLED: False, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, "Wind": { ATTR_DEVICE_CLASS: None, @@ -321,6 +332,7 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { 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, @@ -329,5 +341,6 @@ SENSOR_TYPES: Final[dict[str, SensorDescription]] = { ATTR_UNIT_METRIC: SPEED_KILOMETERS_PER_HOUR, ATTR_UNIT_IMPERIAL: SPEED_MILES_PER_HOUR, ATTR_ENABLED: False, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, } diff --git a/homeassistant/components/accuweather/model.py b/homeassistant/components/accuweather/model.py index cc51efbd0e2..2127629728b 100644 --- a/homeassistant/components/accuweather/model.py +++ b/homeassistant/components/accuweather/model.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import TypedDict -class SensorDescription(TypedDict): +class SensorDescription(TypedDict, total=False): """Sensor description class.""" device_class: str | None @@ -13,3 +13,4 @@ class SensorDescription(TypedDict): unit_metric: str | None unit_imperial: str | None enabled: bool + state_class: str | None diff --git a/homeassistant/components/accuweather/sensor.py b/homeassistant/components/accuweather/sensor.py index bf6b0efd6c2..ba99df14d9e 100644 --- a/homeassistant/components/accuweather/sensor.py +++ b/homeassistant/components/accuweather/sensor.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Any, cast -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_ATTRIBUTION, @@ -89,6 +89,7 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity): self._device_class = None self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION} self.forecast_day = forecast_day + self._attr_state_class = self._description.get(ATTR_STATE_CLASS) @property def name(self) -> str: diff --git a/tests/components/accuweather/test_sensor.py b/tests/components/accuweather/test_sensor.py index 64c49c61fe7..62f282f2cf3 100644 --- a/tests/components/accuweather/test_sensor.py +++ b/tests/components/accuweather/test_sensor.py @@ -4,7 +4,11 @@ import json from unittest.mock import PropertyMock, patch from homeassistant.components.accuweather.const import ATTRIBUTION, DOMAIN -from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + DOMAIN as SENSOR_DOMAIN, + STATE_CLASS_MEASUREMENT, +) from homeassistant.const import ( ATTR_ATTRIBUTION, ATTR_DEVICE_CLASS, @@ -43,6 +47,7 @@ async def test_sensor_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-fog" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == LENGTH_METERS + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_cloud_ceiling") assert entry @@ -55,6 +60,7 @@ async def test_sensor_without_forecast(hass): assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == LENGTH_MILLIMETERS assert state.attributes.get(ATTR_ICON) == "mdi:weather-rainy" assert state.attributes.get("type") is None + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_precipitation") assert entry @@ -66,6 +72,7 @@ async def test_sensor_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:gauge" assert state.attributes.get(ATTR_DEVICE_CLASS) == "accuweather__pressure_tendency" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_pressure_tendency") assert entry @@ -77,6 +84,7 @@ async def test_sensor_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_realfeel_temperature") assert entry @@ -88,6 +96,7 @@ async def test_sensor_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UV_INDEX assert state.attributes.get("level") == "High" + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_uv_index") assert entry @@ -105,6 +114,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-partly-cloudy" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TIME_HOURS + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_hours_of_sun_0d") assert entry @@ -116,6 +126,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_realfeel_temperature_max_0d") assert entry @@ -126,6 +137,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_realfeel_temperature_min_0d") assert entry @@ -137,6 +149,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-lightning" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_thunderstorm_probability_day_0d") assert entry @@ -148,6 +161,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-lightning" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_thunderstorm_probability_night_0d") assert entry @@ -160,6 +174,7 @@ async def test_sensor_with_forecast(hass): assert state.attributes.get(ATTR_ICON) == "mdi:weather-sunny" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UV_INDEX assert state.attributes.get("level") == "Moderate" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_uv_index_0d") assert entry @@ -346,6 +361,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_apparent_temperature") assert entry @@ -357,6 +373,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_cloud_cover") assert entry @@ -368,6 +385,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_dew_point") assert entry @@ -379,6 +397,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_realfeel_temperature_shade") assert entry @@ -390,6 +409,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_wet_bulb_temperature") assert entry @@ -401,6 +421,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_wind_chill_temperature") assert entry @@ -412,6 +433,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_wind_gust") assert entry @@ -423,6 +445,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" + assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT entry = registry.async_get("sensor.home_wind") assert entry @@ -434,6 +457,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_cloud_cover_day_0d") assert entry @@ -445,6 +469,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_cloud_cover_night_0d") assert entry @@ -459,6 +484,7 @@ async def test_sensor_enabled_without_forecast(hass): ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:grass" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_grass_pollen_0d") assert entry @@ -485,6 +511,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get("level") == "Good" assert state.attributes.get(ATTR_ICON) == "mdi:vector-triangle" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_ozone_0d") assert entry @@ -511,6 +538,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_realfeel_temperature_shade_max_0d") assert entry @@ -537,6 +565,7 @@ async def test_sensor_enabled_without_forecast(hass): ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:tree-outline" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_tree_pollen_0d") assert entry @@ -561,6 +590,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "WNW" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_wind_night_0d") assert entry @@ -573,6 +603,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "S" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_wind_gust_day_0d") assert entry @@ -585,6 +616,7 @@ async def test_sensor_enabled_without_forecast(hass): assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "WSW" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" + assert state.attributes.get(ATTR_STATE_CLASS) is None entry = registry.async_get("sensor.home_wind_gust_night_0d") assert entry