Use EntityDescription - openweathermap (#56888)

This commit is contained in:
Marc Mueller 2021-10-11 16:18:18 +02:00 committed by GitHub
parent 748d915909
commit 858739949b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 213 additions and 246 deletions

View file

@ -776,7 +776,6 @@ omit =
homeassistant/components/openweathermap/sensor.py homeassistant/components/openweathermap/sensor.py
homeassistant/components/openweathermap/weather.py homeassistant/components/openweathermap/weather.py
homeassistant/components/openweathermap/weather_update_coordinator.py homeassistant/components/openweathermap/weather_update_coordinator.py
homeassistant/components/openweathermap/abstract_owm_sensor.py
homeassistant/components/opnsense/* homeassistant/components/opnsense/*
homeassistant/components/opple/light.py homeassistant/components/opple/light.py
homeassistant/components/orangepi_gpio/* homeassistant/components/orangepi_gpio/*

View file

@ -1,96 +0,0 @@
"""Abstraction form OWM sensors."""
from homeassistant.components.sensor import SensorEntity
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
ATTRIBUTION,
DEFAULT_NAME,
DOMAIN,
MANUFACTURER,
SENSOR_DEVICE_CLASS,
SENSOR_NAME,
SENSOR_UNIT,
)
class AbstractOpenWeatherMapSensor(SensorEntity):
"""Abstract class for an OpenWeatherMap sensor."""
def __init__(
self,
name,
unique_id,
sensor_type,
sensor_configuration,
coordinator: DataUpdateCoordinator,
):
"""Initialize the sensor."""
self._name = name
self._unique_id = unique_id
self._sensor_type = sensor_type
self._sensor_name = sensor_configuration[SENSOR_NAME]
self._unit_of_measurement = sensor_configuration.get(SENSOR_UNIT)
self._device_class = sensor_configuration.get(SENSOR_DEVICE_CLASS)
self._coordinator = coordinator
@property
def name(self):
"""Return the name of the sensor."""
return f"{self._name} {self._sensor_name}"
@property
def unique_id(self):
"""Return a unique_id for this entity."""
return self._unique_id
@property
def device_info(self):
"""Return the device info."""
split_unique_id = self._unique_id.split("-")
return {
"identifiers": {(DOMAIN, f"{split_unique_id[0]}-{split_unique_id[1]}")},
"name": DEFAULT_NAME,
"manufacturer": MANUFACTURER,
"entry_type": "service",
}
@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return False
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
@property
def device_class(self):
"""Return the device_class."""
return self._device_class
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def extra_state_attributes(self):
"""Return the state attributes."""
return {ATTR_ATTRIBUTION: ATTRIBUTION}
@property
def available(self):
"""Return True if entity is available."""
return self._coordinator.last_update_success
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self._coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Get the latest data from OWM and updates the states."""
await self._coordinator.async_request_refresh()

View file

@ -1,4 +1,7 @@
"""Consts for the OpenWeatherMap.""" """Consts for the OpenWeatherMap."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.weather import ( from homeassistant.components.weather import (
ATTR_CONDITION_CLOUDY, ATTR_CONDITION_CLOUDY,
ATTR_CONDITION_EXCEPTIONAL, ATTR_CONDITION_EXCEPTIONAL,
@ -21,8 +24,6 @@ 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,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
) )
from homeassistant.const import ( from homeassistant.const import (
DEGREE, DEGREE,
@ -65,9 +66,6 @@ ATTR_API_SNOW = "snow"
ATTR_API_UV_INDEX = "uv_index" ATTR_API_UV_INDEX = "uv_index"
ATTR_API_WEATHER_CODE = "weather_code" ATTR_API_WEATHER_CODE = "weather_code"
ATTR_API_FORECAST = "forecast" ATTR_API_FORECAST = "forecast"
SENSOR_NAME = "sensor_name"
SENSOR_UNIT = "sensor_unit"
SENSOR_DEVICE_CLASS = "sensor_device_class"
UPDATE_LISTENER = "update_listener" UPDATE_LISTENER = "update_listener"
PLATFORMS = ["sensor", "weather"] PLATFORMS = ["sensor", "weather"]
@ -84,35 +82,6 @@ FORECAST_MODES = [
] ]
DEFAULT_FORECAST_MODE = FORECAST_MODE_ONECALL_DAILY DEFAULT_FORECAST_MODE = FORECAST_MODE_ONECALL_DAILY
MONITORED_CONDITIONS = [
ATTR_API_WEATHER,
ATTR_API_DEW_POINT,
ATTR_API_TEMPERATURE,
ATTR_API_FEELS_LIKE_TEMPERATURE,
ATTR_API_WIND_SPEED,
ATTR_API_WIND_BEARING,
ATTR_API_HUMIDITY,
ATTR_API_PRESSURE,
ATTR_API_CLOUDS,
ATTR_API_RAIN,
ATTR_API_SNOW,
ATTR_API_PRECIPITATION_KIND,
ATTR_API_UV_INDEX,
ATTR_API_CONDITION,
ATTR_API_WEATHER_CODE,
]
FORECAST_MONITORED_CONDITIONS = [
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_PRESSURE,
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
ATTR_API_CLOUDS,
]
LANGUAGES = [ LANGUAGES = [
"af", "af",
"al", "al",
@ -194,82 +163,135 @@ CONDITION_CLASSES = {
904, 904,
], ],
} }
WEATHER_SENSOR_TYPES = { WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
ATTR_API_WEATHER: {SENSOR_NAME: "Weather"}, SensorEntityDescription(
ATTR_API_DEW_POINT: { key=ATTR_API_WEATHER,
SENSOR_NAME: "Dew Point", name="Weather",
SENSOR_UNIT: TEMP_CELSIUS, ),
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, SensorEntityDescription(
}, key=ATTR_API_DEW_POINT,
ATTR_API_TEMPERATURE: { name="Dew Point",
SENSOR_NAME: "Temperature", native_unit_of_measurement=TEMP_CELSIUS,
SENSOR_UNIT: TEMP_CELSIUS, device_class=DEVICE_CLASS_TEMPERATURE,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, ),
}, SensorEntityDescription(
ATTR_API_FEELS_LIKE_TEMPERATURE: { key=ATTR_API_TEMPERATURE,
SENSOR_NAME: "Feels like temperature", name="Temperature",
SENSOR_UNIT: TEMP_CELSIUS, native_unit_of_measurement=TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, device_class=DEVICE_CLASS_TEMPERATURE,
}, ),
ATTR_API_WIND_SPEED: { SensorEntityDescription(
SENSOR_NAME: "Wind speed", key=ATTR_API_FEELS_LIKE_TEMPERATURE,
SENSOR_UNIT: SPEED_METERS_PER_SECOND, name="Feels like temperature",
}, native_unit_of_measurement=TEMP_CELSIUS,
ATTR_API_WIND_BEARING: {SENSOR_NAME: "Wind bearing", SENSOR_UNIT: DEGREE}, device_class=DEVICE_CLASS_TEMPERATURE,
ATTR_API_HUMIDITY: { ),
SENSOR_NAME: "Humidity", SensorEntityDescription(
SENSOR_UNIT: PERCENTAGE, key=ATTR_API_WIND_SPEED,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, name="Wind speed",
}, native_unit_of_measurement=SPEED_METERS_PER_SECOND,
ATTR_API_PRESSURE: { ),
SENSOR_NAME: "Pressure", SensorEntityDescription(
SENSOR_UNIT: PRESSURE_HPA, key=ATTR_API_WIND_BEARING,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE, name="Wind bearing",
}, native_unit_of_measurement=DEGREE,
ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE}, ),
ATTR_API_RAIN: {SENSOR_NAME: "Rain", SENSOR_UNIT: LENGTH_MILLIMETERS}, SensorEntityDescription(
ATTR_API_SNOW: {SENSOR_NAME: "Snow", SENSOR_UNIT: LENGTH_MILLIMETERS}, key=ATTR_API_HUMIDITY,
ATTR_API_PRECIPITATION_KIND: {SENSOR_NAME: "Precipitation kind"}, name="Humidity",
ATTR_API_UV_INDEX: { native_unit_of_measurement=PERCENTAGE,
SENSOR_NAME: "UV Index", device_class=DEVICE_CLASS_HUMIDITY,
SENSOR_UNIT: UV_INDEX, ),
}, SensorEntityDescription(
ATTR_API_CONDITION: {SENSOR_NAME: "Condition"}, key=ATTR_API_PRESSURE,
ATTR_API_WEATHER_CODE: {SENSOR_NAME: "Weather Code"}, name="Pressure",
} native_unit_of_measurement=PRESSURE_HPA,
FORECAST_SENSOR_TYPES = { device_class=DEVICE_CLASS_PRESSURE,
ATTR_FORECAST_CONDITION: {SENSOR_NAME: "Condition"}, ),
ATTR_FORECAST_PRECIPITATION: { SensorEntityDescription(
SENSOR_NAME: "Precipitation", key=ATTR_API_CLOUDS,
SENSOR_UNIT: LENGTH_MILLIMETERS, name="Cloud coverage",
}, native_unit_of_measurement=PERCENTAGE,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: { ),
SENSOR_NAME: "Precipitation probability", SensorEntityDescription(
SENSOR_UNIT: PERCENTAGE, key=ATTR_API_RAIN,
}, name="Rain",
ATTR_FORECAST_PRESSURE: { native_unit_of_measurement=LENGTH_MILLIMETERS,
SENSOR_NAME: "Pressure", ),
SENSOR_UNIT: PRESSURE_HPA, SensorEntityDescription(
SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE, key=ATTR_API_SNOW,
}, name="Snow",
ATTR_FORECAST_TEMP: { native_unit_of_measurement=LENGTH_MILLIMETERS,
SENSOR_NAME: "Temperature", ),
SENSOR_UNIT: TEMP_CELSIUS, SensorEntityDescription(
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, key=ATTR_API_PRECIPITATION_KIND,
}, name="Precipitation kind",
ATTR_FORECAST_TEMP_LOW: { ),
SENSOR_NAME: "Temperature Low", SensorEntityDescription(
SENSOR_UNIT: TEMP_CELSIUS, key=ATTR_API_UV_INDEX,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, name="UV Index",
}, native_unit_of_measurement=UV_INDEX,
ATTR_FORECAST_TIME: { ),
SENSOR_NAME: "Time", SensorEntityDescription(
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP, key=ATTR_API_CONDITION,
}, name="Condition",
ATTR_API_WIND_BEARING: {SENSOR_NAME: "Wind bearing", SENSOR_UNIT: DEGREE}, ),
ATTR_API_WIND_SPEED: { SensorEntityDescription(
SENSOR_NAME: "Wind speed", key=ATTR_API_WEATHER_CODE,
SENSOR_UNIT: SPEED_METERS_PER_SECOND, name="Weather Code",
}, ),
ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE}, )
} FORECAST_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_FORECAST_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION,
name="Precipitation",
native_unit_of_measurement=LENGTH_MILLIMETERS,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION_PROBABILITY,
name="Precipitation probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_HPA,
device_class=DEVICE_CLASS_PRESSURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP_LOW,
name="Temperature Low",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TIME,
name="Time",
device_class=DEVICE_CLASS_TIMESTAMP,
),
SensorEntityDescription(
key=ATTR_API_WIND_BEARING,
name="Wind bearing",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=ATTR_API_WIND_SPEED,
name="Wind speed",
native_unit_of_measurement=SPEED_METERS_PER_SECOND,
),
SensorEntityDescription(
key=ATTR_API_CLOUDS,
name="Cloud coverage",
native_unit_of_measurement=PERCENTAGE,
),
)

View file

@ -1,13 +1,19 @@
"""Support for the OpenWeatherMap (OWM) service.""" """Support for the OpenWeatherMap (OWM) service."""
from .abstract_owm_sensor import AbstractOpenWeatherMapSensor from __future__ import annotations
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import ( from .const import (
ATTR_API_FORECAST, ATTR_API_FORECAST,
ATTRIBUTION,
DEFAULT_NAME,
DOMAIN, DOMAIN,
ENTRY_NAME, ENTRY_NAME,
ENTRY_WEATHER_COORDINATOR, ENTRY_WEATHER_COORDINATOR,
FORECAST_MONITORED_CONDITIONS,
FORECAST_SENSOR_TYPES, FORECAST_SENSOR_TYPES,
MONITORED_CONDITIONS, MANUFACTURER,
WEATHER_SENSOR_TYPES, WEATHER_SENSOR_TYPES,
) )
from .weather_update_coordinator import WeatherUpdateCoordinator from .weather_update_coordinator import WeatherUpdateCoordinator
@ -19,37 +25,79 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
name = domain_data[ENTRY_NAME] name = domain_data[ENTRY_NAME]
weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR] weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR]
weather_sensor_types = WEATHER_SENSOR_TYPES entities: list[AbstractOpenWeatherMapSensor] = [
forecast_sensor_types = FORECAST_SENSOR_TYPES
entities = []
for sensor_type in MONITORED_CONDITIONS:
unique_id = f"{config_entry.unique_id}-{sensor_type}"
entities.append(
OpenWeatherMapSensor( OpenWeatherMapSensor(
name, name,
unique_id, f"{config_entry.unique_id}-{description.key}",
sensor_type, description,
weather_sensor_types[sensor_type],
weather_coordinator, weather_coordinator,
) )
) for description in WEATHER_SENSOR_TYPES
]
for sensor_type in FORECAST_MONITORED_CONDITIONS: entities.extend(
unique_id = f"{config_entry.unique_id}-forecast-{sensor_type}" [
entities.append(
OpenWeatherMapForecastSensor( OpenWeatherMapForecastSensor(
f"{name} Forecast", f"{name} Forecast",
unique_id, f"{config_entry.unique_id}-forecast-{description.key}",
sensor_type, description,
forecast_sensor_types[sensor_type],
weather_coordinator, weather_coordinator,
) )
for description in FORECAST_SENSOR_TYPES
]
) )
async_add_entities(entities) async_add_entities(entities)
class AbstractOpenWeatherMapSensor(SensorEntity):
"""Abstract class for an OpenWeatherMap sensor."""
_attr_should_poll = False
_attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
def __init__(
self,
name,
unique_id,
description: SensorEntityDescription,
coordinator: DataUpdateCoordinator,
):
"""Initialize the sensor."""
self.entity_description = description
self._coordinator = coordinator
self._attr_name = f"{name} {description.name}"
self._attr_unique_id = unique_id
split_unique_id = unique_id.split("-")
self._attr_device_info = {
"identifiers": {(DOMAIN, f"{split_unique_id[0]}-{split_unique_id[1]}")},
"name": DEFAULT_NAME,
"manufacturer": MANUFACTURER,
"entry_type": "service",
}
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
@property
def available(self):
"""Return True if entity is available."""
return self._coordinator.last_update_success
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self._coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Get the latest data from OWM and updates the states."""
await self._coordinator.async_request_refresh()
class OpenWeatherMapSensor(AbstractOpenWeatherMapSensor): class OpenWeatherMapSensor(AbstractOpenWeatherMapSensor):
"""Implementation of an OpenWeatherMap sensor.""" """Implementation of an OpenWeatherMap sensor."""
@ -57,20 +105,17 @@ class OpenWeatherMapSensor(AbstractOpenWeatherMapSensor):
self, self,
name, name,
unique_id, unique_id,
sensor_type, description: SensorEntityDescription,
sensor_configuration,
weather_coordinator: WeatherUpdateCoordinator, weather_coordinator: WeatherUpdateCoordinator,
): ):
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__( super().__init__(name, unique_id, description, weather_coordinator)
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
)
self._weather_coordinator = weather_coordinator self._weather_coordinator = weather_coordinator
@property @property
def native_value(self): def native_value(self):
"""Return the state of the device.""" """Return the state of the device."""
return self._weather_coordinator.data.get(self._sensor_type, None) return self._weather_coordinator.data.get(self.entity_description.key, None)
class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor): class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor):
@ -80,14 +125,11 @@ class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor):
self, self,
name, name,
unique_id, unique_id,
sensor_type, description: SensorEntityDescription,
sensor_configuration,
weather_coordinator: WeatherUpdateCoordinator, weather_coordinator: WeatherUpdateCoordinator,
): ):
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__( super().__init__(name, unique_id, description, weather_coordinator)
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
)
self._weather_coordinator = weather_coordinator self._weather_coordinator = weather_coordinator
@property @property
@ -95,5 +137,5 @@ class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor):
"""Return the state of the device.""" """Return the state of the device."""
forecasts = self._weather_coordinator.data.get(ATTR_API_FORECAST) forecasts = self._weather_coordinator.data.get(ATTR_API_FORECAST)
if forecasts is not None and len(forecasts) > 0: if forecasts is not None and len(forecasts) > 0:
return forecasts[0].get(self._sensor_type, None) return forecasts[0].get(self.entity_description.key, None)
return None return None