Initial commit

This commit is contained in:
Julian Metzler 2021-03-06 20:47:39 +01:00
commit 278ec3928b
7 changed files with 10742 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.venv/
**/__pycache__
*.pyc
lastrun.txt

66
run.py Normal file
View File

@ -0,0 +1,66 @@
import argparse
import json
from pprint import pprint
from vag_api import VagApi
from vag_zza import VagZza
from station_map import *
def display_train(zza, train):
line = train['Linienname']
via = ""
dest = zza.get_closest_destination(train['Richtungstext'])
if line == "U1":
if dest not in ("Langwasser-Süd", "Fürth Hardhöhe"):
line = "U11"
# Via für Standort Maximilianstraße
if dest in ("Fürth Hardhöhe", "Fürth Klinikum", "Fürth / Stadthalle"):
via = "Stadtgrenze - Fürth / Hauptbahnhof"
elif dest in ("Fürth / Hauptbahnhof", "Jakobinenstraße"):
via = "Stadtgrenze"
elif dest in ("Weißer Turm", "Hauptbahnhof"):
via = "Plärrer"
elif dest in ("Aufseßplatz", "Maffeiplatz", "Frankenstraße", "Hasenbuck", "Bauernfeindstraße", "Messe"):
via = "Plärrer - Hauptbahnhof"
elif dest in ("Scharfreiterring", "Langwasser-Süd"):
via = "Plärrer - Hauptbahnhof - Messe"
if dest == "":
line = "Sonderzug"
dest = "Bitte achten Sie auf die Zugbeschilderung"
zza.set_line(line)
zza.set_via(via)
zza.set_destination(dest)
zza.update()
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--port", type=str, required=True, help="Serial port for display")
parser.add_argument("-s", "--station", type=str, required=True, help="Station name to display departures of")
args = parser.parse_args()
api = VagApi()
api.load_station_data("stations.json")
try:
station_id = int(args.station)
except ValueError:
station_id = api.get_station_info(args.station)[0]['VGNKennung']
departures = api.get_departures(station_id, products=["Ubahn"])
train = departures[0]
zza = VagZza(args.port)
pprint(train)
display_train(zza, train)
if __name__ == "__main__":
main()

8
station_map.py Normal file
View File

@ -0,0 +1,8 @@
MAP_LINE = {
"U1": 3,
"U2": 9
}
MAP_DESTINATION = {
}

10428
stations.json Normal file

File diff suppressed because it is too large Load Diff

41
vag_api.py Normal file
View File

@ -0,0 +1,41 @@
import json
import requests
class VagApi:
def __init__(self):
self.station_data = []
def load_station_data(self, filename):
with open(filename, 'r', encoding='utf-8') as f:
self.station_data = json.load(f)['Haltestellen']
def get_station_info(self, query):
matches = []
if type(query) is str:
query = query.lower()
str_query = True
else:
str_query = False
for station in self.station_data:
if str_query:
if query in station['Haltestellenname'].lower() or query in station['VAGKennung'].lower():
matches.append(station)
else:
if station['VGNKennung'] == query:
matches.append(station)
return matches
def get_stations(self, query = ""):
resp = requests.get("https://start.vag.de/dm/api/haltestellen.json/vgn", params={'name': query})
resp.raise_for_status()
data = resp.json()
return data
def get_departures(self, station, delay_min=0, products=['Ubahn', 'Tram', 'Bus']):
resp = requests.get(f"https://start.vag.de/dm/api/abfahrten.json/vgn/{station}", params={'timedelay': delay_min, 'product': ",".join(products)})
resp.raise_for_status()
data = resp.json()
return data['Abfahrten']

67
vag_zza.py Normal file
View File

