Zum Hauptinhalt springen
Data Connectors · Öffentlicher Nahverkehr

GTFS

Der Node lädt einen statischen GTFS-Feed (ZIP-Archiv mit Textdateien wie stops.txt, routes.txt, trips.txt und stop_times.txt), filtert die Haltestellen mit turf auf die konfigurierten Verwaltungsgebiete, reduziert alle übrigen Dateien auf die dort verkehrenden Fahrten und gibt die Ergebnisse als GtfsAgency-, GtfsStop-, GtfsRoute-, GtfsTrip- und GtfsStopTime-Entitäten über fünf Ausgänge aus. Er ist für sehr große Feeds wie den deutschlandweiten Feed von gtfs.de ausgelegt.

  • Datenquelle
  • Triggerbasiert
  • GTFS statisch
Node-Typ
gtfs-data
Paket
@htag/node-red-contrib-hypertegrity-urbanmobility
Eingänge / Ausgänge
1 / 5
Datenquelle
Beliebiger statischer GTFS-Feed als ZIP über HTTPS (Standard: gtfs.de Deutschland)

Wofür Sie den Node verwenden​

Die General Transit Feed Specification (GTFS) ist das Standardformat für Fahrplandaten des öffentlichen Nahverkehrs. Ein statischer GTFS-Feed ist ein ZIP-Archiv mit Textdateien im CSV-Format, das Verkehrsunternehmen, Haltestellen, Linien, Fahrten, Haltezeiten und Verkehrstage beschreibt. Er ändert sich nur bei Fahrplanwechseln. Davon zu unterscheiden ist GTFS-Realtime, ein Protobuf-Datenstrom mit Verspätungen, Fahrzeugpositionen und Störungsmeldungen, den der Node GTFS-RT verarbeitet.

Deutschlandweite Feeds enthalten mehrere Millionen Fahrten und Haltezeiten. Der GTFS-Node verarbeitet solche Datenmengen in mehreren Durchläufen auf der Festplatte und hält nur die Daten im Speicher, die für Ihre Gebiete relevant sind.

Typische Einsatzfälle sind:

  • Haltestellenverzeichnis einer Kommune mit Barrierefreiheit, bedienten Linien und Einstufung als Knotenpunkt für Karten und Dashboards.
  • Liniennetz und Fahrten als Grundlage für Erreichbarkeitsanalysen oder Auswertungen der Bedienhäufigkeit.
  • Filterbasis für Echtzeitdaten: Die Ausgänge Haltestellen, Linien und Fahrten können direkt an den GTFS-RT-Node übergeben werden, der daraus seine Filterlisten lernt.

So funktioniert der Node​

1

Auslösen und Cache prüfen

Eine eingehende Nachricht startet den Lauf. Gibt es einen gültigen Cache, überspringt der Node den Download.

2

Laden

Das ZIP wird per HTTPS in ein temporäres Verzeichnis geladen und mit dem Systemwerkzeug unzip entpackt.

3

Filtern

Jede Haltestelle aus stops.txt wird mit turf gegen die Polygone der konfigurierten Gebiete geprüft.

4

Kürzen

Mit awk und sort werden stop_times.txt, trips.txt und shapes.txt auf die Fahrten reduziert, die an gefilterten Haltestellen halten.

5

Sichern und ausgeben

Die Entitäten werden zeilenweise (JSONL) in einen Cache geschrieben und anschließend über die fünf Ausgänge gesendet.

Ergebnis: Fünf Ausgänge mit Verkehrsunternehmen, Haltestellen, Linien, Fahrten und Haltezeiten für Ihre Gebiete.

Der Node ist triggerbasiert. Beim ersten Auslösen lädt und verarbeitet er den Feed, was bei großen Feeds einige Minuten dauern kann. Danach beantwortet er Auslöser aus dem Cache, bis die Cache-Dauer abgelaufen ist, die Gebiete geändert wurden oder eine Aktualisierung erzwungen wird. Der Cache liegt im temporären Verzeichnis des Betriebssystems unter node-red-gtfs-data/<Node-ID>, überlebt einen Deploy und wird gelöscht, wenn der Node aus dem Flow entfernt wird.

Konfiguration​

