Use EntityDescription - openweathermap (#56888)

pull/57532/head
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/weather.py
homeassistant/components/openweathermap/weather_update_coordinator.py
homeassistant/components/openweathermap/abstract_owm_sensor.py
homeassistant/components/opnsense/*
homeassistant/components/opple/light.py
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."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.weather import (
ATTR_CONDITION_CLOUDY,
ATTR_CONDITION_EXCEPTIONAL,
@ -21,8 +24,6 @@ from homeassistant.components.weather import (
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
)
from homeassistant.const import (
DEGREE,
@ -65,9 +66,6 @@ ATTR_API_SNOW = "snow"
ATTR_API_UV_INDEX = "uv_index"
ATTR_API_WEATHER_CODE = "weather_code"
ATTR_API_FORECAST = "forecast"
SENSOR_NAME = "sensor_name"
SENSOR_UNIT = "sensor_unit"
SENSOR_DEVICE_CLASS = "sensor_device_class"
UPDATE_LISTENER = "update_listener"
PLATFORMS = ["sensor", "weather"]
@ -84,35 +82,6 @@ FORECAST_MODES = [
]
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 = [
"af",
"al",
@ -194,82 +163,135 @@ CONDITION_CLASSES = {
904,
],
}
WEATHER_SENSOR_TYPES = {
ATTR_API_WEATHER: {SENSOR_NAME: "Weather"},
ATTR_API_DEW_POINT: {
SENSOR_NAME: "Dew Point",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_API_TEMPERATURE: {
SENSOR_NAME: "Temperature",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_API_FEELS_LIKE_TEMPERATURE: {
SENSOR_NAME: "Feels like temperature",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_API_WIND_SPEED: {
SENSOR_NAME: "Wind speed",
SENSOR_UNIT: SPEED_METERS_PER_SECOND,
},
ATTR_API_WIND_BEARING: {SENSOR_NAME: "Wind bearing", SENSOR_UNIT: DEGREE},
ATTR_API_HUMIDITY: {
SENSOR_NAME: "Humidity",
SENSOR_UNIT: PERCENTAGE,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
},
ATTR_API_PRESSURE: {
SENSOR_NAME: "Pressure",
SENSOR_UNIT: PRESSURE_HPA,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
},
ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE},
ATTR_API_RAIN: {SENSOR_NAME: "Rain", SENSOR_UNIT: LENGTH_MILLIMETERS},
ATTR_API_SNOW: {SENSOR_NAME: "Snow", SENSOR_UNIT: LENGTH_MILLIMETERS},
ATTR_API_PRECIPITATION_KIND: {SENSOR_NAME: "Precipitation kind"},
ATTR_API_UV_INDEX: {
SENSOR_NAME: "UV Index",
SENSOR_UNIT: UV_INDEX,
},
ATTR_API_CONDITION: {SENSOR_NAME: "Condition"},
ATTR_API_WEATHER_CODE: {SENSOR_NAME: "Weather Code"},
}
FORECAST_SENSOR_TYPES = {
ATTR_FORECAST_CONDITION: {SENSOR_NAME: "Condition"},
ATTR_FORECAST_PRECIPITATION: {
SENSOR_NAME: "Precipitation",
SENSOR_UNIT: LENGTH_MILLIMETERS,
},
ATTR_FORECAST_PRECIPITATION_PROBABILITY: {
SENSOR_NAME: "Precipitation probability",
SENSOR_UNIT: PERCENTAGE,
},
ATTR_FORECAST_PRESSURE: {
SENSOR_NAME: "Pressure",
SENSOR_UNIT: PRESSURE_HPA,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
},
ATTR_FORECAST_TEMP: {
SENSOR_NAME: "Temperature",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_FORECAST_TEMP_LOW: {
SENSOR_NAME: "Temperature Low",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_FORECAST_TIME: {
SENSOR_NAME: "Time",
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
},
ATTR_API_WIND_BEARING: {SENSOR_NAME: "Wind bearing", SENSOR_UNIT: DEGREE},
ATTR_API_WIND_SPEED: {
SENSOR_NAME: "Wind speed",
SENSOR_UNIT: SPEED_METERS_PER_SECOND,
},
ATTR_API_CLOUDS: {SENSOR_NAME: "Cloud coverage", SENSOR_UNIT: PERCENTAGE},
}
WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_API_WEATHER,
name="Weather",
),
SensorEntityDescription(
key=ATTR_API_DEW_POINT,
name="Dew Point",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_API_TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_API_FEELS_LIKE_TEMPERATURE,
name="Feels like temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_API_WIND_SPEED,
name="Wind speed",
native_unit_of_measurement=SPEED_METERS_PER_SECOND,
),
SensorEntityDescription(
key=ATTR_API_WIND_BEARING,
name="Wind bearing",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=ATTR_API_HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=ATTR_API_PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_HPA,
device_class=DEVICE_CLASS_PRESSURE,
),
SensorEntityDescription(
key=ATTR_API_CLOUDS,
name="Cloud coverage",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_API_RAIN,
name="Rain",
native_unit_of_measurement=LENGTH_MILLIMETERS,
),
SensorEntityDescription(
key=ATTR_API_SNOW,
name="Snow",
native_unit_of_measurement=LENGTH_MILLIMETERS,
),
SensorEntityDescription(
key=ATTR_API_PRECIPITATION_KIND,
name="Precipitation kind",
),
SensorEntityDescription(
key=ATTR_API_UV_INDEX,
name="UV Index",
native_unit_of_measurement=UV_INDEX,
),
SensorEntityDescription(
key=ATTR_API_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_API_WEATHER_CODE,
name="Weather Code",
),
)
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."""
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 (
ATTR_API_FORECAST,
ATTRIBUTION,
DEFAULT_NAME,
DOMAIN,
ENTRY_NAME,
ENTRY_WEATHER_COORDINATOR,
FORECAST_MONITORED_CONDITIONS,
FORECAST_SENSOR_TYPES,
MONITORED_CONDITIONS,
MANUFACTURER,
WEATHER_SENSOR_TYPES,
)
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]
weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR]
weather_sensor_types = WEATHER_SENSOR_TYPES
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(
name,
unique_id,
sensor_type,
weather_sensor_types[sensor_type],
weather_coordinator,
)
entities: list[AbstractOpenWeatherMapSensor] = [
OpenWeatherMapSensor(
name,
f"{config_entry.unique_id}-{description.key}",
description,
weather_coordinator,
)
for description in WEATHER_SENSOR_TYPES
]
for sensor_type in FORECAST_MONITORED_CONDITIONS:
unique_id = f"{config_entry.unique_id}-forecast-{sensor_type}"
entities.append(
entities.extend(
[
OpenWeatherMapForecastSensor(
f"{name} Forecast",
unique_id,
sensor_type,
forecast_sensor_types[sensor_type],
f"{config_entry.unique_id}-forecast-{description.key}",
description,
weather_coordinator,
)
)
for description in FORECAST_SENSOR_TYPES
]
)
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):
"""Implementation of an OpenWeatherMap sensor."""
@ -57,20 +105,17 @@ class OpenWeatherMapSensor(AbstractOpenWeatherMapSensor):
self,
name,
unique_id,
sensor_type,
sensor_configuration,
description: SensorEntityDescription,
weather_coordinator: WeatherUpdateCoordinator,
):
"""Initialize the sensor."""
super().__init__(
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
)
super().__init__(name, unique_id, description, weather_coordinator)
self._weather_coordinator = weather_coordinator
@property
def native_value(self):
"""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):
@ -80,14 +125,11 @@ class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor):
self,
name,
unique_id,
sensor_type,
sensor_configuration,
description: SensorEntityDescription,
weather_coordinator: WeatherUpdateCoordinator,
):
"""Initialize the sensor."""
super().__init__(
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
)
super().__init__(name, unique_id, description, weather_coordinator)
self._weather_coordinator = weather_coordinator
@property
@ -95,5 +137,5 @@ class OpenWeatherMapForecastSensor(AbstractOpenWeatherMapSensor):
"""Return the state of the device."""
forecasts = self._weather_coordinator.data.get(ATTR_API_FORECAST)
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