Departure

Aus FHEMWiki
Zur Navigation springen Zur Suche springen

Departure ist ein Modul zur Anzeige der Abfahrtszeiten von Bahn, Bus, Zug und Fähre des öffentlichen Personennahverkehrs (ÖPNV). Diese Seite basiert auf einem Beitrag im Forum (von sbiermann). Mittlerweile gibt es hierzu ein noch inoffizielles Modul (von uniqueck).

Zusätzlich gibt es ein Widget für die FHEM Tablet UI (FTUI) (von setstate).


Todo: Diese Seite sollte angepasst/überarbeitet werden, wenn das Modul 98_departure offiziell eingecheckt ist.


Vorbereitung

Um die Abfahrtzeiten zu ermitteln wird der REST-Wrapper von sbiermann genutzt, der auf dem Dienst für die Android App "Öffi" basiert. Für die Spätere Abfrage wird der Provider und die ID der Haltestelle benötigt. Beides kann wie folgt ermittelt werden.

1. Ermitteln welche Provider gibt es und welcher ist für mich zuständig.

https://transport.stefan-biermann.de/publictransportapi/rest/provider

Dieses liefert als Antwort im JSON Format:

[{"name":"Sncb","aClass":"SncbProvider"},{"name":"Vbn","aClass":"VbnProvider"},{"name":"Wien","aClass":"WienProvider"},{"name":"Linz","aClass":"LinzProvider"},{"name":"Vrr","aClass":"VrrProvider"},{"name":"Oebb","aClass":"OebbProvider"},{"name":"Gvh","aClass":"GvhProvider"},{"name":"Ns","aClass":"NsProvider"},{"name":"Vao","aClass":"VaoProvider"},{"name":"Tfi","aClass":"TfiProvider"},{"name":"Vgn","aClass":"VgnProvider"},{"name":"Mvg","aClass":"MvgProvider"},{"name":"Pl","aClass":"PlProvider"},{"name":"Vgs","aClass":"VgsProvider"},{"name":"Nasa","aClass":"NasaProvider"},{"name":"Vbb","aClass":"VbbProvider"},{"name":"Ivb","aClass":"IvbProvider"},{"name":"Nvv","aClass":"NvvProvider"},{"name":"Mvv","aClass":"MvvProvider"},{"name":"Vagfr","aClass":"VagfrProvider"},{"name":"Vvv","aClass":"VvvProvider"},{"name":"Sf","aClass":"SfProvider"},{"name":"Vms","aClass":"VmsProvider"},{"name":"Sbb","aClass":"SbbProvider"},{"name":"Bsvag","aClass":"BsvagProvider"},{"name":"Jet","aClass":"JetProvider"},{"name":"Septa","aClass":"SeptaProvider"},{"name":"Bvb","aClass":"BvbProvider"},{"name":"Mersey","aClass":"MerseyProvider"},{"name":"Vvs","aClass":"VvsProvider"},{"name":"Nvbw","aClass":"NvbwProvider"},{"name":"Se","aClass":"SeProvider"},{"name":"Svv","aClass":"SvvProvider"},{"name":"Bahn","aClass":"BahnProvider"},{"name":"Vrs","aClass":"VrsProvider"},{"name":"Stockholm","aClass":"StockholmProvider"},{"name":"Vmv","aClass":"VmvProvider"},{"name":"Stv","aClass":"StvProvider"},{"name":"Sydney","aClass":"SydneyProvider"},{"name":"Paris","aClass":"ParisProvider"},{"name":"Dsb","aClass":"DsbProvider"},{"name":"Rt","aClass":"RtProvider"},{"name":"Dub","aClass":"DubProvider"},{"name":"Bvg","aClass":"BvgProvider"},{"name":"Paca","aClass":"PacaProvider"},{"name":"Vor","aClass":"VorProvider"},{"name":"FrenchSouthWest","aClass":"FrenchSouthWestProvider"},{"name":"Avv","aClass":"AvvProvider"},{"name":"Zvv","aClass":"ZvvProvider"},{"name":"Nri","aClass":"NriProvider"},{"name":"Invg","aClass":"InvgProvider"},{"name":"Eireann","aClass":"EireannProvider"},{"name":"Vbl","aClass":"VblProvider"},{"name":"Vvo","aClass":"VvoProvider"},{"name":"Sh","aClass":"ShProvider"},{"name":"Kvv","aClass":"KvvProvider"},{"name":"Bayern","aClass":"BayernProvider"},{"name":"Atc","aClass":"AtcProvider"},{"name":"Lu","aClass":"LuProvider"},{"name":"Italy","aClass":"ItalyProvider"},{"name":"Vvm","aClass":"VvmProvider"},{"name":"Met","aClass":"MetProvider"},{"name":"Ding","aClass":"DingProvider"},{"name":"Tlem","aClass":"TlemProvider"},{"name":"Vvt","aClass":"VvtProvider"},{"name":"Vrn","aClass":"VrnProvider"}]

