Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use NamedTuple - nws #53293

Merged
merged 1 commit into from Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
176 changes: 92 additions & 84 deletions homeassistant/components/nws/const.py
@@ -1,5 +1,8 @@
"""Constants for National Weather Service Integration."""
from __future__ import annotations

from datetime import timedelta
from typing import NamedTuple

from homeassistant.components.weather import (
ATTR_CONDITION_CLOUDY,
Expand All @@ -17,7 +20,6 @@
ATTR_CONDITION_WINDY_VARIANT,
)
from homeassistant.const import (
ATTR_DEVICE_CLASS,
DEGREE,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PRESSURE,
Expand All @@ -40,11 +42,6 @@

ATTR_FORECAST_DETAILED_DESCRIPTION = "detailed_description"
ATTR_FORECAST_DAYTIME = "daytime"
ATTR_ICON = "icon"
ATTR_LABEL = "label"
ATTR_UNIT = "unit"
ATTR_UNIT_CONVERT = "unit_convert"
ATTR_UNIT_CONVERT_METHOD = "unit_convert_method"

CONDITION_CLASSES = {
ATTR_CONDITION_EXCEPTIONAL: [
Expand Down Expand Up @@ -101,82 +98,93 @@
OBSERVATION_VALID_TIME = timedelta(minutes=20)
FORECAST_VALID_TIME = timedelta(minutes=45)

SENSOR_TYPES = {
"dewpoint": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ATTR_ICON: None,
ATTR_LABEL: "Dew Point",
ATTR_UNIT: TEMP_CELSIUS,
ATTR_UNIT_CONVERT: TEMP_CELSIUS,
},
"temperature": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ATTR_ICON: None,
ATTR_LABEL: "Temperature",
ATTR_UNIT: TEMP_CELSIUS,
ATTR_UNIT_CONVERT: TEMP_CELSIUS,
},
"windChill": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ATTR_ICON: None,
ATTR_LABEL: "Wind Chill",
ATTR_UNIT: TEMP_CELSIUS,
ATTR_UNIT_CONVERT: TEMP_CELSIUS,
},
"heatIndex": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ATTR_ICON: None,
ATTR_LABEL: "Heat Index",
ATTR_UNIT: TEMP_CELSIUS,
ATTR_UNIT_CONVERT: TEMP_CELSIUS,
},
"relativeHumidity": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
ATTR_ICON: None,
ATTR_LABEL: "Relative Humidity",
ATTR_UNIT: PERCENTAGE,
ATTR_UNIT_CONVERT: PERCENTAGE,
},
"windSpeed": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-windy",
ATTR_LABEL: "Wind Speed",
ATTR_UNIT: SPEED_KILOMETERS_PER_HOUR,
ATTR_UNIT_CONVERT: SPEED_MILES_PER_HOUR,
},
"windGust": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:weather-windy",
ATTR_LABEL: "Wind Gust",
ATTR_UNIT: SPEED_KILOMETERS_PER_HOUR,
ATTR_UNIT_CONVERT: SPEED_MILES_PER_HOUR,
},
"windDirection": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:compass-rose",
ATTR_LABEL: "Wind Direction",
ATTR_UNIT: DEGREE,
ATTR_UNIT_CONVERT: DEGREE,
},
"barometricPressure": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
ATTR_ICON: None,
ATTR_LABEL: "Barometric Pressure",
ATTR_UNIT: PRESSURE_PA,
ATTR_UNIT_CONVERT: PRESSURE_INHG,
},
"seaLevelPressure": {
ATTR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
ATTR_ICON: None,
ATTR_LABEL: "Sea Level Pressure",
ATTR_UNIT: PRESSURE_PA,
ATTR_UNIT_CONVERT: PRESSURE_INHG,
},
"visibility": {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:eye",
ATTR_LABEL: "Visibility",
ATTR_UNIT: LENGTH_METERS,
ATTR_UNIT_CONVERT: LENGTH_MILES,
},

class NWSSensorMetadata(NamedTuple):
cdce8p marked this conversation as resolved.
Show resolved Hide resolved
"""Sensor metadata for an individual NWS sensor."""

label: str
icon: str | None
device_class: str | None
unit: str
unit_convert: str


