Use luftdaten module (#10970)

* Use luftdaten module

* Refactoring

* Check meta data

* Make name consistent

* Remove try block
This commit is contained in:
Fabian Affolter 2017-12-12 08:09:47 +01:00 committed by GitHub
parent a79c7ee217
commit ed06b8cead
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 55 deletions

View File

@ -5,85 +5,94 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.luftdaten/ https://home-assistant.io/components/sensor.luftdaten/
""" """
import asyncio import asyncio
import json
import logging
from datetime import timedelta from datetime import timedelta
import logging
import requests
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_NAME, CONF_RESOURCE, CONF_VERIFY_SSL, CONF_MONITORED_CONDITIONS, ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, CONF_NAME, TEMP_CELSIUS)
TEMP_CELSIUS) from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
REQUIREMENTS = ['luftdaten==0.1.1']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
ATTR_SENSOR_ID = 'sensor_id'
CONF_ATTRIBUTION = "Data provided by luftdaten.info"
VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3' VOLUME_MICROGRAMS_PER_CUBIC_METER = 'µg/m3'
SENSOR_TEMPERATURE = 'temperature' SENSOR_TEMPERATURE = 'temperature'
SENSOR_HUMIDITY = 'humidity' SENSOR_HUMIDITY = 'humidity'
SENSOR_PM10 = 'P1' SENSOR_PM10 = 'P1'
SENSOR_PM2_5 = 'P2' SENSOR_PM2_5 = 'P2'
SENSOR_PRESSURE = 'pressure'
SENSOR_TYPES = { SENSOR_TYPES = {
SENSOR_TEMPERATURE: ['Temperature', TEMP_CELSIUS], SENSOR_TEMPERATURE: ['Temperature', TEMP_CELSIUS],
SENSOR_HUMIDITY: ['Humidity', '%'], SENSOR_HUMIDITY: ['Humidity', '%'],
SENSOR_PRESSURE: ['Pressure', 'Pa'],
SENSOR_PM10: ['PM10', VOLUME_MICROGRAMS_PER_CUBIC_METER], SENSOR_PM10: ['PM10', VOLUME_MICROGRAMS_PER_CUBIC_METER],
SENSOR_PM2_5: ['PM2.5', VOLUME_MICROGRAMS_PER_CUBIC_METER] SENSOR_PM2_5: ['PM2.5', VOLUME_MICROGRAMS_PER_CUBIC_METER]
} }
DEFAULT_NAME = 'Luftdaten Sensor' DEFAULT_NAME = 'Luftdaten'
DEFAULT_RESOURCE = 'https://api.luftdaten.info/v1/sensor/'
DEFAULT_VERIFY_SSL = True
CONF_SENSORID = 'sensorid' CONF_SENSORID = 'sensorid'
SCAN_INTERVAL = timedelta(minutes=3) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORID): cv.positive_int, vol.Required(CONF_SENSORID): cv.positive_int,
vol.Required(CONF_MONITORED_CONDITIONS): vol.Required(CONF_MONITORED_CONDITIONS):
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.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_RESOURCE, default=DEFAULT_RESOURCE): cv.string,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean
}) })
@asyncio.coroutine @asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the Luftdaten sensor.""" """Set up the Luftdaten sensor."""
from luftdaten import Luftdaten
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
sensorid = config.get(CONF_SENSORID) sensor_id = config.get(CONF_SENSORID)
verify_ssl = config.get(CONF_VERIFY_SSL)
resource = '{}{}/'.format(config.get(CONF_RESOURCE), sensorid) session = async_get_clientsession(hass)
luftdaten = LuftdatenData(Luftdaten(sensor_id, hass.loop, session))
rest_client = LuftdatenData(resource, verify_ssl) yield from luftdaten.async_update()
rest_client.update()
if rest_client.data is None: if luftdaten.data is None:
_LOGGER.error("Unable to fetch Luftdaten data") _LOGGER.error("Sensor is not available: %s", sensor_id)
return False return
devices = [] devices = []
for variable in config[CONF_MONITORED_CONDITIONS]: for variable in config[CONF_MONITORED_CONDITIONS]:
devices.append(LuftdatenSensor(rest_client, name, variable)) if luftdaten.data.values[variable] is None:
_LOGGER.warning("It might be that sensor %s is not providing "
"measurements for %s", sensor_id, variable)
devices.append(LuftdatenSensor(luftdaten, name, variable, sensor_id))
async_add_devices(devices, True) async_add_devices(devices)
class LuftdatenSensor(Entity): class LuftdatenSensor(Entity):
"""Implementation of a LuftdatenSensor sensor.""" """Implementation of a Luftdaten sensor."""
def __init__(self, rest_client, name, sensor_type): def __init__(self, luftdaten, name, sensor_type, sensor_id):
"""Initialize the LuftdatenSensor sensor.""" """Initialize the Luftdaten sensor."""
self.rest_client = rest_client self.luftdaten = luftdaten
self._name = name self._name = name
self._state = None self._state = None
self._sensor_id = sensor_id
self.sensor_type = sensor_type self.sensor_type = sensor_type
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
@ -95,48 +104,50 @@ class LuftdatenSensor(Entity):
@property @property
def state(self): def state(self):
"""Return the state of the device.""" """Return the state of the device."""
return self._state return self.luftdaten.data.values[self.sensor_type]
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any.""" """Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement return self._unit_of_measurement
def update(self): @property
"""Get the latest data from REST API and update the state.""" def device_state_attributes(self):
self.rest_client.update() """Return the state attributes."""
value = self.rest_client.data if self.luftdaten.data.meta is None:
return
if value is None: attr = {
self._state = None ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
else: ATTR_SENSOR_ID: self._sensor_id,
parsed_json = json.loads(value) 'lat': self.luftdaten.data.meta['latitude'],
'long': self.luftdaten.data.meta['longitude'],
}
return attr
log_entries_count = len(parsed_json) - 1 @asyncio.coroutine
latest_log_entry = parsed_json[log_entries_count] def async_update(self):
sensordata_values = latest_log_entry['sensordatavalues'] """Get the latest data from luftdaten.info and update the state."""
for sensordata_value in sensordata_values: try:
if sensordata_value['value_type'] == self.sensor_type: yield from self.luftdaten.async_update()
self._state = sensordata_value['value'] except TypeError:
pass
class LuftdatenData(object): class LuftdatenData(object):
"""Class for handling the data retrieval.""" """Class for handling the data retrieval."""
def __init__(self, resource, verify_ssl): def __init__(self, data):
"""Initialize the data object.""" """Initialize the data object."""
self._request = requests.Request('GET', resource).prepare() self.data = data
self._verify_ssl = verify_ssl
self.data = None @Throttle(MIN_TIME_BETWEEN_UPDATES)
@asyncio.coroutine
def async_update(self):
"""Get the latest data from luftdaten.info."""
from luftdaten.exceptions import LuftdatenError
def update(self):
"""Get the latest data from Luftdaten service."""
try: try:
with requests.Session() as sess: yield from self.data.async_get_data()
response = sess.send( except LuftdatenError:
self._request, timeout=10, verify=self._verify_ssl) _LOGGER.error("Unable to retrieve data from luftdaten.info")
self.data = response.text
except requests.exceptions.RequestException:
_LOGGER.error("Error fetching data: %s", self._request)
self.data = None

View File

@ -444,6 +444,9 @@ liveboxplaytv==2.0.0
# homeassistant.components.notify.lametric # homeassistant.components.notify.lametric
lmnotify==0.0.4 lmnotify==0.0.4
# homeassistant.components.sensor.luftdaten
luftdaten==0.1.1
# homeassistant.components.sensor.lyft # homeassistant.components.sensor.lyft
lyft_rides==0.2 lyft_rides==0.2