GTFS fixes (#2119)

* Change to official PyGTFS source

* Threading fixes for GTFS

* Actually pygtfs 0.1.3

* Update requirements_all.txt

* Update gtfs version
This commit is contained in:
Robbie Trencheny 2016-05-21 11:04:18 -07:00 committed by Paulus Schoutsen
parent 3ce6c732ab
commit 0f1c4d2f8c
2 changed files with 64 additions and 60 deletions

View File

@ -7,14 +7,15 @@ https://home-assistant.io/components/sensor.gtfs/
import os import os
import logging import logging
import datetime import datetime
import threading
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ["https://github.com/robbiet480/pygtfs/archive/" REQUIREMENTS = ["https://github.com/robbiet480/pygtfs/archive/"
"432414b720c580fb2667a0a48f539118a2d95969.zip#" "00546724e4bbcb3053110d844ca44e2246267dd8.zip#"
"pygtfs==0.1.2"] "pygtfs==0.1.3"]
ICON = "mdi:train" ICON = "mdi:train"
@ -152,9 +153,22 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.error("The given GTFS data file/folder was not found!") _LOGGER.error("The given GTFS data file/folder was not found!")
return False return False
import pygtfs
split_file_name = os.path.splitext(config["data"])
sqlite_file = "{}.sqlite".format(split_file_name[0])
joined_path = os.path.join(gtfs_dir, sqlite_file)
gtfs = pygtfs.Schedule(joined_path)
# pylint: disable=no-member
if len(gtfs.feeds) < 1:
pygtfs.append_feed(gtfs, os.path.join(gtfs_dir,
config["data"]))
dev = [] dev = []
dev.append(GTFSDepartureSensor(config["data"], gtfs_dir, dev.append(GTFSDepartureSensor(gtfs, config["origin"],
config["origin"], config["destination"])) config["destination"]))
add_devices(dev) add_devices(dev)
# pylint: disable=too-many-instance-attributes,too-few-public-methods # pylint: disable=too-many-instance-attributes,too-few-public-methods
@ -163,16 +177,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class GTFSDepartureSensor(Entity): class GTFSDepartureSensor(Entity):
"""Implementation of an GTFS departures sensor.""" """Implementation of an GTFS departures sensor."""
def __init__(self, data_source, gtfs_folder, origin, destination): def __init__(self, pygtfs, origin, destination):
"""Initialize the sensor.""" """Initialize the sensor."""
self._data_source = data_source self._pygtfs = pygtfs
self._gtfs_folder = gtfs_folder
self.origin = origin self.origin = origin
self.destination = destination self.destination = destination
self._name = "GTFS Sensor" self._name = "GTFS Sensor"
self._unit_of_measurement = "min" self._unit_of_measurement = "min"
self._state = 0 self._state = 0
self._attributes = {} self._attributes = {}
self.lock = threading.Lock()
self.update() self.update()
@property @property
@ -202,62 +216,52 @@ class GTFSDepartureSensor(Entity):
def update(self): def update(self):
"""Get the latest data from GTFS and update the states.""" """Get the latest data from GTFS and update the states."""
import pygtfs with self.lock:
self._departure = get_next_departure(self._pygtfs, self.origin,
self.destination)
self._state = self._departure["minutes_until_departure"]
split_file_name = os.path.splitext(self._data_source) origin_station = self._departure["origin_station"]
destination_station = self._departure["destination_station"]
origin_stop_time = self._departure["origin_stop_time"]
destination_stop_time = self._departure["destination_stop_time"]
agency = self._departure["agency"]
route = self._departure["route"]
trip = self._departure["trip"]
sqlite_file = "{}.sqlite".format(split_file_name[0]) name = "{} {} to {} next departure"
gtfs = pygtfs.Schedule(os.path.join(self._gtfs_folder, sqlite_file)) self._name = name.format(agency.agency_name,
origin_station.stop_id,
destination_station.stop_id)
# pylint: disable=no-member # Build attributes
if len(gtfs.feeds) < 1:
pygtfs.append_feed(gtfs, os.path.join(self._gtfs_folder,
self._data_source))
self._departure = get_next_departure(gtfs, self.origin, self._attributes = {}
self.destination)
self._state = self._departure["minutes_until_departure"]
origin_station = self._departure["origin_station"] def dict_for_table(resource):
destination_station = self._departure["destination_station"] """Return a dict for the SQLAlchemy resource given."""
origin_stop_time = self._departure["origin_stop_time"] return dict((col, getattr(resource, col))
destination_stop_time = self._departure["destination_stop_time"] for col in resource.__table__.columns.keys())
agency = self._departure["agency"]
route = self._departure["route"]
trip = self._departure["trip"]
name = "{} {} to {} next departure" def append_keys(resource, prefix=None):
self._name = name.format(agency.agency_name, """Properly format key val pairs to append to attributes."""
origin_station.stop_id, for key, val in resource.items():
destination_station.stop_id) if val == "" or val is None or key == "feed_id":
continue
pretty_key = key.replace("_", " ")
pretty_key = pretty_key.title()
pretty_key = pretty_key.replace("Id", "ID")
pretty_key = pretty_key.replace("Url", "URL")
if prefix is not None and \
pretty_key.startswith(prefix) is False:
pretty_key = "{} {}".format(prefix, pretty_key)
self._attributes[pretty_key] = val
# Build attributes append_keys(dict_for_table(agency), "Agency")
append_keys(dict_for_table(route), "Route")
self._attributes = {} append_keys(dict_for_table(trip), "Trip")
append_keys(dict_for_table(origin_station), "Origin Station")
def dict_for_table(resource): append_keys(dict_for_table(destination_station),
"""Return a dict for the SQLAlchemy resource given.""" "Destination Station")
return dict((col, getattr(resource, col)) append_keys(origin_stop_time, "Origin Stop")
for col in resource.__table__.columns.keys()) append_keys(destination_stop_time, "Destination Stop")
def append_keys(resource, prefix=None):
"""Properly format key val pairs to append to attributes."""
for key, val in resource.items():
if val == "" or val is None or key == "feed_id":
continue
pretty_key = key.replace("_", " ")
pretty_key = pretty_key.title()
pretty_key = pretty_key.replace("Id", "ID")
pretty_key = pretty_key.replace("Url", "URL")
if prefix is not None and \
pretty_key.startswith(prefix) is False:
pretty_key = "{} {}".format(prefix, pretty_key)
self._attributes[pretty_key] = val
append_keys(dict_for_table(agency), "Agency")
append_keys(dict_for_table(route), "Route")
append_keys(dict_for_table(trip), "Trip")
append_keys(dict_for_table(origin_station), "Origin Station")
append_keys(dict_for_table(destination_station), "Destination Station")
append_keys(origin_stop_time, "Origin Stop")
append_keys(destination_stop_time, "Destination Stop")

View File

@ -131,7 +131,7 @@ https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f
https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3 https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3
# homeassistant.components.sensor.gtfs # homeassistant.components.sensor.gtfs
https://github.com/robbiet480/pygtfs/archive/432414b720c580fb2667a0a48f539118a2d95969.zip#pygtfs==0.1.2 https://github.com/robbiet480/pygtfs/archive/00546724e4bbcb3053110d844ca44e2246267dd8.zip#pygtfs==0.1.3
# homeassistant.components.scene.hunterdouglas_powerview # homeassistant.components.scene.hunterdouglas_powerview
https://github.com/sander76/powerviewApi/archive/master.zip#powerviewApi==0.2 https://github.com/sander76/powerviewApi/archive/master.zip#powerviewApi==0.2