Cleaned up a bunch of typos, removed unused code and made it tidier.

This commit is contained in:
Nahuel Lofeudo 2025-01-12 14:35:04 +00:00
parent d9811d3f91
commit 03d22f47d7
5 changed files with 26 additions and 64 deletions

View File

@ -1,6 +1,6 @@
import datetime import datetime
class ArrivalTime(): class ArrivalTime:
""" Represents the arrival times of buses at one of the configured stops """ """ Represents the arrival times of buses at one of the configured stops """
def __init__(self, stop_id: str, route_id: str, destination: str, due_in_seconds: int, is_added: bool = False) -> None: def __init__(self, stop_id: str, route_id: str, destination: str, due_in_seconds: int, is_added: bool = False) -> None:
@ -14,7 +14,7 @@ class ArrivalTime():
def due_in_minutes(self) -> int: def due_in_minutes(self) -> int:
return int(self.due_in_seconds / 60) return int(self.due_in_seconds / 60)
def isDue(self) -> bool: def is_due(self) -> bool:
return self.due_in_minutes < 1 return self.due_in_minutes < 1
def due_in_str(self) -> str: def due_in_str(self) -> str:

View File

@ -6,7 +6,7 @@ class Config:
with open("config.yaml") as f: with open("config.yaml") as f:
self.config = yaml.safe_load(f.read()) self.config = yaml.safe_load(f.read())
# Pre-load some dictionaries to simplify lookups # Preload some dictionaries to simplify lookups
self.walk_time_by_stop = {} self.walk_time_by_stop = {}
for s in self.config.get("stops", []): for s in self.config.get("stops", []):
self.walk_time_by_stop[str(s["stop_id"])] = s["walk_time"] self.walk_time_by_stop[str(s["stop_id"])] = s["walk_time"]

View File

