This commit is contained in:
Paulus Schoutsen 2019-07-31 12:25:30 -07:00
parent da05dfe708
commit 4de97abc3a
2676 changed files with 163166 additions and 140084 deletions

View file

@ -5,51 +5,68 @@ import logging
import voluptuous as vol
from homeassistant.components.weather import (
ATTR_FORECAST_CONDITION, ATTR_FORECAST_PRECIPITATION, ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TIME, ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED, PLATFORM_SCHEMA, WeatherEntity)
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
PLATFORM_SCHEMA,
WeatherEntity,
)
from homeassistant.const import (
CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME,
PRESSURE_HPA, PRESSURE_INHG, STATE_UNKNOWN, TEMP_CELSIUS)
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MODE,
CONF_NAME,
PRESSURE_HPA,
PRESSURE_INHG,
STATE_UNKNOWN,
TEMP_CELSIUS,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle
from homeassistant.util.pressure import convert as convert_pressure
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = 'Data provided by OpenWeatherMap'
ATTRIBUTION = "Data provided by OpenWeatherMap"
FORECAST_MODE = ['hourly', 'daily', 'freedaily']
FORECAST_MODE = ["hourly", "daily", "freedaily"]
DEFAULT_NAME = 'OpenWeatherMap'
DEFAULT_NAME = "OpenWeatherMap"
MIN_TIME_BETWEEN_FORECAST_UPDATES = timedelta(minutes=30)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
CONDITION_CLASSES = {
'cloudy': [803, 804],
'fog': [701, 741],
'hail': [906],
'lightning': [210, 211, 212, 221],
'lightning-rainy': [200, 201, 202, 230, 231, 232],
'partlycloudy': [801, 802],
'pouring': [504, 314, 502, 503, 522],
'rainy': [300, 301, 302, 310, 311, 312, 313, 500, 501, 520, 521],
'snowy': [600, 601, 602, 611, 612, 620, 621, 622],
'snowy-rainy': [511, 615, 616],
'sunny': [800],
'windy': [905, 951, 952, 953, 954, 955, 956, 957],
'windy-variant': [958, 959, 960, 961],
'exceptional': [711, 721, 731, 751, 761, 762, 771, 900, 901, 962, 903,
904],
"cloudy": [803, 804],
"fog": [701, 741],
"hail": [906],
"lightning": [210, 211, 212, 221],
"lightning-rainy": [200, 201, 202, 230, 231, 232],
"partlycloudy": [801, 802],
"pouring": [504, 314, 502, 503, 522],
"rainy": [300, 301, 302, 310, 311, 312, 313, 500, 501, 520, 521],
"snowy": [600, 601, 602, 611, 612, 620, 621, 622],
"snowy-rainy": [511, 615, 616],
"sunny": [800],
"windy": [905, 951, 952, 953, 954, 955, 956, 957],
"windy-variant": [958, 959, 960, 961],
"exceptional": [711, 721, 731, 751, 761, 762, 771, 900, 901, 962, 903, 904],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_MODE, default='hourly'): vol.In(FORECAST_MODE),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_MODE, default="hourly"): vol.In(FORECAST_MODE),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None):
@ -69,8 +86,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
data = WeatherData(owm, latitude, longitude, mode)
add_entities([OpenWeatherMapWeather(
name, data, hass.config.units.temperature_unit, mode)], True)
add_entities(
[OpenWeatherMapWeather(name, data, hass.config.units.temperature_unit, mode)],
True,
)
class OpenWeatherMapWeather(WeatherEntity):
@ -94,15 +113,18 @@ class OpenWeatherMapWeather(WeatherEntity):
def condition(self):
"""Return the current condition."""
try:
return [k for k, v in CONDITION_CLASSES.items() if
self.data.get_weather_code() in v][0]
return [
k
for k, v in CONDITION_CLASSES.items()
if self.data.get_weather_code() in v
][0]
except IndexError:
return STATE_UNKNOWN
@property
def temperature(self):
"""Return the temperature."""
return self.data.get_temperature('celsius').get('temp')
return self.data.get_temperature("celsius").get("temp")
@property
def temperature_unit(self):
@ -112,10 +134,9 @@ class OpenWeatherMapWeather(WeatherEntity):
@property
def pressure(self):
"""Return the pressure."""
pressure = self.data.get_pressure().get('press')
if self.hass.config.units.name == 'imperial':
return round(
convert_pressure(pressure, PRESSURE_HPA, PRESSURE_INHG), 2)
pressure = self.data.get_pressure().get("press")
if self.hass.config.units.name == "imperial":
return round(convert_pressure(pressure, PRESSURE_HPA, PRESSURE_INHG), 2)
return pressure
@property
@ -126,15 +147,15 @@ class OpenWeatherMapWeather(WeatherEntity):
@property
def wind_speed(self):
"""Return the wind speed."""
if self.hass.config.units.name == 'imperial':
return round(self.data.get_wind().get('speed') * 2.24, 2)
if self.hass.config.units.name == "imperial":
return round(self.data.get_wind().get("speed") * 2.24, 2)
return round(self.data.get_wind().get('speed') * 3.6, 2)
return round(self.data.get_wind().get("speed") * 3.6, 2)
@property
def wind_bearing(self):
"""Return the wind bearing."""
return self.data.get_wind().get('deg')
return self.data.get_wind().get("deg")
@property
def attribution(self):
@ -154,47 +175,52 @@ class OpenWeatherMapWeather(WeatherEntity):
return None
return round(rain_value + snow_value, 1)
if self._mode == 'freedaily':
if self._mode == "freedaily":
weather = self.forecast_data.get_weathers()[::8]
else:
weather = self.forecast_data.get_weathers()
for entry in weather:
if self._mode == 'daily':
data.append({
ATTR_FORECAST_TIME:
entry.get_reference_time('unix') * 1000,
ATTR_FORECAST_TEMP:
entry.get_temperature('celsius').get('day'),
ATTR_FORECAST_TEMP_LOW:
entry.get_temperature('celsius').get('night'),
ATTR_FORECAST_PRECIPITATION:
calc_precipitation(
entry.get_rain().get('all'),
entry.get_snow().get('all')),
ATTR_FORECAST_WIND_SPEED:
entry.get_wind().get('speed'),
ATTR_FORECAST_WIND_BEARING:
entry.get_wind().get('deg'),
ATTR_FORECAST_CONDITION:
[k for k, v in CONDITION_CLASSES.items()
if entry.get_weather_code() in v][0]
})
if self._mode == "daily":
data.append(
{
ATTR_FORECAST_TIME: entry.get_reference_time("unix") * 1000,
ATTR_FORECAST_TEMP: entry.get_temperature("celsius").get("day"),
ATTR_FORECAST_TEMP_LOW: entry.get_temperature("celsius").get(
"night"
),
ATTR_FORECAST_PRECIPITATION: calc_precipitation(
entry.get_rain().get("all"), entry.get_snow().get("all")
),
ATTR_FORECAST_WIND_SPEED: entry.get_wind().get("speed"),
ATTR_FORECAST_WIND_BEARING: entry.get_wind().get("deg"),
ATTR_FORECAST_CONDITION: [
k
for k, v in CONDITION_CLASSES.items()
if entry.get_weather_code() in v
][0],
}
)
else:
data.append({
ATTR_FORECAST_TIME:
entry.get_reference_time('unix') * 1000,
ATTR_FORECAST_TEMP:
entry.get_temperature('celsius').get('temp'),
ATTR_FORECAST_PRECIPITATION:
(round(entry.get_rain().get('3h'), 1)
if entry.get_rain().get('3h') is not None
and (round(entry.get_rain().get('3h'), 1) > 0)
else None),
ATTR_FORECAST_CONDITION:
[k for k, v in CONDITION_CLASSES.items()
if entry.get_weather_code() in v][0]
})
data.append(
{
ATTR_FORECAST_TIME: entry.get_reference_time("unix") * 1000,
ATTR_FORECAST_TEMP: entry.get_temperature("celsius").get(
"temp"
),
ATTR_FORECAST_PRECIPITATION: (
round(entry.get_rain().get("3h"), 1)
if entry.get_rain().get("3h") is not None
and (round(entry.get_rain().get("3h"), 1) > 0)
else None
),
ATTR_FORECAST_CONDITION: [
k
for k, v in CONDITION_CLASSES.items()
if entry.get_weather_code() in v
][0],
}
)
return data
def update(self):
@ -240,15 +266,16 @@ class WeatherData:
from pyowm.exceptions.api_call_error import APICallError
try:
if self._mode == 'daily':
if self._mode == "daily":
fcd = self.owm.daily_forecast_at_coords(
self.latitude, self.longitude, 15)
self.latitude, self.longitude, 15
)
else:
fcd = self.owm.three_hours_forecast_at_coords(
self.latitude, self.longitude)
self.latitude, self.longitude
)
except APICallError:
_LOGGER.error("Exception when calling OWM web API "
"to update forecast")
_LOGGER.error("Exception when calling OWM web API " "to update forecast")
return
if fcd is None: