Rewrite of Trafikverket weather - Multiple sensor types supported (#15935)

* Added precipitation type from API

Enables users to see type of precipitation.
Value returned from API is a string in swedish.

* Corrected tox verification errors

Correction of tox findings

* Missed in tox - fixed

* Hound witespace fix

* Updated comment to trigger travis rebuild

Travis tox failed due to problem with tox build process. 
Correcting in a comment to trigger retry in travis..

* Try to retrigger travis/tox successful rebuild

* Cleaning

* Cleaning more

* Trafikverket rebuilt for library

Extended pytrafikverket with weather sensor collction
Changed behaviour of sensor component to use pytrafikverket.
Added more sensors.

User need to change config to use new version.
 [] Documentation needs to be updated

* Cleaned up based on Martins input

Appreciate the feedback
This commit is contained in:
Jonas Karlsson 2018-08-27 06:19:51 +02:00 committed by Martin Hjelmare
parent 5d7a2f92df
commit a439690bd7
2 changed files with 64 additions and 65 deletions

View File

@ -4,119 +4,115 @@ Weather information for air and road temperature, provided by Trafikverket.
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.trafikverket_weatherstation/ https://home-assistant.io/components/sensor.trafikverket_weatherstation/
""" """
import asyncio
from datetime import timedelta from datetime import timedelta
import json
import logging import logging
import requests import aiohttp
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 (
ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME, CONF_TYPE, TEMP_CELSIUS) ATTR_ATTRIBUTION, CONF_API_KEY, CONF_MONITORED_CONDITIONS, CONF_NAME)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv 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
REQUIREMENTS = ['pytrafikverket==0.1.5.8']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_ATTRIBUTION = "Data provided by Trafikverket API" SCAN_INTERVAL = timedelta(seconds=300)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
CONF_ATTRIBUTION = "Data provided by Trafikverket API"
CONF_STATION = 'station' CONF_STATION = 'station'
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
SCAN_INTERVAL = timedelta(seconds=300) SENSOR_TYPES = {
'air_temp': ['Air temperature', '°C', 'air_temp'],
'road_temp': ['Road temperature', '°C', 'road_temp'],
'precipitation': ['Precipitation type', None, 'precipitationtype'],
'wind_direction': ['Wind direction', '°', 'winddirection'],
'wind_direction_text': ['Wind direction text', None, 'winddirectiontext'],
'wind_speed': ['Wind speed', 'm/s', 'windforce'],
'humidity': ['Humidity', '%', 'humidity'],
}
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_NAME): cv.string, vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_STATION): cv.string, vol.Required(CONF_STATION): cv.string,
vol.Required(CONF_TYPE): vol.In(['air', 'road']), vol.Required(CONF_MONITORED_CONDITIONS, default=[]):
[vol.In(SENSOR_TYPES)],
}) })
def setup_platform(hass, config, add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Trafikverket sensor platform.""" """Set up the Trafikverket sensor platform."""
sensor_name = config.get(CONF_NAME) from pytrafikverket.trafikverket_weather import TrafikverketWeather
sensor_api = config.get(CONF_API_KEY)
sensor_station = config.get(CONF_STATION)
sensor_type = config.get(CONF_TYPE)
add_entities([TrafikverketWeatherStation( sensor_name = config[CONF_NAME]
sensor_name, sensor_api, sensor_station, sensor_type)], True) sensor_api = config[CONF_API_KEY]
sensor_station = config[CONF_STATION]
web_session = async_get_clientsession(hass)
weather_api = TrafikverketWeather(web_session, sensor_api)
dev = []
for condition in config[CONF_MONITORED_CONDITIONS]:
dev.append(TrafikverketWeatherStation(
weather_api, sensor_name, condition, sensor_station))
if dev:
async_add_entities(dev, True)
class TrafikverketWeatherStation(Entity): class TrafikverketWeatherStation(Entity):
"""Representation of a Trafikverket sensor.""" """Representation of a Trafikverket sensor."""
def __init__(self, sensor_name, sensor_api, sensor_station, sensor_type): def __init__(self, weather_api, name, sensor_type, sensor_station):
"""Initialize the Trafikverket sensor.""" """Initialize the sensor."""
self._name = sensor_name self._client = name
self._api = sensor_api self._name = SENSOR_TYPES[sensor_type][0]
self._station = sensor_station
self._type = sensor_type self._type = sensor_type
self._state = None self._state = None
self._unit = SENSOR_TYPES[sensor_type][1]
self._station = sensor_station
self._weather_api = weather_api
self._attributes = { self._attributes = {
ATTR_ATTRIBUTION: CONF_ATTRIBUTION, ATTR_ATTRIBUTION: CONF_ATTRIBUTION,
} }
self._weather = None
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
return self._name return '{} {}'.format(self._client, self._name)
@property @property
def state(self): def state(self):
"""Return the state of the sensor.""" """Return the state of the device."""
return self._state return self._state
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement.""" """Return the unit of measurement of this entity, if any."""
return TEMP_CELSIUS return self._unit
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes
@Throttle(MIN_TIME_BETWEEN_UPDATES) @Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self): async def async_update(self):
"""Fetch new state data for the sensor.""" """Get the latest data from Trafikverket and updates the states."""
url = 'http://api.trafikinfo.trafikverket.se/v1.3/data.json'
if self._type == 'road':
air_vs_road = 'Road'
else:
air_vs_road = 'Air'
xml = """
<REQUEST>
<LOGIN authenticationkey='""" + self._api + """' />
<QUERY objecttype="WeatherStation">
<FILTER>
<EQ name="Name" value='""" + self._station + """' />
</FILTER>
<INCLUDE>Measurement.""" + air_vs_road + """.Temp</INCLUDE>
</QUERY>
</REQUEST>"""
# Testing JSON post request.
try: try:
post = requests.post(url, data=xml.encode('utf-8'), timeout=5) self._weather = await self._weather_api.async_get_weather(
except requests.exceptions.RequestException as err: self._station)
_LOGGER.error("Please check network connection: %s", err) self._state = getattr(
return self._weather,
SENSOR_TYPES[self._type][2])
# Checking JSON respons. except (asyncio.TimeoutError,
try: aiohttp.ClientError, ValueError) as error:
data = json.loads(post.text) _LOGGER.error("Couldn't fetch weather data: %s", error)
result = data["RESPONSE"]["RESULT"][0]
final = result["WeatherStation"][0]["Measurement"]
except KeyError:
_LOGGER.error("Incorrect weather station or API key")
return
# air_vs_road contains "Air" or "Road" depending on user input.
self._state = final[air_vs_road]["Temp"]

View File

@ -1171,6 +1171,9 @@ pytrackr==0.0.5
# homeassistant.components.tradfri # homeassistant.components.tradfri
pytradfri[async]==5.5.1 pytradfri[async]==5.5.1
# homeassistant.components.sensor.trafikverket_weatherstation
pytrafikverket==0.1.5.8
# homeassistant.components.device_tracker.unifi # homeassistant.components.device_tracker.unifi
pyunifi==2.13 pyunifi==2.13