@ -0,0 +1,67 @@
import serial
import time
from difflib import SequenceMatcher
from vag_zza_map import *
class VagZza:
def __init__(self, port):
self.port = serial.Serial(port, baudrate=9600)
def home(self):
self.port.write(b"HOME\n")
time.sleep(0.05)
def update(self):
self.port.write(b"START\n")
time.sleep(0.05)
def set_unit(self, pos, code):
self.port.write(f"UNIT:{pos}:{code}\n".encode('ascii'))
time.sleep(0.05)
def set_line(self, line):
code = None
for c, text in MAP_LINE.items():
if text.lower() == line.lower():
code = c
break
if code is None:
raise ValueError(f"Line text not found: {line}")
self.set_unit(0, code)
self.set_unit(3, code)
def set_via(self, via):
code = None
for c, text in MAP_VIA.items():
if text.lower() == via.lower():
code = c
break
if code is None:
raise ValueError(f"Via text not found: {via}")
self.set_unit(1, code)
self.set_unit(4, code)
def set_destination(self, dest):
code = None
for c, text in MAP_DESTINATION.items():
if text.lower() == dest.lower():
code = c
break
if code is None:
raise ValueError(f"Destination text not found: {dest}")
self.set_unit(2, code)
self.set_unit(5, code)
def get_closest_destination(self, dest):
match = ""
match_score = 0.0
for text in MAP_DESTINATION.values():
score = SequenceMatcher(None, dest, text).ratio()
if score > 0.6 and score > match_score:
print(text, score)
match = text
match_score = score
return match

128
vag_zza_map.py Normal file
View File

@ -0,0 +1,128 @@
MAP_LINE = {
0: "Gerät gestört",
1: "",
2: "U1",
3: "U11",
4: "",
5: "U1 Kurzzug",
6: "U11 Kurzzug",
7: "",
8: "U2",
9: "U21",
10: "",
11: "U2 Kurzzug",
12: "U21 Kurzzug",
13: "",
14: "",
15: "",
16: "",
17: "",
18: "",
19: "Kurzzug",
20: "",
21: "",
22: "",
23: "",
24: "",
25: "",
26: "",
27: "Benutzen",
28: "",
29: "",
30: "",
31: "",
32: "",
33: "",
34: "Sonderzug",
35: "Arbeitszug",
36: "Werkstattzug",
37: "Fahrschule",
38: "Abstellanlage",
39: ""
}
MAP_VIA = {
0: "",
1: "",
2: "Plärrer - Hauptbahnhof - Messe",
3: "Hauptbahnhof - Messe",
4: "Messe",
5: "Messe - Hauptbahnhof - Plärrer",
6: "Hauptbahnhof - Plärrer",
7: "Plärrer",
8: "Plärrer - Hauptbahnhof - Rathenauplatz",
9: "Hauptbahnhof - Rathenauplatz",
10: "Rathenauplatz",
11: "Rathenauplatz - Hauptbahnhof - Plärrer",
12: "Plärrer - Hauptbahnhof",
13: "Frankenstraße",
14: "Hauptbahnhof",
15: "Frankenstraße - Messe",
16: "Messe - Langwasser-Mitte",
17: "Langwasser-Mitte",
18: "Maximilianstraße - Stadtgrenze",
19: "Stadtgrenze",
20: "Maximilianstraße",
21: "",
22: "Rothenburgerstraße - Schweinau",
23: "Schweinau",
24: "",
25: "",
26: "",
27: "Sie bitte den",
28: "",
29: "Maximilianstraße - Fürth / Hauptbahnhof",
30: "",
31: "Stadtgrenze - Fürth / Hauptbahnhof",
32: "",
33: "",
34: "",
35: "",
36: "",
37: "",
38: "",
39: ""
}
MAP_DESTINATION = {
0: "",
1: "",
2: "Langwasser-Süd",
3: "Scharfreiterring",
4: "Messe",
5: "Bauernfeindstraße",
6: "Hasenbuck",
7: "Frankenstraße",
8: "Maffeiplatz",
9: "Aufseßplatz",
10: "Weißer Turm",
11: "Plärrer",
12: "Gostenhof",
13: "Bärenschanze",
14: "Eberhardshof",
15: "Muggenhof",
16: "Jakobinenstraße",
17: "Fürth / Hauptbahnhof",
18: "",
19: "Fürth / Stadthalle",
20: "Fürth Klinikum",
21: "Fürth Hardhöhe",
22: "Ziegelstein",
23: "Herrnhütte",
24: "Nordostbahnhof",
25: "Rathenauplatz",
26: "Hauptbahnhof",
27: "Bahnsteig gegenüber",
28: "",
29: "St. Leonhard",
30: "Schweinau",
31: "Hohe Marter",
32: "Röthenbach",
33: "Betriebsschluß Gleis 1",
34: "Bitte achten Sie auf die Zugbeschilderung",
35: "Betriebsschluß Gleis 2",
36: "Bitte achten Sie auf die Lautsprecherdurchsage",
37: "Benutzen Sie bitte die Busse vor dem Bahnhof",
38: "Nicht einsteigen",
39: ""
}