Nextride

Aus Hackerspace Bielefeld Wiki
Zur Navigation springen Zur Suche springen

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.

Suche von Stationen

[1]

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"


Feldwerte
  • table[departure][transport]
Werte
0 ICE/IC/EC
1 Zug
2 S-Bahn
3 U-Bahn
4 Straßenbahn
5 Bus
6 Schwebebahn

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.