Der Bearbeitungsdialog hat drei Registerkarten.

Registerkarte „Allgemein“​

FeldTypStandardBedeutung
NameTextleerAnzeigename des Nodes im Flow.

Registerkarte „Quelle“​

FeldTypStandardBedeutung
GTFS URLTextsiehe untenAdresse des ZIP-Archivs. Nur https://-Adressen werden geladen; Weiterleitungen (HTTP 301/302) werden befolgt.
Aktualisierungsintervall (Std) (refreshInterval)Zahl24Aktualisierungsintervall des Caches in Stunden.
StopTimes-Batch (stopTimesBatchSize)Zahl50000Anzahl der Haltezeiten-Entitäten je Nachricht an Ausgang 5. Die Nachrichten bilden eine Sequenz mit msg.parts.

Standardwerte der URL-Felder:

GTFS URL: https://download.gtfs.de/germany/free/latest.zip

Registerkarte „Gebiete“​

FeldTypStandardBedeutung
SucheSuchfeld mit VorschlägenleerSucht über Nominatim (auf Deutschland eingeschränkt) nach Städten, Gemeinden und Landkreisen. Ein gewählter Treffer wird mit seinem Grenzpolygon in die Liste übernommen.
Gebietsliste und Karte (areas)Liste mit Entfernen-Schaltfläche, Leaflet-KarteleerDie gewählten Gebiete als GeoJSON-Features mit display_name, osm_id, osm_type und place_id. Die Karte zeigt die Polygone. Gespeichert wird die Liste als JSON-Text.

Mindestens ein Gebiet ist Pflicht. Ohne Gebiet verweigert der Node die Verarbeitung, damit nicht versehentlich der komplette Feed für ganz Deutschland erzeugt wird. Eine Änderung der Gebiete macht den Cache ungültig.

Eingang​

Jede Nachricht löst den Lauf aus. Zwei Eigenschaften steuern das Verhalten.

EigenschaftTypBedeutung
msg.payloadbeliebigLöst den Lauf aus. Der Wert "update" erzwingt Download und Neuverarbeitung, auch wenn der Cache noch gültig ist.
msg.actionText"update" erzwingt wie payload eine Aktualisierung und gibt danach alle Ausgänge aus. "agency", "stops", "routes", "trips" oder "stoptimes" geben nur den jeweiligen Ausgang aus. Ohne action werden alle fünf Ausgänge bedient.

Eigenschaften der eingehenden Nachricht werden in die Ausgangsnachrichten übernommen.

Ausgang​

Alle Entitäten tragen eine ID der Form urn:ngsi-ld:Gtfs<Typ>:<ID>; Zeichen außer Buchstaben, Ziffern, _ und - in der GTFS-ID werden durch _ ersetzt. Textwerte werden bereinigt: Umlaute und ß werden umschrieben, Zeichen außerhalb von ASCII als \u-Sequenzen kodiert, die Zeichen ()<>"'=; entfernt. Attribute haben die Form {"value": …}, Zahlen, Wahrheitswerte und Zeitstempel zusätzlich ein type, Verknüpfungen die Form {"type": "Relationship", "object": "urn:…"}. Fehlende Werte erhalten den Text unknown.

Ausgang 1: Agency​

Ein Array von GtfsAgency-Entitäten in einer Nachricht; nur Verkehrsunternehmen, deren Linien im Gebiet verkehren.

[
{
"id": "urn:ngsi-ld:GtfsAgency:example-verkehr",
"type": "GtfsAgency",
"name": {"value": "Beispielverkehr GmbH"},
"page": {"value": "https://www.beispielverkehr.de"},
"timezone": {"value": "Europe/Berlin"},
"source": {"value": "https://download.gtfs.de/germany/free/latest.zip"},
"language": {"value": "de"}
}
]
FeldBedeutung
name, page, timezone, sourceName, Website, Zeitzone des Unternehmens und URL des Feeds.
language, phone, fareUrl, emailNur wenn im Feed vorhanden: Sprache, Telefonnummer, Tarif-Website und E-Mail-Adresse des Unternehmens.

Ausgang 2: Stops​

Ein Array von GtfsStop-Entitäten in einer Nachricht: alle Haltestellen in den Gebieten sowie deren übergeordnete Stationen.

