Use metric units internally in Accuweather integration (#90444)

* Use metric units internally

* Remove unnecessary code

* Simplify sensor classes

* Remove AccuWeatherForecastSensor class

* Update wind speed value in test

* Return suggested_unit_of_measurement for wind entities

* Clean test

* Use _attr_suggested_unit_of_measurement

* Remove _get_suggested_unit()

* Remove unnecessarey code
This commit is contained in:
Maciej Bieniek 2023-03-30 13:11:33 +02:00 committed by GitHub
parent ead88cc3f8
commit 8d21e2b168
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 149 deletions

View File

@ -17,7 +17,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util.unit_system import METRIC_SYSTEM
from .const import ATTR_FORECAST, CONF_FORECAST, DOMAIN, MANUFACTURER from .const import ATTR_FORECAST, CONF_FORECAST, DOMAIN, MANUFACTURER
@ -116,11 +115,7 @@ class AccuWeatherDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
async with timeout(10): async with timeout(10):
current = await self.accuweather.async_get_current_conditions() current = await self.accuweather.async_get_current_conditions()
forecast = ( forecast = (
await self.accuweather.async_get_forecast( await self.accuweather.async_get_forecast() if self.forecast else {}
metric=self.hass.config.units is METRIC_SYSTEM
)
if self.forecast
else {}
) )
except ( except (
ApiError, ApiError,

View File

@ -20,7 +20,6 @@ from homeassistant.components.weather import (
ATTR_CONDITION_WINDY, ATTR_CONDITION_WINDY,
) )
API_IMPERIAL: Final = "Imperial"
API_METRIC: Final = "Metric" API_METRIC: Final = "Metric"
ATTRIBUTION: Final = "Data provided by AccuWeather" ATTRIBUTION: Final = "Data provided by AccuWeather"
ATTR_CATEGORY: Final = "Category" ATTR_CATEGORY: Final = "Category"

View File

@ -26,11 +26,9 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.unit_system import METRIC_SYSTEM
from . import AccuWeatherDataUpdateCoordinator from . import AccuWeatherDataUpdateCoordinator
from .const import ( from .const import (
API_IMPERIAL,
API_METRIC, API_METRIC,
ATTR_CATEGORY, ATTR_CATEGORY,
ATTR_DIRECTION, ATTR_DIRECTION,
@ -51,7 +49,7 @@ PARALLEL_UPDATES = 1
class AccuWeatherSensorDescriptionMixin: class AccuWeatherSensorDescriptionMixin:
"""Mixin for AccuWeather sensor.""" """Mixin for AccuWeather sensor."""
value_fn: Callable[[dict[str, Any], str], StateType] value_fn: Callable[[dict[str, Any]], StateType]
@dataclass @dataclass
@ -61,8 +59,6 @@ class AccuWeatherSensorDescription(
"""Class describing AccuWeather sensor entities.""" """Class describing AccuWeather sensor entities."""
attr_fn: Callable[[dict[str, Any]], dict[str, StateType]] = lambda _: {} attr_fn: Callable[[dict[str, Any]], dict[str, StateType]] = lambda _: {}
metric_unit: str | None = None
us_customary_unit: str | None = None
FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = ( FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
@ -72,7 +68,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Cloud cover day", name="Cloud cover day",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="CloudCoverNight", key="CloudCoverNight",
@ -80,7 +76,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Cloud cover night", name="Cloud cover night",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Grass", key="Grass",
@ -88,7 +84,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Grass pollen", name="Grass pollen",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -96,7 +92,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
icon="mdi:weather-partly-cloudy", icon="mdi:weather-partly-cloudy",
name="Hours of sun", name="Hours of sun",
native_unit_of_measurement=UnitOfTime.HOURS, native_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data, _: cast(float, data), value_fn=lambda data: cast(float, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Mold", key="Mold",
@ -104,7 +100,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Mold pollen", name="Mold pollen",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -112,7 +108,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
icon="mdi:vector-triangle", icon="mdi:vector-triangle",
name="Ozone", name="Ozone",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -121,56 +117,52 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Ragweed pollen", name="Ragweed pollen",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperatureMax", key="RealFeelTemperatureMax",
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
name="RealFeel temperature max", name="RealFeel temperature max",
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperatureMin", key="RealFeelTemperatureMin",
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
name="RealFeel temperature min", name="RealFeel temperature min",
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperatureShadeMax", key="RealFeelTemperatureShadeMax",
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
name="RealFeel temperature shade max", name="RealFeel temperature shade max",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperatureShadeMin", key="RealFeelTemperatureShadeMin",
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
name="RealFeel temperature shade min", name="RealFeel temperature shade min",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="ThunderstormProbabilityDay", key="ThunderstormProbabilityDay",
icon="mdi:weather-lightning", icon="mdi:weather-lightning",
name="Thunderstorm probability day", name="Thunderstorm probability day",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="ThunderstormProbabilityNight", key="ThunderstormProbabilityNight",
icon="mdi:weather-lightning", icon="mdi:weather-lightning",
name="Thunderstorm probability night", name="Thunderstorm probability night",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Tree", key="Tree",
@ -178,7 +170,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Tree pollen", name="Tree pollen",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER, native_unit_of_measurement=CONCENTRATION_PARTS_PER_CUBIC_METER,
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -186,7 +178,7 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
icon="mdi:weather-sunny", icon="mdi:weather-sunny",
name="UV index", name="UV index",
native_unit_of_measurement=UV_INDEX, native_unit_of_measurement=UV_INDEX,
value_fn=lambda data, _: cast(int, data[ATTR_VALUE]), value_fn=lambda data: cast(int, data[ATTR_VALUE]),
attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]}, attr_fn=lambda data: {ATTR_LEVEL: data[ATTR_CATEGORY]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -194,9 +186,8 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
device_class=SensorDeviceClass.WIND_SPEED, device_class=SensorDeviceClass.WIND_SPEED,
name="Wind gust day", name="Wind gust day",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]}, attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -204,27 +195,24 @@ FORECAST_SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
device_class=SensorDeviceClass.WIND_SPEED, device_class=SensorDeviceClass.WIND_SPEED,
name="Wind gust night", name="Wind gust night",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]}, attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="WindDay", key="WindDay",
device_class=SensorDeviceClass.WIND_SPEED, device_class=SensorDeviceClass.WIND_SPEED,
name="Wind day", name="Wind day",
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]}, attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="WindNight", key="WindNight",
device_class=SensorDeviceClass.WIND_SPEED, device_class=SensorDeviceClass.WIND_SPEED,
name="Wind night", name="Wind night",
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
value_fn=lambda data, _: cast(float, data[ATTR_SPEED][ATTR_VALUE]),
attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]}, attr_fn=lambda data: {"direction": data[ATTR_DIRECTION][ATTR_ENGLISH]},
), ),
) )
@ -236,9 +224,8 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Apparent temperature", name="Apparent temperature",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Ceiling", key="Ceiling",
@ -246,9 +233,8 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
icon="mdi:weather-fog", icon="mdi:weather-fog",
name="Cloud ceiling", name="Cloud ceiling",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfLength.METERS, native_unit_of_measurement=UnitOfLength.METERS,
us_customary_unit=UnitOfLength.FEET, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
suggested_display_precision=0, suggested_display_precision=0,
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -258,7 +244,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="DewPoint", key="DewPoint",
@ -266,18 +252,16 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Dew point", name="Dew point",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperature", key="RealFeelTemperature",
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
name="RealFeel temperature", name="RealFeel temperature",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="RealFeelTemperatureShade", key="RealFeelTemperatureShade",
@ -285,18 +269,16 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="RealFeel temperature shade", name="RealFeel temperature shade",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Precipitation", key="Precipitation",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY, device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
name="Precipitation", name="Precipitation",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR, native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_customary_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
attr_fn=lambda data: {"type": data["PrecipitationType"]}, attr_fn=lambda data: {"type": data["PrecipitationType"]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -306,7 +288,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Pressure tendency", name="Pressure tendency",
options=["falling", "rising", "steady"], options=["falling", "rising", "steady"],
translation_key="pressure_tendency", translation_key="pressure_tendency",
value_fn=lambda data, _: cast(str, data["LocalizedText"]).lower(), value_fn=lambda data: cast(str, data["LocalizedText"]).lower(),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="UVIndex", key="UVIndex",
@ -314,7 +296,7 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="UV index", name="UV index",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UV_INDEX, native_unit_of_measurement=UV_INDEX,
value_fn=lambda data, _: cast(int, data), value_fn=lambda data: cast(int, data),
attr_fn=lambda data: {ATTR_LEVEL: data["UVIndexText"]}, attr_fn=lambda data: {ATTR_LEVEL: data["UVIndexText"]},
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
@ -323,9 +305,8 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Wet bulb temperature", name="Wet bulb temperature",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="WindChillTemperature", key="WindChillTemperature",
@ -333,18 +314,16 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Wind chill temperature", name="Wind chill temperature",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
us_customary_unit=UnitOfTemperature.FAHRENHEIT, value_fn=lambda data: cast(float, data[API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="Wind", key="Wind",
device_class=SensorDeviceClass.WIND_SPEED, device_class=SensorDeviceClass.WIND_SPEED,
name="Wind", name="Wind",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[ATTR_SPEED][unit][ATTR_VALUE]),
), ),
AccuWeatherSensorDescription( AccuWeatherSensorDescription(
key="WindGust", key="WindGust",
@ -352,9 +331,8 @@ SENSOR_TYPES: tuple[AccuWeatherSensorDescription, ...] = (
name="Wind gust", name="Wind gust",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
metric_unit=UnitOfSpeed.KILOMETERS_PER_HOUR, native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
us_customary_unit=UnitOfSpeed.MILES_PER_HOUR, value_fn=lambda data: cast(float, data[ATTR_SPEED][API_METRIC][ATTR_VALUE]),
value_fn=lambda data, unit: cast(float, data[ATTR_SPEED][unit][ATTR_VALUE]),
), ),
) )
@ -374,7 +352,7 @@ async def async_setup_entry(
# Some air quality/allergy sensors are only available for certain # Some air quality/allergy sensors are only available for certain
# locations. # locations.
sensors.extend( sensors.extend(
AccuWeatherForecastSensor(coordinator, description, forecast_day=day) AccuWeatherSensor(coordinator, description, forecast_day=day)
for day in range(MAX_FORECAST_DAYS + 1) for day in range(MAX_FORECAST_DAYS + 1)
for description in FORECAST_SENSOR_TYPES for description in FORECAST_SENSOR_TYPES
if description.key in coordinator.data[ATTR_FORECAST][0] if description.key in coordinator.data[ATTR_FORECAST][0]
@ -413,34 +391,27 @@ class AccuWeatherSensor(
self._attr_unique_id = ( self._attr_unique_id = (
f"{coordinator.location_key}-{description.key}".lower() f"{coordinator.location_key}-{description.key}".lower()
) )
self._attr_native_unit_of_measurement = description.native_unit_of_measurement
if self.coordinator.hass.config.units is METRIC_SYSTEM:
self._unit_system = API_METRIC
if metric_unit := description.metric_unit:
self._attr_native_unit_of_measurement = metric_unit
else:
self._unit_system = API_IMPERIAL
if us_customary_unit := description.us_customary_unit:
self._attr_native_unit_of_measurement = us_customary_unit
self._attr_device_info = coordinator.device_info self._attr_device_info = coordinator.device_info
if forecast_day is not None: self.forecast_day = forecast_day
self.forecast_day = forecast_day
@property @property
def native_value(self) -> StateType: def native_value(self) -> StateType:
"""Return the state.""" """Return the state."""
return self.entity_description.value_fn(self._sensor_data, self._unit_system) return self.entity_description.value_fn(self._sensor_data)
@property @property
def extra_state_attributes(self) -> dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes.""" """Return the state attributes."""
if self.forecast_day is not None:
return self.entity_description.attr_fn(self._sensor_data)
return self.entity_description.attr_fn(self.coordinator.data) return self.entity_description.attr_fn(self.coordinator.data)
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
"""Handle data update.""" """Handle data update."""
self._sensor_data = _get_sensor_data( self._sensor_data = _get_sensor_data(
self.coordinator.data, self.entity_description.key self.coordinator.data, self.entity_description.key, self.forecast_day
) )
self.async_write_ha_state() self.async_write_ha_state()
@ -458,20 +429,3 @@ def _get_sensor_data(
return sensors["PrecipitationSummary"]["PastHour"] return sensors["PrecipitationSummary"]["PastHour"]
return sensors[kind] return sensors[kind]
class AccuWeatherForecastSensor(AccuWeatherSensor):
"""Define an AccuWeather forecast entity."""
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return self.entity_description.attr_fn(self._sensor_data)
@callback
def _handle_coordinator_update(self) -> None:
"""Handle data update."""
self._sensor_data = _get_sensor_data(
self.coordinator.data, self.entity_description.key, self.forecast_day
)
self.async_write_ha_state()

View File

@ -28,17 +28,9 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import utc_from_timestamp from homeassistant.util.dt import utc_from_timestamp
from homeassistant.util.unit_system import METRIC_SYSTEM
from . import AccuWeatherDataUpdateCoordinator from . import AccuWeatherDataUpdateCoordinator
from .const import ( from .const import API_METRIC, ATTR_FORECAST, ATTRIBUTION, CONDITION_CLASSES, DOMAIN
API_IMPERIAL,
API_METRIC,
ATTR_FORECAST,
ATTRIBUTION,
CONDITION_CLASSES,
DOMAIN,
)
PARALLEL_UPDATES = 1 PARALLEL_UPDATES = 1
@ -66,20 +58,11 @@ class AccuWeatherEntity(
# Coordinator data is used also for sensors which don't have units automatically # Coordinator data is used also for sensors which don't have units automatically
# converted, hence the weather entity's native units follow the configured unit # converted, hence the weather entity's native units follow the configured unit
# system # system
if coordinator.hass.config.units is METRIC_SYSTEM: self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS self._attr_native_pressure_unit = UnitOfPressure.HPA
self._attr_native_pressure_unit = UnitOfPressure.HPA self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS self._attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
self._attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
self._unit_system = API_METRIC
else:
self._unit_system = API_IMPERIAL
self._attr_native_precipitation_unit = UnitOfPrecipitationDepth.INCHES
self._attr_native_pressure_unit = UnitOfPressure.INHG
self._attr_native_temperature_unit = UnitOfTemperature.FAHRENHEIT
self._attr_native_visibility_unit = UnitOfLength.MILES
self._attr_native_wind_speed_unit = UnitOfSpeed.MILES_PER_HOUR
self._attr_unique_id = coordinator.location_key self._attr_unique_id = coordinator.location_key
self._attr_attribution = ATTRIBUTION self._attr_attribution = ATTRIBUTION
self._attr_device_info = coordinator.device_info self._attr_device_info = coordinator.device_info
@ -99,16 +82,12 @@ class AccuWeatherEntity(
@property @property
def native_temperature(self) -> float: def native_temperature(self) -> float:
"""Return the temperature.""" """Return the temperature."""
return cast( return cast(float, self.coordinator.data["Temperature"][API_METRIC]["Value"])
float, self.coordinator.data["Temperature"][self._unit_system]["Value"]
)
@property @property
def native_pressure(self) -> float: def native_pressure(self) -> float:
"""Return the pressure.""" """Return the pressure."""
return cast( return cast(float, self.coordinator.data["Pressure"][API_METRIC]["Value"])
float, self.coordinator.data["Pressure"][self._unit_system]["Value"]
)
@property @property
def humidity(self) -> int: def humidity(self) -> int:
@ -118,9 +97,7 @@ class AccuWeatherEntity(
@property @property
def native_wind_speed(self) -> float: def native_wind_speed(self) -> float:
"""Return the wind speed.""" """Return the wind speed."""
return cast( return cast(float, self.coordinator.data["Wind"]["Speed"][API_METRIC]["Value"])
float, self.coordinator.data["Wind"]["Speed"][self._unit_system]["Value"]
)
@property @property
def wind_bearing(self) -> int: def wind_bearing(self) -> int:
@ -130,9 +107,7 @@ class AccuWeatherEntity(
@property @property
def native_visibility(self) -> float: def native_visibility(self) -> float:
"""Return the visibility.""" """Return the visibility."""
return cast( return cast(float, self.coordinator.data["Visibility"][API_METRIC]["Value"])
float, self.coordinator.data["Visibility"][self._unit_system]["Value"]
)
@property @property
def ozone(self) -> int | None: def ozone(self) -> int | None:

View File

@ -741,11 +741,21 @@ async def test_sensor_imperial_units(hass: HomeAssistant) -> None:
state = hass.states.get("sensor.home_cloud_ceiling") state = hass.states.get("sensor.home_cloud_ceiling")
assert state assert state
assert state.state == "10500.0" assert state.state == "10498.687664042"
assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION
assert state.attributes.get(ATTR_ICON) == "mdi:weather-fog"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfLength.FEET assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfLength.FEET
state = hass.states.get("sensor.home_wind")
assert state
assert state.state == "9.0"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfSpeed.MILES_PER_HOUR
state = hass.states.get("sensor.home_realfeel_temperature")
assert state
assert state.state == "77.2"
assert (
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfTemperature.FAHRENHEIT
)
async def test_state_update(hass: HomeAssistant) -> None: async def test_state_update(hass: HomeAssistant) -> None:
"""Ensure the sensor state changes after updating the data.""" """Ensure the sensor state changes after updating the data."""