Define WeatherEntity entity attributes as class variables (#51899)

This commit is contained in:
Franck Nijhof 2021-06-17 10:16:16 +02:00 committed by GitHub
parent 7947946793
commit 3b00e87ebc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 40 deletions

View File

@ -13,6 +13,7 @@ from homeassistant.components.weather import (
ATTR_FORECAST_TIME, ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING, ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED, ATTR_FORECAST_WIND_SPEED,
Forecast,
WeatherEntity, WeatherEntity,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -156,12 +157,12 @@ class AccuWeatherEntity(CoordinatorEntity, WeatherEntity):
return None return None
@property @property
def forecast(self) -> list[dict[str, Any]] | None: def forecast(self) -> list[Forecast] | None:
"""Return the forecast array.""" """Return the forecast array."""
if not self.coordinator.forecast: if not self.coordinator.forecast:
return None return None
# remap keys from library to keys understood by the weather component # remap keys from library to keys understood by the weather component
forecast = [ return [
{ {
ATTR_FORECAST_TIME: utc_from_timestamp(item["EpochDate"]).isoformat(), ATTR_FORECAST_TIME: utc_from_timestamp(item["EpochDate"]).isoformat(),
ATTR_FORECAST_TEMP: item["TemperatureMax"]["Value"], ATTR_FORECAST_TEMP: item["TemperatureMax"]["Value"],
@ -183,7 +184,6 @@ class AccuWeatherEntity(CoordinatorEntity, WeatherEntity):
} }
for item in self.coordinator.data[ATTR_FORECAST] for item in self.coordinator.data[ATTR_FORECAST]
] ]
return forecast
@staticmethod @staticmethod
def _calc_precipitation(day: dict[str, Any]) -> float: def _calc_precipitation(day: dict[str, Any]) -> float:

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import Any, Final, TypedDict from typing import Final, TypedDict
import aiohttp import aiohttp
import async_timeout import async_timeout
@ -31,6 +31,7 @@ from homeassistant.components.weather import (
ATTR_FORECAST_TEMP, ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME, ATTR_FORECAST_TIME,
Forecast,
WeatherEntity, WeatherEntity,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -235,12 +236,12 @@ class SmhiWeather(WeatherEntity):
return "Swedish weather institute (SMHI)" return "Swedish weather institute (SMHI)"
@property @property
def forecast(self) -> list[dict[str, Any]] | None: def forecast(self) -> list[Forecast] | None:
"""Return the forecast.""" """Return the forecast."""
if self._forecasts is None or len(self._forecasts) < 2: if self._forecasts is None or len(self._forecasts) < 2:
return None return None
data = [] data: list[Forecast] = []
for forecast in self._forecasts[1:]: for forecast in self._forecasts[1:]:
condition = next( condition = next(

View File

@ -1,7 +1,9 @@
"""Weather component that handles meteorological data for your location.""" """Weather component that handles meteorological data for your location."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final from typing import Final, TypedDict, final
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PRECISION_TENTHS, PRECISION_WHOLE, TEMP_CELSIUS from homeassistant.const import PRECISION_TENTHS, PRECISION_WHOLE, TEMP_CELSIUS
@ -35,15 +37,15 @@ ATTR_CONDITION_SUNNY = "sunny"
ATTR_CONDITION_WINDY = "windy" ATTR_CONDITION_WINDY = "windy"
ATTR_CONDITION_WINDY_VARIANT = "windy-variant" ATTR_CONDITION_WINDY_VARIANT = "windy-variant"
ATTR_FORECAST = "forecast" ATTR_FORECAST = "forecast"
ATTR_FORECAST_CONDITION = "condition" ATTR_FORECAST_CONDITION: Final = "condition"
ATTR_FORECAST_PRECIPITATION = "precipitation" ATTR_FORECAST_PRECIPITATION: Final = "precipitation"
ATTR_FORECAST_PRECIPITATION_PROBABILITY = "precipitation_probability" ATTR_FORECAST_PRECIPITATION_PROBABILITY: Final = "precipitation_probability"
ATTR_FORECAST_PRESSURE = "pressure" ATTR_FORECAST_PRESSURE: Final = "pressure"
ATTR_FORECAST_TEMP = "temperature" ATTR_FORECAST_TEMP: Final = "temperature"
ATTR_FORECAST_TEMP_LOW = "templow" ATTR_FORECAST_TEMP_LOW: Final = "templow"
ATTR_FORECAST_TIME = "datetime" ATTR_FORECAST_TIME: Final = "datetime"
ATTR_FORECAST_WIND_BEARING = "wind_bearing" ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
ATTR_FORECAST_WIND_SPEED = "wind_speed" ATTR_FORECAST_WIND_SPEED: Final = "wind_speed"
ATTR_WEATHER_ATTRIBUTION = "attribution" ATTR_WEATHER_ATTRIBUTION = "attribution"
ATTR_WEATHER_HUMIDITY = "humidity" ATTR_WEATHER_HUMIDITY = "humidity"
ATTR_WEATHER_OZONE = "ozone" ATTR_WEATHER_OZONE = "ozone"
@ -60,6 +62,20 @@ ENTITY_ID_FORMAT = DOMAIN + ".{}"
SCAN_INTERVAL = timedelta(seconds=30) SCAN_INTERVAL = timedelta(seconds=30)
class Forecast(TypedDict, total=False):
"""Typed weather forecast dict."""
condition: str | None
datetime: str
precipitation_probability: int | None
precipitation: float | None
pressure: float | None
temperature: float | None
templow: float | None
wind_bearing: float | str | None
wind_speed: float | None
async def async_setup(hass, config): async def async_setup(hass, config):
"""Set up the weather component.""" """Set up the weather component."""
component = hass.data[DOMAIN] = EntityComponent( component = hass.data[DOMAIN] = EntityComponent(
@ -84,59 +100,75 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
class WeatherEntity(Entity): class WeatherEntity(Entity):
"""ABC for weather data.""" """ABC for weather data."""
_attr_attribution: str | None = None
_attr_condition: str | None
_attr_forecast: list[Forecast] | None = None
_attr_humidity: float | None = None
_attr_ozone: float | None = None
_attr_precision: float
_attr_pressure: float | None = None
_attr_state: None = None
_attr_temperature_unit: str
_attr_temperature: float | None
_attr_visibility: float | None = None
_attr_wind_bearing: float | str | None = None
_attr_wind_speed: float | None = None
@property @property
def temperature(self): def temperature(self) -> float | None:
"""Return the platform temperature.""" """Return the platform temperature."""
raise NotImplementedError() return self._attr_temperature
@property @property
def temperature_unit(self): def temperature_unit(self) -> str:
"""Return the unit of measurement.""" """Return the unit of measurement."""
raise NotImplementedError() return self._attr_temperature_unit
@property @property
def pressure(self): def pressure(self) -> float | None:
"""Return the pressure.""" """Return the pressure."""
return None return self._attr_pressure
@property @property
def humidity(self): def humidity(self) -> float | None:
"""Return the humidity.""" """Return the humidity."""
raise NotImplementedError() return self._attr_humidity
@property @property
def wind_speed(self): def wind_speed(self) -> float | None:
"""Return the wind speed.""" """Return the wind speed."""
return None return self._attr_wind_speed
@property @property
def wind_bearing(self): def wind_bearing(self) -> float | str | None:
"""Return the wind bearing.""" """Return the wind bearing."""
return None return self._attr_wind_bearing
@property @property
def ozone(self): def ozone(self) -> float | None:
"""Return the ozone level.""" """Return the ozone level."""
return None return self._attr_ozone
@property @property
def attribution(self): def attribution(self) -> str | None:
"""Return the attribution.""" """Return the attribution."""
return None return self._attr_attribution
@property @property
def visibility(self): def visibility(self) -> float | None:
"""Return the visibility.""" """Return the visibility."""
return None return self._attr_visibility
@property @property
def forecast(self): def forecast(self) -> list[Forecast] | None:
"""Return the forecast.""" """Return the forecast."""
return None return self._attr_forecast
@property @property
def precision(self): def precision(self) -> float:
"""Return the precision of the temperature value.""" """Return the precision of the temperature value."""
if hasattr(self, "_attr_precision"):
return self._attr_precision
return ( return (
PRECISION_TENTHS PRECISION_TENTHS
if self.temperature_unit == TEMP_CELSIUS if self.temperature_unit == TEMP_CELSIUS
@ -205,11 +237,12 @@ class WeatherEntity(Entity):
return data return data
@property @property
def state(self): @final
def state(self) -> str | None:
"""Return the current state.""" """Return the current state."""
return self.condition return self.condition
@property @property
def condition(self): def condition(self) -> str | None:
"""Return the current condition.""" """Return the current condition."""
raise NotImplementedError() return self._attr_condition