[
{
"id": "urn:ngsi-ld:GtfsStop:de_07312_1001",
"type": "GtfsStop",
"code": {"value": "unknown"},
"name": {"value": "Beispielstadt Hauptbahnhof"},
"location": {"value": {"type": "Point", "coordinates": [7.7640, 49.4360]}},
"wheelchairBoarding": {"value": true},
"stopType": {"value": "Stop"},
"parentStationName": {"value": "Beispielstadt Hbf"},
"routeCount": {"value": 12, "type": "Number"},
"hubCategory": {"value": "Major Interchange"},
"servedByRoutes": {"value": [{"id": "de:vrn:12-345", "shortName": "105", "type": "Bus"}]}
}
]
FeldBedeutung
code, name, description, pageHaltestellencode, Name, optionale Beschreibung und Website.
locationGeoJSON-Punkt [Länge, Breite], nur bei gültigen Koordinaten.
wheelchairBoardingtrue, false oder unknown aus wheelchair_boarding.
stopTypeStop, Station oder Entrance aus location_type.
parentStationNameName der übergeordneten Station, falls vorhanden.
routeCount, hubCategoryAnzahl der bedienenden Linien und daraus abgeleitete Einstufung: ab 10 Linien „Major Interchange“, ab 3 „Hub“, sonst „Local Stop“.
servedByRoutesListe der bedienenden Linien mit ID, Kurzname und Verkehrsmittel (Tram, Subway, Rail, Bus, Ferry, …).

Ausgang 3: Routes​

Ein Array von GtfsRoute-Entitäten in einer Nachricht.

[
{
"id": "urn:ngsi-ld:GtfsRoute:de_vrn_12-345",
"type": "GtfsRoute",
"shortName": {"value": "105"},
"name": {"value": "Hauptbahnhof - Universitaet"},
"routeType": {"value": "3"},
"routeColor": {"value": "#E2001A"},
"operatedBy": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsAgency:example-verkehr"}
}
]
FeldBedeutung
shortName, name, description, pageLiniennummer, Linienname, optionale Beschreibung und Website.
routeTypeGTFS-Verkehrsmittelcode als Text (0 Tram, 1 U-Bahn, 2 Bahn, 3 Bus, 4 Fähre, …).
routeColor, routeTextColorLinienfarben als Hex-Wert mit #, falls im Feed vorhanden.
operatedByVerknüpfung zum Verkehrsunternehmen.

Ausgang 4: Trips​

GtfsTrip-Entitäten als Sequenz von Nachrichten mit msg.parts (id, index, type: "array", auf der letzten Nachricht zusätzlich count), standardmäßig 50000 Fahrten je Nachricht.

[
{
"id": "urn:ngsi-ld:GtfsTrip:de_vrn_12-345_67",
"type": "GtfsTrip",
"headSign": {"value": "Universitaet"},
"shortName": {"value": "unknown"},
"direction": {"value": 0, "type": "Number"},
"block": {"value": "unknown"},
"wheelchairAccessible": {"value": true},
"hasRoute": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsRoute:de_vrn_12-345"},
"hasService": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsService:T0-1"},
"hasShape": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsShape:12-345-H"},
"totalDuration": {"value": 24, "type": "Number"},
"startStopName": {"value": "Beispielstadt Hauptbahnhof"},
"endStopName": {"value": "Universitaet"},
"routeShortName": {"value": "105"},
"routeLongName": {"value": "Hauptbahnhof - Universitaet"},
"routeType": {"value": "Bus"},
"agencyName": {"value": "Beispielverkehr GmbH"},
"serviceDays": {"value": "MoTuWeThFr...."},
"validFrom": {"value": "2026-06-15T00:00:00Z", "type": "DateTime"},
"validTo": {"value": "2026-12-12T00:00:00Z", "type": "DateTime"}
}
]
FeldBedeutung
headSign, shortName, direction, block, wheelchairAccessibleFahrtziel, Kurzname, Richtung (0 oder 1), Umlaufblock und Barrierefreiheit aus trips.txt.
hasRoute, hasService, hasShapeVerknüpfungen zu Linie, Verkehrstagen und Linienverlauf.
totalDurationFahrtdauer in Minuten vom ersten bis zum letzten Halt im Gebiet. Bei nur einem Halt im Gebiet oder negativer Dauer unknown und zusätzlich isPartial: true.
startStopName, endStopNameNamen des ersten und letzten Halts innerhalb der Gebiete.
routeShortName, routeLongName, routeType, agencyNameAngaben der zugehörigen Linie und des Unternehmens; routeType hier als Name (Bus, Tram, …).
serviceDays, validFrom, validToVerkehrstage als Kürzelkette (Mo, Tu, … oder ..) und Gültigkeitszeitraum aus calendar.txt.

