Use EntityDescription - nws (#53523)

* Use EntityDescription - nws

* Bugfix

* Bugfix 2
pull/53534/head
Marc Mueller 2021-07-27 01:46:01 +02:00 committed by GitHub
parent 6376b4be5c
commit 3e08e50050
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 91 additions and 86 deletions

View File

@ -1,9 +1,10 @@
"""Constants for National Weather Service Integration."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from typing import NamedTuple
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.weather import (
ATTR_CONDITION_CLOUDY,
ATTR_CONDITION_EXCEPTIONAL,
@ -99,92 +100,100 @@ OBSERVATION_VALID_TIME = timedelta(minutes=20)
FORECAST_VALID_TIME = timedelta(minutes=45)
class NWSSensorMetadata(NamedTuple):
"""Sensor metadata for an individual NWS sensor."""
@dataclass
class NWSSensorEntityDescription(SensorEntityDescription):
"""Class describing NWSSensor entities."""
label: str
icon: str | None
device_class: str | None
unit: str
unit_convert: str
unit_convert: str | None = None
SENSOR_TYPES: dict[str, NWSSensorMetadata] = {
"dewpoint": NWSSensorMetadata(
"Dew Point",
SENSOR_TYPES: tuple[NWSSensorEntityDescription, ...] = (
NWSSensorEntityDescription(
key="dewpoint",
name="Dew Point",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_of_measurement=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"temperature": NWSSensorMetadata(
"Temperature",
NWSSensorEntityDescription(
key="temperature",
name="Temperature",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_of_measurement=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"windChill": NWSSensorMetadata(
"Wind Chill",
NWSSensorEntityDescription(
key="windChill",
name="Wind Chill",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_of_measurement=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"heatIndex": NWSSensorMetadata(
"Heat Index",
NWSSensorEntityDescription(
key="heatIndex",
name="Heat Index",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_of_measurement=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"relativeHumidity": NWSSensorMetadata(
"Relative Humidity",
NWSSensorEntityDescription(
key="relativeHumidity",
name="Relative Humidity",
icon=None,
device_class=DEVICE_CLASS_HUMIDITY,
unit=PERCENTAGE,
unit_of_measurement=PERCENTAGE,
unit_convert=PERCENTAGE,
),
"windSpeed": NWSSensorMetadata(
"Wind Speed",
NWSSensorEntityDescription(
key="windSpeed",
name="Wind Speed",
icon="mdi:weather-windy",
device_class=None,
unit=SPEED_KILOMETERS_PER_HOUR,
unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
unit_convert=SPEED_MILES_PER_HOUR,
),
"windGust": NWSSensorMetadata(
"Wind Gust",
NWSSensorEntityDescription(
key="windGust",
name="Wind Gust",
icon="mdi:weather-windy",
device_class=None,
unit=SPEED_KILOMETERS_PER_HOUR,
unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
unit_convert=SPEED_MILES_PER_HOUR,
),
"windDirection": NWSSensorMetadata(
"Wind Direction",
NWSSensorEntityDescription(
key="windDirection",
name="Wind Direction",
icon="mdi:compass-rose",
device_class=None,
unit=DEGREE,
unit_of_measurement=DEGREE,
unit_convert=DEGREE,
),
"barometricPressure": NWSSensorMetadata(
"Barometric Pressure",
NWSSensorEntityDescription(
key="barometricPressure",
name="Barometric Pressure",
icon=None,
device_class=DEVICE_CLASS_PRESSURE,
unit=PRESSURE_PA,
unit_of_measurement=PRESSURE_PA,
unit_convert=PRESSURE_INHG,
),
"seaLevelPressure": NWSSensorMetadata(
"Sea Level Pressure",
NWSSensorEntityDescription(
key="seaLevelPressure",
name="Sea Level Pressure",
icon=None,
device_class=DEVICE_CLASS_PRESSURE,
unit=PRESSURE_PA,
unit_of_measurement=PRESSURE_PA,
unit_convert=PRESSURE_INHG,
),
"visibility": NWSSensorMetadata(
"Visibility",
NWSSensorEntityDescription(
key="visibility",
name="Visibility",
icon="mdi:eye",
device_class=None,
unit=LENGTH_METERS,
unit_of_measurement=LENGTH_METERS,
unit_convert=LENGTH_MILES,
),
}
)

View File

@ -28,7 +28,7 @@ from .const import (
NWS_DATA,
OBSERVATION_VALID_TIME,
SENSOR_TYPES,
NWSSensorMetadata,
NWSSensorEntityDescription,
)
PARALLEL_UPDATES = 0
@ -39,32 +39,29 @@ async def async_setup_entry(hass, entry, async_add_entities):
hass_data = hass.data[DOMAIN][entry.entry_id]
station = entry.data[CONF_STATION]
entities = []
for sensor_type, metadata in SENSOR_TYPES.items():
entities.append(
async_add_entities(
NWSSensor(
hass,
entry.data,
hass_data,
sensor_type,
metadata,
station,
),
hass=hass,
entry_data=entry.data,
hass_data=hass_data,
description=description,
station=station,
)
for description in SENSOR_TYPES
)
async_add_entities(entities, False)
class NWSSensor(CoordinatorEntity, SensorEntity):
"""An NWS Sensor Entity."""
entity_description: NWSSensorEntityDescription
def __init__(
self,
hass: HomeAssistant,
entry_data,
hass_data,
sensor_type,
metadata: NWSSensorMetadata,
description: NWSSensorEntityDescription,
station,
):
"""Initialise the platform with a data instance."""
@ -72,32 +69,29 @@ class NWSSensor(CoordinatorEntity, SensorEntity):
self._nws = hass_data[NWS_DATA]
self._latitude = entry_data[CONF_LATITUDE]
self._longitude = entry_data[CONF_LONGITUDE]
self._type = sensor_type
self._metadata = metadata
self.entity_description = description
self._attr_name = f"{station} {metadata.label}"
self._attr_icon = metadata.icon
self._attr_device_class = metadata.device_class
if hass.config.units.is_metric:
self._attr_unit_of_measurement = metadata.unit
else:
self._attr_unit_of_measurement = metadata.unit_convert
self._attr_name = f"{station} {description.name}"
if not hass.config.units.is_metric:
self._attr_unit_of_measurement = description.unit_convert
@property
def state(self):
"""Return the state."""
value = self._nws.observation.get(self._type)
value = self._nws.observation.get(self.entity_description.key)
if value is None:
return None
if self._attr_unit_of_measurement == SPEED_MILES_PER_HOUR:
# Set alias to unit property -> prevent unnecessary hasattr calls
unit_of_measurement = self.unit_of_measurement
if unit_of_measurement == SPEED_MILES_PER_HOUR:
return round(convert_distance(value, LENGTH_KILOMETERS, LENGTH_MILES))
if self._attr_unit_of_measurement == LENGTH_MILES:
if unit_of_measurement == LENGTH_MILES:
return round(convert_distance(value, LENGTH_METERS, LENGTH_MILES))
if self._attr_unit_of_measurement == PRESSURE_INHG:
if unit_of_measurement == PRESSURE_INHG:
return round(convert_pressure(value, PRESSURE_PA, PRESSURE_INHG), 2)
if self._attr_unit_of_measurement == TEMP_CELSIUS:
if unit_of_measurement == TEMP_CELSIUS:
return round(value, 1)
if self._attr_unit_of_measurement == PERCENTAGE:
if unit_of_measurement == PERCENTAGE:
return round(value)
return value
@ -109,7 +103,7 @@ class NWSSensor(CoordinatorEntity, SensorEntity):
@property
def unique_id(self):
"""Return a unique_id for this entity."""
return f"{base_unique_id(self._latitude, self._longitude)}_{self._type}"
return f"{base_unique_id(self._latitude, self._longitude)}_{self.entity_description.key}"
@property
def available(self):

View File

@ -35,12 +35,12 @@ async def test_imperial_metric(
"""Test with imperial and metric units."""
registry = await hass.helpers.entity_registry.async_get_registry()
for sensor_name, metadata in SENSOR_TYPES.items():
for description in SENSOR_TYPES:
registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
f"35_-75_{sensor_name}",
suggested_object_id=f"abc_{metadata.label}",
f"35_-75_{description.key}",
suggested_object_id=f"abc_{description.name}",
disabled_by=None,
)
@ -53,10 +53,11 @@ async def test_imperial_metric(
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
for sensor_name, metadata in SENSOR_TYPES.items():
state = hass.states.get(f"sensor.abc_{slugify(metadata.label)}")
for description in SENSOR_TYPES:
assert description.name
state = hass.states.get(f"sensor.abc_{slugify(description.name)}")
assert state
assert state.state == result_observation[sensor_name]
assert state.state == result_observation[description.key]
assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION
@ -67,12 +68,12 @@ async def test_none_values(hass, mock_simple_nws, no_weather):
registry = await hass.helpers.entity_registry.async_get_registry()
for sensor_name, metadata in SENSOR_TYPES.items():
for description in SENSOR_TYPES:
registry.async_get_or_create(
SENSOR_DOMAIN,
DOMAIN,
f"35_-75_{sensor_name}",
suggested_object_id=f"abc_{metadata.label}",
f"35_-75_{description.key}",
suggested_object_id=f"abc_{description.name}",
disabled_by=None,
)
@ -84,7 +85,8 @@ async def test_none_values(hass, mock_simple_nws, no_weather):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
for sensor_name, metadata in SENSOR_TYPES.items():
state = hass.states.get(f"sensor.abc_{slugify(metadata.label)}")
for description in SENSOR_TYPES:
assert description.name
state = hass.states.get(f"sensor.abc_{slugify(description.name)}")
assert state
assert state.state == STATE_UNKNOWN