Create a separate config file, move settings there
This commit is contained in:
parent
eb41b52b52
commit
e5019b137d
|
|
@ -1 +0,0 @@
|
||||||
API KEY FROM https://developer.nationaltransport.ie/ GOES HERE
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
def __init__(self):
|
||||||
|
# Load the config file
|
||||||
|
with open("config.yaml") as f:
|
||||||
|
self.__config = yaml.safe_load(f.read())
|
||||||
|
|
||||||
|
# Pre-load some dictionaries to simplify lookups
|
||||||
|
self.__walk_time_by_stop = {}
|
||||||
|
for s in self.__config.get("stops", []):
|
||||||
|
self.__walk_time_by_stop[s["stop_id"]] = s["walk_time"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gtfs_feed_url(self) -> str:
|
||||||
|
return self.__config.get("gtfs-feed-url")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gtfs_api_url(self) -> str:
|
||||||
|
return self.__config.get("gtfs-r-api-url")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gtfs_api_key(self) -> str:
|
||||||
|
return self.__config.get("gtfs-r-api_key")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def update_interval_seconds(self) -> int:
|
||||||
|
return self.__config.get("update-interval-seconds")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stop_codes(self) -> list[str]:
|
||||||
|
return [str(s["stop_id"]) for s in self.__config.get("stops")]
|
||||||
|
|
||||||
|
def minutes_to_stop(self, stop_id) -> int:
|
||||||
|
return self.__walk_time_by_stop.get(stop_id, 0)
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Global parameters
|
||||||
|
|
||||||
|
# URLs and API keys for the different parts of the GTFS-R feed
|
||||||
|
# You should not change these unless a new version of the API is released
|
||||||
|
gtfs-feed-url: "https://www.transportforireland.ie/transitData/Data/GTFS_Realtime.zip"
|
||||||
|
gtfs-r-api-url: "https://api.nationaltransport.ie/gtfsr/v2/gtfsr?format=json"
|
||||||
|
|
||||||
|
# You should change this one. Use the key you get from TFI when you register for GTFS-R access
|
||||||
|
gtfs-r-api_key: "API KEY GOES HERE"
|
||||||
|
|
||||||
|
# How often to refresh the display.
|
||||||
|
# It must be strictly larger than 60 because the GTFS-R API will throttle us otherwise
|
||||||
|
update-interval-seconds: 62
|
||||||
|
|
||||||
|
stops: [
|
||||||
|
{
|
||||||
|
# Route 15A
|
||||||
|
stop_id: 1114,
|
||||||
|
walk_time: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# route 54A
|
||||||
|
stop_id: 2410,
|
||||||
|
walk_time: 9
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,7 +17,8 @@ class GTFSClient():
|
||||||
GTFS_URL = "https://api.nationaltransport.ie/gtfsr/v2/gtfsr?format=json"
|
GTFS_URL = "https://api.nationaltransport.ie/gtfsr/v2/gtfsr?format=json"
|
||||||
API_KEY = open("api-key.txt").read().strip()
|
API_KEY = open("api-key.txt").read().strip()
|
||||||
|
|
||||||
def __init__(self, feed_url: str, stop_codes: list[str], update_queue: queue.Queue, update_interval_seconds: int = 60):
|
def __init__(self, feed_url: str, gtfs_r_url: str, gtfs_r_api_key: str,
|
||||||
|
stop_codes: list[str], update_queue: queue.Queue, update_interval_seconds: int = 60):
|
||||||
self.stop_codes = stop_codes
|
self.stop_codes = stop_codes
|
||||||
feed_name = feed_url.split('/')[-1]
|
feed_name = feed_url.split('/')[-1]
|
||||||
|
|
||||||
|
|
@ -86,7 +87,7 @@ class GTFSClient():
|
||||||
# Finally, load stop_times.txt
|
# Finally, load stop_times.txt
|
||||||
# Obtain the list of IDs of the desired stops. This is similar to what __wanted_stop_ids() does,
|
# Obtain the list of IDs of the desired stops. This is similar to what __wanted_stop_ids() does,
|
||||||
# but without a dependency on a fully formed feed object
|
# but without a dependency on a fully formed feed object
|
||||||
wanted_stop_ids = feed_dict.get("stops")[feed_dict.get("stops")["stop_code"].isin(stop_codes)]["stop_id"]
|
wanted_stop_ids = feed_dict.get("stops")[feed_dict.get("stops")["stop_code"].isin(self.stop_codes)]["stop_id"]
|
||||||
with z.open("stop_times.txt") as f:
|
with z.open("stop_times.txt") as f:
|
||||||
iter_csv = pd.read_csv(f, iterator=True, chunksize=1000, dtype=gk.cs.DTYPE, encoding="utf-8-sig")
|
iter_csv = pd.read_csv(f, iterator=True, chunksize=1000, dtype=gk.cs.DTYPE, encoding="utf-8-sig")
|
||||||
df = pd.concat([chunk[chunk["stop_id"].isin(wanted_stop_ids)] for chunk in iter_csv])
|
df = pd.concat([chunk[chunk["stop_id"].isin(wanted_stop_ids)] for chunk in iter_csv])
|
||||||
|
|
@ -239,8 +240,8 @@ class GTFSClient():
|
||||||
deltas[trip_id] = deltas_for_trip
|
deltas[trip_id] = deltas_for_trip
|
||||||
|
|
||||||
elif trip_action == "ADDED":
|
elif trip_action == "ADDED":
|
||||||
# TODO: Add support for added trips
|
route_id = e.get("trip_update").get("trip").get("route_id")
|
||||||
pass
|
|
||||||
elif trip_action == "CANCELED":
|
elif trip_action == "CANCELED":
|
||||||
canceled_trips.add(trip_id)
|
canceled_trips.add(trip_id)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
37
main.py
37
main.py
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from config import Config
|
||||||
from curses import COLOR_GREEN, COLOR_RED
|
from curses import COLOR_GREEN, COLOR_RED
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
|
|
@ -22,27 +23,17 @@ COLOR_LCD_RED: pygame.Color = pygame.Color(0xff, 0x3a, 0x4a)
|
||||||
COLOR_BACKGROUND = pygame.Color(0, 0, 0)
|
COLOR_BACKGROUND = pygame.Color(0, 0, 0)
|
||||||
UPDATE_INTERVAL_SECONDS = 62
|
UPDATE_INTERVAL_SECONDS = 62
|
||||||
TEXT_SIZE = 160 # Size of the font in pixels
|
TEXT_SIZE = 160 # Size of the font in pixels
|
||||||
STOPS = ['2410', '1114']
|
|
||||||
|
|
||||||
# Define how long it takes to walk to a particular stop
|
|
||||||
MINUTES_TO_ROUTE = {
|
|
||||||
'15A': 15,
|
|
||||||
'54A': 9
|
|
||||||
}
|
|
||||||
|
|
||||||
# Offsets of each part within a line
|
# Offsets of each part within a line
|
||||||
XOFFSET_ROUTE = 24
|
XOFFSET_ROUTE = 24
|
||||||
XOFFSET_DESTINATION = 300
|
XOFFSET_DESTINATION = 300
|
||||||
XOFFSEET_TIME_LEFT = 1606
|
XOFFSEET_TIME_LEFT = 1606
|
||||||
INTER_LINE_SPACE = -15 # 1920x720 -> 0
|
INTER_LINE_SPACE = -15
|
||||||
|
|
||||||
# Some global variables
|
# Some global variables
|
||||||
window : pygame.Surface = None
|
window : pygame.Surface = None
|
||||||
font: pygame.font.Font = None
|
font: pygame.font.Font = None
|
||||||
update_queue = queue.Queue(maxsize=10)
|
update_queue = queue.Queue(maxsize=10)
|
||||||
#scheduler = DublinBusSoapClient(stops=STOPS, update_queue=update_queue, update_interval_seconds=UPDATE_INTERVAL_SECONDS)
|
|
||||||
scheduler = GTFSClient(feed_url='https://www.transportforireland.ie/transitData/Data/GTFS_Realtime.zip',
|
|
||||||
stop_codes=STOPS, update_queue=update_queue, update_interval_seconds=UPDATE_INTERVAL_SECONDS)
|
|
||||||
|
|
||||||
def get_line_offset(line: int) -> int:
|
def get_line_offset(line: int) -> int:
|
||||||
""" Calculate the Y offset within the display for a given text line """
|
""" Calculate the Y offset within the display for a given text line """
|
||||||
|
|
@ -77,12 +68,12 @@ def write_line(line: int, text: str, text_color: Color = COLOR_LCD_AMBER):
|
||||||
window.blit(text_img, dest=(XOFFSET_ROUTE, vertical_offset))
|
window.blit(text_img, dest=(XOFFSET_ROUTE, vertical_offset))
|
||||||
|
|
||||||
|
|
||||||
def update_screen(updates: list[ArrivalTime]) -> None:
|
def update_screen(config: Config(), updates: list[ArrivalTime]) -> None:
|
||||||
""" Repaint the screen with the new arrival times """
|
""" Repaint the screen with the new arrival times """
|
||||||
updates = updates[0:LINE_COUNT] # take the first X lines
|
updates = updates[0:LINE_COUNT] # take the first X lines
|
||||||
for line_num, update in enumerate(updates):
|
for line_num, update in enumerate(updates):
|
||||||
# Find what color we need to use for the ETA
|
# Find what color we need to use for the ETA
|
||||||
time_to_walk = update.due_in_minutes - (MINUTES_TO_ROUTE.get(update.route_id) or 0)
|
time_to_walk = update.due_in_minutes - (config.minutes_to_stop(update.stop_id) or 0)
|
||||||
lcd_color = None
|
lcd_color = None
|
||||||
if time_to_walk > 5:
|
if time_to_walk > 5:
|
||||||
lcd_color = COLOR_LCD_GREEN
|
lcd_color = COLOR_LCD_GREEN
|
||||||
|
|
@ -122,16 +113,30 @@ def main():
|
||||||
|
|
||||||
global font
|
global font
|
||||||
global window
|
global window
|
||||||
|
global update_queue
|
||||||
|
|
||||||
""" Main method. Initialise graphics context """
|
config = Config()
|
||||||
|
|
||||||
|
# Initialise graphics context
|
||||||
pygame.init()
|
pygame.init()
|
||||||
window = init_screen()
|
window = init_screen()
|
||||||
pygame.font.init()
|
pygame.font.init()
|
||||||
font = pygame.font.Font(TEXT_FONT, TEXT_SIZE)
|
font = pygame.font.Font(TEXT_FONT, TEXT_SIZE)
|
||||||
|
|
||||||
# Paint black
|
# Init screen
|
||||||
clear_screen()
|
clear_screen()
|
||||||
|
write_line(0, "Dublin Bus display")
|
||||||
|
write_line(1, "Loading feeds...")
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
|
# Create scheduler; load time tables
|
||||||
|
scheduler = GTFSClient(feed_url=config.gtfs_feed_url,
|
||||||
|
gtfs_r_url=config.gtfs_api_url,
|
||||||
|
gtfs_r_api_key=config.gtfs_api_key,
|
||||||
|
stop_codes=config.stop_codes,
|
||||||
|
update_queue=update_queue,
|
||||||
|
update_interval_seconds=config.update_interval_seconds)
|
||||||
|
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
|
|
||||||
# Main event loop
|
# Main event loop
|
||||||
|
|
@ -152,7 +157,7 @@ def main():
|
||||||
if update_queue.qsize() > 0:
|
if update_queue.qsize() > 0:
|
||||||
clear_screen()
|
clear_screen()
|
||||||
updates = update_queue.get()
|
updates = update_queue.get()
|
||||||
update_screen(updates)
|
update_screen(config, updates)
|
||||||
|
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
# Display update ends
|
# Display update ends
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue