2019-04-03 15:40:03 +00:00
|
|
|
"""Support for WUnderground weather service."""
|
2018-02-16 22:54:11 +00:00
|
|
|
import asyncio
|
2016-08-17 19:06:12 +00:00
|
|
|
from datetime import timedelta
|
|
|
|
import logging
|
2016-11-25 20:03:12 +00:00
|
|
|
import re
|
2019-08-04 15:05:43 +00:00
|
|
|
from typing import Any, Callable, Optional, Union
|
2018-02-16 22:54:11 +00:00
|
|
|
|
|
|
|
import aiohttp
|
|
|
|
import async_timeout
|
2016-08-18 04:18:37 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2018-03-17 12:14:53 +00:00
|
|
|
from homeassistant.components import sensor
|
2018-05-02 18:23:07 +00:00
|
|
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
2016-08-20 22:40:16 +00:00
|
|
|
from homeassistant.const import (
|
2019-12-09 13:47:53 +00:00
|
|
|
ATTR_ATTRIBUTION,
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_API_KEY,
|
|
|
|
CONF_LATITUDE,
|
|
|
|
CONF_LONGITUDE,
|
2019-12-09 13:47:53 +00:00
|
|
|
CONF_MONITORED_CONDITIONS,
|
2020-02-25 01:52:14 +00:00
|
|
|
IRRADIATION_WATTS_PER_SQUARE_METER,
|
2019-12-09 13:47:53 +00:00
|
|
|
LENGTH_FEET,
|
2019-07-31 19:25:30 +00:00
|
|
|
LENGTH_INCHES,
|
|
|
|
LENGTH_KILOMETERS,
|
|
|
|
LENGTH_MILES,
|
2020-02-25 01:52:14 +00:00
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
2019-12-09 13:47:53 +00:00
|
|
|
TEMP_CELSIUS,
|
|
|
|
TEMP_FAHRENHEIT,
|
2020-04-11 14:54:11 +00:00
|
|
|
UNIT_DEGREE,
|
2020-02-28 19:46:48 +00:00
|
|
|
UNIT_PERCENTAGE,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2017-11-25 20:19:52 +00:00
|
|
|
from homeassistant.exceptions import PlatformNotReady
|
2018-02-16 22:54:11 +00:00
|
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
2016-10-11 07:28:19 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2019-12-09 13:47:53 +00:00
|
|
|
from homeassistant.helpers.entity import Entity
|
|
|
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
|
|
|
from homeassistant.util import Throttle
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
_RESOURCE = "http://api.wunderground.com/api/{}/{}/{}/q/"
|
2016-08-17 19:06:12 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-02-14 21:09:22 +00:00
|
|
|
ATTRIBUTION = "Data provided by the WUnderground weather service"
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_PWS_ID = "pws_id"
|
|
|
|
CONF_LANG = "lang"
|
2016-12-11 23:43:42 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_LANG = "EN"
|
2016-08-20 22:40:16 +00:00
|
|
|
|
2017-05-06 17:11:31 +00:00
|
|
|
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)
|
|
|
|
|
|
|
|
|
|
|
|
# Helper classes for declaring sensor configurations
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2018-07-20 08:45:20 +00:00
|
|
|
class WUSensorConfig:
|
2017-05-06 17:11:31 +00:00
|
|
|
"""WU Sensor Configuration.
|
|
|
|
|
|
|
|
defines basic HA properties of the weather sensor and
|
|
|
|
stores callbacks that can parse sensor values out of
|
|
|
|
the json data received by WU API.
|
|
|
|
"""
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2019-08-04 15:05:43 +00:00
|
|
|
friendly_name: Union[str, Callable],
|
|
|
|
feature: str,
|
|
|
|
value: Callable[["WUndergroundData"], Any],
|
|
|
|
unit_of_measurement: Optional[str] = None,
|
2019-07-31 19:25:30 +00:00
|
|
|
entity_picture=None,
|
2019-08-04 15:05:43 +00:00
|
|
|
icon: str = "mdi:gauge",
|
2019-07-31 19:25:30 +00:00
|
|
|
device_state_attributes=None,
|
|
|
|
device_class=None,
|
|
|
|
):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param friendly_name: Friendly name
|
|
|
|
:param feature: WU feature. See:
|
2017-05-06 17:11:31 +00:00
|
|
|
https://www.wunderground.com/weather/api/d/docs?d=data/index
|
2019-08-04 15:05:43 +00:00
|
|
|
:param value: callback that extracts desired value from WUndergroundData object
|
|
|
|
:param unit_of_measurement: unit of measurement
|
|
|
|
:param entity_picture: value or callback returning URL of entity picture
|
|
|
|
:param icon: icon name or URL
|
|
|
|
:param device_state_attributes: dictionary of attributes, or callable that returns it
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
self.friendly_name = friendly_name
|
|
|
|
self.unit_of_measurement = unit_of_measurement
|
|
|
|
self.feature = feature
|
|
|
|
self.value = value
|
|
|
|
self.entity_picture = entity_picture
|
|
|
|
self.icon = icon
|
|
|
|
self.device_state_attributes = device_state_attributes or {}
|
2018-11-01 13:10:43 +00:00
|
|
|
self.device_class = device_class
|
2017-05-06 17:11:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
class WUCurrentConditionsSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining sensor configurations for current conditions."""
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2019-08-04 15:05:43 +00:00
|
|
|
friendly_name: Union[str, Callable],
|
|
|
|
field: str,
|
|
|
|
icon: Optional[str] = "mdi:gauge",
|
|
|
|
unit_of_measurement: Optional[str] = None,
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class=None,
|
|
|
|
):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize current conditions sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param friendly_name: Friendly name of sensor
|
|
|
|
:field: Field name in the "current_observation" dictionary.
|
|
|
|
:icon: icon name or URL, if None sensor will use current weather symbol
|
|
|
|
:unit_of_measurement: unit of measurement
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
|
|
|
friendly_name,
|
|
|
|
"conditions",
|
2019-07-31 19:25:30 +00:00
|
|
|
value=lambda wu: wu.data["current_observation"][field],
|
2017-05-06 17:11:31 +00:00
|
|
|
icon=icon,
|
|
|
|
unit_of_measurement=unit_of_measurement,
|
2019-07-31 19:25:30 +00:00
|
|
|
entity_picture=lambda wu: wu.data["current_observation"]["icon_url"]
|
|
|
|
if icon is None
|
|
|
|
else None,
|
2017-05-06 17:11:31 +00:00
|
|
|
device_state_attributes={
|
2019-07-31 19:25:30 +00:00
|
|
|
"date": lambda wu: wu.data["current_observation"]["observation_time"]
|
2018-11-01 13:10:43 +00:00
|
|
|
},
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class=device_class,
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class WUDailyTextForecastSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining sensor configurations for daily text forecasts."""
|
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
def __init__(
|
|
|
|
self, period: int, field: str, unit_of_measurement: Optional[str] = None
|
|
|
|
):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize daily text forecast sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param period: forecast period number
|
|
|
|
:param field: field name to use as value
|
|
|
|
:param unit_of_measurement: unit of measurement
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
2019-07-31 19:25:30 +00:00
|
|
|
friendly_name=lambda wu: wu.data["forecast"]["txt_forecast"]["forecastday"][
|
|
|
|
period
|
|
|
|
]["title"],
|
|
|
|
feature="forecast",
|
|
|
|
value=lambda wu: wu.data["forecast"]["txt_forecast"]["forecastday"][period][
|
|
|
|
field
|
|
|
|
],
|
|
|
|
entity_picture=lambda wu: wu.data["forecast"]["txt_forecast"][
|
|
|
|
"forecastday"
|
|
|
|
][period]["icon_url"],
|
2017-05-06 17:11:31 +00:00
|
|
|
unit_of_measurement=unit_of_measurement,
|
|
|
|
device_state_attributes={
|
2019-07-31 19:25:30 +00:00
|
|
|
"date": lambda wu: wu.data["forecast"]["txt_forecast"]["date"]
|
|
|
|
},
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class WUDailySimpleForecastSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining sensor configurations for daily simpleforecasts."""
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2019-08-04 15:05:43 +00:00
|
|
|
friendly_name: str,
|
|
|
|
period: int,
|
|
|
|
field: str,
|
|
|
|
wu_unit: Optional[str] = None,
|
|
|
|
ha_unit: Optional[str] = None,
|
2019-07-31 19:25:30 +00:00
|
|
|
icon=None,
|
|
|
|
device_class=None,
|
|
|
|
):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize daily simple forecast sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param friendly_name: friendly_name of the sensor
|
|
|
|
:param period: forecast period number
|
|
|
|
:param field: field name to use as value
|
|
|
|
:param wu_unit: "fahrenheit", "celsius", "degrees" etc. see the example json at:
|
|
|
|
https://www.wunderground.com/weather/api/d/docs?d=data/forecast&MR=1
|
2020-01-05 12:09:17 +00:00
|
|
|
:param ha_unit: corresponding unit in Home Assistant
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
|
|
|
friendly_name=friendly_name,
|
2019-07-31 19:25:30 +00:00
|
|
|
feature="forecast",
|
|
|
|
value=(
|
|
|
|
lambda wu: wu.data["forecast"]["simpleforecast"]["forecastday"][period][
|
|
|
|
field
|
|
|
|
][wu_unit]
|
|
|
|
)
|
|
|
|
if wu_unit
|
|
|
|
else (
|
|
|
|
lambda wu: wu.data["forecast"]["simpleforecast"]["forecastday"][period][
|
|
|
|
field
|
|
|
|
]
|
|
|
|
),
|
2017-05-06 17:11:31 +00:00
|
|
|
unit_of_measurement=ha_unit,
|
2019-07-31 19:25:30 +00:00
|
|
|
entity_picture=lambda wu: wu.data["forecast"]["simpleforecast"][
|
|
|
|
"forecastday"
|
|
|
|
][period]["icon_url"]
|
|
|
|
if not icon
|
|
|
|
else None,
|
2017-05-06 17:11:31 +00:00
|
|
|
icon=icon,
|
|
|
|
device_state_attributes={
|
2019-07-31 19:25:30 +00:00
|
|
|
"date": lambda wu: wu.data["forecast"]["simpleforecast"]["forecastday"][
|
|
|
|
period
|
|
|
|
]["date"]["pretty"]
|
2018-11-01 13:10:43 +00:00
|
|
|
},
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class=device_class,
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class WUHourlyForecastSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining sensor configurations for hourly text forecasts."""
|
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
def __init__(self, period: int, field: int):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize hourly forecast sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param period: forecast period number
|
|
|
|
:param field: field name to use as value
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
2020-04-05 15:48:55 +00:00
|
|
|
friendly_name=lambda wu: (
|
|
|
|
f"{wu.data['hourly_forecast'][period]['FCTTIME']['weekday_name_abbrev']} "
|
|
|
|
f"{wu.data['hourly_forecast'][period]['FCTTIME']['civil']}"
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
feature="hourly",
|
|
|
|
value=lambda wu: wu.data["hourly_forecast"][period][field],
|
|
|
|
entity_picture=lambda wu: wu.data["hourly_forecast"][period]["icon_url"],
|
2017-05-06 17:11:31 +00:00
|
|
|
device_state_attributes={
|
2019-07-31 19:25:30 +00:00
|
|
|
"temp_c": lambda wu: wu.data["hourly_forecast"][period]["temp"][
|
|
|
|
"metric"
|
|
|
|
],
|
|
|
|
"temp_f": lambda wu: wu.data["hourly_forecast"][period]["temp"][
|
|
|
|
"english"
|
|
|
|
],
|
|
|
|
"dewpoint_c": lambda wu: wu.data["hourly_forecast"][period]["dewpoint"][
|
|
|
|
"metric"
|
|
|
|
],
|
|
|
|
"dewpoint_f": lambda wu: wu.data["hourly_forecast"][period]["dewpoint"][
|
|
|
|
"english"
|
|
|
|
],
|
|
|
|
"precip_prop": lambda wu: wu.data["hourly_forecast"][period]["pop"],
|
|
|
|
"sky": lambda wu: wu.data["hourly_forecast"][period]["sky"],
|
|
|
|
"precip_mm": lambda wu: wu.data["hourly_forecast"][period]["qpf"][
|
|
|
|
"metric"
|
|
|
|
],
|
|
|
|
"precip_in": lambda wu: wu.data["hourly_forecast"][period]["qpf"][
|
|
|
|
"english"
|
|
|
|
],
|
|
|
|
"humidity": lambda wu: wu.data["hourly_forecast"][period]["humidity"],
|
|
|
|
"wind_kph": lambda wu: wu.data["hourly_forecast"][period]["wspd"][
|
|
|
|
"metric"
|
|
|
|
],
|
|
|
|
"wind_mph": lambda wu: wu.data["hourly_forecast"][period]["wspd"][
|
|
|
|
"english"
|
|
|
|
],
|
|
|
|
"pressure_mb": lambda wu: wu.data["hourly_forecast"][period]["mslp"][
|
|
|
|
"metric"
|
|
|
|
],
|
|
|
|
"pressure_inHg": lambda wu: wu.data["hourly_forecast"][period]["mslp"][
|
|
|
|
"english"
|
|
|
|
],
|
|
|
|
"date": lambda wu: wu.data["hourly_forecast"][period]["FCTTIME"][
|
|
|
|
"pretty"
|
|
|
|
],
|
|
|
|
},
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class WUAlmanacSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining field configurations for almanac sensors."""
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2019-08-04 15:05:43 +00:00
|
|
|
friendly_name: Union[str, Callable],
|
|
|
|
field: str,
|
|
|
|
value_type: str,
|
|
|
|
wu_unit: str,
|
|
|
|
unit_of_measurement: str,
|
|
|
|
icon: str,
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class=None,
|
|
|
|
):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialize almanac sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param friendly_name: Friendly name
|
|
|
|
:param field: value name returned in 'almanac' dict as returned by the WU API
|
|
|
|
:param value_type: "record" or "normal"
|
|
|
|
:param wu_unit: unit name in WU API
|
|
|
|
:param unit_of_measurement: unit of measurement
|
|
|
|
:param icon: icon name or URL
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
|
|
|
friendly_name=friendly_name,
|
|
|
|
feature="almanac",
|
2019-07-31 19:25:30 +00:00
|
|
|
value=lambda wu: wu.data["almanac"][field][value_type][wu_unit],
|
2017-05-06 17:11:31 +00:00
|
|
|
unit_of_measurement=unit_of_measurement,
|
2018-11-01 13:10:43 +00:00
|
|
|
icon=icon,
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class="temperature",
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class WUAlertsSensorConfig(WUSensorConfig):
|
|
|
|
"""Helper for defining field configuration for alerts."""
|
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
def __init__(self, friendly_name: Union[str, Callable]):
|
2019-12-10 22:25:06 +00:00
|
|
|
"""Initialiize alerts sensor configuration.
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2019-08-04 15:05:43 +00:00
|
|
|
:param friendly_name: Friendly name
|
2017-05-06 17:11:31 +00:00
|
|
|
"""
|
|
|
|
super().__init__(
|
|
|
|
friendly_name=friendly_name,
|
|
|
|
feature="alerts",
|
2019-07-31 19:25:30 +00:00
|
|
|
value=lambda wu: len(wu.data["alerts"]),
|
2017-05-06 17:11:31 +00:00
|
|
|
icon=lambda wu: "mdi:alert-circle-outline"
|
2019-07-31 19:25:30 +00:00
|
|
|
if wu.data["alerts"]
|
|
|
|
else "mdi:check-circle-outline",
|
|
|
|
device_state_attributes=self._get_attributes,
|
2017-05-06 17:11:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _get_attributes(rest):
|
|
|
|
|
|
|
|
attrs = {}
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
if "alerts" not in rest.data:
|
2017-05-06 17:11:31 +00:00
|
|
|
return attrs
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
alerts = rest.data["alerts"]
|
2017-05-06 17:11:31 +00:00
|
|
|
multiple_alerts = len(alerts) > 1
|
|
|
|
for data in alerts:
|
|
|
|
for alert in ALERTS_ATTRS:
|
|
|
|
if data[alert]:
|
|
|
|
if multiple_alerts:
|
2020-04-04 21:09:34 +00:00
|
|
|
dkey = f"{alert.capitalize()}_{data['type']}"
|
2017-05-06 17:11:31 +00:00
|
|
|
else:
|
|
|
|
dkey = alert.capitalize()
|
|
|
|
attrs[dkey] = data[alert]
|
|
|
|
return attrs
|
|
|
|
|
|
|
|
|
|
|
|
# Declaration of supported WU sensors
|
|
|
|
# (see above helper classes for argument explanation)
|
2016-08-17 19:06:12 +00:00
|
|
|
|
|
|
|
SENSOR_TYPES = {
|
2019-07-31 19:25:30 +00:00
|
|
|
"alerts": WUAlertsSensorConfig("Alerts"),
|
|
|
|
"dewpoint_c": WUCurrentConditionsSensorConfig(
|
|
|
|
"Dewpoint", "dewpoint_c", "mdi:water", TEMP_CELSIUS
|
|
|
|
),
|
|
|
|
"dewpoint_f": WUCurrentConditionsSensorConfig(
|
|
|
|
"Dewpoint", "dewpoint_f", "mdi:water", TEMP_FAHRENHEIT
|
|
|
|
),
|
|
|
|
"dewpoint_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Dewpoint Summary", "dewpoint_string", "mdi:water"
|
|
|
|
),
|
|
|
|
"feelslike_c": WUCurrentConditionsSensorConfig(
|
|
|
|
"Feels Like", "feelslike_c", "mdi:thermometer", TEMP_CELSIUS
|
|
|
|
),
|
|
|
|
"feelslike_f": WUCurrentConditionsSensorConfig(
|
|
|
|
"Feels Like", "feelslike_f", "mdi:thermometer", TEMP_FAHRENHEIT
|
|
|
|
),
|
|
|
|
"feelslike_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Feels Like", "feelslike_string", "mdi:thermometer"
|
|
|
|
),
|
|
|
|
"heat_index_c": WUCurrentConditionsSensorConfig(
|
|
|
|
"Heat index", "heat_index_c", "mdi:thermometer", TEMP_CELSIUS
|
|
|
|
),
|
|
|
|
"heat_index_f": WUCurrentConditionsSensorConfig(
|
|
|
|
"Heat index", "heat_index_f", "mdi:thermometer", TEMP_FAHRENHEIT
|
|
|
|
),
|
|
|
|
"heat_index_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Heat Index Summary", "heat_index_string", "mdi:thermometer"
|
|
|
|
),
|
|
|
|
"elevation": WUSensorConfig(
|
|
|
|
"Elevation",
|
|
|
|
"conditions",
|
|
|
|
value=lambda wu: wu.data["current_observation"]["observation_location"][
|
|
|
|
"elevation"
|
|
|
|
].split()[0],
|
2017-05-06 17:11:31 +00:00
|
|
|
unit_of_measurement=LENGTH_FEET,
|
2019-07-31 19:25:30 +00:00
|
|
|
icon="mdi:elevation-rise",
|
|
|
|
),
|
|
|
|
"location": WUSensorConfig(
|
|
|
|
"Location",
|
|
|
|
"conditions",
|
|
|
|
value=lambda wu: wu.data["current_observation"]["display_location"]["full"],
|
|
|
|
icon="mdi:map-marker",
|
|
|
|
),
|
|
|
|
"observation_time": WUCurrentConditionsSensorConfig(
|
|
|
|
"Observation Time", "observation_time", "mdi:clock"
|
|
|
|
),
|
|
|
|
"precip_1hr_in": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation 1hr", "precip_1hr_in", "mdi:umbrella", LENGTH_INCHES
|
|
|
|
),
|
|
|
|
"precip_1hr_metric": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation 1hr", "precip_1hr_metric", "mdi:umbrella", "mm"
|
|
|
|
),
|
|
|
|
"precip_1hr_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation 1hr", "precip_1hr_string", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"precip_today_in": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation Today", "precip_today_in", "mdi:umbrella", LENGTH_INCHES
|
|
|
|
),
|
|
|
|
"precip_today_metric": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation Today", "precip_today_metric", "mdi:umbrella", "mm"
|
|
|
|
),
|
|
|
|
"precip_today_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Precipitation Today", "precip_today_string", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"pressure_in": WUCurrentConditionsSensorConfig(
|
|
|
|
"Pressure", "pressure_in", "mdi:gauge", "inHg", device_class="pressure"
|
|
|
|
),
|
|
|
|
"pressure_mb": WUCurrentConditionsSensorConfig(
|
|
|
|
"Pressure", "pressure_mb", "mdi:gauge", "mb", device_class="pressure"
|
|
|
|
),
|
|
|
|
"pressure_trend": WUCurrentConditionsSensorConfig(
|
|
|
|
"Pressure Trend", "pressure_trend", "mdi:gauge", device_class="pressure"
|
|
|
|
),
|
|
|
|
"relative_humidity": WUSensorConfig(
|
|
|
|
"Relative Humidity",
|
|
|
|
"conditions",
|
|
|
|
value=lambda wu: int(wu.data["current_observation"]["relative_humidity"][:-1]),
|
2020-02-28 19:46:48 +00:00
|
|
|
unit_of_measurement=UNIT_PERCENTAGE,
|
2018-11-01 13:10:43 +00:00
|
|
|
icon="mdi:water-percent",
|
2019-07-31 19:25:30 +00:00
|
|
|
device_class="humidity",
|
|
|
|
),
|
|
|
|
"station_id": WUCurrentConditionsSensorConfig(
|
|
|
|
"Station ID", "station_id", "mdi:home"
|
|
|
|
),
|
|
|
|
"solarradiation": WUCurrentConditionsSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Solar Radiation",
|
|
|
|
"solarradiation",
|
|
|
|
"mdi:weather-sunny",
|
|
|
|
IRRADIATION_WATTS_PER_SQUARE_METER,
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"temperature_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Temperature Summary", "temperature_string", "mdi:thermometer"
|
|
|
|
),
|
|
|
|
"temp_c": WUCurrentConditionsSensorConfig(
|
|
|
|
"Temperature",
|
|
|
|
"temp_c",
|
|
|
|
"mdi:thermometer",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_f": WUCurrentConditionsSensorConfig(
|
|
|
|
"Temperature",
|
|
|
|
"temp_f",
|
|
|
|
"mdi:thermometer",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"UV": WUCurrentConditionsSensorConfig("UV", "UV", "mdi:sunglasses"),
|
|
|
|
"visibility_km": WUCurrentConditionsSensorConfig(
|
|
|
|
"Visibility (km)", "visibility_km", "mdi:eye", LENGTH_KILOMETERS
|
|
|
|
),
|
|
|
|
"visibility_mi": WUCurrentConditionsSensorConfig(
|
|
|
|
"Visibility (miles)", "visibility_mi", "mdi:eye", LENGTH_MILES
|
|
|
|
),
|
|
|
|
"weather": WUCurrentConditionsSensorConfig("Weather Summary", "weather", None),
|
|
|
|
"wind_degrees": WUCurrentConditionsSensorConfig(
|
2020-04-11 14:54:11 +00:00
|
|
|
"Wind Degrees", "wind_degrees", "mdi:weather-windy", UNIT_DEGREE
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_dir": WUCurrentConditionsSensorConfig(
|
|
|
|
"Wind Direction", "wind_dir", "mdi:weather-windy"
|
|
|
|
),
|
|
|
|
"wind_gust_kph": WUCurrentConditionsSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Wind Gust", "wind_gust_kph", "mdi:weather-windy", SPEED_KILOMETERS_PER_HOUR
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_mph": WUCurrentConditionsSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Wind Gust", "wind_gust_mph", "mdi:weather-windy", SPEED_MILES_PER_HOUR
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_kph": WUCurrentConditionsSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Wind Speed", "wind_kph", "mdi:weather-windy", SPEED_KILOMETERS_PER_HOUR
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_mph": WUCurrentConditionsSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Wind Speed", "wind_mph", "mdi:weather-windy", SPEED_MILES_PER_HOUR
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_string": WUCurrentConditionsSensorConfig(
|
|
|
|
"Wind Summary", "wind_string", "mdi:weather-windy"
|
|
|
|
),
|
|
|
|
"temp_high_record_c": WUAlmanacSensorConfig(
|
2020-04-05 15:48:55 +00:00
|
|
|
lambda wu: (
|
|
|
|
f"High Temperature Record "
|
|
|
|
f"({wu.data['almanac']['temp_high']['recordyear']})"
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"temp_high",
|
|
|
|
"record",
|
|
|
|
"C",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_high_record_f": WUAlmanacSensorConfig(
|
2020-04-05 15:48:55 +00:00
|
|
|
lambda wu: (
|
|
|
|
f"High Temperature Record "
|
|
|
|
f"({wu.data['almanac']['temp_high']['recordyear']})"
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"temp_high",
|
|
|
|
"record",
|
|
|
|
"F",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_low_record_c": WUAlmanacSensorConfig(
|
2020-04-05 15:48:55 +00:00
|
|
|
lambda wu: (
|
|
|
|
f"Low Temperature Record "
|
|
|
|
f"({wu.data['almanac']['temp_low']['recordyear']})"
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"temp_low",
|
|
|
|
"record",
|
|
|
|
"C",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_low_record_f": WUAlmanacSensorConfig(
|
2020-04-05 15:48:55 +00:00
|
|
|
lambda wu: (
|
|
|
|
f"Low Temperature Record "
|
|
|
|
f"({wu.data['almanac']['temp_low']['recordyear']})"
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"temp_low",
|
|
|
|
"record",
|
|
|
|
"F",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_low_avg_c": WUAlmanacSensorConfig(
|
|
|
|
"Historic Average of Low Temperatures for Today",
|
|
|
|
"temp_low",
|
|
|
|
"normal",
|
|
|
|
"C",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_low_avg_f": WUAlmanacSensorConfig(
|
|
|
|
"Historic Average of Low Temperatures for Today",
|
|
|
|
"temp_low",
|
|
|
|
"normal",
|
|
|
|
"F",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_high_avg_c": WUAlmanacSensorConfig(
|
|
|
|
"Historic Average of High Temperatures for Today",
|
|
|
|
"temp_high",
|
|
|
|
"normal",
|
|
|
|
"C",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"temp_high_avg_f": WUAlmanacSensorConfig(
|
|
|
|
"Historic Average of High Temperatures for Today",
|
|
|
|
"temp_high",
|
|
|
|
"normal",
|
|
|
|
"F",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
),
|
|
|
|
"weather_1d": WUDailyTextForecastSensorConfig(0, "fcttext"),
|
|
|
|
"weather_1d_metric": WUDailyTextForecastSensorConfig(0, "fcttext_metric"),
|
|
|
|
"weather_1n": WUDailyTextForecastSensorConfig(1, "fcttext"),
|
|
|
|
"weather_1n_metric": WUDailyTextForecastSensorConfig(1, "fcttext_metric"),
|
|
|
|
"weather_2d": WUDailyTextForecastSensorConfig(2, "fcttext"),
|
|
|
|
"weather_2d_metric": WUDailyTextForecastSensorConfig(2, "fcttext_metric"),
|
|
|
|
"weather_2n": WUDailyTextForecastSensorConfig(3, "fcttext"),
|
|
|
|
"weather_2n_metric": WUDailyTextForecastSensorConfig(3, "fcttext_metric"),
|
|
|
|
"weather_3d": WUDailyTextForecastSensorConfig(4, "fcttext"),
|
|
|
|
"weather_3d_metric": WUDailyTextForecastSensorConfig(4, "fcttext_metric"),
|
|
|
|
"weather_3n": WUDailyTextForecastSensorConfig(5, "fcttext"),
|
|
|
|
"weather_3n_metric": WUDailyTextForecastSensorConfig(5, "fcttext_metric"),
|
|
|
|
"weather_4d": WUDailyTextForecastSensorConfig(6, "fcttext"),
|
|
|
|
"weather_4d_metric": WUDailyTextForecastSensorConfig(6, "fcttext_metric"),
|
|
|
|
"weather_4n": WUDailyTextForecastSensorConfig(7, "fcttext"),
|
|
|
|
"weather_4n_metric": WUDailyTextForecastSensorConfig(7, "fcttext_metric"),
|
|
|
|
"weather_1h": WUHourlyForecastSensorConfig(0, "condition"),
|
|
|
|
"weather_2h": WUHourlyForecastSensorConfig(1, "condition"),
|
|
|
|
"weather_3h": WUHourlyForecastSensorConfig(2, "condition"),
|
|
|
|
"weather_4h": WUHourlyForecastSensorConfig(3, "condition"),
|
|
|
|
"weather_5h": WUHourlyForecastSensorConfig(4, "condition"),
|
|
|
|
"weather_6h": WUHourlyForecastSensorConfig(5, "condition"),
|
|
|
|
"weather_7h": WUHourlyForecastSensorConfig(6, "condition"),
|
|
|
|
"weather_8h": WUHourlyForecastSensorConfig(7, "condition"),
|
|
|
|
"weather_9h": WUHourlyForecastSensorConfig(8, "condition"),
|
|
|
|
"weather_10h": WUHourlyForecastSensorConfig(9, "condition"),
|
|
|
|
"weather_11h": WUHourlyForecastSensorConfig(10, "condition"),
|
|
|
|
"weather_12h": WUHourlyForecastSensorConfig(11, "condition"),
|
|
|
|
"weather_13h": WUHourlyForecastSensorConfig(12, "condition"),
|
|
|
|
"weather_14h": WUHourlyForecastSensorConfig(13, "condition"),
|
|
|
|
"weather_15h": WUHourlyForecastSensorConfig(14, "condition"),
|
|
|
|
"weather_16h": WUHourlyForecastSensorConfig(15, "condition"),
|
|
|
|
"weather_17h": WUHourlyForecastSensorConfig(16, "condition"),
|
|
|
|
"weather_18h": WUHourlyForecastSensorConfig(17, "condition"),
|
|
|
|
"weather_19h": WUHourlyForecastSensorConfig(18, "condition"),
|
|
|
|
"weather_20h": WUHourlyForecastSensorConfig(19, "condition"),
|
|
|
|
"weather_21h": WUHourlyForecastSensorConfig(20, "condition"),
|
|
|
|
"weather_22h": WUHourlyForecastSensorConfig(21, "condition"),
|
|
|
|
"weather_23h": WUHourlyForecastSensorConfig(22, "condition"),
|
|
|
|
"weather_24h": WUHourlyForecastSensorConfig(23, "condition"),
|
|
|
|
"weather_25h": WUHourlyForecastSensorConfig(24, "condition"),
|
|
|
|
"weather_26h": WUHourlyForecastSensorConfig(25, "condition"),
|
|
|
|
"weather_27h": WUHourlyForecastSensorConfig(26, "condition"),
|
|
|
|
"weather_28h": WUHourlyForecastSensorConfig(27, "condition"),
|
|
|
|
"weather_29h": WUHourlyForecastSensorConfig(28, "condition"),
|
|
|
|
"weather_30h": WUHourlyForecastSensorConfig(29, "condition"),
|
|
|
|
"weather_31h": WUHourlyForecastSensorConfig(30, "condition"),
|
|
|
|
"weather_32h": WUHourlyForecastSensorConfig(31, "condition"),
|
|
|
|
"weather_33h": WUHourlyForecastSensorConfig(32, "condition"),
|
|
|
|
"weather_34h": WUHourlyForecastSensorConfig(33, "condition"),
|
|
|
|
"weather_35h": WUHourlyForecastSensorConfig(34, "condition"),
|
|
|
|
"weather_36h": WUHourlyForecastSensorConfig(35, "condition"),
|
|
|
|
"temp_high_1d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature Today",
|
|
|
|
0,
|
|
|
|
"high",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_2d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature Tomorrow",
|
|
|
|
1,
|
|
|
|
"high",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_3d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature in 3 Days",
|
|
|
|
2,
|
|
|
|
"high",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_4d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature in 4 Days",
|
|
|
|
3,
|
|
|
|
"high",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_1d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature Today",
|
|
|
|
0,
|
|
|
|
"high",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_2d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature Tomorrow",
|
|
|
|
1,
|
|
|
|
"high",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_3d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature in 3 Days",
|
|
|
|
2,
|
|
|
|
"high",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_high_4d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"High Temperature in 4 Days",
|
|
|
|
3,
|
|
|
|
"high",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_1d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature Today",
|
|
|
|
0,
|
|
|
|
"low",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_2d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature Tomorrow",
|
|
|
|
1,
|
|
|
|
"low",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_3d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature in 3 Days",
|
|
|
|
2,
|
|
|
|
"low",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_4d_c": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature in 4 Days",
|
|
|
|
3,
|
|
|
|
"low",
|
|
|
|
"celsius",
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_1d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature Today",
|
|
|
|
0,
|
|
|
|
"low",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_2d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature Tomorrow",
|
|
|
|
1,
|
|
|
|
"low",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_3d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature in 3 Days",
|
|
|
|
2,
|
|
|
|
"low",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"temp_low_4d_f": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Low Temperature in 4 Days",
|
|
|
|
3,
|
|
|
|
"low",
|
|
|
|
"fahrenheit",
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
"mdi:thermometer",
|
|
|
|
device_class="temperature",
|
|
|
|
),
|
|
|
|
"wind_gust_1d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind Today",
|
|
|
|
0,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_2d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind Tomorrow",
|
|
|
|
1,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_3d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind in 3 Days",
|
|
|
|
2,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_4d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind in 4 Days",
|
|
|
|
3,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_1d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind Today",
|
|
|
|
0,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_2d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind Tomorrow",
|
|
|
|
1,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_3d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind in 3 Days",
|
|
|
|
2,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_gust_4d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Max. Wind in 4 Days",
|
|
|
|
3,
|
|
|
|
"maxwind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_1d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind Today",
|
|
|
|
0,
|
|
|
|
"avewind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_2d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind Tomorrow",
|
|
|
|
1,
|
|
|
|
"avewind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_3d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind in 3 Days",
|
|
|
|
2,
|
|
|
|
"avewind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_4d_kph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind in 4 Days",
|
|
|
|
3,
|
|
|
|
"avewind",
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_1d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind Today",
|
|
|
|
0,
|
|
|
|
"avewind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_2d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind Tomorrow",
|
|
|
|
1,
|
|
|
|
"avewind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_3d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind in 3 Days",
|
|
|
|
2,
|
|
|
|
"avewind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"wind_4d_mph": WUDailySimpleForecastSensorConfig(
|
2020-02-25 01:52:14 +00:00
|
|
|
"Avg. Wind in 4 Days",
|
|
|
|
3,
|
|
|
|
"avewind",
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
SPEED_MILES_PER_HOUR,
|
|
|
|
"mdi:weather-windy",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"precip_1d_mm": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity Today", 0, "qpf_allday", "mm", "mm", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"precip_2d_mm": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity Tomorrow", 1, "qpf_allday", "mm", "mm", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"precip_3d_mm": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity in 3 Days", 2, "qpf_allday", "mm", "mm", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"precip_4d_mm": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity in 4 Days", 3, "qpf_allday", "mm", "mm", "mdi:umbrella"
|
|
|
|
),
|
|
|
|
"precip_1d_in": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity Today",
|
|
|
|
0,
|
|
|
|
"qpf_allday",
|
|
|
|
"in",
|
|
|
|
LENGTH_INCHES,
|
|
|
|
"mdi:umbrella",
|
|
|
|
),
|
|
|
|
"precip_2d_in": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity Tomorrow",
|
|
|
|
1,
|
|
|
|
"qpf_allday",
|
|
|
|
"in",
|
|
|
|
LENGTH_INCHES,
|
|
|
|
"mdi:umbrella",
|
|
|
|
),
|
|
|
|
"precip_3d_in": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity in 3 Days",
|
|
|
|
2,
|
|
|
|
"qpf_allday",
|
|
|
|
"in",
|
|
|
|
LENGTH_INCHES,
|
|
|
|
"mdi:umbrella",
|
|
|
|
),
|
|
|
|
"precip_4d_in": WUDailySimpleForecastSensorConfig(
|
|
|
|
"Precipitation Intensity in 4 Days",
|
|
|
|
3,
|
|
|
|
"qpf_allday",
|
|
|
|
"in",
|
|
|
|
LENGTH_INCHES,
|
|
|
|
"mdi:umbrella",
|
|
|
|
),
|
|
|
|
"precip_1d": WUDailySimpleForecastSensorConfig(
|
2020-02-28 19:46:48 +00:00
|
|
|
"Precipitation Probability Today",
|
|
|
|
0,
|
|
|
|
"pop",
|
|
|
|
None,
|
|
|
|
UNIT_PERCENTAGE,
|
|
|
|
"mdi:umbrella",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"precip_2d": WUDailySimpleForecastSensorConfig(
|
2020-02-28 19:46:48 +00:00
|
|
|
"Precipitation Probability Tomorrow",
|
|
|
|
1,
|
|
|
|
"pop",
|
|
|
|
None,
|
|
|
|
UNIT_PERCENTAGE,
|
|
|
|
"mdi:umbrella",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"precip_3d": WUDailySimpleForecastSensorConfig(
|
2020-02-28 19:46:48 +00:00
|
|
|
"Precipitation Probability in 3 Days",
|
|
|
|
2,
|
|
|
|
"pop",
|
|
|
|
None,
|
|
|
|
UNIT_PERCENTAGE,
|
|
|
|
"mdi:umbrella",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
|
|
|
"precip_4d": WUDailySimpleForecastSensorConfig(
|
2020-02-28 19:46:48 +00:00
|
|
|
"Precipitation Probability in 4 Days",
|
|
|
|
3,
|
|
|
|
"pop",
|
|
|
|
None,
|
|
|
|
UNIT_PERCENTAGE,
|
|
|
|
"mdi:umbrella",
|
2019-07-31 19:25:30 +00:00
|
|
|
),
|
2016-08-17 19:06:12 +00:00
|
|
|
}
|
|
|
|
|
2016-10-15 04:35:27 +00:00
|
|
|
# Alert Attributes
|
2019-07-31 19:25:30 +00:00
|
|
|
ALERTS_ATTRS = ["date", "description", "expires", "message"]
|
2016-10-15 04:35:27 +00:00
|
|
|
|
2016-12-11 23:43:42 +00:00
|
|
|
# Language Supported Codes
|
|
|
|
LANG_CODES = [
|
2019-07-31 19:25:30 +00:00
|
|
|
"AF",
|
|
|
|
"AL",
|
|
|
|
"AR",
|
|
|
|
"HY",
|
|
|
|
"AZ",
|
|
|
|
"EU",
|
|
|
|
"BY",
|
|
|
|
"BU",
|
|
|
|
"LI",
|
|
|
|
"MY",
|
|
|
|
"CA",
|
|
|
|
"CN",
|
|
|
|
"TW",
|
|
|
|
"CR",
|
|
|
|
"CZ",
|
|
|
|
"DK",
|
|
|
|
"DV",
|
|
|
|
"NL",
|
|
|
|
"EN",
|
|
|
|
"EO",
|
|
|
|
"ET",
|
|
|
|
"FA",
|
|
|
|
"FI",
|
|
|
|
"FR",
|
|
|
|
"FC",
|
|
|
|
"GZ",
|
|
|
|
"DL",
|
|
|
|
"KA",
|
|
|
|
"GR",
|
|
|
|
"GU",
|
|
|
|
"HT",
|
|
|
|
"IL",
|
|
|
|
"HI",
|
|
|
|
"HU",
|
|
|
|
"IS",
|
|
|
|
"IO",
|
|
|
|
"ID",
|
|
|
|
"IR",
|
|
|
|
"IT",
|
|
|
|
"JP",
|
|
|
|
"JW",
|
|
|
|
"KM",
|
|
|
|
"KR",
|
|
|
|
"KU",
|
|
|
|
"LA",
|
|
|
|
"LV",
|
|
|
|
"LT",
|
|
|
|
"ND",
|
|
|
|
"MK",
|
|
|
|
"MT",
|
|
|
|
"GM",
|
|
|
|
"MI",
|
|
|
|
"MR",
|
|
|
|
"MN",
|
|
|
|
"NO",
|
|
|
|
"OC",
|
|
|
|
"PS",
|
|
|
|
"GN",
|
|
|
|
"PL",
|
|
|
|
"BR",
|
|
|
|
"PA",
|
|
|
|
"RO",
|
|
|
|
"RU",
|
|
|
|
"SR",
|
|
|
|
"SK",
|
|
|
|
"SL",
|
|
|
|
"SP",
|
|
|
|
"SI",
|
|
|
|
"SW",
|
|
|
|
"CH",
|
|
|
|
"TL",
|
|
|
|
"TT",
|
|
|
|
"TH",
|
|
|
|
"TR",
|
|
|
|
"TK",
|
|
|
|
"UA",
|
|
|
|
"UZ",
|
|
|
|
"VU",
|
|
|
|
"CY",
|
|
|
|
"SN",
|
|
|
|
"JI",
|
|
|
|
"YI",
|
2016-12-11 23:43:42 +00:00
|
|
|
]
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
|
|
{
|
|
|
|
vol.Required(CONF_API_KEY): cv.string,
|
|
|
|
vol.Optional(CONF_PWS_ID): cv.string,
|
|
|
|
vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.All(vol.In(LANG_CODES)),
|
|
|
|
vol.Inclusive(
|
|
|
|
CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together"
|
|
|
|
): cv.latitude,
|
|
|
|
vol.Inclusive(
|
|
|
|
CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together"
|
|
|
|
): cv.longitude,
|
|
|
|
vol.Required(CONF_MONITORED_CONDITIONS): vol.All(
|
|
|
|
cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_TYPES)]
|
|
|
|
),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def async_setup_platform(
|
|
|
|
hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info=None
|
|
|
|
):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Set up the WUnderground sensor."""
|
2017-06-17 08:41:11 +00:00
|
|
|
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
|
|
|
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
2018-05-02 18:23:07 +00:00
|
|
|
pws_id = config.get(CONF_PWS_ID)
|
2017-06-17 08:41:11 +00:00
|
|
|
|
2017-05-02 16:18:47 +00:00
|
|
|
rest = WUndergroundData(
|
2019-07-31 19:25:30 +00:00
|
|
|
hass,
|
|
|
|
config.get(CONF_API_KEY),
|
|
|
|
pws_id,
|
|
|
|
config.get(CONF_LANG),
|
|
|
|
latitude,
|
|
|
|
longitude,
|
|
|
|
)
|
2018-05-02 18:23:07 +00:00
|
|
|
|
|
|
|
if pws_id is None:
|
2019-09-03 19:12:51 +00:00
|
|
|
unique_id_base = f"@{longitude:06f},{latitude:06f}"
|
2018-05-02 18:23:07 +00:00
|
|
|
else:
|
|
|
|
# Manually specified weather station, use that for unique_id
|
|
|
|
unique_id_base = pws_id
|
2016-08-17 19:06:12 +00:00
|
|
|
sensors = []
|
2016-08-18 16:38:34 +00:00
|
|
|
for variable in config[CONF_MONITORED_CONDITIONS]:
|
2019-07-31 19:25:30 +00:00
|
|
|
sensors.append(WUndergroundSensor(hass, rest, variable, unique_id_base))
|
2016-08-18 04:29:25 +00:00
|
|
|
|
2018-04-28 23:26:20 +00:00
|
|
|
await rest.async_update()
|
2017-11-25 20:19:52 +00:00
|
|
|
if not rest.data:
|
|
|
|
raise PlatformNotReady
|
2016-08-18 04:29:25 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
async_add_entities(sensors, True)
|
2016-08-17 19:06:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
class WUndergroundSensor(Entity):
|
2016-08-18 16:46:04 +00:00
|
|
|
"""Implementing the WUnderground sensor."""
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(self, hass: HomeAssistantType, rest, condition, unique_id_base: str):
|
2016-08-17 19:06:12 +00:00
|
|
|
"""Initialize the sensor."""
|
|
|
|
self.rest = rest
|
|
|
|
self._condition = condition
|
2017-11-25 20:19:52 +00:00
|
|
|
self._state = None
|
2019-02-14 21:09:22 +00:00
|
|
|
self._attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
2017-11-25 20:19:52 +00:00
|
|
|
self._icon = None
|
|
|
|
self._entity_picture = None
|
|
|
|
self._unit_of_measurement = self._cfg_expand("unit_of_measurement")
|
2017-05-06 17:11:31 +00:00
|
|
|
self.rest.request_feature(SENSOR_TYPES[condition].feature)
|
2018-05-02 18:23:07 +00:00
|
|
|
# This is only the suggested entity id, it might get changed by
|
|
|
|
# the entity registry later.
|
2020-01-03 13:47:06 +00:00
|
|
|
self.entity_id = sensor.ENTITY_ID_FORMAT.format(f"pws_{condition}")
|
2019-09-03 19:12:51 +00:00
|
|
|
self._unique_id = f"{unique_id_base},{condition}"
|
2018-11-01 13:10:43 +00:00
|
|
|
self._device_class = self._cfg_expand("device_class")
|
2017-05-06 17:11:31 +00:00
|
|
|
|
|
|
|
def _cfg_expand(self, what, default=None):
|
2017-11-25 20:19:52 +00:00
|
|
|
"""Parse and return sensor data."""
|
2017-05-06 17:11:31 +00:00
|
|
|
cfg = SENSOR_TYPES[self._condition]
|
|
|
|
val = getattr(cfg, what)
|
2017-11-25 20:19:52 +00:00
|
|
|
if not callable(val):
|
|
|
|
return val
|
2017-05-06 17:11:31 +00:00
|
|
|
try:
|
|
|
|
val = val(self.rest)
|
2017-11-25 20:19:52 +00:00
|
|
|
except (KeyError, IndexError, TypeError, ValueError) as err:
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.warning(
|
2020-01-02 19:17:10 +00:00
|
|
|
"Failed to expand cfg from WU API. Condition: %s Attr: %s Error: %s",
|
2019-07-31 19:25:30 +00:00
|
|
|
self._condition,
|
|
|
|
what,
|
|
|
|
repr(err),
|
|
|
|
)
|
2017-05-06 17:11:31 +00:00
|
|
|
val = default
|
|
|
|
|
|
|
|
return val
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2017-11-25 20:19:52 +00:00
|
|
|
def _update_attrs(self):
|
|
|
|
"""Parse and update device state attributes."""
|
|
|
|
attrs = self._cfg_expand("device_state_attributes", {})
|
|
|
|
|
|
|
|
for (attr, callback) in attrs.items():
|
|
|
|
if callable(callback):
|
|
|
|
try:
|
|
|
|
self._attributes[attr] = callback(self.rest)
|
|
|
|
except (KeyError, IndexError, TypeError, ValueError) as err:
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.warning(
|
|
|
|
"Failed to update attrs from WU API."
|
|
|
|
" Condition: %s Attr: %s Error: %s",
|
|
|
|
self._condition,
|
|
|
|
attr,
|
|
|
|
repr(err),
|
|
|
|
)
|
2017-11-25 20:19:52 +00:00
|
|
|
else:
|
|
|
|
self._attributes[attr] = callback
|
|
|
|
|
2016-08-17 19:06:12 +00:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the sensor."""
|
2018-02-12 21:15:28 +00:00
|
|
|
return self._cfg_expand("friendly_name")
|
2016-08-17 19:06:12 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def state(self):
|
|
|
|
"""Return the state of the sensor."""
|
2017-11-25 20:19:52 +00:00
|
|
|
return self._state
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2016-10-11 07:28:19 +00:00
|
|
|
@property
|
|
|
|
def device_state_attributes(self):
|
|
|
|
"""Return the state attributes."""
|
2017-11-25 20:19:52 +00:00
|
|
|
return self._attributes
|
2016-10-11 07:28:19 +00:00
|
|
|
|
2017-05-06 17:11:31 +00:00
|
|
|
@property
|
|
|
|
def icon(self):
|
|
|
|
"""Return icon."""
|
2017-11-25 20:19:52 +00:00
|
|
|
return self._icon
|
2017-05-06 17:11:31 +00:00
|
|
|
|
2016-08-17 19:06:12 +00:00
|
|
|
@property
|
|
|
|
def entity_picture(self):
|
|
|
|
"""Return the entity picture."""
|
2017-11-25 20:19:52 +00:00
|
|
|
return self._entity_picture
|
2016-08-17 19:06:12 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def unit_of_measurement(self):
|
|
|
|
"""Return the units of measurement."""
|
2017-11-25 20:19:52 +00:00
|
|
|
return self._unit_of_measurement
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2018-11-01 13:10:43 +00:00
|
|
|
@property
|
|
|
|
def device_class(self):
|
|
|
|
"""Return the units of measurement."""
|
|
|
|
return self._device_class
|
|
|
|
|
2018-10-01 06:55:43 +00:00
|
|
|
async def async_update(self):
|
2016-08-17 19:06:12 +00:00
|
|
|
"""Update current conditions."""
|
2018-10-01 06:55:43 +00:00
|
|
|
await self.rest.async_update()
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2017-11-25 20:19:52 +00:00
|
|
|
if not self.rest.data:
|
|
|
|
# no data, return
|
|
|
|
return
|
|
|
|
|
2018-02-16 22:54:11 +00:00
|
|
|
self._state = self._cfg_expand("value")
|
2017-11-25 20:19:52 +00:00
|
|
|
self._update_attrs()
|
|
|
|
self._icon = self._cfg_expand("icon", super().icon)
|
|
|
|
url = self._cfg_expand("entity_picture")
|
|
|
|
if isinstance(url, str):
|
2019-07-31 19:25:30 +00:00
|
|
|
self._entity_picture = re.sub(
|
|
|
|
r"^http://", "https://", url, flags=re.IGNORECASE
|
|
|
|
)
|
2017-11-25 20:19:52 +00:00
|
|
|
|
2018-05-02 18:23:07 +00:00
|
|
|
@property
|
|
|
|
def unique_id(self) -> str:
|
|
|
|
"""Return a unique ID."""
|
|
|
|
return self._unique_id
|
|
|
|
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2018-07-20 08:45:20 +00:00
|
|
|
class WUndergroundData:
|
2016-08-18 16:46:04 +00:00
|
|
|
"""Get data from WUnderground."""
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2017-06-17 08:41:11 +00:00
|
|
|
def __init__(self, hass, api_key, pws_id, lang, latitude, longitude):
|
2016-08-17 19:06:12 +00:00
|
|
|
"""Initialize the data object."""
|
2016-08-18 04:28:05 +00:00
|
|
|
self._hass = hass
|
2016-08-17 19:06:12 +00:00
|
|
|
self._api_key = api_key
|
|
|
|
self._pws_id = pws_id
|
2019-09-03 19:12:51 +00:00
|
|
|
self._lang = f"lang:{lang}"
|
2017-06-17 08:41:11 +00:00
|
|
|
self._latitude = latitude
|
|
|
|
self._longitude = longitude
|
2017-05-06 17:11:31 +00:00
|
|
|
self._features = set()
|
2016-08-17 19:06:12 +00:00
|
|
|
self.data = None
|
2018-02-16 22:54:11 +00:00
|
|
|
self._session = async_get_clientsession(self._hass)
|
2017-05-06 17:11:31 +00:00
|
|
|
|
|
|
|
def request_feature(self, feature):
|
|
|
|
"""Register feature to be fetched from WU API."""
|
|
|
|
self._features.add(feature)
|
2016-08-17 19:06:12 +00:00
|
|
|
|
2016-10-15 04:35:27 +00:00
|
|
|
def _build_url(self, baseurl=_RESOURCE):
|
2017-05-06 17:11:31 +00:00
|
|
|
url = baseurl.format(
|
2019-07-31 19:25:30 +00:00
|
|
|
self._api_key, "/".join(sorted(self._features)), self._lang
|
|
|
|
)
|
2016-08-18 04:22:11 +00:00
|
|
|
if self._pws_id:
|
2020-01-03 13:47:06 +00:00
|
|
|
url = f"{url}pws:{self._pws_id}"
|
2016-08-18 04:22:11 +00:00
|
|
|
else:
|
2020-01-03 13:47:06 +00:00
|
|
|
url = f"{url}{self._latitude},{self._longitude}"
|
2016-08-18 04:22:11 +00:00
|
|
|
|
2020-01-03 13:47:06 +00:00
|
|
|
return f"{url}.json"
|
2016-08-18 04:22:11 +00:00
|
|
|
|
2017-05-06 17:11:31 +00:00
|
|
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
2018-03-10 03:38:51 +00:00
|
|
|
async def async_update(self):
|
2016-08-18 16:46:04 +00:00
|
|
|
"""Get the latest data from WUnderground."""
|
2016-08-17 19:06:12 +00:00
|
|
|
try:
|
2019-05-23 04:09:59 +00:00
|
|
|
with async_timeout.timeout(10):
|
2018-03-10 03:38:51 +00:00
|
|
|
response = await self._session.get(self._build_url())
|
|
|
|
result = await response.json()
|
2019-07-31 19:25:30 +00:00
|
|
|
if "error" in result["response"]:
|
|
|
|
raise ValueError(result["response"]["error"]["description"])
|
2018-02-16 22:54:11 +00:00
|
|
|
self.data = result
|
2016-08-17 19:06:12 +00:00
|
|
|
except ValueError as err:
|
2016-08-18 16:46:04 +00:00
|
|
|
_LOGGER.error("Check WUnderground API %s", err.args)
|
2018-02-16 22:54:11 +00:00
|
|
|
except (asyncio.TimeoutError, aiohttp.ClientError) as err:
|
2017-11-25 20:19:52 +00:00
|
|
|
_LOGGER.error("Error fetching WUnderground data: %s", repr(err))
|