Add missing configuration variables (#11390)

* Add missing configuration variables

* Minor changes

* Sync platforms and other minor updates
This commit is contained in:
Fabian Affolter 2018-01-06 21:53:14 +01:00 committed by GitHub
parent 3fbf09e7d9
commit c613585100
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 61 deletions

View File

@ -4,23 +4,28 @@ Support for UK Met Office weather service.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.metoffice/ https://home-assistant.io/components/sensor.metoffice/
""" """
import logging
from datetime import timedelta from datetime import timedelta
import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
CONF_MONITORED_CONDITIONS, TEMP_CELSIUS, STATE_UNKNOWN, CONF_NAME, ATTR_ATTRIBUTION, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE,
ATTR_ATTRIBUTION, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE) CONF_MONITORED_CONDITIONS, CONF_NAME, TEMP_CELSIUS)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['datapoint==0.4.3'] REQUIREMENTS = ['datapoint==0.4.3']
ATTR_LAST_UPDATE = 'last_update'
ATTR_SENSOR_ID = 'sensor_id'
ATTR_SITE_ID = 'site_id'
ATTR_SITE_NAME = 'site_name'
CONF_ATTRIBUTION = "Data provided by the Met Office" CONF_ATTRIBUTION = "Data provided by the Met Office"
CONDITION_CLASSES = { CONDITION_CLASSES = {
@ -40,6 +45,8 @@ CONDITION_CLASSES = {
'exceptional': [], 'exceptional': [],
} }
DEFAULT_NAME = "Met Office"
VISIBILTY_CLASSES = { VISIBILTY_CLASSES = {
'VP': '<1', 'VP': '<1',
'PO': '1-4', 'PO': '1-4',
@ -49,7 +56,7 @@ VISIBILTY_CLASSES = {
'EX': '>40' 'EX': '>40'
} }
SCAN_INTERVAL = timedelta(minutes=35) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=35)
# Sensor types are defined like: Name, units # Sensor types are defined like: Name, units
SENSOR_TYPES = { SENSOR_TYPES = {
@ -68,77 +75,83 @@ SENSOR_TYPES = {
} }
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=None): cv.string,
vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_MONITORED_CONDITIONS, default=[]): vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
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,
}) })
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Metoffice sensor platform.""" """Set up the Met Office sensor platform."""
import datapoint as dp import datapoint as dp
datapoint = dp.connection(api_key=config.get(CONF_API_KEY))
api_key = config.get(CONF_API_KEY)
latitude = config.get(CONF_LATITUDE, hass.config.latitude) latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
name = config.get(CONF_NAME)
datapoint = dp.connection(api_key=api_key)
if None in (latitude, longitude): if None in (latitude, longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config") _LOGGER.error("Latitude or longitude not set in Home Assistant config")
return False return
try: try:
site = datapoint.get_nearest_site(latitude=latitude, site = datapoint.get_nearest_site(
longitude=longitude) latitude=latitude, longitude=longitude)
except dp.exceptions.APIException as err: except dp.exceptions.APIException as err:
_LOGGER.error("Received error from Met Office Datapoint: %s", err) _LOGGER.error("Received error from Met Office Datapoint: %s", err)
return False return
if not site: if not site:
_LOGGER.error("Unable to get nearest Met Office forecast site") _LOGGER.error("Unable to get nearest Met Office forecast site")
return False return
# Get data
data = MetOfficeCurrentData(hass, datapoint, site) data = MetOfficeCurrentData(hass, datapoint, site)
try: data.update()
data.update() if data.data is None:
except (ValueError, dp.exceptions.APIException) as err: return
_LOGGER.error("Received error from Met Office Datapoint: %s", err)
return False
# Add sensors = []
add_devices([MetOfficeCurrentSensor(site, data, variable) for variable in config[CONF_MONITORED_CONDITIONS]:
for variable in config[CONF_MONITORED_CONDITIONS]]) sensors.append(MetOfficeCurrentSensor(site, data, variable, name))
return True
add_devices(sensors, True)
class MetOfficeCurrentSensor(Entity): class MetOfficeCurrentSensor(Entity):
"""Implementation of a Met Office current sensor.""" """Implementation of a Met Office current sensor."""
def __init__(self, site, data, condition): def __init__(self, site, data, condition, name):
"""Initialize the sensor.""" """Initialize the sensor."""
self.site = site
self.data = data
self._condition = condition self._condition = condition
self.data = data
self._name = name
self.site = site
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
return 'Met Office {}'.format(SENSOR_TYPES[self._condition][0]) return '{} {}'.format(self._name, SENSOR_TYPES[self._condition][0])
@property @property
def state(self): def state(self):
"""Return the state of the sensor.""" """Return the state of the sensor."""
if (self._condition == 'visibility_distance' and if (self._condition == 'visibility_distance' and
'visibility' in self.data.data.__dict__.keys()): hasattr(self.data.data, 'visibility')):
return VISIBILTY_CLASSES.get(self.data.data.visibility.value) return VISIBILTY_CLASSES.get(self.data.data.visibility.value)
if self._condition in self.data.data.__dict__.keys(): if hasattr(self.data.data, self._condition):
variable = getattr(self.data.data, self._condition) variable = getattr(self.data.data, self._condition)
if self._condition == "weather": if self._condition == 'weather':
return [k for k, v in CONDITION_CLASSES.items() if return [k for k, v in CONDITION_CLASSES.items() if
self.data.data.weather.value in v][0] self.data.data.weather.value in v][0]
return variable.value return variable.value
return STATE_UNKNOWN return None
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
@ -149,11 +162,11 @@ class MetOfficeCurrentSensor(Entity):
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the device.""" """Return the state attributes of the device."""
attr = {} attr = {}
attr['Sensor Id'] = self._condition
attr['Site Id'] = self.site.id
attr['Site Name'] = self.site.name
attr['Last Update'] = self.data.data.date
attr[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION attr[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION
attr[ATTR_LAST_UPDATE] = self.data.data.date
attr[ATTR_SENSOR_ID] = self._condition
attr[ATTR_SITE_ID] = self.site.id
attr[ATTR_SITE_NAME] = self.site.name
return attr return attr
def update(self): def update(self):
@ -166,21 +179,19 @@ class MetOfficeCurrentData(object):
def __init__(self, hass, datapoint, site): def __init__(self, hass, datapoint, site):
"""Initialize the data object.""" """Initialize the data object."""
self._hass = hass
self._datapoint = datapoint self._datapoint = datapoint
self._site = site self._site = site
self.data = None self.data = None
@Throttle(SCAN_INTERVAL) @Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self): def update(self):
"""Get the latest data from Datapoint.""" """Get the latest data from Datapoint."""
import datapoint as dp import datapoint as dp
try: try:
forecast = self._datapoint.get_forecast_for_site( forecast = self._datapoint.get_forecast_for_site(
self._site.id, "3hourly") self._site.id, '3hourly')
self.data = forecast.now() self.data = forecast.now()
except (ValueError, dp.exceptions.APIException) as err: except (ValueError, dp.exceptions.APIException) as err:
_LOGGER.error("Check Met Office %s", err.args) _LOGGER.error("Check Met Office %s", err.args)
self.data = None self.data = None
raise

View File

@ -8,27 +8,34 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.weather import WeatherEntity, PLATFORM_SCHEMA from homeassistant.components.sensor.metoffice import (
CONDITION_CLASSES, CONF_ATTRIBUTION, MetOfficeCurrentData)
from homeassistant.components.weather import PLATFORM_SCHEMA, WeatherEntity
from homeassistant.const import ( from homeassistant.const import (
CONF_NAME, TEMP_CELSIUS, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE) CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, TEMP_CELSIUS)
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
# Reuse data and API logic from the sensor implementation
from homeassistant.components.sensor.metoffice import \
MetOfficeCurrentData, CONF_ATTRIBUTION, CONDITION_CLASSES
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['datapoint==0.4.3'] REQUIREMENTS = ['datapoint==0.4.3']
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "Met Office"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
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,
}) })
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Met Office weather platform.""" """Set up the Met Office weather platform."""
import datapoint as dp import datapoint as dp
name = config.get(CONF_NAME)
datapoint = dp.connection(api_key=config.get(CONF_API_KEY)) datapoint = dp.connection(api_key=config.get(CONF_API_KEY))
latitude = config.get(CONF_LATITUDE, hass.config.latitude) latitude = config.get(CONF_LATITUDE, hass.config.latitude)
@ -36,36 +43,35 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if None in (latitude, longitude): if None in (latitude, longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config") _LOGGER.error("Latitude or longitude not set in Home Assistant config")
return False return
try: try:
site = datapoint.get_nearest_site(latitude=latitude, site = datapoint.get_nearest_site(
longitude=longitude) latitude=latitude, longitude=longitude)
except dp.exceptions.APIException as err: except dp.exceptions.APIException as err:
_LOGGER.error("Received error from Met Office Datapoint: %s", err) _LOGGER.error("Received error from Met Office Datapoint: %s", err)
return False return
if not site: if not site:
_LOGGER.error("Unable to get nearest Met Office forecast site") _LOGGER.error("Unable to get nearest Met Office forecast site")
return False return
# Get data
data = MetOfficeCurrentData(hass, datapoint, site) data = MetOfficeCurrentData(hass, datapoint, site)
try: try:
data.update() data.update()
except (ValueError, dp.exceptions.APIException) as err: except (ValueError, dp.exceptions.APIException) as err:
_LOGGER.error("Received error from Met Office Datapoint: %s", err) _LOGGER.error("Received error from Met Office Datapoint: %s", err)
return False return
add_devices([MetOfficeWeather(site, data, config.get(CONF_NAME))],
True) add_devices([MetOfficeWeather(site, data, name)], True)
return True
class MetOfficeWeather(WeatherEntity): class MetOfficeWeather(WeatherEntity):
"""Implementation of a Met Office weather condition.""" """Implementation of a Met Office weather condition."""
def __init__(self, site, data, config): def __init__(self, site, data, name):
"""Initialise the platform with a data instance and site.""" """Initialise the platform with a data instance and site."""
self._name = name
self.data = data self.data = data
self.site = site self.site = site
@ -76,7 +82,7 @@ class MetOfficeWeather(WeatherEntity):
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
return 'Met Office ({})'.format(self.site.name) return '{} {}'.format(self._name, self.site.name)
@property @property
def condition(self): def condition(self):
@ -84,8 +90,6 @@ class MetOfficeWeather(WeatherEntity):
return [k for k, v in CONDITION_CLASSES.items() if return [k for k, v in CONDITION_CLASSES.items() if
self.data.data.weather.value in v][0] self.data.data.weather.value in v][0]
# Now implement the WeatherEntity interface
@property @property
def temperature(self): def temperature(self):
"""Return the platform temperature.""" """Return the platform temperature."""