Ausgang 5: StopTimes​

GtfsStopTime-Entitäten als Sequenz von Nachrichten mit msg.parts, Batch-Größe nach Konfiguration.

[
{
"id": "urn:ngsi-ld:GtfsStopTime:de_vrn_12-345_67_5",
"type": "GtfsStopTime",
"hasTrip": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsTrip:de_vrn_12-345_67"},
"hasStop": {"type": "Relationship", "object": "urn:ngsi-ld:GtfsStop:de_07312_1001"},
"arrivalTime": {"value": "08:17:00"},
"departureTime": {"value": "08:18:00"},
"stopSequence": {"value": 5, "type": "Number"}
}
]
FeldBedeutung
hasTrip, hasStopVerknüpfungen zu Fahrt und Haltestelle; bei flexiblen Angeboten auch hasLocationGroup, hasLocation, hasPickupBookingRule, hasDropOffBookingRule.
arrivalTime, departureTimeAnkunfts- und Abfahrtszeit als Text HH:MM:SS; Werte über 24:00:00 bezeichnen den Folgetag.
stopSequenceReihenfolge des Halts innerhalb der Fahrt.
stopHeadsign, pickupType, dropOffType, shapeDistTraveled, timepoint, continuousPickup, continuousDropOff, startPickupDropOffWindow, endPickupDropOffWindowNur wenn vorhanden und ungleich dem GTFS-Standardwert.

Beispiel-Flow​

Das Paket bringt einen Beispiel-Flow mit. Sie importieren ihn in Node-RED über Menü → Importieren → Beispiele → @htag/node-red-contrib-hypertegrity-urbanmobility → gtfs-data. Alternativ laden Sie die Datei gtfs-data.json herunter und importieren sie über Menü → Importieren. Der Beispiel-Flow enthält das vollständige Grenzpolygon der Stadt Kaiserslautern; in der Kurzfassung unten ist es durch einen Platzhalter ersetzt.

Schritt 1

Inject

Ein Inject-Node löst den Lauf täglich um 01:00 Uhr aus (Cron 00 01 * * *).

Schritt 2

GTFS

Der Node lädt den Deutschland-Feed von gtfs.de und filtert ihn auf das Stadtgebiet Kaiserslautern.

Schritt 3

Fünf Debug-Nodes

Je ein Debug-Node zeigt Agency, Stops, Routes, Trips und StopTimes in der Seitenleiste an.

Beispiel-Flow als JSON anzeigen
[
{"id": "tab1", "type": "tab", "label": "Gtfs-data", "disabled": false, "info": ""},
{"id": "inject1", "type": "inject", "z": "tab1", "name": "01:00 daily", "props": [{"p": "payload"}], "repeat": "", "crontab": "00 01 * * *", "once": false, "onceDelay": "30", "topic": "", "payload": "", "payloadType": "date", "x": 130, "y": 200, "wires": [["gtfs1"]]},
{"id": "gtfs1", "type": "gtfs-data", "z": "tab1", "name": "gtfs.de", "url": "https://download.gtfs.de/germany/free/latest.zip", "refreshInterval": "23", "stopTimesBatchSize": 50000, "areas": "[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[\"<POLYGON-KOORDINATEN>\"]]},\"properties\":{\"display_name\":\"Kaiserslautern, Rheinland-Pfalz, Deutschland\",\"osm_id\":62652,\"osm_type\":\"relation\"}}]", "x": 350, "y": 200, "wires": [["debug1"], ["debug2"], ["debug3"], ["debug4"], ["debug5"]]},
{"id": "debug1", "type": "debug", "z": "tab1", "name": "Agency", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 540, "y": 120, "wires": []},
{"id": "debug2", "type": "debug", "z": "tab1", "name": "Stops", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 530, "y": 160, "wires": []},
{"id": "debug3", "type": "debug", "z": "tab1", "name": "Routes", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 540, "y": 200, "wires": []},
{"id": "debug4", "type": "debug", "z": "tab1", "name": "Trips", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 530, "y": 240, "wires": []},
{"id": "debug5", "type": "debug", "z": "tab1", "name": "StopTimes", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 550, "y": 280, "wires": []}
]