SENSOR_TYPES: dict[str, NWSSensorMetadata] = {
"dewpoint": NWSSensorMetadata(
"Dew Point",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"temperature": NWSSensorMetadata(
"Temperature",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"windChill": NWSSensorMetadata(
"Wind Chill",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"heatIndex": NWSSensorMetadata(
"Heat Index",
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
unit=TEMP_CELSIUS,
unit_convert=TEMP_CELSIUS,
),
"relativeHumidity": NWSSensorMetadata(
"Relative Humidity",
icon=None,
device_class=DEVICE_CLASS_HUMIDITY,
unit=PERCENTAGE,
unit_convert=PERCENTAGE,
),
"windSpeed": NWSSensorMetadata(
"Wind Speed",
icon="mdi:weather-windy",
device_class=None,
unit=SPEED_KILOMETERS_PER_HOUR,
unit_convert=SPEED_MILES_PER_HOUR,
),
"windGust": NWSSensorMetadata(
"Wind Gust",
icon="mdi:weather-windy",
device_class=None,
unit=SPEED_KILOMETERS_PER_HOUR,
unit_convert=SPEED_MILES_PER_HOUR,
),
"windDirection": NWSSensorMetadata(
"Wind Direction",
icon="mdi:compass-rose",
device_class=None,
unit=DEGREE,
unit_convert=DEGREE,
),
"barometricPressure": NWSSensorMetadata(
"Barometric Pressure",
icon=None,
device_class=DEVICE_CLASS_PRESSURE,
unit=PRESSURE_PA,
unit_convert=PRESSURE_INHG,
),
"seaLevelPressure": NWSSensorMetadata(
"Sea Level Pressure",
icon=None,
device_class=DEVICE_CLASS_PRESSURE,
unit=PRESSURE_PA,
unit_convert=PRESSURE_INHG,
),
"visibility": NWSSensorMetadata(
"Visibility",
icon="mdi:eye",
device_class=None,
unit=LENGTH_METERS,
unit_convert=LENGTH_MILES,
),
}
69 changes: 21 additions & 48 deletions homeassistant/components/nws/sensor.py
Expand Up @@ -2,7 +2,6 @@
from homeassistant.components.sensor import SensorEntity
from homeassistant.const import (
ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS,
CONF_LATITUDE,
CONF_LONGITUDE,
LENGTH_KILOMETERS,
Expand All @@ -14,24 +13,22 @@
SPEED_MILES_PER_HOUR,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.distance import convert as convert_distance
from homeassistant.util.dt import utcnow
from homeassistant.util.pressure import convert as convert_pressure

from . import base_unique_id
from .const import (
ATTR_ICON,
ATTR_LABEL,
ATTR_UNIT,
ATTR_UNIT_CONVERT,
ATTRIBUTION,
CONF_STATION,
COORDINATOR_OBSERVATION,
DOMAIN,
NWS_DATA,
OBSERVATION_VALID_TIME,
SENSOR_TYPES,
NWSSensorMetadata,
)

PARALLEL_UPDATES = 0
Expand All @@ -43,21 +40,15 @@ async def async_setup_entry(hass, entry, async_add_entities):
station = entry.data[CONF_STATION]

entities = []
for sensor_type, sensor_data in SENSOR_TYPES.items():
if hass.config.units.is_metric:
unit = sensor_data[ATTR_UNIT]
else:
unit = sensor_data[ATTR_UNIT_CONVERT]
for sensor_type, metadata in SENSOR_TYPES.items():
entities.append(
NWSSensor(
hass,
entry.data,
hass_data,
sensor_type,
metadata,
station,
sensor_data[ATTR_LABEL],
sensor_data[ATTR_ICON],
sensor_data[ATTR_DEVICE_CLASS],
unit,
),
)

Expand All @@ -69,70 +60,52 @@ class NWSSensor(CoordinatorEntity, SensorEntity):

def __init__(
self,
hass: HomeAssistant,
entry_data,
hass_data,
sensor_type,
metadata: NWSSensorMetadata,
station,
label,
icon,
device_class,
unit,
):
"""Initialise the platform with a data instance."""
super().__init__(hass_data[COORDINATOR_OBSERVATION])
self._nws = hass_data[NWS_DATA]
self._latitude = entry_data[CONF_LATITUDE]
self._longitude = entry_data[CONF_LONGITUDE]
self._type = sensor_type
self._station = station
self._label = label
self._icon = icon
self._device_class = device_class
self._unit = unit
self._metadata = metadata

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

@property
def state(self):
"""Return the state."""
value = self._nws.observation.get(self._type)
if value is None:
return None
if self._unit == SPEED_MILES_PER_HOUR:
if self._attr_unit_of_measurement == SPEED_MILES_PER_HOUR:
return round(convert_distance(value, LENGTH_KILOMETERS, LENGTH_MILES))
if self._unit == LENGTH_MILES:
if self._attr_unit_of_measurement == LENGTH_MILES:
return round(convert_distance(value, LENGTH_METERS, LENGTH_MILES))
if self._unit == PRESSURE_INHG:
if self._attr_unit_of_measurement == PRESSURE_INHG:
return round(convert_pressure(value, PRESSURE_PA, PRESSURE_INHG), 2)
if self._unit == TEMP_CELSIUS:
if self._attr_unit_of_measurement == TEMP_CELSIUS:
return round(value, 1)
if self._unit == PERCENTAGE:
if self._attr_unit_of_measurement == PERCENTAGE:
return round(value)
return value

@property
def icon(self):
"""Return the icon."""
return self._icon

@property
def device_class(self):
"""Return the device class."""
return self._device_class

@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit

@property
def device_state_attributes(self):
"""Return the attribution."""
return {ATTR_ATTRIBUTION: ATTRIBUTION}

@property
def name(self):
"""Return the name of the station."""
return f"{self._station} {self._label}"

@property
def unique_id(self):
"""Return a unique_id for this entity."""
Expand Down