commit d2c8a6e89d5b7a9f35822469ccab7b872bcba5ac Author: Julian Metzler Date: Sat Feb 5 22:57:12 2022 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4347dab --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.pyc +*.egg-info/ +build/ +dist/ +__pycache__/ +.venv/ +_confsel.py diff --git a/map_alnum.txt b/map_alnum.txt new file mode 100644 index 0000000..88b916c --- /dev/null +++ b/map_alnum.txt @@ -0,0 +1,79 @@ +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 A +11 B +12 C +13 D +14 E +15 F +16 G +17 H +18 I +19 J +20 K +21 L +22 M +23 N +24 O +25 P +26 Q +27 R +28 S +29 T +30 U +31 V +32 W +33 X +34 Y +35 Z +36 Ä +37 Ö +38 Ü +39 - +40 . +41 ' +42 ( +43 ) +44 ? +45 ! +46 * +47 : +48 / +49 ; +50 " +51 “ +52 „ +53 , +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 \ No newline at end of file diff --git a/map_hinweis1.txt b/map_hinweis1.txt new file mode 100644 index 0000000..416a79b --- /dev/null +++ b/map_hinweis1.txt @@ -0,0 +1,79 @@ +0 EC mit Zuschlag +1 IC mit Zuschlag +2 IR InterRegio +3 IR InterRegio Zuschlag siehe Abfahrtsplan +4 +5 +6 D Schnellzug +7 D Schnellzug Zuschlag siehe Abfahrtsplan +8 +9 CNL besonderer Fahrpreis +10 +11 M Messe-Schnellzug nur 1. Klasse +12 Reisebüro-Sonderzug +13 Sonderzug +14 Gesellschafts-Sonderzug +15 Touristik-Sonderzug +16 EC mit Zuschlag zusätzlicher Zug +17 IC mit Zuschlag zusätzlicher Zug +18 Zusätzlicher Zug +19 Liegewagen +20 D nur Schlaf- und Liegewagen +21 D Schnellzug mit Schlaf- und Liegewagen +22 ICE besonderer Fahrpreis +23 ICE zusätzlicher Zug besonderer Fahrpreis +24 ICE Sprinterpreis +25 +26 EC mit Zuschlag Kurswagen Graz +27 EC mit Zuschlag Kurswagen Zell am See +28 IC mit Zuschlag Kurswagen Dagebüll +29 RB VRN +30 RE VRN +31 +32 +33 mehrere Zugteile +34 +35 etwa 5 Min. später +36 etwa 10 Min. später +37 etwa 15 Min. später +38 etwa 20 Min. später +39 etwa 30 Min. später +40 etwa 45 Min. später +41 Über 45 Min. später +42 +43 SE VRN +44 +45 Über 60 Min. später +46 +47 EXE ExpoExpress zubuchungspflichtig +48 EX ExpoZug zubuchungspflichtig +49 +50 IRE InterRegioExpress +51 +52 ICE InterCityExpress +53 EC EuroCity +54 IC InterCity +55 +56 S-Bahn Langzug 1 Traktion hinten +57 S-Bahn 2 Langzug Traktionen hinten +58 S-Bahn 1 Langzug Traktion vorne +59 S-Bahn 2 Langzug Traktionen vorne +60 S-Bahn 1 Lanzug Traktion hinten +61 S-Bahn 1 Vollzug Traktion hinten +62 S-Bahn 1 Vollzug Traktion vorne +63 S-Bahn Langzug +64 S-Bahn Kurzzug vorne +65 S-Bahn Vollzug vorne/ mitte +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 \ No newline at end of file diff --git a/map_hinweis2.txt b/map_hinweis2.txt new file mode 100644 index 0000000..3dd6bd6 --- /dev/null +++ b/map_hinweis2.txt @@ -0,0 +1,79 @@ +0 Holland-Italien-Express +1 Italien-Holland-Express +2 Schweiz-Express +3 Istambul-Express +4 Riviera-Express +5 Wagenstand 1.Kl. A & 1. Kl. E +6 Wagenstand 1. Kl. B +7 Wagenstand 1. Kl. A +8 TUI FerienExpress +9 Alpen-See-Express +10 Alpen-See-Express / TUI FerienExpress +11 Liegewagenzug +12 Schlaf- und Liegewagen +13 Airport-City +14 bis Hamburg=Altona +15 bis Greifswald +16 bis Hannover +17 bis Braunschweig +18 Wagenstand 1. Kl. A-B +19 Wagenstand 1. Kl. A-B +20 Wagenstand 1. Kl. A-B +21 Wagenstand 1. Kl. A-B +22 Wagenstand 1. Kl. A-B +23 Wagenstand 1. Kl. D +24 Wagenstand 1. Kl. A-B +25 Wagenstand 1. Kl. B-C +26 Kurswagen Amsterdam +27 Hält überall +28 Hält bis Heidelberg überall +29 Hält bis Darmstadt überall +30 Hält nicht in Mainz-Laubheim +31 Wagenstand 1. Kl. D +32 Wagenstand 1. Kl. B-C +33 Aufpreis Sprinter +34 Wagenstand 1. Kl. A & C-D +35 +36 S-Bahn Langzug 1 Traktion hinten +37 S-Bahn Langzug 2 Traktionen hinten/mitte +38 S-Bahn Langzug 1 Traktion vorne +39 S-Bahn Langzug 2 Traktionen vorne/mitte +40 S-Bahn Langzug 1 Traktion hinten +41 S-Bahn Vollzug 1 Traktion hinten +42 S-Bahn Vollzug 1 Traktion vorne +43 S-Bahn Langzug 3 Traktionen +44 S-Bahn Kurzzug vorne +45 S-Bahn Vollzug vorne/mitte +46 Kurswagen siehe Abfahrtsplan +47 heute aus Gleis 1 +48 heute aus Gleis 2 +49 heute aus Gleis 3 +50 heute aus Gleis 4 +51 heute aus Gleis 5 +52 heute aus Gleis 7 +53 Bitte Ansage beachten +54 Nicht einsteigen +55 Hält nicht überall +56 platzkartenprlichtig +57 nicht über Frankfurt Hbf +58 nicht über Heidelberg +59 Hält nicht in LU=Mundenheim und LU=Rheingönheim +60 Hält bis Neckarsteinach überall +61 Hält nicht in Neckarhausen +62 Hält bis Homburg(Saar) überall +63 Zug hält hier nur zum Aussteigen +64 Zug verkehrt in zwei Teilen Ansage beachten +65 Urlaubs-Express +66 2 Züge im Gleis Zugbeschriftung beachten +67 hintere Wagen bleiben stehen: Zugbeschriftung beachten +68 Über 60 Min. später +69 heute aus Gleis 8 +70 heute aus Gleis 9 +71 heute aus Gleis 10 +72 Etwa 5 Min. später +73 Etwa 10 Min. später +74 Etwa 15 Min. später +75 Etwa 20 Min. später +76 Etwa 30 Min. später +77 Etwa 45 Min. später +78 Über 45 Min. später \ No newline at end of file diff --git a/map_zuglauf1.txt b/map_zuglauf1.txt new file mode 100644 index 0000000..f2bc6f9 --- /dev/null +++ b/map_zuglauf1.txt @@ -0,0 +1,79 @@ +0 Schwetzingen +1 Karlsruhe +2 Karlsruhe - Baden-Baden +3 Karlsruhe - Kehl +4 Karlsruhe - Offenburg +5 Karlsruhe - Basel Bad Bf +6 Karlsruhe - Basel SBB +7 Karlsruhe - Baden-Baden - Offenburg - Freiburg +8 Chiasso - Milano +9 Bruchsal - Stuttgart +10 Heidelberg +11 Heidelberg - Bruchsal +12 Heidelberg - Karlsruhe +13 Heidelberg - Sinsheim +14 Heidelberg - Neckarelz +15 Heidelberg - Stuttgart +16 Heidelberg - München +17 Heidelberg - Eberbach +18 Stuttgart +19 Neustadt - Kaiserslautern +20 Heppenheim - (Bergstr) +21 Bensheim - Darmstadt +22 MA-Friedrichsfeld +23 Weinheim +24 Darmstadt - Frankfurt +25 Darmstadt - Mainz - Wiesbaden - Bonn +26 Darmstadt - Mainz - Bonn +27 Frankfurt/M +28 Frankfurt/M - Bebra +29 Frankfurt(M) - Hannover +30 Frankfurt/M Fulda +31 MA-Käfertal +32 MA-Luzenberg +33 MA-Waldhof +34 MA-Neckarstadt +35 Ludwigshafen - Neustadt +36 Mainz +37 Ludwigshafen (Rh) +38 Ludwigshafen - Speyer +39 Neustadt (Weinstr) +40 Ludwigshafen - Mainz +41 Ludwigshafen - Worms +42 MA-Seckenheim +43 Heidelberg - Stuttgart - Ulm - Augsburg +44 Frankfurt(M) - Kassel-Wilhelmshöhe +45 Milano - Bologna +46 Chiasso +47 Worms - Bonn - Köln +48 Mainz - Koblenz +49 Mainz - Koblenz - Bonn - Köln +50 Mainz - Bonn - Köln +51 Mainz - Bonn +52 Mainz - Köln +53 Mainz - Bonn - Köln - Essen - Dortmund +54 Mainz - Bonn - Köln - Hagen - Dortmund +55 +56 Ludwigshafen - Freinsheim +57 +58 Frankfurt(M) - KS-Wilhelmshöhe +59 Worms - Mainz +60 +61 Frankfurt/M Flughafen +62 +63 +64 +65 S3 SPEYER +66 S2 SCHIFFERSTADT +67 S2 MOSBACH/BADEN +68 S1/S2 EBERBACH +69 S4 BRUCHSAL +70 S2 HEIDELBERG +71 S1/S2 KAISERSLAUTERN +72 S1/S2 NEUSTADT +73 S1 OSTERBURKEN +74 S1/S2 MOSBACH-NECKARELZ +75 S3 KARLSRUHE +76 S2 LUDWIGSHAFEN +77 +78 \ No newline at end of file diff --git a/map_zuglauf2.txt b/map_zuglauf2.txt new file mode 100644 index 0000000..7ce4f77 --- /dev/null +++ b/map_zuglauf2.txt @@ -0,0 +1,79 @@ +0 Karlsruhe +1 Offenburg +2 Offenburg - Freiburg +3 Freiburg(Brsg) +4 Freiburg - Basel SBB +5 Heilbronn +6 Crailsheim +7 Ulm +8 Ulm - Lindau +9 Ulm - Augsburg +10 München +11 München - Kufstein +12 München - Salzburg +13 Salzburg +14 Bebra +15 Bebra - Erfurt +16 Frankfurt/M Süd +17 Hannover +18 Hamburg +19 Hannover - Hamburg +20 Saarbrücken +21 Frankfurt Sportfeld +22 Mainz +23 Bonn - Köln - Essen +24 Aachen +25 Nijmegen +26 Venlo +27 Düsseldorf - Emmerich +28 Düsseldorf - Essen +29 Essen - Dortmund +30 Essen - Gelsenkirchen +31 Hagen +32 Hagen - Dortmund +33 Bremen +34 Forbach - Bordeaux +35 Basel Bad Bf +36 Basel SBB +37 MA- Waldhof +38 MA-Friedrichsfeld Süd +39 Hockenheim +40 Weinheim (Bergstr) +41 Vaihingen (Enz) +42 Homburg (Saar) +43 Leipzig - Dresden +44 Braunschweig - Magdeburg +45 Erfurt - Leipzig +46 Eisenach - Erfurt +47 Neustadt - Kaiserslautern +48 Worms - Biblis +49 Graben - Neudorf +50 Gießen +51 München - Kufstein - Innsbruck - Verona +52 Darmstadt +53 Biblis +54 Germersheim - Wörth +55 Kaiserslautern - Saarbrücken +56 Bruchsal +57 Landau +58 Koblenz - Bonn +59 München - Mittenwald +60 Braunschweig +61 Kassel-Wi. - Hannover +62 +63 Strasbourg - Avignon +64 +65 S3 SPEYER +66 S2 SCHIFFERSTADT +67 S2 MOSBACH/BADEN +68 S1/S2 EBERBACH +69 S4 BRUCHSAL +70 S2 HEIDELBERG +71 S1/S2 KAISERSLAUTERN +72 S1/S2 NEUSTADT +73 S1 OSTERBURKEN +74 S1/S2 MOSBACH - NECKARELZ +75 S3 KARLSRUHE +76 S2 LUDWIGSHAFEN +77 +78 \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..bae9cb6 --- /dev/null +++ b/run.py @@ -0,0 +1,177 @@ +from deutschebahn import DBInfoscreen +from pyfis.krone import Krone8200Display +from pyfis.krone.exceptions import CommunicationError +from pyfis.utils import get_vias +from util import timeout, TimeoutError + +import hashlib +import json +import time +import traceback + +from _confsel import CONFIG + +if CONFIG == "PHALOS-TYP-M-ZZA": + from settings_phalos import * + + +def route_from(route, station): + start_found = False + new_route = [] + for stop in route: + if not start_found: + start_found = stop == station + if start_found: + new_route.append(stop) + return new_route + +@timeout(30) +def get_trains(dbi, station): + return dbi.get_trains(station) + + +def update_display(display, dbi): + try: + trains = dbi.calc_real_times(get_trains(dbi, STATION_CODE)) + trains.sort(key=dbi.time_sort) + except: + traceback.print_exc() + display.info_1.set(OUT_OF_ORDER_TEXT) + print(display.render_ascii()) + display.update() + return display.render_ascii() + + if not trains: + display.info_1.set(NO_TRAINS_TEXT) + print(display.render_ascii()) + display.update() + return display.render_ascii() + + train = trains[0] + + parts = train['train'].split() + train_type = parts[0] + if train_type == "RE": + display.info_2.set(NO_STOP_EVERYWHERE_TEXT) + + is_arrival = train['destination'] == STATION_NAME + + if train['platform'] != PLATFORM: + platform = int("".join(c for c in train['platform'] if c.isdigit())) + display.info_2.set(PLATFORM_CHANGE_FORMAT.format(platform)) + + if train['scheduledDeparture']: + hour, minute = map(int, train['scheduledDeparture'].split(":")) + display.hour.set(DEPARTURE_HOUR_FORMAT.format(hour)) + display.minute.set(DEPARTURE_MIN_FORMAT.format(minute)) + delay = dbi.round_delay(train['delayDeparture']) if train['delayDeparture'] else 0 + delay_raw = train['delayDeparture'] or 0 + elif train['scheduledArrival']: + hour, minute = map(int, train['scheduledArrival'].split(":")) + display.hour.set(ARRIVAL_HOUR_FORMAT.format(hour)) + display.minute.set(ARRIVAL_MIN_FORMAT.format(minute)) + delay = dbi.round_delay(train['delayArrival']) if train['delayArrival'] else 0 + delay_raw = train['delayArrival'] or 0 + + if train['isCancelled']: + display.info_1.set(CANCELLED_TEXT) + else: + delay_text = "" + if CONFIG == "PHALOS-TYP-M-ZZA": + if 5 <= delay <= 20: + delay_text = DELAY_FORMAT.format(delay) + elif 20 < delay <= 30: + delay_text = DELAY_FORMAT.format(30) + elif 30 < delay <= 45: + delay_text = DELAY_FORMAT.format(45) + elif 45 < delay <= 60: + delay_text = DELAY_ABOVE_FORMAT.format(45) + elif delay > 60: + delay_text = UNSPECIFIC_DELAY_TEXT + display.info_1.set(delay_text) + + route = route_from([VIA_MAP.get(stop['name'], stop['name']) for stop in train['route']], STATION_NAME)[:-1] + via_combination = get_vias(route, VIA_WEIGHTS, VIA_1, VIA_2, check_dashes=False, debug=True) + if via_combination: + via_code_1, via_code_2 = via_combination + display.via_1.set(MAP_VIA_1[via_code_1]) + display.via_2.set(MAP_VIA_2[via_code_2]) + + if train['destination'] == STATION_NAME: + display.info_2.set(DO_NOT_BOARD_TEXT) + display.destination.set("von " + DESTINATION_MAP.get(train['route'][0]['name'], train['route'][0]['name']).replace("ß", "ss")) + else: + display.destination.set(DESTINATION_MAP.get(train['destination'], train['destination']).replace("ß", "ss")) + + print(display.render_ascii()) + return display.render_ascii() + + +def main(): + ctrl = Krone8200Display(SERIAL_PORT, address=(0x41, 0x49), debug=True) + ctrl.port.timeout=5.0 + + dbi = DBInfoscreen(DBI_HOST) + + display = TypMZZA(ctrl) + display.clear() + + last_update = 0 + last_heartbeat = 0 + while True: + now = time.time() + + if now - last_heartbeat >= 10: + print("\n" + "=" * 60 + "\n") + print("Sending heartbeat") + ctrl.send_end_comm() + last_heartbeat = now + continue + + if now - last_update < 60: + time.sleep(1) + continue + + print("\n" + "=" * 60 + "\n") + + try: + display_id = update_display(display, dbi) + + try: + with open("/tmp/m-zza-status.json", 'r') as f: + status = json.load(f) + except (FileNotFoundError, ValueError): + status = {'displayHash': None} + + display_hash = hashlib.sha256(bytes(display_id, 'utf-8')).hexdigest() + + update = True + if status['displayHash'] == display_hash: + print("No need to update display.") + update = False + else: + status['displayHash'] = display_hash + + if update: + num_tries = 10 + for i in range(num_tries): + try: + display.update() + break + except CommunicationError: + print("Communication error! Retrying... {}/{}".format(i+1, num_tries)) + time.sleep(5) + + with open("/tmp/m-zza-status.json", 'w') as f: + json.dump(status, f) + except: + traceback.print_exc() + + last_update = now + + + display.update() + + +if __name__ == "__main__": + main() diff --git a/settings_phalos.py b/settings_phalos.py new file mode 100644 index 0000000..e634cbc --- /dev/null +++ b/settings_phalos.py @@ -0,0 +1,218 @@ +from pyfis.splitflap_display import SplitFlapDisplay, TextField, CustomMapField, MirrorField + + +def _load_map(file): + _map = {} + with open(file, 'r') as f: + lines = f.readlines() + for line in lines: + line = line.strip() + if not line: + continue + parts = line.split(maxsplit=1) + pos = int(parts[0]) + if len(parts) > 1: + text = parts[1] + _map[pos] = text + return _map + + +SERIAL_PORT = "/dev/serial/by-path/platform-3f980000.usb-usb-0:1.5:1.0-port0" +DBI_HOST = "trains.xatlabs.com" +STATION_CODE = "RM" +STATION_NAME = "Mannheim Hbf" +PLATFORM = "0" +DEFAULT_OPERATOR = "DB" + +ARRIVAL_HOUR_FORMAT = "Ankunft {}" +ARRIVAL_MIN_FORMAT = "{:02d}" +DEPARTURE_HOUR_FORMAT = "Abfahrt {}" +DEPARTURE_MIN_FORMAT = "{:02d}" +PLATFORM_CHANGE_FORMAT = "heute aus Gleis {}" +OUT_OF_ORDER_TEXT = "" +NO_TRAINS_TEXT = "" +CANCELLED_TEXT = "" +DELAY_FORMAT = "etwa {} Min. später" +DELAY_ABOVE_FORMAT = "Über {} Min. später" +SMALL_DELAY_TEXT = "" +UNSPECIFIC_DELAY_TEXT = "Über 60 Min. später" +DO_NOT_BOARD_TEXT = "Nicht einsteigen" +NO_STOP_EVERYWHERE_TEXT = "Hält nicht überall" + + +MAP_HOUR = dict([(i, f"Abfahrt {i}") for i in range(24)] + [(i+30, f"Ankunft {i}") for i in range(24)]) +MAP_MINUTE = dict([(i, f"{i:02d}") for i in range(60)]) + +MAP_INFO_1 = _load_map("map_hinweis1.txt") +MAP_INFO_2 = _load_map("map_hinweis2.txt") +MAP_ALNUM = _load_map("map_alnum.txt") + + +VIA_1 = { + 0: {'text': "Schwetzingen", 'stations': ["Schwetzingen"]}, + 1: {'text': "Karlsruhe", 'stations': ["Karlsruhe Hbf"]}, + 2: {'text': "Karlsruhe - Baden-Baden", 'stations': ["Karlsruhe Hbf", "Baden-Baden"]}, + 3: {'text': "Karlsruhe - Kehl", 'stations': ["Karlsruhe Hbf", "Kehl"]}, + 4: {'text': "Karlsruhe - Offenburg", 'stations': ["Karlsruhe Hbf", "Offenburg"]}, + 5: {'text': "Karlsruhe - Basel Bad Bf", 'stations': ["Karlsruhe Hbf", "Basel Bad Bf"]}, + 6: {'text': "Karlsruhe - Basel SBB", 'stations': ["Karlsruhe Hbf", "Basel SBB"]}, + 7: {'text': "Karlsruhe - Baden-Baden - Offenburg - Freiburg", 'stations': ["Karlsruhe Hbf", "Baden-Baden", "Offenburg", "Freiburg(Breisgau) Hbf"]}, + 8: {'text': "Chiasso - Milano", 'stations': ["Chiasso", "Milano Centrale"]}, + 9: {'text': "Bruchsal - Stuttgart", 'stations': ["Bruchsal", "Stuttgart Hbf"]}, + 10: {'text': "Heidelberg", 'stations': ["Heidelberg Hbf"]}, + 11: {'text': "Heidelberg - Bruchsal", 'stations': ["Heidelberg Hbf", "Bruchsal"]}, + 12: {'text': "Heidelberg - Karlsruhe", 'stations': ["Heidelberg Hbf", "Karlsruhe Hbf"]}, + 13: {'text': "Heidelberg - Sinsheim", 'stations': ["Heidelberg Hbf", "Sinsheim(Elsenz) Hbf"]}, + 14: {'text': "Heidelberg - Neckarelz", 'stations': ["Heidelberg Hbf", "Mosbach-Neckarelz"]}, + 15: {'text': "Heidelberg - Stuttgart", 'stations': ["Heidelberg Hbf", "Stuttgart Hbf"]}, + 16: {'text': "Heidelberg - München", 'stations': ["Heidelberg Hbf", "München Hbf"]}, + 17: {'text': "Heidelberg - Eberbach", 'stations': ["Heidelberg Hbf", "Eberbach"]}, + 18: {'text': "Stuttgart", 'stations': ["Stuttgart Hbf"]}, + 19: {'text': "Neustadt - Kaiserslautern", 'stations': ["Neustadt(Weinstr)Hbf", "Kaiserslautern"]}, + 20: {'text': "Heppenheim (Bergstr)", 'stations': ["Heppenheim(Bergstr)"]}, + 21: {'text': "Bensheim - Darmstadt", 'stations': ["Bensheim", "Darmstadt Hbf"]}, + 22: {'text': "MA-Friedrichsfeld", 'stations': ["Mannheim-Friedrichsfeld Süd"]}, + 23: {'text': "Weinheim", 'stations': ["Weinheim(Bergstr)Hbf"]}, + 24: {'text': "Darmstadt - Frankfurt", 'stations': ["Darmstadt Hbf", "Frankfurt(Main)Hbf"]}, + 25: {'text': "Darmstadt - Mainz - Wiesbaden - Bonn", 'stations': ["Darmstadt Hbf", "Mainz Hbf", "Wiesbaden Hbf", "Bonn Hbf"]}, + 26: {'text': "Darmstadt - Mainz - Bonn", 'stations': ["Darmstadt Hbf", "Mainz Hbf", "Bonn Hbf"]}, + 27: {'text': "Frankfurt/M", 'stations': ["Frankfurt(Main)Hbf"]}, + 28: {'text': "Frankfurt/M - Bebra", 'stations': ["Frankfurt(Main)Hbf", "Bebra"]}, + 29: {'text': "Frankfurt(M) - Hannover", 'stations': ["Frankfurt(Main)Hbf", "Hannover Hbf"]}, + 30: {'text': "Frankfurt/M - Fulda", 'stations': ["Frankfurt(Main)Hbf", "Fulda"]}, + 31: {'text': "MA-Käfertal", 'stations': ["Mannheim-Käfertal"]}, + 32: {'text': "MA-Luzenberg", 'stations': ["Mannheim-Luzenberg"]}, + 33: {'text': "MA-Waldhof", 'stations': ["Mannheim-Waldhof"]}, + 34: {'text': "MA-Neckarstadt", 'stations': ["Mannheim-Neckarstadt"]}, + 35: {'text': "Ludwigshafen - Neustadt", 'stations': ["Ludwigshafen(Rh)Hbf", "Neustadt(Weinstr)Hbf"]}, + 36: {'text': "Mainz", 'stations': ["Mainz Hbf"]}, + 37: {'text': "Ludwigshafen (Rh)", 'stations': ["Ludwigshafen(Rh)Hbf"]}, + 38: {'text': "Ludwigshafen - Speyer", 'stations': ["Ludwigshafen(Rh)Hbf", "Speyer Hbf"]}, + 39: {'text': "Neustadt (Weinstr)", 'stations': ["Neustadt(Weinstr)Hbf"]}, + 40: {'text': "Ludwigshafen - Mainz", 'stations': ["Ludwigshafen(Rh)Hbf", "Mainz Hbf"]}, + 41: {'text': "Ludwigshafen - Worms", 'stations': ["Ludwigshafen(Rh)Hbf", "Worms Hbf"]}, + 42: {'text': "MA-Seckenheim", 'stations': ["Mannheim-Seckenheim"]}, + 43: {'text': "Heidelberg - Stuttgart - Ulm - Augsburg", 'stations': ["Heidelberg Hbf", "Stuttgart Hbf", "Ulm Hbf", "Augsburg Hbf"]}, + 44: {'text': "Frankfurt(M) - Kassel-Wilhelmshöhe", 'stations': ["Frankfurt(Main)Hbf", "Kassel-Wilhelmshöhe"]}, + 45: {'text': "Milano - Bologna", 'stations': ["Milano Centrale", "Bologna Centrale"]}, + 46: {'text': "Chiasso", 'stations': ["Chiasso"]}, + 47: {'text': "Worms - Bonn - Köln", 'stations': ["Worms Hbf", "Bonn Hbf", "Köln Hbf"]}, + 48: {'text': "Mainz - Koblenz", 'stations': ["Mainz Hbf", "Koblenz Hbf"]}, + 49: {'text': "Mainz - Koblenz - Bonn - Köln", 'stations': ["Mainz Hbf", "Koblenz Hbf", "Bonn Hbf", "Köln Hbf"]}, + 50: {'text': "Mainz - Bonn - Köln", 'stations': ["Mainz Hbf", "Bonn Hbf", "Köln Hbf"]}, + 51: {'text': "Mainz - Bonn", 'stations': ["Mainz Hbf", "Bonn Hbf"]}, + 52: {'text': "Mainz - Köln", 'stations': ["Mainz Hbf", "Köln Hbf"]}, + 53: {'text': "Mainz - Bonn - Köln - Essen - Dortmund", 'stations': ["Mainz Hbf", "Bonn Hbf", "Köln Hbf", "Essen Hbf", "Dortmund Hbf"]}, + 54: {'text': "Mainz - Bonn - Köln - Hagen - Dortmund", 'stations': ["Mainz Hbf", "Bonn Hbf", "Köln Hbf", "Hagen Hbf", "Dortmund Hbf"]}, + 56: {'text': "Ludwigshafen - Freinsheim", 'stations': ["Ludwigshafen(Rh)Hbf", "Freinsheim"]}, + 58: {'text': "Frankfurt(M) - KS-Wilhelmshöhe", 'stations': ["Frankfurt(Main)Hbf", "Kassel-Wilhelmshöhe"]}, + 59: {'text': "Worms - Mainz", 'stations': ["Worms Hbf", "Mainz Hbf"]}, + 61: {'text': "Frankfurt/M Flughafen", 'stations': ["Frankfurt(M) Flughafen Fernbf"]}, + 99: {'text': "", 'stations': []} +} +MAP_VIA_1 = {key: value['text'] for key, value in VIA_1.items()} + +VIA_2 = { + 0: {'text': "Karlsruhe", 'stations': ["Karlsruhe Hbf"]}, + 1: {'text': "Offenburg", 'stations': ["Offenburg"]}, + 2: {'text': "Offenburg - Freiburg", 'stations': ["Offenburg", "Freiburg(Breisgau) Hbf"]}, + 3: {'text': "Freiburg(Brsg)", 'stations': ["Freiburg(Breisgau) Hbf"]}, + 4: {'text': "Freiburg - Basel SBB", 'stations': ["Freiburg(Breisgau) Hbf", "Basel SBB"]}, + 5: {'text': "Heilbronn", 'stations': ["Heilbronn Hbf"]}, + 6: {'text': "Crailsheim", 'stations': ["Crailsheim"]}, + 7: {'text': "Ulm", 'stations': ["Ulm Hbf"]}, + 8: {'text': "Ulm - Lindau", 'stations': ["Ulm Hbf", ["Lindau-Insel", "Lindau-Aeschach", "Lindau-Reutin"]]}, + 9: {'text': "Ulm - Augsburg", 'stations': ["Ulm Hbf", "Augsburg Hbf"]}, + 10: {'text': "München", 'stations': ["München Hbf"]}, + 11: {'text': "München - Kufstein", 'stations': ["München Hbf", "Kufstein"]}, + 12: {'text': "München - Salzburg", 'stations': ["München Hbf", "Salzburg Hbf"]}, + 13: {'text': "Salzburg", 'stations': ["Salzburg Hbf"]}, + 14: {'text': "Bebra", 'stations': ["Bebra"]}, + 15: {'text': "Bebra - Erfurt", 'stations': ["Bebra", "Erfurt Hbf"]}, + 16: {'text': "Frankfurt/M Süd", 'stations': ["Frankfurt(Main)Süd"]}, + 17: {'text': "Hannover", 'stations': ["Hannover Hbf"]}, + 18: {'text': "Hamburg", 'stations': [["Hamburg Hbf", "Hamburg-Altona"]]}, + 19: {'text': "Hannover - Hamburg", 'stations': ["Hannover Hbf", ["Hamburg Hbf", "Hamburg-Altona"]]}, + 20: {'text': "Saarbrücken", 'stations': ["Saarbrücken Hbf"]}, + 21: {'text': "Frankfurt Sportfeld", 'stations': ["Frankfurt am Main - Stadion"]}, + 22: {'text': "Mainz", 'stations': ["Mainz Hbf"]}, + 23: {'text': "Bonn - Köln - Essen", 'stations': ["Bonn Hbf", "Köln Hbf", "Essen Hbf"]}, + 24: {'text': "Aachen", 'stations': ["Aachen Hbf"]}, + 25: {'text': "Nijmegen", 'stations': ["Nijmegen"]}, + 26: {'text': "Venlo", 'stations': ["Venlo"]}, + 27: {'text': "Düsseldorf - Emmerich", 'stations': ["Düsseldorf Hbf", "Emmerich"]}, + 28: {'text': "Düsseldorf - Essen", 'stations': ["Düsseldorf Hbf", "Essen Hbf"]}, + 29: {'text': "Essen - Dortmund", 'stations': ["Essen Hbf", "Dortmund Hbf"]}, + 30: {'text': "Essen - Gelsenkirchen", 'stations': ["Essen Hbf", "Gelsenkirchen Hbf"]}, + 31: {'text': "Hagen", 'stations': ["Hagen Hbf"]}, + 32: {'text': "Hagen - Dortmund", 'stations': ["Hagen Hbf", "Dortmund Hbf"]}, + 33: {'text': "Bremen", 'stations': ["Bremen Hbf"]}, + 34: {'text': "Forbach - Bordeaux", 'stations': [["Forbach(F)", "Forbach(Schwarzw)"], "Bordeaux-St-Jean"]}, + 35: {'text': "Basel Bad Bf", 'stations': ["Basel Bad Bf"]}, + 36: {'text': "Basel SBB", 'stations': ["Basel SBB"]}, + 37: {'text': "MA- Waldhof", 'stations': ["Mannheim-Waldhof"]}, + 38: {'text': "MA-Friedrichsfeld Süd", 'stations': ["Mannheim-Friedrichsfeld Süd"]}, + 39: {'text': "Hockenheim", 'stations': ["Hockenheim"]}, + 40: {'text': "Weinheim (Bergstr)", 'stations': ["Weinheim(Bergstr)Hbf"]}, + 41: {'text': "Vaihingen (Enz)", 'stations': ["Vaihingen(Enz)"]}, + 42: {'text': "Homburg (Saar)", 'stations': ["Homburg(Saar)Hbf"]}, + 43: {'text': "Leipzig - Dresden", 'stations': ["Leipzig Hbf", "Dresden Hbf"]}, + 44: {'text': "Braunschweig - Magdeburg", 'stations': ["Braunschweig Hbf", "Magdeburg Hbf"]}, + 45: {'text': "Erfurt - Leipzig", 'stations': ["Erfurt Hbf", "Leipzig Hbf"]}, + 46: {'text': "Eisenach - Erfurt", 'stations': ["Eisenach", "Erfurt Hbf"]}, + 47: {'text': "Neustadt - Kaiserslautern", 'stations': ["Neustadt(Weinstr)Hbf", "Kaiserslautern Hbf"]}, + 48: {'text': "Worms - Biblis", 'stations': ["Worms Hbf", "Biblis"]}, + 49: {'text': "Graben-Neudorf", 'stations': ["Graben-Neudorf"]}, + 50: {'text': "Gießen", 'stations': ["Gießen"]}, + 51: {'text': "München - Kufstein - Innsbruck - Verona", 'stations': ["München Hbf", "Kufstein", "Innsbruck Hbf", "Verona Porta Nuova"]}, + 52: {'text': "Darmstadt", 'stations': ["Darmstadt Hbf"]}, + 53: {'text': "Biblis", 'stations': ["Biblis"]}, + 54: {'text': "Germersheim - Wörth", 'stations': ["Germersheim", "Wörth(Rhein)"]}, + 55: {'text': "Kaiserslautern - Saarbrücken", 'stations': ["Kaiserslautern Hbf", "Saarbrücken Hbf"]}, + 56: {'text': "Bruchsal", 'stations': ["Bruchsal"]}, + 57: {'text': "Landau", 'stations': ["Landau(Pfalz)Hbf"]}, + 58: {'text': "Koblenz - Bonn", 'stations': ["Koblenz Hbf", "Bonn Hbf"]}, + 59: {'text': "München - Mittenwald", 'stations': ["München Hbf", "Mittenwald"]}, + 60: {'text': "Braunschweig", 'stations': ["Braunschweig Hbf"]}, + 61: {'text': "Kassel-Wi. - Hannover", 'stations': ["Kassel-Wilhelmshöhe", "Hannover Hbf"]}, + 63: {'text': "Strasbourg - Avignon", 'stations': ["Strasbourg", "Avignon Centre"]}, + 99: {'text': "", 'stations': []} +} +MAP_VIA_2 = {key: value['text'] for key, value in VIA_2.items()} + + + +DESTINATION_MAP = { + "Frankfurt(Main)Hbf": "Frankfurt Hbf", + "Freiburg(Breisgau) Hbf": "Freiburg Hbf", + "Homburg(Saar)Hbf": "Homburg (Saar)", + "Neustadt(Weinstr)Hbf": "Neustadt Hbf", + "Mosbach(Baden)": "Mosbach", + "Berlin Hbf (tief)": "Berlin Hbf", +} + +VIA_MAP = { + +} + +VIA_WEIGHTS = { + +} + + +class TypMZZA(SplitFlapDisplay): + hour = CustomMapField(MAP_HOUR, start_address=1, x=0, y=0, module_width=12, module_height=2, home_pos=99) + minute = CustomMapField(MAP_MINUTE, start_address=2, x=12, y=0, module_width=4, module_height=2, home_pos=99) + info_1 = CustomMapField(MAP_INFO_1, start_address=4, x=0, y=2, module_width=16, module_height=2, home_pos=99) + info_2 = CustomMapField(MAP_INFO_2, start_address=5, x=0, y=4, module_width=16, module_height=2, home_pos=99) + via_1 = CustomMapField(MAP_VIA_1, start_address=6, x=16, y=2, module_width=16, module_height=2, home_pos=99) + via_2 = CustomMapField(MAP_VIA_2, start_address=7, x=16, y=4, module_width=16, module_height=2, home_pos=99) + destination = TextField(start_address=8, length=16, x=0, y=6, module_width=2, module_height=2, display_mapping=MAP_ALNUM, home_pos=99) + + hour_b = MirrorField(hour, start_address=24, x=0, y=10) + minute_b = MirrorField(minute, start_address=25, x=12, y=10) + info_1_b = MirrorField(info_1, start_address=26, x=0, y=12) + info_2_b = MirrorField(info_2, start_address=28, x=0, y=14) + via_1_b = MirrorField(via_1, start_address=27, x=16, y=12) + via_2_b = MirrorField(via_2, start_address=29, x=16, y=14) + destination_b = MirrorField(destination, start_address=30, length=16, x=0, y=16) diff --git a/util.py b/util.py new file mode 100644 index 0000000..fecf6b3 --- /dev/null +++ b/util.py @@ -0,0 +1,28 @@ +import errno +import os +import signal + +from functools import wraps + + +class TimeoutError(Exception): + pass + + +def timeout(seconds, error_message = os.strerror(errno.ETIME)): + def decorator(func): + def _handle_timeout(signum, frame): + raise TimeoutError(error_message) + + def wrapper(*args, **kwargs): + signal.signal(signal.SIGALRM, _handle_timeout) + signal.alarm(seconds) + try: + result = func(*args, **kwargs) + finally: + signal.alarm(0) + return result + + return wraps(func)(wrapper) + + return decorator