@ -10,10 +10,9 @@ import refresh_feed
import requests import requests
import sys import sys
import time import time
import threading
import zipfile import zipfile
class GTFSClient(): class GTFSClient:
def __init__(self, feed_url: str, gtfs_r_url: str, gtfs_r_api_key: str, def __init__(self, feed_url: str, gtfs_r_url: str, gtfs_r_api_key: str,
stop_codes: list[str], routes_for_stops: dict[str, str], stop_codes: list[str], routes_for_stops: dict[str, str],
update_queue: queue.Queue, update_interval_seconds: int = 60): update_queue: queue.Queue, update_interval_seconds: int = 60):
@ -31,10 +30,10 @@ class GTFSClient():
except: except:
last_mtime = 0 last_mtime = 0
refreshed, new_mtime = refresh_feed.update_local_file_from_url_v1(last_mtime, feed_name, feed_url) _, new_mtime = refresh_feed.update_local_file_from_url_v1(last_mtime, feed_name, feed_url)
# Load the feed # Load the feed
self.feed = self._read_feed(feed_name, dist_units='km', stop_codes = stop_codes) self.feed = self._read_feed(feed_name, dist_units='km')
gc.collect() gc.collect()
self.stop_ids = self.__wanted_stop_ids() self.stop_ids = self.__wanted_stop_ids()
self.deltas = {} self.deltas = {}
@ -46,7 +45,7 @@ class GTFSClient():
if update_interval_seconds and update_queue: if update_interval_seconds and update_queue:
self._update_interval_seconds = update_interval_seconds self._update_interval_seconds = update_interval_seconds
def _read_feed(self, path: gk.Path, dist_units: str, stop_codes: list[str]) -> gk.Feed: def _read_feed(self, path: str, dist_units: str) -> gk.Feed:
""" """
NOTE: This helper method was extracted from gtfs_kit.feed to modify it NOTE: This helper method was extracted from gtfs_kit.feed to modify it
to only load the stop_times for the stops we are interested in, to only load the stop_times for the stops we are interested in,
@ -55,7 +54,7 @@ class GTFSClient():
This version also reads CSV data straight from the zip file to avoid This version also reads CSV data straight from the zip file to avoid
wearing out the Pi's SD card. wearing out the Pi's SD card.
""" """
FILES_TO_LOAD = [ files_to_load = [
# List of feed files to load. stop_times.txt is loaded separately. # List of feed files to load. stop_times.txt is loaded separately.
'trips.txt', 'trips.txt',
'routes.txt', 'routes.txt',
@ -65,8 +64,7 @@ class GTFSClient():
'agency.txt' 'agency.txt'
] ]
path = gk.Path(path) if not os.path.exists(path):
if not path.exists():
raise ValueError("Path {} does not exist".format(path)) raise ValueError("Path {} does not exist".format(path))
print("Loading GTFS feed {}".format(path), file=sys.stderr) print("Loading GTFS feed {}".format(path), file=sys.stderr)
@ -74,7 +72,7 @@ class GTFSClient():
feed_dict = {table: None for table in gk.cs.GTFS_REF["table"]} feed_dict = {table: None for table in gk.cs.GTFS_REF["table"]}
with zipfile.ZipFile(path) as z: with zipfile.ZipFile(path) as z:
for filename in FILES_TO_LOAD: for filename in files_to_load:
table = filename.split(".")[0] table = filename.split(".")[0]
# read the file # read the file
with z.open(filename) as f: with z.open(filename) as f:
@ -216,20 +214,22 @@ class GTFSClient():
next_buses.drop(index=ids_to_delete, inplace=True) next_buses.drop(index=ids_to_delete, inplace=True)
return next_buses return next_buses
def __time_to_seconds(self, s: str) -> int: @staticmethod
def __time_to_seconds(s: str) -> int:
sx = s.split(":") sx = s.split(":")
if len(sx) != 3: if len(sx) != 3:
print("Malformed timestamp:", s) print("Malformed timestamp:", s)
return 0 return 0
return int(sx[0]) * 3600 + int(sx[1]) * 60 + int (sx[2]) return int(sx[0]) * 3600 + int(sx[1]) * 60 + int (sx[2])
def __due_in_seconds(self, time_str: str) -> int: @staticmethod
def __due_in_seconds(time_str: str) -> int:
""" """
Returns the number of seconds in the future that the time_str (format hh:mm:ss) is Returns the number of seconds in the future that the time_str (format hh:mm:ss) is
""" """
now = datetime.datetime.now().strftime("%H:%M:%S") now = datetime.datetime.now().strftime("%H:%M:%S")
tnow = self.__time_to_seconds(now) tnow = GTFSClient.__time_to_seconds(now)
tstop = self.__time_to_seconds(time_str) tstop = GTFSClient.__time_to_seconds(time_str)
if tstop > tnow: if tstop > tnow:
return tstop - tnow return tstop - tnow
else: else:
@ -251,8 +251,7 @@ class GTFSClient():
return destination return destination
def __poll_gtfsr_deltas(self) -> list[map, set]: def __poll_gtfsr_deltas(self) -> tuple[dict, list, list]:
try: try:
# Poll GTFS-R API # Poll GTFS-R API
if self.gtfs_r_api_key != "": if self.gtfs_r_api_key != "":
@ -260,7 +259,7 @@ class GTFSClient():
response = requests.get(url = self.gtfs_r_url, headers = headers, timeout=(2, 10)) response = requests.get(url = self.gtfs_r_url, headers = headers, timeout=(2, 10))
if response.status_code != 200: if response.status_code != 200:
print("GTFS-R sent non-OK response: {}\n{}".format(response.status_code, response.text)) print("GTFS-R sent non-OK response: {}\n{}".format(response.status_code, response.text))
return ({}, [], []) return {}, [], []
deltas_json = json.loads(response.text) deltas_json = json.loads(response.text)
else: else:
@ -277,7 +276,6 @@ class GTFSClient():
today = datetime.date.today().strftime("%Y%m%d") today = datetime.date.today().strftime("%Y%m%d")
for e in deltas_json.get("entity", []): for e in deltas_json.get("entity", []):
is_deleted = e.get("is_deleted") or False
try: try:
trip_update = e.get("trip_update") trip_update = e.get("trip_update")
trip = trip_update.get("trip") trip = trip_update.get("trip")
@ -328,12 +326,12 @@ class GTFSClient():
print("Unsupported action:", trip_action) print("Unsupported action:", trip_action)
except Exception as x: except Exception as x:
print("Error parsing GTFS-R entry:", str(e)) print("Error parsing GTFS-R entry:", str(e))
raise(x) raise x
return deltas, canceled_trips, added_stops return deltas, canceled_trips, added_stops
except Exception as e: except Exception as e:
print("Polling for GTFS-R failed:", str(e)) print("Polling for GTFS-R failed:", str(e))
return ({}, [], []) return {}, [], []
def get_next_n_buses(self, num_entries: int) -> pd.core.frame.DataFrame: def get_next_n_buses(self, num_entries: int) -> pd.core.frame.DataFrame:
@ -362,7 +360,7 @@ class GTFSClient():
self.added_stops = added_stops self.added_stops = added_stops
arrivals = [] arrivals = []
# take more entries than we need in case there are cancelations # take more entries than we need in case there are cancellations
buses = self.get_next_n_buses(15) buses = self.get_next_n_buses(15)
for index, bus in buses.iterrows(): for index, bus in buses.iterrows():
@ -374,7 +372,7 @@ class GTFSClient():
arrival = ArrivalTime(stop_id = bus["stop_code"], arrival = ArrivalTime(stop_id = bus["stop_code"],
route_id = bus["route_short_name"], route_id = bus["route_short_name"],
destination = bus["trip_headsign"], destination = bus["trip_headsign"],
due_in_seconds = self.__due_in_seconds(bus["arrival_time"]) + delta, due_in_seconds = GTFSClient.__due_in_seconds(bus["arrival_time"]) + delta,
is_added = False is_added = False
) )
arrivals.append(arrival) arrivals.append(arrival)

