Zum Inhalt springen
RailFX Zugzielanzeiger ESP32 Live

RailFX: Arduino Zugzielanzeiger mit Live-Daten der Deutschen Bahn

    RailFX: Arduino Zugzielanzeiger – Dieses Modul des RailFX-Systems zeigt Live-Daten eines einstellbaren Bahnhofes auf OLED-Displays als Zielzuganzeiger dar. Es bezieht die Daten per Wi-Fi von der API der Deutschen Bahn und rechnet die Dauer bis zur Abfahrt aus. Bei einer API (Application Programming Interface) handelt es sich um eine Programmierschnittstelle, über die wir Daten der Bahn empfangen können.

    Eines vorweg: Dieses Modul ist nur durch die Vorarbeit von Arduino Hannover und der leicht zugänglichen API der Deutschen Bahn möglich geworden. Die Idee hab ich von Klaus zugeschickt bekommen – danke dafür :-)

    Im Gegensatz zu den meisten anderen Modulen des RailFX-Systems basiert dieses auf dem ESP32-NodeMCU. Es verfügt über Wi-Fi und lässt sich über die Arduino-IDE wie ein normales Arduino programmieren. Ein weiterer Unterschied besteht darin, dass wir keine Verbindung zum Control-Modul benötigen. Dieses stellt normalerweise die Synchronisation aller Module sicher, indem es ein Modellbau-Zeitsignal sendet. Da wir für dieses Projekt aber die »echte« Uhrzeit verwenden, ist dieses Signal hier unnötig.


    Sieh dir jetzt meinen neuen Arduino-Videokurs an: Jetzt ansehen!


    Sehen wir uns aber zuerst den elektronischen Aufbau an.

    Schaltplan

    RailFX Zugzielanzeiger ESP32 Arduino Schaltplan Schaltbild Schaltung

    Das RailFX Zugzielanzeiger-Modul verwendet bis zu acht 0,91 Zoll OLED Displays. Sie werden per I2C-Schnittstelle angesprochen. Da sie aber leider alle die gleiche feste I2C-Adresse haben, müssen wir einen I2C-Multiplexer (TCA9548A) verwenden, der die I2C-Daten auf die jeweiligen Displays verteilt. Die I2C-Pins des NodeMCUs sind an den Eingangspins des Multiplexers angeschlossen. Dieser hat acht Kanäle mit jeweils zwei Anschlüssen für I2C-Geräte (SD0, SC0 – SD7, SC7). Hier sind die Displays verbunden. Darüber hinaus werden sowohl die Displays, als auch der Multiplexer über den GND und den 3.3V-Pin des NodeMCUs versorgt.

    Der Aufbau auf dem Breadboard stelle eine kleine Herausforderung dar, weil das NodeMCU mit ESP32 nicht auf ein normales Breadboard passt. Breadboards lassen sich aber in der Regel zerlegen und so habe ich von einem eine der seitlichen Verteilungen entfernt (muss man unten das Klebepad einschneiden) und mit einem anderen Breadboard zusammengesteckt.

    Bauteile

    Natürlich kann man das ganze auch mit anderen Bauteilen umsetzen, aber das bedarf wahrscheinlich größerer Änderungen im Code.

    RailFX Zugzielanzeiger ESP32 Arduino IDE Ansicht von oben

    Vorbereitung

    Dieses Projekt ist nicht ganz trivial, da man einiges an Vorbereitungen treffen muss. Also legen wir Schritt für Schritt los.

    1. Installation des ESP32-Boards in der Arduino-IDE

    Als Erstes müssen wir das ESP32 zur Arduino-IDE hinzufügen. Öffne die Arduino-Software und klicke im Hauptmenü auf Arduino>Voreinstellungen. Trage in die Zeile zusätzliche Boardverwalter-URLs folgendes ein:

    https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json
    RailFX Zugzielanzeiger ESP32 Arduino IDE Boardverwalter URLs hinzufügen

    Bestätige mit OK und starte die Arduino-Software neu.

    Klicke jetzt im Arduino-Menü auf Werkzeuge>Board>Boardverwalter und gib im Suchfeld »esp32« ein. Installiere die Board-Software von Expressif-Systems in der aktuellen Version.

    RailFX Zugzielanzeiger ESP32 Arduino IDE Boardverwalter von Expressif hinzufügen

    Starte die Arduino-Software noch einmal neu.

    2. Installation der SSD1306Ascii-Bibliothek

    Nun müssen wir ein paar Libraries installieren. Gehe dafür im Arduino-Menü auf Sketch>Bibliotheken einbinden>Bibliotheken verwalten und suche nach »SSD1306Ascii« und installiere die aktuelle Version.

    RailFX Zugzielanzeiger ESP32 Arduino IDE SSD1306 Ascii Bibliothek

    3. Installation der DBAPI-Bibliothek

    Um die Bibliothek für die Deutsche Bahn API einzubinden, gehe auf die folgende Website: https://github.com/ArduinoHannover/DBAPI, klicke auf die grüne Code-Schaltfläche und wähle Download Zip.

    RailFX Zugzielanzeiger ESP32 Arduino IDE Deutsche Bahn API Bibliothek hinzufügen DB

    Nun wird die Bibliothek heruntergeladen. Entpacke sie und benenne den Ordner von DBAPI-master in DBAPI um. Kopiere den ganzen Ordner in deinen Arduino-Sketchbook-Library-Ordner (z.B. C:\<Benutzername>\Arduino\libraries). Starte die Arduino-Software neu.

    4. Board auswählen

    Wähle nun im Arduino-Menü unter Werkzeuge>Board den Eintrag ESP32 Dev-Module aus. Unter Werkzeuge>Port muss nun noch die Verbindung ausgewählt werden. Bei mir ist das /dev/cu.usbserial-0001.

    5. Neuen Sketch anlegen und einrichten

    Kopiere den Programmtext aus dem Codefenster in einen neuen Sketch und passe den WiFi-Namen und das WiFi-Passwort an.

    const char* ssid = "Wifi-Name";               // WiFi-Name
    const char* password = "Wifi-Passwort";       // WiFi-Passwort

    Jetzt kannst du das Programm auf das NodeMCU-Board übertragen.

    Starte den seriellen Monitor (Baud-Rate 115200). Wenn alles geklappt hat, sollte der Sketch starten und es sollten Zugdaten auf den Zugzielanzeigern erscheinen. Bis die korrekten Zeiten angezeigt werden, kann es 30 Sekunden dauern.

    Programm-Code – RailFX: Arduino Zugzielanzeiger

    Hier ist erstmal der gesamte Programm-Text. Erklärungen und Einstellungen erkläre ich weiter unten.

    #include <WiFi.h>                             // WiFi-Funktionalität
    #include <Wire.h>                             // I2C-Funktionalität
    #include "SSD1306Ascii.h"                     // OLED-Display (Adafruit GFX)
    #include "SSD1306AsciiWire.h"                 // OLED-Display (I2C)
    #include <DBAPI.h>                            // Schnittstelle zur Deutschen Bahn API
    
    /*
        Rail-FX Live-Zugzielanzeiger der Deutschen Bahn
        StartHardware.org
    */
    
    /* ***** Einstellungen ***** */
    const char* ssid            = "wifi-name";       // WiFi-Name
    const char* password        = "wifi-password";    // WiFi-Passwort
    const char* bahnhofsName    = "Berlin Hbf";   // Beispielstation (Liste z. B. unter https://data.deutschebahn.com/dataset/data-haltestellen.html)
    String removeString1        = "Berlin ";      // Zu entfernender String
    String removeString2        = "Berlin-";      // Zu entfernender String
    int showPlatform[8]         = {15, 16, 1, 2, 5, 6, 7, 8}; // Display-Gleis-Zuordnung
    
    long anzeigeTimeout         = 10000;          // Anzeigewechselintervall (ms)
    int apiCallTimeout          = 20000;          // Pause zwischen API-Abfragen (ms)
    int maxPlatforms            = 20;
    
    /* ***** Globale Objekte und Variablen ***** */
    DBAPI db;                                      // DB API Objekt
    #define I2C_ADDRESS 0x3C                       // OLED I2C Adresse
    
    String theDates[250];       // Datum-Strings (Format: TT.MM.JJJJ)
    String theTimes[250];       // Uhrzeit-Strings (Format: HH:MM)
    String theProducts[250];    // Zugtyp (z. B. ICE)
    String theTargets[250];     // Zielhaltestelle
    String thePlatforms[250];   // Gleisnummer als String
    String theTextdelays[250];  // Verspätung als Text
    int myIndex = 0;            // Anzahl der erfassten Einträge
    
    const char* ntpServer       = "pool.ntp.org"; // NTP-Server
    const long  gmtOffset_sec   = 3600;           // Zeitzonenoffset (CET)
    const int   daylightOffset_sec = 0;           // Sommerzeit-Offset
    
    // Aktuelle Zeitvariablen
    int myDay, myMonth, myYear, myHour, myMinute;
    
    // Timer Variablen
    long anzeigeTimer = 0;
    long apiCallTime  = 0;
    
    // OLED Objekt
    SSD1306AsciiWire oled;
    
    /* Funktionsprototypen */
    void TCA9548A(uint8_t bus);
    void drawTest(uint8_t displayNr);
    void drawInfo(uint8_t displayNr, int platformToDisplay);
    void anzeigeTafel();
    void getLocalTime();
    int theTimeDifference(String theDepartureTime, String theDepartureDate);
    void callDBApi();
    
    void setup() {
      Wire.begin();
      Wire.setClock(400000L);
      
      // Initialisiere alle 8 Displays (falls alle angeschlossen sind)
      for (int i = 0; i < 8; i++) {
        TCA9548A(i);
        oled.begin(&Adafruit128x32, I2C_ADDRESS);
      }
    
      Serial.begin(115200);
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        Serial.write('.');
        delay(500);
      }
    
      // Führe einen kurzen Test auf einigen Displays durch
      for (int i = 0; i < 4; i++) {
        drawTest(i);
      }
    
      // Abfrage der Bahnhofsdaten
      DBstation* station = db.getStation(bahnhofsName);
      if (station != NULL) {
        Serial.println();
        Serial.print("Name:      ");
        Serial.println(station->name);
        Serial.print("ID:        ");
        Serial.println(station->stationId);
        Serial.print("Latitude:  ");
        Serial.println(station->latitude);
        Serial.print("Longitude: ");
        Serial.println(station->longitude);
      }
      
      callDBApi();
      anzeigeTimer = millis() - anzeigeTimeout; // sofortige erste Aktualisierung der Anzeige
    }
    
    void loop() {
      if (apiCallTime + apiCallTimeout < millis()) {
        configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
        getLocalTime();
        callDBApi();
        apiCallTime = millis();
      }
      anzeigeTafel();
    }
    
    /* ===== Anzeige-Funktionen ===== */
    void anzeigeTafel() {
      if (anzeigeTimer + anzeigeTimeout < millis()) {
        anzeigeTimer = millis();
        // Aktualisiere alle 8 Displays (Index 0 bis 7)
        for (int i = 0; i < 8; i++) {
          drawInfo(i, showPlatform[i]);
        }
      }
    }
    
    void drawInfo(uint8_t displayNr, int platformToDisplay) {
      Serial.print("Draw: ");
      Serial.println(displayNr);
      TCA9548A(displayNr);
      
      // Ermittle bis zu 4 Einträge, die diesem Gleis zugeordnet sind
      int theEntryIndexes[4] = {-1, -1, -1, -1};
      int idx = 0;
      for (int j = 0; j < myIndex && idx < 4; j++) {
        if (thePlatforms[j].toInt() == platformToDisplay) {
          theEntryIndexes[idx++] = j;
          Serial.print(displayNr);
          Serial.print(" <- Display \t ");
          Serial.print(j);
          Serial.print(" <- Index \t ");
          Serial.println(thePlatforms[j].toInt());
        }
      }
    
      oled.clear();
      oled.setFont(Adafruit5x7);
      for (int i = 0; i < 4; i++) {
        if (theEntryIndexes[i] != -1) {
          oled.setCursor(0, i);
          oled.println(theTimeDifference(theTimes[theEntryIndexes[i]], theDates[theEntryIndexes[i]]));
          oled.setCursor(20, i);
          oled.println(theTargets[theEntryIndexes[i]]);
        }
      }
      delay(100);
    }
    
    void drawTest(uint8_t displayNr) {
      Serial.print("DrawTest: ");
      Serial.println(displayNr);
      TCA9548A(displayNr);
      oled.clear();
      oled.setFont(Adafruit5x7);
      // Zeige Test-Text an
      oled.setCursor(0, 0); oled.println("RailFX");
      oled.setCursor(0, 1); oled.println("RailFX");
      oled.setCursor(0, 2); oled.println("RailFX");
      oled.setCursor(0, 3); oled.println("RailFX");
      oled.setCursor(30, 0); oled.println("StartHardware");
      oled.setCursor(30, 1); oled.println("StartHardware");
      oled.setCursor(30, 2); oled.println("StartHardware");
      oled.setCursor(30, 3); oled.println("StartHardware");
    }
    
    /* ===== I2C-Multiplexer ===== */
    void TCA9548A(uint8_t bus) {
      if (bus > 7) return;
      Wire.beginTransmission(0x70);
      Wire.write(1 << bus);
      Wire.endTransmission();
    }
    
    /* ===== Zeitfunktionen ===== */
    void getLocalTime() {
      time_t nowTime = time(nullptr);
      struct tm *tm_struct = localtime(&nowTime);
      myDay    = tm_struct->tm_mday;
      myMonth  = tm_struct->tm_mon + 1;
      myYear   = tm_struct->tm_year + 1900;
      myHour   = tm_struct->tm_hour;
      myMinute = tm_struct->tm_min;
    }
    
    // Gibt die Differenz in Minuten zwischen Abfahrtszeit und aktueller Zeit zurück
    int theTimeDifference(String theDepartureTime, String theDepartureDate) {
      int depHour, depMinute, depDay, depMonth, depYear;
      // Lese Abfahrtszeit und Datum aus den Strings
      sscanf(theDepartureTime.c_str(), "%d:%d", &depHour, &depMinute);
      sscanf(theDepartureDate.c_str(), "%d.%d.%d", &depDay, &depMonth, &depYear);
    
      // Debug-Ausgaben für die Eingangsdaten und die geparsten Werte
      Serial.print("DEBUG: theDepartureTime = ");
      Serial.println(theDepartureTime);
      Serial.print("DEBUG: theDepartureDate = ");
      Serial.println(theDepartureDate);
      Serial.print("DEBUG: Parsed departure time = ");
      Serial.print(depHour);
      Serial.print(":");
      Serial.println(depMinute);
      Serial.print("DEBUG: Parsed departure date = ");
      Serial.print(depDay);
      Serial.print(".");
      Serial.print(depMonth);
      Serial.print(".");
      Serial.println(depYear);
    
      // Bestimme, ob die Abfahrt morgen ist
      bool departureTomorrow = (depYear > myYear) ||
                               (depYear == myYear && depMonth > myMonth) ||
                               (depYear == myYear && depMonth == myMonth && depDay > myDay);
    
      // Berechne die aktuelle Zeit in Minuten
      int currentMinutes = myHour * 60 + myMinute;
      // Berechne die Abfahrtszeit in Minuten
      int departureMinutes = depHour * 60 + depMinute;
    
      if (departureTomorrow) {
        Serial.println("DEBUG: Departure is tomorrow, adding 24*60 minutes");
        departureMinutes += 24 * 60;
      }
    
      int diff = departureMinutes - currentMinutes;
      Serial.print("DEBUG: Final departureMinutes = ");
      Serial.println(departureMinutes);
      Serial.print("DEBUG: Time difference = ");
      Serial.println(diff);
    
      return diff;
    }
    
    /* ===== API-Aufruf ===== */
    void callDBApi() {
      Serial.println("Call DB API");
      DBstation* station = db.getStation(bahnhofsName);
      myIndex = 0;
      // Abrufen der Abfahrtsdaten (mit 40 Ergebnissen, 1 Stunde Dauer, gewünschte Verkehrsmittel)
      DBdeparr* da = db.getDepartures(station->stationId, NULL, NULL, 20, 1,
                                        PROD_ICE | PROD_IC_EC | PROD_IR | PROD_RE | PROD_S);
      
      while (da != NULL && myIndex < 250) {
        yield();
        
        // Konvertiere den time_t-Wert in Datum und Uhrzeit als String
        char dateBuffer[20];
        char timeBuffer[10];
        //struct tm *tm_info = localtime(&da->time);
        struct tm *tm_info = gmtime(&da->time);
        strftime(dateBuffer, sizeof(dateBuffer), "%d.%m.%Y", tm_info);
        strftime(timeBuffer, sizeof(timeBuffer), "%H:%M", tm_info);
    
        theDates[myIndex]    = String(dateBuffer);
        theTimes[myIndex]    = String(timeBuffer);
        theProducts[myIndex] = String(da->product);
        theTargets[myIndex]  = String(da->target);
        thePlatforms[myIndex]= String(da->platform);
        theTextdelays[myIndex] = String(da->delay)+ " min";
        
        da = da->next;
        myIndex++;
      }
    
      // Ausgabe der abgerufenen Daten über Serial
      for (int platform = 0; platform < maxPlatforms; platform++) {
        for (int i = 0; i < myIndex; i++) {
          if (thePlatforms[i].toInt() == platform) {
            Serial.print(i); Serial.print("\t");
            Serial.print(theTimes[i]); Serial.print("\t");
            Serial.print(theProducts[i]); Serial.print("\t");
            Serial.print(thePlatforms[i]); Serial.print("\t");
            Serial.print(theTextdelays[i]); Serial.print("\t");
            // Entferne überflüssige Zeichen aus dem Zielnamen
            String targetClean = theTargets[i];
            targetClean.replace(removeString1, "");
            targetClean.replace(removeString2, "");
            Serial.println(targetClean);
          }
        }
      }
      Serial.println("\n\n");
    }
    

    Wenn das Programm erstmal läuft, hast du die schwierigsten Schritte hinter dir. Herzlichen Glückwunsch! Jetzt gucken wir uns an, was wir im Code einstellen können.

    Einstellungen im Code

    Im Code muss man erstmal die WiFi-Einstellungen treffen. Das haben wir ja schon weiter oben angesehen.

    Des Weiteren kann man sich nun einen Bahnhof aussuchen, von dem man die Zugzieldaten anzeigen möchte. Im Beispiel habe ich »Berlin Hbf« gewählt, aber die API der Deutschen Bahn bietet eine Übersicht mit allen Bahnhöfen an.

    Da in Berlin viele Ziele mit Berlin oder Berlin- anfangen, habe ich zwei Variablen eingefügt, mit denen eben diese Wörter aus dem Ziel entfernt werden können. Aus »Berlin-Wannsee« wird also z.B. »Wannsee«.

    Über die Variable showPlatform kann man nun entscheiden, welche Bahnsteige auf den OLED-Displays angezeigt werden sollen. OLED1 zeigt in meinem Fall Gleis 15 an. Natürlich kann man auf mehreren OLEDs das gleiche Gleis anzeigen lassen, falls man z.B. zwei Zugzielanzeiger auf einem Bahnsteig hat.

    Über anzeigeTimeout kann man einstellen, wie oft die Displays aktualisiert werden. Die Zeit wird in Millisekunden angegeben.

    Die Variable apiCallTimeout gibt an, wie groß der Abstand zwischen den Aufrufen der API sein soll, also wie oft neue Daten abgefragt werden sollen.

    Die Variable maxPlatforms gibt an, wie viele Bahnsteige es höchstens gibt. Normalerweise sollte man sie nicht ändern müssen.

    /* ***** Einstellungen ***** */
    const char* ssid            = "wifi-name";       // WiFi-Name
    const char* password        = "wifi-password";    // WiFi-Passwort
    const char* bahnhofsName    = "Berlin Hbf";   // Beispielstation (Liste z. B. unter https://data.deutschebahn.com/dataset/data-haltestellen.html)
    String removeString1        = "Berlin ";      // Zu entfernender String
    String removeString2        = "Berlin-";      // Zu entfernender String
    int showPlatform[8]         = {15, 16, 1, 2, 5, 6, 7, 8}; // Display-Gleis-Zuordnung
    
    long anzeigeTimeout         = 10000;          // Anzeigewechselintervall (ms)
    int apiCallTimeout          = 20000;          // Pause zwischen API-Abfragen (ms)
    int maxPlatforms            = 20;

    Noch ein Hinweis zum Code: Hier gibt es mit Sicherheit noch einiges an Optimierungspotential. Ich bin für Vorschläge offen :-)

    Troubleshooting

    Ich hab jetzt den Code geupdatet und hatte arge Probleme, ihn auf das ESP32 zu laden. Fehler:
    A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header

    Nach längerer Suche lag es daran, dass das USB-Kabel an einem USB-Hub war. Hab es direkt in den Computer gesteckt und die Boot-Taste am ESP gedrückt, als die Meldung Connecting… aufgetaucht ist, dann ging es :-)

    -> Die alte Version ist hier auf Github zu finden.


    Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!

    • Die beliebtesten Arduino-Projekte von StartHardware
    • Inklusive Schaltplan, Beschreibung und Code
    • Arduino-Schnellstart-Kapitel
    • Kompakter Programmierkurs


    0 0 votes
    Article Rating
    Abonnieren
    Benachrichtige mich bei

    Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..

    20 Comments
    Newest
    Oldest Most Voted
    Inline Feedbacks
    Alle Kommentare anzeigen
    juergen
    2 Monate zuvor

    hi,
    aktuell scheint der Wurm drin.
    aus getDepatures kann ich Departures machen
    in der dbapi.h kann ich times_t date einfügen
    bleibt aber die weiteren Fehler
    Kann jemand helfen?
    Oder mache ich was falsch?
    Danke
    F:\util\ptools\arduino\zug\zug.ino: In function ‚void callDBApi()‘:
    F:\util\ptools\arduino\zug\zug.ino:211:21: error: ‚class DBAPI‘ has no member named ‚getDepatures‘; did you mean ‚getDepartures‘?
    211 | DBdeparr* da = db.getDepatures(station->stationId, NULL, NULL, NULL, 0, PROD_ICE | PROD_IC_EC | PROD_IR | PROD_RE | PROD_S);
    | ^~~~~~~~~~~~
    | getDepartures
    F:\util\ptools\arduino\zug\zug.ino:215:29: error: ’struct DBdeparr‘ has no member named ‚date‘
    215 | theDates[myIndex] = da->date;
    | ^~~~
    F:\util\ptools\arduino\zug\zug.ino:216:29: error: invalid conversion from ‚time_t‘ {aka ‚long long int‘} to ‚char*‘ [-fpermissive]
    216 | theTimes[myIndex] = da->time;
    | ~~~~^~~~
    | |
    | time_t {aka long long int}
    F:\util\ptools\arduino\zug\zug.ino:220:34: error: ’struct DBdeparr‘ has no member named ‚textdelay‘
    220 | theTextdelays[myIndex] = da->textdelay;
    | ^~~~~~~~~

    exit status 1

    Compilation error: ‚class DBAPI‘ has no member named ‚getDepatures‘; did you mean ‚getDepartures‘?

    juergen
    Antworte an  Stefan Hermann
    1 Monat zuvor

    hi,
    zumindest klappts bei mir jetzt auch mit Deinem Beispielen und ohne Kompilerfehler.
    Muss mich jetzt mal durch die Stringformatierung kämpfen, damit es für mich passend wird.
    Dankeschön

    AndreasG
    2 Monate zuvor

    Hallo,
    bis zur Beurteilung, ob die DBAPI funktioniert, komme ich leider gar nicht, DBAPI.h et. al. sind übrigens installiert.
    Hier in Ihrer Zeile 211 stolpert meine Arduino IDE (Version 2.3.4) leider über „getDepatures“. Compilation error: ‚class DBAPI‘ has no member named ‚getDepatures‘; did you mean ‚getDepartures‘?
    Das möglicherweise fehlende „r“ ist schnell ergänzt – ist aber nicht die Ursache.
    Merkwürdigerweise verwendet „Arduino Hannover“ in einem ihrer Test-Beispiele auf Github (DBAPI/examples/HannoverHBF/src
    /HannoverHBF.ino) dieses vermeindlich falsch geschriebene Wort gleich 7-mal (bspw. day(depature->time)), auch hier gibt es Abbrüche.
    Schade, ich wüßte zu gerne, woran das liegt. Hat jemand eine Idee? Offensichlich läuft der Sketch ja bei Anderen.

    Mit freundlichen Grüßen

    Andreas

    Berthold
    4 Monate zuvor

    Hallo
    Habe ein Problem das meine Displays dunkel bleiben.
    Habe die Hartware schon X mal überprüft und auch neu aufgebaut, das Hochladen ist ohne Fehlermeldung gelaufen, im serielen Monitor läuft es einwandfrei.
    Kann es daran liegen das ich nur 4 Displays angeschlosen habe?
    Danke für die schönen Ideen und über eine Antwort würde ich mich freuen.

    Andreas
    Antworte an  Berthold
    3 Monate zuvor

    Hallo
    Finde es schade das die Daten Nicht mehr Funktionieren von der DB Die Schaltung hat gut funktioniert seit par Tagen erscheint nur noch auf den Display Start Hardware Org.
    Wie Bekommt man Die Schaltung Wider zum Laufen .Hat die Bahn die API abfrage Deaktiviert.Würde mich auf eine Antwort freuen.

    Peter Rothenpieler
    Antworte an  Stefan Hermann
    2 Monate zuvor

    Hallo zusammen,

    leider hat die DB den Service: https://reiseauskunft.bahn.de
    eingestellt.
    503 Service Temporarily Unavailable.
    Daher können wir keine Daten empfangen.
    Eine neue API bei der DB kostet mittlerweile Geld wenn man die Infos via JSON empfangen will.
    Mal sehen ob einer eine passende Idee hat.

    Viele Grüße

    Peter

    Uwe Porwich
    10 Monate zuvor

    Hallo Stefan, ich bin grade dabei deine RailFX Module nach zu bauen.
    Bei der Zugzielanzeige scheitere ich grade an der API der Deutschen Bahn.
    Dein Link in diesem Text funkioniert nicht mehr:
    „Des Weiteren kann man sich nun einen Bahnhof aussuchen, von dem man die Zugzieldaten anzeigen möchte. Im Beispiel habe ich »Berlin Hbf« gewählt, aber die API der Deutschen Bahn bietet eine ( Link(Übersicht mit allen Bahnhöfen)) an.“
    Kannst Du mir da bitte weiterhelfen ?

    Gruß Uwe

    Thomas Lay
    1 Jahr zuvor

    Hallo Freunde ,
    Ich bin von diesem Zugzielanzeiger total angetan.Es ist ganz toll.Würde dieses gerne selbst nachbauen um es später bei mir in der Moba zu integrieren.Bis auf den ESP 32,habe ich alles da.Welcher ist der richtige?ASIN: B071P98VTG wird mir bei Amazon angezeigt.Könnte man diesen nehmen?Und eine weitere Frage…,ich möchte gerne im Empfangsgebäude meiner Moba oder außerhalb des Gebäudes an der Grundmauer einen etwas größeren OLED,der mir alle aktualisierten Abfahrtszeiten auf allen Bahnsteigen anzeigt.Zusätzlich deine hier vorgestellte Idee.Ich habe 5 Bahnsteigpontons,das heisst,ich müsste 8 Oled’s /Ponton haben.Pro Bahnsteig 4x 0,91 zoll oled.2 oled Display zusammen,sodass ich von beiden Seiten die Informationen sehen kann.Und jetzt meine Frage,a)Wie setze ich das um?,b)Welche Bauteile benötige ich in welcher Anzahl?
    Ich bedanke mich im voraus schon mal für das Lesen hier und die hierfür zugewendete Zeit.Bin für jeden Tip/Vorschlag dankbar.

    Mfg Thomas

    Martin
    2 Jahre zuvor

    Hallo,
    ich finde das Projekt auch sehr cool und habe mir gleich die passenden Teile organisiert. Da ich noch ein Anfänger bin, hatte ich Probleme, die auf der Seite nicht beschrieben sind.
    Es muss sicherlich noch erwähnt werden, dass für das NodeMCU mit ESP32* erst die Treiber noch installiert werden müssen. Erst dann konnte ich den Sketch hochladen. Leider blieben meine Displays anschließend noch leer. Der I2C Multiplexer muss unbedingt verlötet werden, dann klappt es auch hier.
    Alles in allem bin ich sehr zufrieden.

    Andreas
    2 Jahre zuvor

    Hallo
    Möchte mir diese tolle Schaltung auf meine Modellbahn machen habe alle Komponenten gekauft und nach Schaltplan vertratet. Habe folgendes Proplem das ich mich nicht mit dem ESP32 in Mein internet verbunden werde haben sie mir vieleicht eine deteilierte Anleitung wie ich mich mit dem internet verbinde bin neu auf diesem gebiet.Ich danke ihne schon mal im voraus auf ihre Hilfe.

    Andrea
    Antworte an  Stefan Hermann
    3 Monate zuvor

    Hallo
    Die Schaltung und das Programm hat super geklappt.hab seit dem Wochenende ein Problem das es nur noch start Hardware org im Display anzeigt und keine Daten mehr von der DB bekommt.Ist vielleicht die Abi CoD abgelaufen wie bekomme ich den Code her. Danke schonmal für ihre Antwort.

    Rothenpieler, Peter
    3 Jahre zuvor

    Hi,
    das ist ein Superprojekt und für mich der passende Einstieg.
    Anfangs habe ich mir die Fahrplandaten immer abgetippt, wieder im ESP32 eingelesen und auf einem OLED 0,91 und für die Bahnhofstafel mit einem TFT SPI 1,8″ ausgegeben.
    Jetzt habe ich online Daten.
    Allerdings ist die Verbindung zur API noch nicht stabil genug.
    Öfters bekomme ich keine Daten zur Bahnhofstafel.
    Ich habe den Sketch ein wenig für meine Bedürfnisse passend gemacht.
    Was ich auch noch nicht ganz hinbekomme: Kann man für einen Bahnhof den gesamten Fahrplan einlesen oder geht das wie in Deinem Sketch nur stückweise?

    Auf jeden Fall ist es eine Super Arbeit von Dir .
    Bin sehr begeistert.

    Viele Grüße

    Peter

    20
    0
    Ich würde mich über deine Meinung freuen.x