Buienradar newconditions (#8897)
* new monitored conditions and support for new weathercard * new monitored conditions and support for new weathercard * minor changes
This commit is contained in:
parent
3342db33e4
commit
e7ce110dc6
3 changed files with 241 additions and 38 deletions
|
@ -23,12 +23,14 @@ from homeassistant.helpers.event import (
|
|||
async_track_point_in_utc_time)
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
REQUIREMENTS = ['buienradar==0.8']
|
||||
REQUIREMENTS = ['buienradar==0.9']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
MEASURED_LABEL = 'Measured'
|
||||
TIMEFRAME_LABEL = 'Timeframe'
|
||||
SYMBOL = 'symbol'
|
||||
|
||||
# Schedule next call after (minutes):
|
||||
SCHEDULE_OK = 10
|
||||
# When an error occurred, new call after (minutes):
|
||||
|
@ -38,6 +40,10 @@ SCHEDULE_NOK = 2
|
|||
# Key: ['label', unit, icon]
|
||||
SENSOR_TYPES = {
|
||||
'stationname': ['Stationname', None, None],
|
||||
'condition': ['Condition', None, None],
|
||||
'conditioncode': ['Condition code', None, None],
|
||||
'conditiondetailed': ['Detailed condition', None, None],
|
||||
'conditionexact': ['Full condition', None, None],
|
||||
'symbol': ['Symbol', None, None],
|
||||
'humidity': ['Humidity', '%', 'mdi:water-percent'],
|
||||
'temperature': ['Temperature', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
|
@ -55,7 +61,67 @@ SENSOR_TYPES = {
|
|||
'precipitation_forecast_average': ['Precipitation forecast average',
|
||||
'mm/h', 'mdi:weather-pouring'],
|
||||
'precipitation_forecast_total': ['Precipitation forecast total',
|
||||
'mm', 'mdi:weather-pouring']
|
||||
'mm', 'mdi:weather-pouring'],
|
||||
'temperature_1d': ['Temperature 1d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'temperature_2d': ['Temperature 2d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'temperature_3d': ['Temperature 3d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'temperature_4d': ['Temperature 4d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'temperature_5d': ['Temperature 5d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'mintemp_1d': ['Minimum temperature 1d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'mintemp_2d': ['Minimum temperature 2d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'mintemp_3d': ['Minimum temperature 3d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'mintemp_4d': ['Minimum temperature 4d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'mintemp_5d': ['Minimum temperature 5d', TEMP_CELSIUS, 'mdi:thermometer'],
|
||||
'rain_1d': ['Rain 1d', 'mm', 'mdi:weather-pouring'],
|
||||
'rain_2d': ['Rain 2d', 'mm', 'mdi:weather-pouring'],
|
||||
'rain_3d': ['Rain 3d', 'mm', 'mdi:weather-pouring'],
|
||||
'rain_4d': ['Rain 4d', 'mm', 'mdi:weather-pouring'],
|
||||
'rain_5d': ['Rain 5d', 'mm', 'mdi:weather-pouring'],
|
||||
'snow_1d': ['Snow 1d', 'cm', 'mdi:snowflake'],
|
||||
'snow_2d': ['Snow 2d', 'cm', 'mdi:snowflake'],
|
||||
'snow_3d': ['Snow 3d', 'cm', 'mdi:snowflake'],
|
||||
'snow_4d': ['Snow 4d', 'cm', 'mdi:snowflake'],
|
||||
'snow_5d': ['Snow 5d', 'cm', 'mdi:snowflake'],
|
||||
'rainchance_1d': ['Rainchance 1d', '%', 'mdi:weather-pouring'],
|
||||
'rainchance_2d': ['Rainchance 2d', '%', 'mdi:weather-pouring'],
|
||||
'rainchance_3d': ['Rainchance 3d', '%', 'mdi:weather-pouring'],
|
||||
'rainchance_4d': ['Rainchance 4d', '%', 'mdi:weather-pouring'],
|
||||
'rainchance_5d': ['Rainchance 5d', '%', 'mdi:weather-pouring'],
|
||||
'sunchance_1d': ['Sunchance 1d', '%', 'mdi:weather-partlycloudy'],
|
||||
'sunchance_2d': ['Sunchance 2d', '%', 'mdi:weather-partlycloudy'],
|
||||
'sunchance_3d': ['Sunchance 3d', '%', 'mdi:weather-partlycloudy'],
|
||||
'sunchance_4d': ['Sunchance 4d', '%', 'mdi:weather-partlycloudy'],
|
||||
'sunchance_5d': ['Sunchance 5d', '%', 'mdi:weather-partlycloudy'],
|
||||
'windforce_1d': ['Wind force 1d', 'Bft', 'mdi:weather-windy'],
|
||||
'windforce_2d': ['Wind force 2d', 'Bft', 'mdi:weather-windy'],
|
||||
'windforce_3d': ['Wind force 3d', 'Bft', 'mdi:weather-windy'],
|
||||
'windforce_4d': ['Wind force 4d', 'Bft', 'mdi:weather-windy'],
|
||||
'windforce_5d': ['Wind force 5d', 'Bft', 'mdi:weather-windy'],
|
||||
'condition_1d': ['Condition 1d', None, None],
|
||||
'condition_2d': ['Condition 2d', None, None],
|
||||
'condition_3d': ['Condition 3d', None, None],
|
||||
'condition_4d': ['Condition 4d', None, None],
|
||||
'condition_5d': ['Condition 5d', None, None],
|
||||
'conditioncode_1d': ['Condition code 1d', None, None],
|
||||
'conditioncode_2d': ['Condition code 2d', None, None],
|
||||
'conditioncode_3d': ['Condition code 3d', None, None],
|
||||
'conditioncode_4d': ['Condition code 4d', None, None],
|
||||
'conditioncode_5d': ['Condition code 5d', None, None],
|
||||
'conditiondetailed_1d': ['Detailed condition 1d', None, None],
|
||||
'conditiondetailed_2d': ['Detailed condition 2d', None, None],
|
||||
'conditiondetailed_3d': ['Detailed condition 3d', None, None],
|
||||
'conditiondetailed_4d': ['Detailed condition 4d', None, None],
|
||||
'conditiondetailed_5d': ['Detailed condition 5d', None, None],
|
||||
'conditionexact_1d': ['Full condition 1d', None, None],
|
||||
'conditionexact_2d': ['Full condition 2d', None, None],
|
||||
'conditionexact_3d': ['Full condition 3d', None, None],
|
||||
'conditionexact_4d': ['Full condition 4d', None, None],
|
||||
'conditionexact_5d': ['Full condition 5d', None, None],
|
||||
'symbol_1d': ['Symbol 1d', None, None],
|
||||
'symbol_2d': ['Symbol 2d', None, None],
|
||||
'symbol_3d': ['Symbol 3d', None, None],
|
||||
'symbol_4d': ['Symbol 4d', None, None],
|
||||
'symbol_5d': ['Symbol 5d', None, None],
|
||||
}
|
||||
|
||||
CONF_TIMEFRAME = 'timeframe'
|
||||
|
@ -126,23 +192,86 @@ class BrSensor(Entity):
|
|||
def load_data(self, data):
|
||||
"""Load the sensor with relevant data."""
|
||||
# Find sensor
|
||||
from buienradar.buienradar import (ATTRIBUTION, IMAGE, MEASURED,
|
||||
from buienradar.buienradar import (ATTRIBUTION, CONDITION, CONDCODE,
|
||||
DETAILED, EXACT, EXACTNL, FORECAST,
|
||||
IMAGE, MEASURED,
|
||||
PRECIPITATION_FORECAST, STATIONNAME,
|
||||
SYMBOL, TIMEFRAME)
|
||||
TIMEFRAME)
|
||||
|
||||
self._attribution = data.get(ATTRIBUTION)
|
||||
self._stationname = data.get(STATIONNAME)
|
||||
self._measured = data.get(MEASURED)
|
||||
if self.type == SYMBOL:
|
||||
# update weather symbol & status text
|
||||
new_state = data.get(self.type)
|
||||
img = data.get(IMAGE)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
if new_state != self._state or img != self._entity_picture:
|
||||
self._state = new_state
|
||||
self._entity_picture = img
|
||||
return True
|
||||
if self.type.endswith('_1d') or \
|
||||
self.type.endswith('_2d') or \
|
||||
self.type.endswith('_3d') or \
|
||||
self.type.endswith('_4d') or \
|
||||
self.type.endswith('_5d'):
|
||||
|
||||
fcday = 0
|
||||
if self.type.endswith('_2d'):
|
||||
fcday = 1
|
||||
if self.type.endswith('_3d'):
|
||||
fcday = 2
|
||||
if self.type.endswith('_4d'):
|
||||
fcday = 3
|
||||
if self.type.endswith('_5d'):
|
||||
fcday = 4
|
||||
|
||||
# update all other sensors
|
||||
if self.type.startswith(SYMBOL) or self.type.startswith(CONDITION):
|
||||
condition = data.get(FORECAST)[fcday].get(CONDITION)
|
||||
if condition:
|
||||
new_state = condition.get(CONDITION, None)
|
||||
if self.type.startswith(SYMBOL):
|
||||
new_state = condition.get(EXACTNL, None)
|
||||
if self.type.startswith('conditioncode'):
|
||||
new_state = condition.get(CONDCODE, None)
|
||||
if self.type.startswith('conditiondetailed'):
|
||||
new_state = condition.get(DETAILED, None)
|
||||
if self.type.startswith('conditionexact'):
|
||||
new_state = condition.get(EXACT, None)
|
||||
|
||||
img = condition.get(IMAGE, None)
|
||||
|
||||
if new_state != self._state or img != self._entity_picture:
|
||||
self._state = new_state
|
||||
self._entity_picture = img
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
new_state = data.get(FORECAST)[fcday].get(self.type[:-3])
|
||||
|
||||
if new_state != self._state:
|
||||
self._state = new_state
|
||||
return True
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
if self.type == SYMBOL or self.type.startswith(CONDITION):
|
||||
# update weather symbol & status text
|
||||
condition = data.get(CONDITION, None)
|
||||
if condition:
|
||||
if self.type == SYMBOL:
|
||||
new_state = condition.get(EXACTNL, None)
|
||||
if self.type == CONDITION:
|
||||
new_state = condition.get(CONDITION, None)
|
||||
if self.type == 'conditioncode':
|
||||
new_state = condition.get(CONDCODE, None)
|
||||
if self.type == 'conditiondetailed':
|
||||
new_state = condition.get(DETAILED, None)
|
||||
if self.type == 'conditionexact':
|
||||
new_state = condition.get(EXACT, None)
|
||||
|
||||
img = condition.get(IMAGE, None)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
if new_state != self._state or img != self._entity_picture:
|
||||
self._state = new_state
|
||||
self._entity_picture = img
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
if self.type.startswith(PRECIPITATION_FORECAST):
|
||||
|
@ -187,11 +316,6 @@ class BrSensor(Entity):
|
|||
@property
|
||||
def entity_picture(self):
|
||||
"""Weather symbol if type is symbol."""
|
||||
from buienradar.buienradar import SYMBOL
|
||||
|
||||
if self.type != SYMBOL:
|
||||
return None
|
||||
|
||||
return self._entity_picture
|
||||
|
||||
@property
|
||||
|
@ -360,8 +484,8 @@ class BrData(object):
|
|||
@property
|
||||
def condition(self):
|
||||
"""Return the condition."""
|
||||
from buienradar.buienradar import SYMBOL
|
||||
return self.data.get(SYMBOL)
|
||||
from buienradar.buienradar import CONDITION
|
||||
return self.data.get(CONDITION)
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
|
@ -390,6 +514,15 @@ class BrData(object):
|
|||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
@property
|
||||
def visibility(self):
|
||||
"""Return the visibility, or None."""
|
||||
from buienradar.buienradar import VISIBILITY
|
||||
try:
|
||||
return int(self.data.get(VISIBILITY))
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
@property
|
||||
def wind_speed(self):
|
||||
"""Return the windspeed, or None."""
|
||||
|
@ -402,9 +535,9 @@ class BrData(object):
|
|||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the wind bearing, or None."""
|
||||
from buienradar.buienradar import WINDDIRECTION
|
||||
from buienradar.buienradar import WINDAZIMUTH
|
||||
try:
|
||||
return int(self.data.get(WINDDIRECTION))
|
||||
return int(self.data.get(WINDAZIMUTH))
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ https://home-assistant.io/components/weather.buienradar/
|
|||
import logging
|
||||
import asyncio
|
||||
from homeassistant.components.weather import (
|
||||
WeatherEntity, PLATFORM_SCHEMA)
|
||||
WeatherEntity, PLATFORM_SCHEMA, ATTR_FORECAST_TEMP, ATTR_FORECAST_TIME)
|
||||
from homeassistant.const import \
|
||||
CONF_NAME, TEMP_CELSIUS, CONF_LATITUDE, CONF_LONGITUDE
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
@ -16,14 +16,37 @@ from homeassistant.components.sensor.buienradar import (
|
|||
BrData)
|
||||
import voluptuous as vol
|
||||
|
||||
REQUIREMENTS = ['buienradar==0.8']
|
||||
REQUIREMENTS = ['buienradar==0.9']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_CONDITION = 'buienradar_condition'
|
||||
|
||||
DEFAULT_TIMEFRAME = 60
|
||||
|
||||
CONF_FORECAST = 'forecast'
|
||||
|
||||
ATTR_FORECAST_CONDITION = 'condition'
|
||||
ATTR_FORECAST_TEMP_LOW = 'templow'
|
||||
|
||||
|
||||
CONDITION_CLASSES = {
|
||||
'cloudy': ['c', 'p'],
|
||||
'fog': ['d', 'n'],
|
||||
'hail': [],
|
||||
'lightning': ['g'],
|
||||
'lightning-rainy': ['s'],
|
||||
'partlycloudy': ['b', 'j', 'o', 'r'],
|
||||
'pouring': ['l', 'q'],
|
||||
'rainy': ['f', 'h', 'k', 'm'],
|
||||
'snowy': ['u', 'i', 'v', 't'],
|
||||
'snowy-rainy': ['w'],
|
||||
'sunny': ['a'],
|
||||
'windy': [],
|
||||
'windy-variant': [],
|
||||
'exceptional': [],
|
||||
}
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_LATITUDE): cv.latitude,
|
||||
|
@ -50,8 +73,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
# create weather device:
|
||||
_LOGGER.debug("Initializing buienradar weather: coordinates %s",
|
||||
coordinates)
|
||||
async_add_devices([BrWeather(data, config.get(CONF_FORECAST, True),
|
||||
config.get(CONF_NAME, None))])
|
||||
|
||||
# create condition helper
|
||||
if DATA_CONDITION not in hass.data:
|
||||
cond_keys = [str(chr(x)) for x in range(97, 123)]
|
||||
hass.data[DATA_CONDITION] = dict.fromkeys(cond_keys)
|
||||
for cond, condlst in CONDITION_CLASSES.items():
|
||||
for condi in condlst:
|
||||
hass.data[DATA_CONDITION][condi] = cond
|
||||
|
||||
async_add_devices([BrWeather(data, config)])
|
||||
|
||||
# schedule the first update in 1 minute from now:
|
||||
yield from data.schedule_update(1)
|
||||
|
@ -60,10 +91,10 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
class BrWeather(WeatherEntity):
|
||||
"""Representation of a weather condition."""
|
||||
|
||||
def __init__(self, data, forecast, stationname=None):
|
||||
def __init__(self, data, config):
|
||||
"""Initialise the platform with a data instance and station name."""
|
||||
self._stationname = stationname
|
||||
self._forecast = forecast
|
||||
self._stationname = config.get(CONF_NAME, None)
|
||||
self._forecast = config.get(CONF_FORECAST)
|
||||
self._data = data
|
||||
|
||||
@property
|
||||
|
@ -79,17 +110,32 @@ class BrWeather(WeatherEntity):
|
|||
|
||||
@property
|
||||
def condition(self):
|
||||
"""Return the name of the sensor."""
|
||||
return self._data.condition
|
||||
"""Return the current condition."""
|
||||
from buienradar.buienradar import (CONDCODE)
|
||||
if self._data and self._data.condition:
|
||||
ccode = self._data.condition.get(CONDCODE)
|
||||
if ccode:
|
||||
conditions = self.hass.data.get(DATA_CONDITION)
|
||||
if conditions:
|
||||
return conditions.get(ccode)
|
||||
|
||||
@property
|
||||
def entity_picture(self):
|
||||
"""Return the entity picture to use in the frontend, if any."""
|
||||
from buienradar.buienradar import (IMAGE)
|
||||
|
||||
if self._data and self._data.condition:
|
||||
return self._data.condition.get(IMAGE, None)
|
||||
return None
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
"""Return the name of the sensor."""
|
||||
"""Return the current temperature."""
|
||||
return self._data.temperature
|
||||
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the name of the sensor."""
|
||||
"""Return the current pressure."""
|
||||
return self._data.pressure
|
||||
|
||||
@property
|
||||
|
@ -97,14 +143,19 @@ class BrWeather(WeatherEntity):
|
|||
"""Return the name of the sensor."""
|
||||
return self._data.humidity
|
||||
|
||||
@property
|
||||
def visibility(self):
|
||||
"""Return the current visibility."""
|
||||
return self._data.visibility
|
||||
|
||||
@property
|
||||
def wind_speed(self):
|
||||
"""Return the name of the sensor."""
|
||||
"""Return the current windspeed."""
|
||||
return self._data.wind_speed
|
||||
|
||||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the name of the sensor."""
|
||||
"""Return the current wind bearing (degrees)."""
|
||||
return self._data.wind_bearing
|
||||
|
||||
@property
|
||||
|
@ -114,6 +165,25 @@ class BrWeather(WeatherEntity):
|
|||
|
||||
@property
|
||||
def forecast(self):
|
||||
"""Return the forecast."""
|
||||
"""Return the forecast array."""
|
||||
from buienradar.buienradar import (CONDITION, CONDCODE, DATETIME,
|
||||
MIN_TEMP, MAX_TEMP)
|
||||
|
||||
if self._forecast:
|
||||
return self._data.forecast
|
||||
fcdata_out = []
|
||||
cond = self.hass.data[DATA_CONDITION]
|
||||
if self._data.forecast:
|
||||
for data_in in self._data.forecast:
|
||||
# remap keys from external library to
|
||||
# keys understood by the weather component:
|
||||
data_out = {}
|
||||
condcode = data_in.get(CONDITION, []).get(CONDCODE)
|
||||
|
||||
data_out[ATTR_FORECAST_TIME] = data_in.get(DATETIME)
|
||||
data_out[ATTR_FORECAST_CONDITION] = cond[condcode]
|
||||
data_out[ATTR_FORECAST_TEMP_LOW] = data_in.get(MIN_TEMP)
|
||||
data_out[ATTR_FORECAST_TEMP] = data_in.get(MAX_TEMP)
|
||||
|
||||
fcdata_out.append(data_out)
|
||||
|
||||
return fcdata_out
|
||||
|
|
|
@ -128,7 +128,7 @@ broadlink==0.5
|
|||
|
||||
# homeassistant.components.sensor.buienradar
|
||||
# homeassistant.components.weather.buienradar
|
||||
buienradar==0.8
|
||||
buienradar==0.9
|
||||
|
||||
# homeassistant.components.notify.ciscospark
|
||||
ciscosparkapi==0.4.2
|
||||
|
|
Loading…
Add table
Reference in a new issue