Allow to set coordinates (#8858)

This commit is contained in:
Fabian Affolter 2017-08-06 15:20:51 +02:00 committed by GitHub
parent 24e9fa238a
commit b655fe6e04
2 changed files with 50 additions and 40 deletions

View file

@ -5,11 +5,11 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.zamg/ https://home-assistant.io/components/sensor.zamg/
""" """
import csv import csv
from datetime import datetime, timedelta
import gzip import gzip
import json import json
import logging import logging
import os import os
from datetime import datetime, timedelta
import pytz import pytz
import requests import requests
@ -26,6 +26,8 @@ from homeassistant.const import (
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__)
ATTR_STATION = 'station' ATTR_STATION = 'station'
ATTR_UPDATED = 'updated' ATTR_UPDATED = 'updated'
ATTRIBUTION = 'Data provided by ZAMG' ATTRIBUTION = 'Data provided by ZAMG'
@ -35,7 +37,7 @@ CONF_STATION_ID = 'station_id'
DEFAULT_NAME = 'zamg' DEFAULT_NAME = 'zamg'
# Data source updates once per hour, so we do nothing if it's been less time # Data source updates once per hour, so we do nothing if it's been less time
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
SENSOR_TYPES = { SENSOR_TYPES = {
ATTR_WEATHER_PRESSURE: ('Pressure', 'hPa', 'LDstat hPa', float), ATTR_WEATHER_PRESSURE: ('Pressure', 'hPa', 'LDstat hPa', float),
@ -58,34 +60,38 @@ SENSOR_TYPES = {
} }
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Required(CONF_MONITORED_CONDITIONS): vol.Required(CONF_MONITORED_CONDITIONS, default=['temperature']):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
vol.Optional(CONF_STATION_ID): cv.string, vol.Optional(CONF_STATION_ID): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): 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 ZAMG sensor platform.""" """Set up the ZAMG sensor platform."""
logger = logging.getLogger(__name__) name = config.get(CONF_NAME)
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
station_id = config.get(CONF_STATION_ID) or closest_station( station_id = config.get(CONF_STATION_ID) or closest_station(
config.get(CONF_LATITUDE), latitude, longitude, hass.config.config_dir)
config.get(CONF_LONGITUDE),
hass.config.config_dir)
if station_id not in zamg_stations(hass.config.config_dir): if station_id not in zamg_stations(hass.config.config_dir):
logger.error("Configured ZAMG %s (%s) is not a known station", _LOGGER.error("Configured ZAMG %s (%s) is not a known station",
CONF_STATION_ID, station_id) CONF_STATION_ID, station_id)
return False return False
probe = ZamgData(station_id=station_id, logger=logger) probe = ZamgData(station_id=station_id)
try: try:
probe.update() probe.update()
except ValueError as err: except (ValueError, TypeError) as err:
logger.error("Received error from ZAMG: %s", err) _LOGGER.error("Received error from ZAMG: %s", err)
return False return False
add_devices([ZamgSensor(probe, variable, config.get(CONF_NAME)) add_devices([ZamgSensor(probe, variable, name)
for variable in config[CONF_MONITORED_CONDITIONS]], True) for variable in config[CONF_MONITORED_CONDITIONS]], True)
@ -97,11 +103,6 @@ class ZamgSensor(Entity):
self.probe = probe self.probe = probe
self.client_name = name self.client_name = name
self.variable = variable self.variable = variable
self.update()
def update(self):
"""Delegate update to probe."""
self.probe.update()
@property @property
def name(self): def name(self):
@ -127,6 +128,10 @@ class ZamgSensor(Entity):
ATTR_UPDATED: self.probe.last_update.isoformat(), ATTR_UPDATED: self.probe.last_update.isoformat(),
} }
def update(self):
"""Delegate update to probe."""
self.probe.update()
class ZamgData(object): class ZamgData(object):
"""The class for handling the data retrieval.""" """The class for handling the data retrieval."""
@ -136,9 +141,8 @@ class ZamgData(object):
'User-Agent': '{} {}'.format('home-assistant.zamg/', __version__), 'User-Agent': '{} {}'.format('home-assistant.zamg/', __version__),
} }
def __init__(self, logger, station_id): def __init__(self, station_id):
"""Initialize the probe.""" """Initialize the probe."""
self._logger = logger
self._station_id = station_id self._station_id = station_id
self.data = {} self.data = {}
@ -160,8 +164,8 @@ class ZamgData(object):
response.encoding = 'UTF8' response.encoding = 'UTF8'
return csv.DictReader(response.text.splitlines(), return csv.DictReader(response.text.splitlines(),
delimiter=';', quotechar='"') delimiter=';', quotechar='"')
except Exception: # pylint:disable=broad-except except requests.exceptions.HTTPError:
logging.getLogger(__name__).exception("While fetching data") _LOGGER.error("While fetching data")
@Throttle(MIN_TIME_BETWEEN_UPDATES) @Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self): def update(self):
@ -182,8 +186,8 @@ class ZamgData(object):
if col_heading in api_fields and v} if col_heading in api_fields and v}
break break
else: else:
raise ValueError('No weather data for station {}' raise ValueError(
.format(self._station_id)) "No weather data for station {}".format(self._station_id))
def get_data(self, variable): def get_data(self, variable):
"""Get the data.""" """Get the data."""
@ -204,8 +208,8 @@ def _get_zamg_stations():
float(row[coord].replace(',', '.')) float(row[coord].replace(',', '.'))
for coord in ['breite_dezi', 'länge_dezi']) for coord in ['breite_dezi', 'länge_dezi'])
except KeyError: except KeyError:
logging.getLogger(__name__).exception( _LOGGER.error(
'ZAMG schema changed again, cannot autodetect station.') "ZAMG schema changed again, cannot autodetect station")
return stations return stations
@ -232,7 +236,7 @@ def closest_station(lat, lon, cache_dir):
stations = zamg_stations(cache_dir) stations = zamg_stations(cache_dir)
def comparable_dist(zamg_id): def comparable_dist(zamg_id):
"""Calculater psudeo-distance from lat/lon.""" """Calculate the psudeo-distance from lat/lon."""
station_lat, station_lon = stations[zamg_id] station_lat, station_lon = stations[zamg_id]
return (lat - station_lat) ** 2 + (lon - station_lon) ** 2 return (lat - station_lat) ** 2 + (lon - station_lon) ** 2

View file

@ -12,8 +12,8 @@ from homeassistant.components.weather import (
WeatherEntity, ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_PRESSURE, WeatherEntity, ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_PRESSURE,
ATTR_WEATHER_TEMPERATURE, ATTR_WEATHER_WIND_BEARING, ATTR_WEATHER_TEMPERATURE, ATTR_WEATHER_WIND_BEARING,
ATTR_WEATHER_WIND_SPEED, PLATFORM_SCHEMA) ATTR_WEATHER_WIND_SPEED, PLATFORM_SCHEMA)
from homeassistant.const import \ from homeassistant.const import (
CONF_NAME, TEMP_CELSIUS, CONF_LATITUDE, CONF_LONGITUDE CONF_NAME, TEMP_CELSIUS, CONF_LATITUDE, CONF_LONGITUDE)
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 # Reuse data and API logic from the sensor implementation
from homeassistant.components.sensor.zamg import ( from homeassistant.components.sensor.zamg import (
@ -24,28 +24,34 @@ _LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_STATION_ID): cv.string, vol.Optional(CONF_STATION_ID): 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 ZAMG sensor platform.""" """Set up the ZAMG weather platform."""
name = config.get(CONF_NAME)
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
station_id = config.get(CONF_STATION_ID) or closest_station( station_id = config.get(CONF_STATION_ID) or closest_station(
config.get(CONF_LATITUDE), latitude, longitude, hass.config.config_dir)
config.get(CONF_LONGITUDE),
hass.config.config_dir)
if station_id not in zamg_stations(hass.config.config_dir): if station_id not in zamg_stations(hass.config.config_dir):
_LOGGER.error("Configured ZAMG %s (%s) is not a known station", _LOGGER.error("Configured ZAMG %s (%s) is not a known station",
CONF_STATION_ID, station_id) CONF_STATION_ID, station_id)
return False return False
probe = ZamgData(station_id=station_id, logger=_LOGGER) probe = ZamgData(station_id=station_id)
try: try:
probe.update() probe.update()
except ValueError as err: except (ValueError, TypeError) as err:
_LOGGER.error("Received error from ZAMG: %s", err) _LOGGER.error("Received error from ZAMG: %s", err)
return False return False
add_devices([ZamgWeather(probe, config.get(CONF_NAME))], True) add_devices([ZamgWeather(probe, name)], True)
class ZamgWeather(WeatherEntity): class ZamgWeather(WeatherEntity):
@ -56,10 +62,6 @@ class ZamgWeather(WeatherEntity):
self.zamg_data = zamg_data self.zamg_data = zamg_data
self.stationname = stationname self.stationname = stationname
def update(self):
"""Update current conditions."""
self.zamg_data.update()
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
@ -105,3 +107,7 @@ class ZamgWeather(WeatherEntity):
def wind_bearing(self): def wind_bearing(self):
"""Return the wind bearing.""" """Return the wind bearing."""
return self.zamg_data.get_data(ATTR_WEATHER_WIND_BEARING) return self.zamg_data.get_data(ATTR_WEATHER_WIND_BEARING)
def update(self):
"""Update current conditions."""
self.zamg_data.update()