Das was bei Name steht wird verwendet, der Wert aClass ist intern und braucht hier nicht weiter verwendet werden. Im Beispiel haben die Verkehrsbetriebe Stuttgart (VVS) den Namen "Vvs".

2. Ermitteln der StationId für die Haltestelle deren Abfahrtszeiten ich gerne haben möchte. In diesem Beispiel die Haltstelle "SSB-Zentrum"

https://transport.stefan-biermann.de/publictransportapi/rest/station/suggest?q=SSB-Zentrum&provider=Vvs

Dieses liefert als Antwort im JSON Format:

[{"type":"STATION","id":"5000350","lat":48726856,"lon":9129721,"place":"Stuttgart","name":"SSB-Zentrum","products":null,"lonAsDouble":9.129721,"latAsDouble":48.726856,"identified":true},{"type":"STATION","id":"5002601","lat":48722757,"lon":9129058,"place":"Stuttgart","name":"Industriestraße (SSB-Zentrum)","products":null,"lonAsDouble":9.129058,"latAsDouble":48.722757,"identified":true}]

Wie man sehen kann gibt es mehrere Treffer für SSB-Zentrum. Es wird aber nur der Typ "STATION" benötigt und somit lautet die StationId "5000350".

3. Abfrage der Departure Zeiten für die Haltestelle "SSB-Zentrum". Diese liefert die Daten im passenden Format für das zugehörige departure Widget für FTUI

https://transport.stefan-biermann.de/publictransportapi/rest/departure/FHEM?from=5000350&provider=Vvs

dieses liefert als Antwort im passenden Format:

[["U8","Vaihingen","3"],["U12","Dürrlewang","6"],["U8","Ostfildern","5"],["U3","Vaihingen","6"],["U12","Hallschlag","7"],["U3","Plieningen","9"],["U8","Vaihingen","12"],["U12","Dürrlewang","17"],["U8","Waldau","15"],["U3","Vaihingen","16"]]

Die Zeiten sind immer inklusive Verspätung angegeben, sofern der Provider diese Daten mit sendet.

Einbindung in FHEM

Wie in der Einleitung erwähnt gibt es aktuell zwei Wege, die Abfahrtszeiten einzubinden: über HTTPMOD oder über das noch inofizielle Modul 98_departure

define myDeparture HTTPMOD none 0
attr myDeparture get01Name SSB-Zentrum
attr myDeparture get01URL https://transport.stefan-biermann.de/publictransportapi/rest/departure/FHEM?from=5000350&provider=Vvs
attr myDeparture get01Regex (\[\[.*\]\]).*
attr VAG timeout 30

Es können mehrere Haltestellen in einem Device hinterlegt werden, hierzu einfach die drei Attribute get01Name, get01URL und get01Regex duplizieren und durchnummerieren. Dabei müssen natürlich Name und URL angepasst werden. Bei dieser Konfiguration erfolgt die Aktualisierung über das FTUI Widget!

Alternativ wird im Forum erläutert, wie man mit HTTPMOD die Abfahrtszeiten erhalten kann. Erstmal auf der Bahn-Seite https://reiseauskunft.bahn.de/bin/bhftafel.exe/dox? den gewünschten Bahnhof raussuchen, es sind wie gesagt aber nicht nur Bahnhöfe drin sondern auch die meisten Haltestellen der regionalen Verkehrsverbünde. Einmal Abfahrt oder Ankunft wählen und dann "Später" drücken, erst dann ist oben in der URL der Parameter "si" mit der Bahnhofs-ID zu sehen.

