This commit is contained in:
Paulus Schoutsen 2019-07-31 12:25:30 -07:00
parent da05dfe708
commit 4de97abc3a
2676 changed files with 163166 additions and 140084 deletions

View file

@ -6,7 +6,7 @@ from datetime import timedelta
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (CONF_NAME, ATTR_ATTRIBUTION)
from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
@ -15,57 +15,64 @@ from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__)
CONF_NEXT_DEPARTURE = 'next_departure'
CONF_NEXT_DEPARTURE = "next_departure"
CONF_STATION = 'station'
CONF_DESTINATIONS = 'destinations'
CONF_DIRECTION = 'direction'
CONF_LINES = 'lines'
CONF_PRODUCTS = 'products'
CONF_TIME_OFFSET = 'time_offset'
CONF_MAX_JOURNEYS = 'max_journeys'
CONF_TIMEOUT = 'timeout'
CONF_STATION = "station"
CONF_DESTINATIONS = "destinations"
CONF_DIRECTION = "direction"
CONF_LINES = "lines"
CONF_PRODUCTS = "products"
CONF_TIME_OFFSET = "time_offset"
CONF_MAX_JOURNEYS = "max_journeys"
CONF_TIMEOUT = "timeout"
DEFAULT_NAME = 'RMV Journey'
DEFAULT_NAME = "RMV Journey"
VALID_PRODUCTS = ['U-Bahn', 'Tram', 'Bus', 'S', 'RB', 'RE', 'EC', 'IC', 'ICE']
VALID_PRODUCTS = ["U-Bahn", "Tram", "Bus", "S", "RB", "RE", "EC", "IC", "ICE"]
ICONS = {
'U-Bahn': 'mdi:subway',
'Tram': 'mdi:tram',
'Bus': 'mdi:bus',
'S': 'mdi:train',
'RB': 'mdi:train',
'RE': 'mdi:train',
'EC': 'mdi:train',
'IC': 'mdi:train',
'ICE': 'mdi:train',
'SEV': 'mdi:checkbox-blank-circle-outline',
None: 'mdi:clock'
"U-Bahn": "mdi:subway",
"Tram": "mdi:tram",
"Bus": "mdi:bus",
"S": "mdi:train",
"RB": "mdi:train",
"RE": "mdi:train",
"EC": "mdi:train",
"IC": "mdi:train",
"ICE": "mdi:train",
"SEV": "mdi:checkbox-blank-circle-outline",
None: "mdi:clock",
}
ATTRIBUTION = "Data provided by opendata.rmv.de"
SCAN_INTERVAL = timedelta(seconds=60)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_NEXT_DEPARTURE): [{
vol.Required(CONF_STATION): cv.string,
vol.Optional(CONF_DESTINATIONS, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_DIRECTION): cv.string,
vol.Optional(CONF_LINES, default=[]):
vol.All(cv.ensure_list, [cv.positive_int, cv.string]),
vol.Optional(CONF_PRODUCTS, default=VALID_PRODUCTS):
vol.All(cv.ensure_list, [vol.In(VALID_PRODUCTS)]),
vol.Optional(CONF_TIME_OFFSET, default=0): cv.positive_int,
vol.Optional(CONF_MAX_JOURNEYS, default=5): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string}],
vol.Optional(CONF_TIMEOUT, default=10): cv.positive_int
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_NEXT_DEPARTURE): [
{
vol.Required(CONF_STATION): cv.string,
vol.Optional(CONF_DESTINATIONS, default=[]): vol.All(
cv.ensure_list, [cv.string]
),
vol.Optional(CONF_DIRECTION): cv.string,
vol.Optional(CONF_LINES, default=[]): vol.All(
cv.ensure_list, [cv.positive_int, cv.string]
),
vol.Optional(CONF_PRODUCTS, default=VALID_PRODUCTS): vol.All(
cv.ensure_list, [vol.In(VALID_PRODUCTS)]
),
vol.Optional(CONF_TIME_OFFSET, default=0): cv.positive_int,
vol.Optional(CONF_MAX_JOURNEYS, default=5): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
],
vol.Optional(CONF_TIMEOUT, default=10): cv.positive_int,
}
)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the RMV departure sensor."""
timeout = config.get(CONF_TIMEOUT)
@ -84,7 +91,9 @@ async def async_setup_platform(hass, config, async_add_entities,
next_departure.get(CONF_TIME_OFFSET),
next_departure.get(CONF_MAX_JOURNEYS),
next_departure.get(CONF_NAME),
timeout))
timeout,
)
)
tasks = [sensor.async_update() for sensor in sensors]
if tasks:
@ -98,15 +107,34 @@ async def async_setup_platform(hass, config, async_add_entities,
class RMVDepartureSensor(Entity):
"""Implementation of an RMV departure sensor."""
def __init__(self, session, station, destinations, direction, lines,
products, time_offset, max_journeys, name, timeout):
def __init__(
self,
session,
station,
destinations,
direction,
lines,
products,
time_offset,
max_journeys,
name,
timeout,
):
"""Initialize the sensor."""
self._station = station
self._name = name
self._state = None
self.data = RMVDepartureData(session, station, destinations,
direction, lines, products, time_offset,
max_journeys, timeout)
self.data = RMVDepartureData(
session,
station,
destinations,
direction,
lines,
products,
time_offset,
max_journeys,
timeout,
)
self._icon = ICONS[None]
@property
@ -129,13 +157,12 @@ class RMVDepartureSensor(Entity):
"""Return the state attributes."""
try:
return {
'next_departures': [val for val in self.data.departures[1:]],
'direction': self.data.departures[0].get('direction'),
'line': self.data.departures[0].get('line'),
'minutes': self.data.departures[0].get('minutes'),
'departure_time':
self.data.departures[0].get('departure_time'),
'product': self.data.departures[0].get('product'),
"next_departures": [val for val in self.data.departures[1:]],
"direction": self.data.departures[0].get("direction"),
"line": self.data.departures[0].get("line"),
"minutes": self.data.departures[0].get("minutes"),
"departure_time": self.data.departures[0].get("departure_time"),
"product": self.data.departures[0].get("product"),
}
except IndexError:
return {}
@ -161,15 +188,25 @@ class RMVDepartureSensor(Entity):
if self._name == DEFAULT_NAME:
self._name = self.data.station
self._station = self.data.station
self._state = self.data.departures[0].get('minutes')
self._icon = ICONS[self.data.departures[0].get('product')]
self._state = self.data.departures[0].get("minutes")
self._icon = ICONS[self.data.departures[0].get("product")]
class RMVDepartureData:
"""Pull data from the opendata.rmv.de web page."""
def __init__(self, session, station_id, destinations, direction, lines,
products, time_offset, max_journeys, timeout):
def __init__(
self,
session,
station_id,
destinations,
direction,
lines,
products,
time_offset,
max_journeys,
timeout,
):
"""Initialize the sensor."""
from RMVtransport import RMVtransport
@ -190,34 +227,36 @@ class RMVDepartureData:
from RMVtransport.rmvtransport import RMVtransportApiConnectionError
try:
_data = await self.rmv.get_departures(self._station_id,
products=self._products,
directionId=self._direction,
maxJourneys=50)
_data = await self.rmv.get_departures(
self._station_id,
products=self._products,
directionId=self._direction,
maxJourneys=50,
)
except RMVtransportApiConnectionError:
self.departures = []
_LOGGER.warning("Could not retrive data from rmv.de")
return
self.station = _data.get('station')
self.station = _data.get("station")
_deps = []
for journey in _data['journeys']:
for journey in _data["journeys"]:
# find the first departure meeting the criteria
_nextdep = {ATTR_ATTRIBUTION: ATTRIBUTION}
if self._destinations:
dest_found = False
for dest in self._destinations:
if dest in journey['stops']:
if dest in journey["stops"]:
dest_found = True
_nextdep['destination'] = dest
_nextdep["destination"] = dest
if not dest_found:
continue
elif self._lines and journey['number'] not in self._lines:
elif self._lines and journey["number"] not in self._lines:
continue
elif journey['minutes'] < self._time_offset:
elif journey["minutes"] < self._time_offset:
continue
for attr in ['direction', 'departure_time', 'product', 'minutes']:
_nextdep[attr] = journey.get(attr, '')
_nextdep['line'] = journey.get('number', '')
for attr in ["direction", "departure_time", "product", "minutes"]:
_nextdep[attr] = journey.get(attr, "")
_nextdep["line"] = journey.get("number", "")
_deps.append(_nextdep)
if len(_deps) > self._max_journeys:
break