Nextride: Unterschied zwischen den Versionen
KKeine Bearbeitungszusammenfassung |
(Nextride is dead, long live nextride!) |
||
Zeile 1: | Zeile 1: | ||
{{ | == Wann fährt die nächste Bahn? == | ||
[[ | |||
* [http://haltestellenmonitor.vrr.de/monitor/5c1a5bf76de06ea27630edc685232626 Mobiel/VRR Abfahrzeiten Ziegelstraße] | |||
== Nextride 2.0? == | |||
Im alten Space an der Sudbrackstraße hatten wir ein Display der nächsten Nahverkehr-Abfahrzeiten (s.u.), an der Blomestraße fehlt so etwas leider bisher. Der Link oben wurde mit dem [https://haltestellenmonitor.vrr.de/vu/mobiel#/index VRR-Haltestellenmonitor] erstellt. | |||
Der eigentliche API-Endpunkt hinter dem Haltestellenmonitor ist '''"https://haltestellenmonitor.vrr.de/backend/api/stations/table''', darauf aufbauend könnte ein neues '''nextride''' entstehen. | |||
Als neue Anzeigemöglichkeit könnte ich mir zB. -- energiesparend :) -- einen Arduino mit eInk-Display vorstellen? | |||
=== VRR API === | |||
Dokumentation zu diesem API habe ich beim VRR auf die Schnelle nicht gefunden, es gibt dort zwar einen "Open Data" Bereich, aber dort scheinen nur Download-Datensätze angeboten zu werden, aber keine Live-Daten. Daher ist alles was hier folgt Ergebnis von Reverse Engineering. | |||
==== Request ==== | |||
Der Haltestellenmonitor schickt die Haltestellendaten als POST-Request, und die POST-Parameter für eine Haltestelle sind konstant, zB. für die Stadtbahn-Haltestelle Ziegelstraße: | |||
<nowiki> | |||
table%5Bdeparture%5D%5BstationId%5D=23005614&table%5Bdeparture%5D%5BstationName%5D=Bielefeld+Ziegelstra%C3%9Fe&table%5Bdeparture%5D%5BplatformVisibility%5D=1&table%5Bdeparture%5D%5Btransport%5D=0%2C1%2C2%2C3%2C4%2C15%2C6&table%5Bdeparture%5D%5BuseAllLines%5D=1&table%5Bdeparture%5D%5BlinesFilter%5D=&table%5Bdeparture%5D%5BoptimizedForStation%5D=0&table%5Bdeparture%5D%5BrowCount%5D=6&table%5Bdeparture%5D%5BrefreshInterval%5D=60&table%5Bdeparture%5D%5Bdistance%5D=0&table%5Bdeparture%5D%5Bmarquee%5D=-1&table%5BsortBy%5D=0 | |||
</nowiki> | |||
oder netter formatiert: | |||
<nowiki> | |||
table[departure][stationId] "23005614" | |||
table[departure][stationName] "Bielefeld+Ziegelstraße" | |||
table[departure][platformVisibility] "1" | |||
table[departure][transport] "0,1,2,3,4,15,6" | |||
table[departure][useAllLines] "1" | |||
table[departure][linesFilter] "" | |||
table[departure][optimizedForStation] "0" | |||
table[departure][rowCount] "6" | |||
table[departure][refreshInterval] "60" | |||
table[departure][distance] "0" | |||
table[departure][marquee] "-1" | |||
table[sortBy] "0" | |||
</nowiki> | |||
==== Response ==== | |||
Die Antwort kommt als JSON-Dokument zurück, damit lässt sich gut weiterarbeiten: | |||
<nowiki> | |||
{ | |||
"departureData":[ | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Altenhagen", | |||
"directionCode":"H", | |||
"route":"Bielefeld, Altenhagen", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"03", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"00", | |||
"countdown":"4", | |||
"platform":"", | |||
"delay":"3", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682233380", | |||
"orgFullTime":"1682233200", | |||
"supplement":"", | |||
"key":"231" | |||
}, | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Sieker", | |||
"directionCode":"R", | |||
"route":"Bielefeld, Sieker", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"04", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"04", | |||
"countdown":"5", | |||
"platform":"", | |||
"delay":"0", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682233440", | |||
"orgFullTime":"1682233440", | |||
"supplement":"", | |||
"key":"38" | |||
}, | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Altenhagen", | |||
"directionCode":"H", | |||
"route":"Bielefeld, Altenhagen", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"15", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"15", | |||
"countdown":"16", | |||
"platform":"", | |||
"delay":"0", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682234100", | |||
"orgFullTime":"1682234100", | |||
"supplement":"", | |||
"key":"234" | |||
}, | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Sieker", | |||
"directionCode":"R", | |||
"route":"Bielefeld, Sieker", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"19", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"19", | |||
"countdown":"20", | |||
"platform":"", | |||
"delay":"0", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682234340", | |||
"orgFullTime":"1682234340", | |||
"supplement":"", | |||
"key":"40" | |||
}, | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Altenhagen", | |||
"directionCode":"H", | |||
"route":"Bielefeld, Altenhagen", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"30", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"30", | |||
"countdown":"31", | |||
"platform":"", | |||
"delay":"0", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682235000", | |||
"orgFullTime":"1682235000", | |||
"supplement":"", | |||
"key":"236" | |||
}, | |||
{ | |||
"name":"2", | |||
"lineNumber":"2", | |||
"lineCode":"31002", | |||
"subname":"Stadtbahn", | |||
"direction":"Bielefeld, Sieker", | |||
"directionCode":"R", | |||
"route":"Bielefeld, Sieker", | |||
"type":4, | |||
"day":"23", | |||
"month":"4", | |||
"year":"2023", | |||
"hour":"9", | |||
"minute":"34", | |||
"orgDay":"23", | |||
"orgHour":"9", | |||
"orgMinute":"34", | |||
"countdown":"35", | |||
"platform":"", | |||
"delay":"0", | |||
"isRealTime":true, | |||
"isDateOverflow":false, | |||
"lineInfo":{ | |||
"lineInfo":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
}, | |||
"lineBlocking":{ | |||
"messages":[ | |||
], | |||
"text":"", | |||
"priority":0 | |||
} | |||
}, | |||
"fullTime":"1682235240", | |||
"orgFullTime":"1682235240", | |||
"supplement":"", | |||
"key":"43" | |||
} | |||
], | |||
"departureInfo":{ | |||
"stopInfo":{ | |||
"text":"" | |||
}, | |||
"stopBlocking":{ | |||
"text":"" | |||
}, | |||
"areaInfo":{ | |||
"text":"" | |||
}, | |||
"areaBlocking":{ | |||
"text":"" | |||
} | |||
}, | |||
"globalInfo":"", | |||
"stationName":"Bielefeld, Ziegelstra\u00dfe", | |||
"marquee":-1, | |||
"stationInfo":[ | |||
], | |||
"currentTime":1682233123, | |||
"currentTimeReal":1682233123 | |||
} | |||
</nowiki> | |||
==== Q&D Example ==== | |||
"Bielefeld existiert, und PHP ist OK" ;) | |||
<nowiki> | |||
<?php | |||
$url = "https://haltestellenmonitor.vrr.de/backend/api/stations/table"; | |||
$data = "table%5Bdeparture%5D%5BstationId%5D=23005614&table%5Bdeparture%5D%5BstationName%5D=Bielefeld+Ziegelstra%C3%9Fe&table%5Bdeparture%5D%5BplatformVisibility%5D=1&table%5Bdeparture%5D%5Btransport%5D=0%2C1%2C2%2C3%2C4%2C15%2C6&table%5Bdeparture%5D%5BuseAllLines%5D=1&table%5Bdeparture%5D%5BlinesFilter%5D=&table%5Bdeparture%5D%5BoptimizedForStation%5D=0&table%5Bdeparture%5D%5BrowCount%5D=6&table%5Bdeparture%5D%5BrefreshInterval%5D=60&table%5Bdeparture%5D%5Bdistance%5D=0&table%5Bdeparture%5D%5Bmarquee%5D=-1&table%5BsortBy%5D=0"; | |||
$curl = curl_init(); | |||
curl_setopt($curl, CURLOPT_URL, $url); | |||
curl_setopt($curl, CURLOPT_POST, true); | |||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); | |||
$resp = curl_exec($curl); | |||
curl_close($curl); | |||
$data = json_decode($resp, true); | |||
foreach ($data["departureData"] as $dep) { | |||
$dir = $dep["direction"]; | |||
$time = strftime("%R", $dep["orgFullTime"]); | |||
if ($dep["delay"] > 0) { | |||
$time .= " +".$dep["delay"]; | |||
} | |||
$left = ($dep["fullTime"] - time())/60; | |||
printf("+%-3d %-15s %s\n", $left, $time, $dir); | |||
} | |||
</nowiki> | |||
== Nextride in der Sudbrackstraße == | |||
Der nextride-Teil bestand aus einem Haskell-Programm, welches cronjob-gesteuert die Bahn-Seite für die nächstgelegene Straßenbahnhaltestelle abgriff und die Abfahrtszeiten als JSON in eine Datei schrieb. Diese Datei wurde bei Änderung vom Infobeamer ([[Armageddon_Notifier]]) per Lua-Script eingelesen und dargestellt. | |||
Diese Lösung funktioniert aus verschiedenen Gründen leider nicht mehr, unter anderem weil das damals genutzte API der Bahn keine Daten anderer Verkehrsbetriebe mehr zur Verfügung stellt. | |||
* [https://github.com/HackerspaceBielefeld/Nextride nextride code auf GitHub] | |||
[[Kategorie:Projekt]] | [[Kategorie:Projekt]] | ||
[[Kategorie:Sudbrackstraße]] |
Version vom 23. April 2023, 09:43 Uhr
Wann fährt die nächste Bahn?
Nextride 2.0?
Im alten Space an der Sudbrackstraße hatten wir ein Display der nächsten Nahverkehr-Abfahrzeiten (s.u.), an der Blomestraße fehlt so etwas leider bisher. Der Link oben wurde mit dem VRR-Haltestellenmonitor erstellt.
Der eigentliche API-Endpunkt hinter dem Haltestellenmonitor ist "https://haltestellenmonitor.vrr.de/backend/api/stations/table, darauf aufbauend könnte ein neues nextride entstehen.
Als neue Anzeigemöglichkeit könnte ich mir zB. -- energiesparend :) -- einen Arduino mit eInk-Display vorstellen?
VRR API
Dokumentation zu diesem API habe ich beim VRR auf die Schnelle nicht gefunden, es gibt dort zwar einen "Open Data" Bereich, aber dort scheinen nur Download-Datensätze angeboten zu werden, aber keine Live-Daten. Daher ist alles was hier folgt Ergebnis von Reverse Engineering.
Request
Der Haltestellenmonitor schickt die Haltestellendaten als POST-Request, und die POST-Parameter für eine Haltestelle sind konstant, zB. für die Stadtbahn-Haltestelle Ziegelstraße:
table%5Bdeparture%5D%5BstationId%5D=23005614&table%5Bdeparture%5D%5BstationName%5D=Bielefeld+Ziegelstra%C3%9Fe&table%5Bdeparture%5D%5BplatformVisibility%5D=1&table%5Bdeparture%5D%5Btransport%5D=0%2C1%2C2%2C3%2C4%2C15%2C6&table%5Bdeparture%5D%5BuseAllLines%5D=1&table%5Bdeparture%5D%5BlinesFilter%5D=&table%5Bdeparture%5D%5BoptimizedForStation%5D=0&table%5Bdeparture%5D%5BrowCount%5D=6&table%5Bdeparture%5D%5BrefreshInterval%5D=60&table%5Bdeparture%5D%5Bdistance%5D=0&table%5Bdeparture%5D%5Bmarquee%5D=-1&table%5BsortBy%5D=0
oder netter formatiert:
table[departure][stationId] "23005614" table[departure][stationName] "Bielefeld+Ziegelstraße" table[departure][platformVisibility] "1" table[departure][transport] "0,1,2,3,4,15,6" table[departure][useAllLines] "1" table[departure][linesFilter] "" table[departure][optimizedForStation] "0" table[departure][rowCount] "6" table[departure][refreshInterval] "60" table[departure][distance] "0" table[departure][marquee] "-1" table[sortBy] "0"
Response
Die Antwort kommt als JSON-Dokument zurück, damit lässt sich gut weiterarbeiten:
{ "departureData":[ { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Altenhagen", "directionCode":"H", "route":"Bielefeld, Altenhagen", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"03", "orgDay":"23", "orgHour":"9", "orgMinute":"00", "countdown":"4", "platform":"", "delay":"3", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682233380", "orgFullTime":"1682233200", "supplement":"", "key":"231" }, { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Sieker", "directionCode":"R", "route":"Bielefeld, Sieker", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"04", "orgDay":"23", "orgHour":"9", "orgMinute":"04", "countdown":"5", "platform":"", "delay":"0", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682233440", "orgFullTime":"1682233440", "supplement":"", "key":"38" }, { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Altenhagen", "directionCode":"H", "route":"Bielefeld, Altenhagen", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"15", "orgDay":"23", "orgHour":"9", "orgMinute":"15", "countdown":"16", "platform":"", "delay":"0", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682234100", "orgFullTime":"1682234100", "supplement":"", "key":"234" }, { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Sieker", "directionCode":"R", "route":"Bielefeld, Sieker", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"19", "orgDay":"23", "orgHour":"9", "orgMinute":"19", "countdown":"20", "platform":"", "delay":"0", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682234340", "orgFullTime":"1682234340", "supplement":"", "key":"40" }, { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Altenhagen", "directionCode":"H", "route":"Bielefeld, Altenhagen", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"30", "orgDay":"23", "orgHour":"9", "orgMinute":"30", "countdown":"31", "platform":"", "delay":"0", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682235000", "orgFullTime":"1682235000", "supplement":"", "key":"236" }, { "name":"2", "lineNumber":"2", "lineCode":"31002", "subname":"Stadtbahn", "direction":"Bielefeld, Sieker", "directionCode":"R", "route":"Bielefeld, Sieker", "type":4, "day":"23", "month":"4", "year":"2023", "hour":"9", "minute":"34", "orgDay":"23", "orgHour":"9", "orgMinute":"34", "countdown":"35", "platform":"", "delay":"0", "isRealTime":true, "isDateOverflow":false, "lineInfo":{ "lineInfo":{ "messages":[ ], "text":"", "priority":0 }, "lineBlocking":{ "messages":[ ], "text":"", "priority":0 } }, "fullTime":"1682235240", "orgFullTime":"1682235240", "supplement":"", "key":"43" } ], "departureInfo":{ "stopInfo":{ "text":"" }, "stopBlocking":{ "text":"" }, "areaInfo":{ "text":"" }, "areaBlocking":{ "text":"" } }, "globalInfo":"", "stationName":"Bielefeld, Ziegelstra\u00dfe", "marquee":-1, "stationInfo":[ ], "currentTime":1682233123, "currentTimeReal":1682233123 }
Q&D Example
"Bielefeld existiert, und PHP ist OK" ;)
<?php $url = "https://haltestellenmonitor.vrr.de/backend/api/stations/table"; $data = "table%5Bdeparture%5D%5BstationId%5D=23005614&table%5Bdeparture%5D%5BstationName%5D=Bielefeld+Ziegelstra%C3%9Fe&table%5Bdeparture%5D%5BplatformVisibility%5D=1&table%5Bdeparture%5D%5Btransport%5D=0%2C1%2C2%2C3%2C4%2C15%2C6&table%5Bdeparture%5D%5BuseAllLines%5D=1&table%5Bdeparture%5D%5BlinesFilter%5D=&table%5Bdeparture%5D%5BoptimizedForStation%5D=0&table%5Bdeparture%5D%5BrowCount%5D=6&table%5Bdeparture%5D%5BrefreshInterval%5D=60&table%5Bdeparture%5D%5Bdistance%5D=0&table%5Bdeparture%5D%5Bmarquee%5D=-1&table%5BsortBy%5D=0"; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); $resp = curl_exec($curl); curl_close($curl); $data = json_decode($resp, true); foreach ($data["departureData"] as $dep) { $dir = $dep["direction"]; $time = strftime("%R", $dep["orgFullTime"]); if ($dep["delay"] > 0) { $time .= " +".$dep["delay"]; } $left = ($dep["fullTime"] - time())/60; printf("+%-3d %-15s %s\n", $left, $time, $dir); }
Nextride in der Sudbrackstraße
Der nextride-Teil bestand aus einem Haskell-Programm, welches cronjob-gesteuert die Bahn-Seite für die nächstgelegene Straßenbahnhaltestelle abgriff und die Abfahrtszeiten als JSON in eine Datei schrieb. Diese Datei wurde bei Änderung vom Infobeamer (Armageddon_Notifier) per Lua-Script eingelesen und dargestellt.
Diese Lösung funktioniert aus verschiedenen Gründen leider nicht mehr, unter anderem weil das damals genutzte API der Bahn keine Daten anderer Verkehrsbetriebe mehr zur Verfügung stellt.