Eine URL für den Hauptbahnhof Hannover würde jetzt so aussehen:

https://reiseauskunft.bahn.de/bin/bhftafel.exe/dox?si=8000152&bt=dep&p=1111111111&max=5&rt=1&use_realtime_filter=1&start=yes&

in FHEM dann damit ein

define bhf_HannoverHbf HTTPMOD https://reiseauskunft.bahn.de/bin/bhftafel.exe/dox?si=8000152&bt=dep&p=1111111111&max=5&rt=1&use_realtime_filter=1&start=yes& 0

In dem angelegtem Device auf Raw-Definition gehen und alles löschen und das eintragen

defmod bhf_HannoverHbf HTTPMOD https://reiseauskunft.bahn.de/bin/bhftafel.exe/dox?si=8000152&bt=dep&p=1111111111&max=5&rt=1&use_realtime_filter=1&start=yes& 0
attr bhf_HannoverHbf userattr get1Name reading01-10Name reading01-11Name reading01-12Name reading01-13Name reading01-14Name reading01-15Name reading01-16Name reading01-17Name reading01-18Name reading01-19Name reading01-1Name reading01-20Name reading01-2Name reading01-3Name reading01-4Name reading01-5Name reading01-6Name reading01-7Name reading01-8Name reading01-9Name reading01Name reading01OExpr reading01RegOpt reading01Regex
attr bhf_HannoverHbf get1Name Update
attr bhf_HannoverHbf reading01-10Name departure_3_destination
attr bhf_HannoverHbf reading01-11Name departure_3_time
attr bhf_HannoverHbf reading01-12Name departure_3_delay
attr bhf_HannoverHbf reading01-13Name departure_4_product
attr bhf_HannoverHbf reading01-14Name departure_4_destination
attr bhf_HannoverHbf reading01-15Name departure_4_time
attr bhf_HannoverHbf reading01-16Name departure_4_delay
attr bhf_HannoverHbf reading01-17Name departure_5_product
attr bhf_HannoverHbf reading01-18Name departure_5_destination
attr bhf_HannoverHbf reading01-19Name departure_5_time
attr bhf_HannoverHbf reading01-1Name departure_1_product
attr bhf_HannoverHbf reading01-20Name departure_5_delay
attr bhf_HannoverHbf reading01-2Name departure_1_destination
attr bhf_HannoverHbf reading01-3Name departure_1_time
attr bhf_HannoverHbf reading01-4Name departure_1_delay
attr bhf_HannoverHbf reading01-5Name departure_2_product
attr bhf_HannoverHbf reading01-6Name departure_2_destination
attr bhf_HannoverHbf reading01-7Name departure_2_time
attr bhf_HannoverHbf reading01-8Name departure_2_delay
attr bhf_HannoverHbf reading01-9Name departure_3_product
attr bhf_HannoverHbf reading01Name reading
attr bhf_HannoverHbf reading01OExpr {$val =~ s/<br\/><span class="delay.*">//g;; $val =~ s/<\/span>.*//g;; $val =~ s/.* ;.*//g;; $val =~ s/, <span.*//g;; $val =~ s/(;/(/g;; $val =~ s/);/)/g;; $val =~ s/ü;/ü/g;; $val =~ s/ö;/ö/g;; $val =~ s/ä;/ä/g;; $val =~ s/ß;/ß/g;; $val;;}
attr bhf_HannoverHbf reading01RegOpt gm
attr bhf_HannoverHbf reading01Regex <span class="bold">(.*)<\/span>\s<\/a>[\w\W]&[gl]t;;&[gl]t;;\s(.*)\s<br \/>[\w\W]<span class="bold">(\d\d:\d\d)<\/span>(.*)<\/div>
attr bhf_HannoverHbf stateFormat departure_1_product departure_1_destination departure_1_time (departure_1_delay)

Jetzt gibt es oben den Update Button oder "get bhf_HannoverHbf Update" in der FHEM Befehlzeile wählen, dann sollten ein paar Readings erscheinen:

READINGS:
     2019-12-22 17:15:23   departure_1_delay 17:16
     2019-12-22 17:15:23   departure_1_destination Hauptbahnhof/ZOB, Hannover
     2019-12-22 17:15:23   departure_1_product STB   10
     2019-12-22 17:15:23   departure_1_time 17:14
     2019-12-22 17:15:23   departure_2_delay 17:17
     2019-12-22 17:15:23   departure_2_destination Sarstedt (Endpunkt GVH)
     2019-12-22 17:15:23   departure_2_product STB    1
     2019-12-22 17:15:23   departure_2_time 17:14
     2019-12-22 17:15:23   departure_3_delay 17:15
     2019-12-22 17:15:23   departure_3_destination Haltenhoffstraße, Hannover
     2019-12-22 17:15:23   departure_3_product Bus  121
     2019-12-22 17:15:23   departure_3_time 17:14
     2019-12-22 17:15:23   departure_4_delay 17:15
     2019-12-22 17:15:23   departure_4_destination Ahlem, Hannover
     2019-12-22 17:15:23   departure_4_product STB   10
     2019-12-22 17:15:23   departure_4_time 17:15
     2019-12-22 17:15:23   departure_5_delay 
     2019-12-22 17:15:23   departure_5_destination Hauptbahnhof/ZOB, Hannover
     2019-12-22 17:15:23   departure_5_product Bussprin
     2019-12-22 17:15:23   departure_5_time 17:15

Man kann in der Bahnabfrage auch eine Linie auswählen, die Info muss dann im URL Parameter "tn" stehen. Wenn man eine bestimmte Richtung ausfiltern will geht das auch im Atrribut reading01Regex, da könnte man z.B. dort wo das jeweils zweite Reading erzeugt wird ....t;;\s(Leipzig.*)\s<br..... schreiben.

Läuft bei jetzt seit ein paar Tagen ganz gut. Allerdings scheint nicht bei allen Verkehrsverbünden die Verspätungsanzeige schon zu funktionieren, da bleibt dann das Reading delay leer, bei mir im VBN geht es aber auch für lokale Bushaltestellen.

Falls es nicht für alle Abfahrten Echtzeiten gibt kann man mit einem Userreading noch definieren, dass dann ein Planzeit angezeigt wird, z.B. so:

departure_1_delay_time { ReadingsVal($NAME,"departure_1_delay",0) eq "" ? ReadingsVal($NAME,"departure_1_time",0) : ReadingsVal($NAME,"departure_1_delay",0);}

oder wenn man z.B. eine Farbsteuerung bei Verspätungen benötigt ein Userreading was zwischen 0 und 1 umschaltet.

departure_1_is_delay { ReadingsVal($NAME,"departure_1_delay",0) eq ReadingsVal($NAME,"departure_1_time",0) ? 0 : 1;}

Bekannte Probleme

UTC versus lokale Zeitzone

Die Uhrzeit unter departure_0_time und departure_0_time_human_readable wird in UTC und nicht in lokaler Zeit angezeigt. Hierfuer kann man sich ein User-Reading erstellen, welches die Zeitzonen-Differenz ermittelt und anschliessend auf die Abfahrtszeit in UTC vorzeichenrichtig drauf addiert. Das entsprechende Atrrribut "UserReading" lautet wie folgt:

departure_0_only_time {my $oldtime = ReadingsVal($NAME,"departure_0_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_1_only_time {my $oldtime = ReadingsVal($NAME,"departure_1_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_2_only_time {my $oldtime = ReadingsVal($NAME,"departure_2_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_3_only_time {my $oldtime = ReadingsVal($NAME,"departure_3_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_4_only_time {my $oldtime = ReadingsVal($NAME,"departure_4_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_5_only_time {my $oldtime = ReadingsVal($NAME,"departure_5_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_6_only_time {my $oldtime = ReadingsVal($NAME,"departure_6_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_7_only_time {my $oldtime = ReadingsVal($NAME,"departure_7_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_8_only_time {my $oldtime = ReadingsVal($NAME,"departure_8_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;},
departure_9_only_time {my $oldtime = ReadingsVal($NAME,"departure_9_time",0);$oldtime =~ s/.*T//;$oldtime =~ s/\+.*//;my @lt = localtime(12*60*60);my @gt = gmtime(12*60*60);my $tz = $lt[2] - $gt[2];my @DepTimeSplit = split(":", $oldtime);my $newtime = $DepTimeSplit[0]+$tz . ":" . $DepTimeSplit[1];$newtime;}

Dieses schneidet auch gleich das Datum raus.

Links