Status und Fehler​

AnzeigeBedeutung
Blauer Punkt „Herunterladen...“Das ZIP-Archiv wird geladen.
Gelber Ring „Entpacken...“Das Archiv wird mit unzip entpackt.
Gelber Punkt „Pass 1: Geographic Stop Filtering...“ bis „Pass 5: Writing Cache...“Die fünf Verarbeitungsdurchläufe: Haltestellen filtern, Vorfilterung mit awk, Metadaten laden, Linien abschließen, Cache schreiben.
Grüner Punkt „Bereit: 412 Haltestellen“Die Verarbeitung ist abgeschlossen; die Zahl nennt die Haltestellen im Gebiet.
Roter Ring „Fehler“Download, Entpacken oder Verarbeitung sind fehlgeschlagen, zum Beispiel „Status 404“, „Unzip failed: …“ oder „Missing required column (stop_id/trip_id/stop_sequence) in stop_times.txt or trips.txt“.
Roter Ring „No areas configured“Es ist kein Gebiet konfiguriert. Fehlermeldung: „No areas configured. Please configure at least one geographic area to prevent downloading data for entire Germany.“
Warnung „Updating GTFS data...“ oder „Cache expired (older than 24 hours). Updating GTFS data...“Ein neuer Download beginnt, weil kein Cache vorhanden ist, er abgelaufen ist oder eine Aktualisierung erzwungen wurde.
Warnung „Areas configuration has changed. Cache will be invalidated.“Die Gebiete wurden geändert; der Cache wird neu aufgebaut.
Warnung „GTFS data is already processing, please wait...“ oder „Still processing...“Ein Lauf ist noch aktiv; der Auslöser wird verworfen.
Fehler „No data available.“ oder „Cache read failed: …“Es gibt keinen Cache oder er ist nicht lesbar.

Fehler werden über node.error gemeldet und können mit einem Catch-Node abgefangen werden.

Hinweise​

  • Systemvoraussetzungen: Der Node ruft die Kommandozeilenwerkzeuge unzip, awk, sort, head, tail und rm auf. Er läuft daher nur auf Linux- oder Unix-Systemen (auch in Containern), auf denen diese Werkzeuge installiert sind.
  • Speicherplatz und Laufzeit: Der deutschlandweite Feed von gtfs.de ist komprimiert mehrere hundert Megabyte groß; entpackt und während der Verarbeitung werden mehrere Gigabyte im temporären Verzeichnis benötigt. Planen Sie die Aktualisierung in verkehrsarme Zeiten, zum Beispiel nachts.
  • Große Nachrichten: Fahrten und Haltezeiten werden in Batches mit msg.parts gesendet. Verwenden Sie bei Debug-Nodes die Option „Nachrichtenzähler“ oder begrenzen Sie die Ausgabe; die vollständige Anzeige großer Arrays kann den Browser überlasten.
  • Lizenz der Daten: Der Feed von gtfs.de steht unter den dort genannten Bedingungen (DELFI-Daten, Creative Commons mit Namensnennung). Andere Feeds haben eigene Lizenzen.
  • Personenbezogene Daten: GTFS-Fahrplandaten enthalten keine personenbezogenen Daten. agency.txt kann Telefonnummer und E-Mail-Adresse des Verkehrsunternehmens enthalten; das sind in der Regel Unternehmenskontakte.
  • Zeitangaben: Haltezeiten sind lokale Zeiten in der Zeitzone des Verkehrsunternehmens; Gültigkeitsdaten werden als YYYY-MM-DDT00:00:00Z ausgegeben.

Weiterführende Themen​

Referenzen​