View File

@ -90,7 +90,7 @@ def update_screen(config: Config, updates: list[ArrivalTime]) -> None:
line = line_num, line = line_num,
route = update.route_id, route = update.route_id,
destination = update.destination, destination = update.destination,
time_left = 'Due' if update.isDue() else update.due_in_str(), time_left = 'Due' if update.is_due() else update.due_in_str(),
time_color = lcd_color, time_color = lcd_color,
text_color = COLOR_LCD_GREEN if update.is_added else COLOR_LCD_AMBER text_color = COLOR_LCD_GREEN if update.is_added else COLOR_LCD_AMBER
) )
@ -146,7 +146,9 @@ def main():
update_queue=update_queue, update_queue=update_queue,
update_interval_seconds=config.update_interval_seconds) update_interval_seconds=config.update_interval_seconds)
# Schedule feed refresh, and force the first one
schedule.every(config.update_interval_seconds).seconds.do(scheduler.refresh) schedule.every(config.update_interval_seconds).seconds.do(scheduler.refresh)
scheduler.refresh()
# Main event loop # Main event loop
running = True running = True

View File

@ -73,41 +73,3 @@ def update_local_file_from_url_v1(last_mtime, local_file, url):
print('No need to refresh feed.', file=sys.stderr) print('No need to refresh feed.', file=sys.stderr)
return updated, mtime return updated, mtime
# v2: download remote file conditionally, with HTTP's If-Modified-Since header.
# This requires the remote server to support both sending the Last-Modified
# header and receiving the If-Modified-Since header.
#
def update_local_file_from_url_v2(last_mtime, local_file, url):
# Get the remote file, but only if it has changed
r = requests.get(url, headers={
'If-Modified-Since': ts_to_httpdate(last_mtime)
})
updated, mtime = False, last_mtime
if r.status_code == requests.codes.ok:
# File is updated and we just downloaded the content
updated = True
# write new content to local file
write_file_with_time(local_file, r.content, mtime)
# Update our notion of the file's last modification time
if 'Last-Modified' in r.headers:
mtime = httpdate_to_ts(r.headers['Last-Modified'])
else:
print('HEY! no Last-Modified header for {}'.format(url),
file=sys.stderr)
elif r.status_code == requests.codes.not_modified:
# Successful call, but no updates to file
print('As of {}, server says {} is the same'.format(time.ctime(), url))
else:
# http request failed
print('HEY! get for {} returned {}'.format(url, r.status_code),
file=sys.stderr)
return updated, mtime