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:
mjj4791 2017-08-16 08:07:04 +02:00 committed by Paulus Schoutsen
parent 3342db33e4
commit e7ce110dc6
3 changed files with 241 additions and 38 deletions

View File

@ -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

View File

@ -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

View File

@ -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