schnurloses Gleisbildstellwerk

tomy99
Beiträge: 4
Registriert: 20.06.2026, 13:02
Hat sich bedankt: 1 Mal

schnurloses Gleisbildstellwerk

Beitrag von tomy99 » 23.06.2026, 13:17

Hallo,
an genau sowas probiere ich mich auch gerade, mit Hilfe von KI, aber leider bekomme ich keine Verbindung zur Z21 (schwarz)hin.
Wäre es möglich den Code aus dem Video zu bekommen? Perfekt wäre für Adruino IDE.

Ich hatte allerdings für jede LED einen separaten PIN genutzt so brauch man keine NPN / PNP. Aber vielleicht spart man bei deiner Methode ja PINS ein und brauch keine Erweiterung aller MCP23017.

Ich stelle mal meinen Code ein, vielleicht findet ja jemand den Fehler.
Der Webserver ist erstmal ein „nice to have“, und nicht wirklich nötig.

Fehler stecken sicher irgendwo im "Z21 Weichenbefehl senden" (void sendWeiche). Aber wir (KI und ich) haben es an einen ganzen Nachmittag nicht hinbekommen eine Verbindung aufzubauen.

Folgende Funktion sind im Code:

-4 Weichen (Adressen 120–123)
-Entprellung (Taster)
-LED-Update
-Z21-Rückmeldung
-Start-Synchronisation
-Weichenbefehl senden

Loop:

-Z21 Rückmeldungen empfangen
-Taster entprellen
-Weichen schalten
-LEDs aktualisieren

Quelltext:

Code: Alles auswählen

#include <wifi_config.h>		//WLAN Login
#include <WiFi.h>
#include <WiFiUdp.h>
#include <WebServer.h>
#include <EEPROM.h>

IPAddress z21(192,168,0,111);

WiFiUDP udp;
WebServer server(80);

#define EEPROM_SIZE 64

// -----------------------------
// Weichen-Struct
// -----------------------------
struct Weiche {
  uint16_t adresse;      // DCC-Adresse
  uint8_t tasterPin;     // Taster-Pin
  uint8_t ledGerade;     // LED für "gerade"
  uint8_t ledAbzweig;    // LED für "abzweig"

  bool state;            // Weichenstellung (false = gerade)
  bool lastState;        // letzter Rohwert
  bool stableState;      // entprellter Zustand
  unsigned long lastChangeTime;
};

// -----------------------------
// 4 Weichen
// Adresse, Taster, Led1, LED2
// -----------------------------
Weiche weichen[] = {
  { 120, 15, 18, 19, false, HIGH, HIGH, 0 }, 
  { 121, 4, 21, 22, false, HIGH, HIGH, 0 },
  { 122, 13, 23, 25, false, HIGH, HIGH, 0 },
  { 123, 14, 26, 27, false, HIGH, HIGH, 0 }
};

const int anzahlWeichen = sizeof(weichen) / sizeof(weichen[0]);
const unsigned long debounceTime = 50;

// -----------------------------
// LED-Update
// -----------------------------
void updateLEDs(Weiche &w) {
  if (w.state == false) {        // gerade
    digitalWrite(w.ledGerade, HIGH);
    digitalWrite(w.ledAbzweig, LOW);
  } else {                       // abzweig
    digitalWrite(w.ledGerade, LOW);
    digitalWrite(w.ledAbzweig, HIGH);
  }
}

// -----------------------------
// EEPROM: Weichen speichern
// -----------------------------
void saveWeichenToEEPROM() {
  Serial.println("Speichere Weichen in EEPROM...");
  for (int i = 0; i < anzahlWeichen; i++) {
    EEPROM.write(i, weichen[i].state ? 1 : 0);

    Serial.print("  Weiche ");
    Serial.print(weichen[i].adresse);
    Serial.print(" -> ");
    Serial.println(weichen[i].state ? "Abzweig" : "Gerade");
  }
  EEPROM.commit();
}

// -----------------------------
// EEPROM: Weichen laden
// -----------------------------
void loadWeichenFromEEPROM() {
  Serial.println("Lade Weichen aus EEPROM...");
  for (int i = 0; i < anzahlWeichen; i++) {
    uint8_t v = EEPROM.read(i);
    weichen[i].state = (v != 0);
    updateLEDs(weichen[i]);

    Serial.print("  Weiche ");
    Serial.print(weichen[i].adresse);
    Serial.print(" -> ");
    Serial.println(weichen[i].state ? "Abzweig" : "Gerade");
  }
}

// -----------------------------
// Z21 Weichenbefehl senden
// -----------------------------
void sendWeiche(uint16_t addr, bool gerade) {
  uint8_t buf[6];
  buf[0] = 0x04;
  buf[1] = 0x00;
  buf[2] = 0x40;
  buf[3] = 0x00;
  buf[4] = (addr >> 8) & 0xFF;
  buf[5] = (addr & 0xFF) << 1;
  buf[5] |= 0x02;
  if (!gerade) buf[5] |= 0x01;

  udp.beginPacket(z21, 21105);
  udp.write(buf, 6);
  udp.endPacket();

  Serial.print("Z21 SEND: Weiche ");
  Serial.print(addr);
  Serial.print(" -> ");
  Serial.println(gerade ? "Gerade" : "Abzweig");
}

// -----------------------------
// Z21 Rückmeldungen empfangen
// -----------------------------
void empfangeZ21() {
  int packetSize = udp.parsePacket();
  if (packetSize <= 0) return;

  uint8_t buf[20];
  udp.read(buf, packetSize);

  if (buf[2] == 0x40 && buf[3] == 0x00 && packetSize >= 6) {

    uint16_t addr = (buf[4] << 8) | (buf[5] >> 1);
    bool gerade = !(buf[5] & 0x01);

    Serial.print("Z21 RECV: Weiche ");
    Serial.print(addr);
    Serial.print(" -> ");
    Serial.println(gerade ? "Gerade" : "Abzweig");

    for (int i = 0; i < anzahlWeichen; i++) {
      if (weichen[i].adresse == addr) {
        weichen[i].state = !gerade;
        updateLEDs(weichen[i]);
        saveWeichenToEEPROM();
      }
    }
  }
}

// -----------------------------
// Z21 Status beim Start anfordern
// -----------------------------
void requestZ21WeichenStatus() {
  uint8_t buf[5] = {0x05, 0x00, 0x40, 0x00, 0xF0};

  udp.beginPacket(z21, 21105);
  udp.write(buf, 5);
  udp.endPacket();

  Serial.println("Z21: Statusanforderung gesendet.");
}

// -----------------------------
// Webinterface HTML
// -----------------------------
String buildPage() {
  String html = "<html><head><meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<style>body{font-family:sans-serif;}button{width:120px;height:40px;font-size:18px;margin:10px;}</style></head><body>";
  html += "<h2>Weichensteuerung</h2>";

  for (int i = 0; i < anzahlWeichen; i++) {
    html += "Weiche ";
    html += weichen[i].adresse;
    html += ": ";

    html += "<a href='/toggle?i=" + String(i) + "'>";
    html += "<button>";
    html += (weichen[i].state ? "Abzweig" : "Gerade");
    html += "</button></a><br>";
  }

  html += "</body></html>";
  return html;
}

void handleRoot() {
  server.send(200, "text/html", buildPage());
}

void handleToggle() {
  int i = server.arg("i").toInt();

  Serial.print("WEB: Weiche ");
  Serial.print(weichen[i].adresse);
  Serial.println(" getoggelt.");

  weichen[i].state = !weichen[i].state;
  sendWeiche(weichen[i].adresse, !weichen[i].state);
  updateLEDs(weichen[i]);
  saveWeichenToEEPROM();

  server.sendHeader("Location", "/");
  server.send(303);

// -----------------------------
// Setup
// -----------------------------
void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Starte ESP32 Weichensteuerung...");
  Serial.print("Verbinde mit WLAN: ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);

  int counter = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    counter++;
    if (counter % 10 == 0) {
      Serial.print("  (warte ");
      Serial.print(counter / 2);
      Serial.println(" Sekunden)");
    }
  }

  Serial.println();
  Serial.println("WLAN verbunden!");
  Serial.print("IP-Adresse: ");
  Serial.println(WiFi.localIP());
  Serial.println("--------------------------------------");

  udp.begin(21105);

  EEPROM.begin(EEPROM_SIZE);

  for (int i = 0; i < anzahlWeichen; i++) {
    pinMode(weichen[i].tasterPin, INPUT_PULLUP);
    pinMode(weichen[i].ledGerade, OUTPUT);
    pinMode(weichen[i].ledAbzweig, OUTPUT);
  }

  loadWeichenFromEEPROM();

  delay(300);
  requestZ21WeichenStatus();

  server.on("/", handleRoot);
  server.on("/toggle", handleToggle);
  server.begin();
}

// -----------------------------
// Loop
// -----------------------------
void loop() {

  server.handleClient();
  empfangeZ21();  // Z21 Rückmeldungen verarbeiten

  for (int i = 0; i < anzahlWeichen; i++) {

    bool reading = digitalRead(weichen[i].tasterPin);

    if (reading != weichen[i].lastState) {
      weichen[i].lastChangeTime = millis();
      weichen[i].lastState = reading;
    }

    if ((millis() - weichen[i].lastChangeTime) > debounceTime) {

      if (reading != weichen[i].stableState) {
        weichen[i].stableState = reading;

        if (reading == LOW) {
          weichen[i].state = !weichen[i].state;

          Serial.print("TASTER: Weiche ");
          Serial.print(weichen[i].adresse);
          Serial.print(" -> ");
          Serial.println(weichen[i].state ? "Abzweig" : "Gerade");

          sendWeiche(weichen[i].adresse, !weichen[i].state);
          updateLEDs(weichen[i]);
          saveWeichenToEEPROM();
        }
      }
    }
  }
}
Gruß Tom

Norbert
Beiträge: 308
Registriert: 31.12.2018, 08:07
Hat sich bedankt: 1 Mal
Danksagung erhalten: 74 Mal

Re: schnurloses Gleisbildstellwerk -- Die elektronischen Grundlagen

Beitrag von Norbert » 23.06.2026, 16:44

Mit Svens Generator erstellt funktioniert das bis heute einwandfrei.
Gruß N.
Zuletzt geändert von Norbert am 23.06.2026, 17:30, insgesamt 1-mal geändert.

little.yoda
Site Admin
Beiträge: 992
Registriert: 14.09.2018, 19:05
Hat sich bedankt: 35 Mal
Danksagung erhalten: 176 Mal

Re: schnurloses Gleisbildstellwerk -- Die elektronischen Grundlagen

Beitrag von little.yoda » 23.06.2026, 16:58

Hi

Die Funktion ist Teil von meinem Framework.
https://github.com/littleyoda/littleyoda-DCC-Decoder/
https://littleyoda.github.io/littleyoda ... coder-DOC/

ArduinoIDE unterstütze ich nicht mehr. PlatformIO benötigst du oder aber du flasht es über den Browser.
https://littleyoda.github.io/littleyoda ... DOC/Flash/

Ein Config-File kannst du über https://spurg.open4me.de/configgenerator generieren.
Hier kannst du direkt die Funktion Gleisbildstellpult aktivieren.

[Ich weiß, viele Informationen auf einmal]
[Ich habe deinen Beitrag in einen neuen Thread verschoben]

Gruß

tomy99
Beiträge: 4
Registriert: 20.06.2026, 13:02
Hat sich bedankt: 1 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von tomy99 » 23.06.2026, 19:04

Danke für die Info's

Also den Config Generator hab ich schon ausprobiert. Aber dafür muss ich ja vorher noch was installieren, den DCC-Decoder wie du schreibst, werde mich mal mit der verlinkten Webseite beschäftigen. Aber Platform IO habe ich auch installiert.

Zu deinem Schaltplan, PIN 1 wäre der deklarierte LED PIN in deinem Config Generator und
PIN 2 der Taster-Ausgang. wenn ich das richtig verstehe. Und dann Haben wir noch 2x Ground, +3,3v Spannung. Sollte ich hinbekommen :)

Habe vor gelbe LED's zu verwenden. mit 2mA Diodenstrom, Betriebsspannung 1.8 bis 2.1V sagt das Datenblatt.
sollte ja mit denWiderstanden 3x 220 Ohm passen.

Funktioniert auch ein BC337 statt dem BC327?, den hätte ich da.

Tomy

little.yoda
Site Admin
Beiträge: 992
Registriert: 14.09.2018, 19:05
Hat sich bedankt: 35 Mal
Danksagung erhalten: 176 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von little.yoda » 23.06.2026, 20:03

In mein Schaltplan benötigst du einen NPN und einen PNP Transistor:
2N2222A (NPN) und BC327-40 (PNP)

Dein BC337 wäre ein NPN-Transistor und somit eine Alternative zum 2N2222A.

Norbert
Beiträge: 308
Registriert: 31.12.2018, 08:07
Hat sich bedankt: 1 Mal
Danksagung erhalten: 74 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von Norbert » 24.06.2026, 06:42

Nun habe ich praktisch keine Ahnung von dem, was du da machst,
was mir aber sofort auffiel, ist die Schreibweise der Z21-IP....
Die kenne ich so überhaupt nicht:
IPAddress z21(192,168,0,111) statt 192.168.0.111
Bist du sicher, dass das Format stimmt?? Getrennt duch Kommata ??
Ist die relevant oder nur eine Kommentierung?
Ansonsten finde ich keine weitere IP bei dir...., die eine Verbindung zur Z21 herstellen könnte.

Gruß N.

little.yoda
Site Admin
Beiträge: 992
Registriert: 14.09.2018, 19:05
Hat sich bedankt: 35 Mal
Danksagung erhalten: 176 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von little.yoda » 24.06.2026, 09:40

Norbert hat geschrieben:
24.06.2026, 06:42
IPAddress z21(192,168,0,111) statt 192.168.0.111
passt schon. Du kennst es normalerweise als String "192.168.0.111". In seinem Beispiel wird die IP-Adresse als Parameter einer Funktion übergeben.

little.yoda
Site Admin
Beiträge: 992
Registriert: 14.09.2018, 19:05
Hat sich bedankt: 35 Mal
Danksagung erhalten: 176 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von little.yoda » 24.06.2026, 09:41

little.yoda hat geschrieben:
23.06.2026, 20:03
In mein Schaltplan benötigst du einen NPN und einen PNP Transistor:
2N2222A (NPN) und BC327-40 (PNP)
Dein BC337 wäre ein NPN-Transistor und somit eine Alternative zum 2N2222A.
Zum Testen reicht auch ein Transistor. Dann hast du halt nur eine LED, die nur bei einer Weichenstellung leuchtet.


EDIT: Bitte bei den Weichen-ID aufpassen. Hier gibt es ggf. eine Verschiebung der ID um 4. Mehr steht in der Anleitung der Z21.

tomy99
Beiträge: 4
Registriert: 20.06.2026, 13:02
Hat sich bedankt: 1 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von tomy99 » 24.06.2026, 18:11

Hallo,
hatte die BC327 zum glück noch da, und die 2N2222a kurzer Hand neu gekauft.

Nun hab ich den ESP32 über die Webseite gefläscht und die milligram.min.css und css.css hochgeladen.
Die config.json hab ich über den selben Weg hochgeladen, ist das richtig?

Ich denke es ist Richtig, denn es funktioniert so wie in deinem Video :D :D

Allerdings ist es um 1 Adresse versetzt nicht um 4 wie bei RCN-213
Es bewegt sich Weiche 121 statt Weiche 120. Aber ich denke das Problem bekommen wir noch irgendwie gelöst. (in der Z21 APP bewegt sich auch die 121 Weiche) Die KI meinte mal das zwischen Z21 schwarz und weiß eine Adresse unterschied ist, kann ich mir nicht direkt vorstellen, @Norbert, welche Z21 hast du im Einsatz?

Soll der Accespoint 192.168.4.1 danach aktiv bleiben, oder schaltet sich dieser dann ab? Oder wenn er aktiv bleiben soll, möchte ich ihn mit einem Kennwort sichern(das Wlan).

Die eine LED ist dunkler als die andere, obwohl es 3x der Gleiche Widerstand ist, komisch?

Die Zahlen am NPN und PNP sind die Korrekt? oder ist da nur die Beschriftung im Schaltplan falsch?
hab mal rangeschrieben wie ich es machen würde. Aber ich bin ja auch nicht Fehler frei.


Grüße, ein glücklicher Tomy
Dateianhänge
NPN 2N2222a.png
NPN 2N2222a.png (12.25 KiB) 15 mal betrachtet
PNP BC327.png
PNP BC327.png (11.61 KiB) 15 mal betrachtet

little.yoda
Site Admin
Beiträge: 992
Registriert: 14.09.2018, 19:05
Hat sich bedankt: 35 Mal
Danksagung erhalten: 176 Mal

Re: schnurloses Gleisbildstellwerk

Beitrag von little.yoda » 24.06.2026, 21:04

Schön den nächsten glücklichen Nutzer zu haben.
tomy99 hat geschrieben:
24.06.2026, 18:11
Allerdings ist es um 1 Adresse versetzt nicht um 4 wie bei RCN-213
Es bewegt sich Weiche 121 statt Weiche 120. Aber ich denke das Problem bekommen wir noch irgendwie gelöst. (in der Z21 APP bewegt sich auch die 121 Weiche)
Wahrscheinlich fange ich in meinem Framework mit ID=0 an und die Z21 mit ID=1 oder umgekehrt.
Muss ich mir nochmal in Ruhe anschauen.
Im Zweifelsfall musst du für den Moment die ID entsprechend um eins verschoben eintragen.
tomy99 hat geschrieben:
24.06.2026, 18:11
Soll der Accespoint 192.168.4.1 danach aktiv bleiben, oder schaltet sich dieser dann ab? Oder wenn er aktiv bleiben soll, möchte ich ihn mit einem Kennwort sichern(das Wlan).
Kannst du mal deine Konfiguration posten? Eigentlich sollte er einen Accesspoint nur öffnen, wenn ein Fehler auftritt oder du es explizit ausgewählt hast.
tomy99 hat geschrieben:
24.06.2026, 18:11
Die eine LED ist dunkler als die andere, obwohl es 3x der Gleiche Widerstand ist, komisch?
Gleichfarbige LEDs oder unterschiedliche Farben?
Wenn es unterschiedliche Farben sind, könnte ich es verstehen. Dort müsste man dann mal mit den Widerständen spielen.
Wenn es gleichfarbige LEDs sind, kann ich es nicht richtig verstehen, weil die Serienstreuung eigentlich nicht so groß sein sollte.

tomy99 hat geschrieben:
24.06.2026, 18:11
Die Zahlen am NPN und PNP sind die Korrekt? oder ist da nur die Beschriftung im Schaltplan falsch?
hab mal rangeschrieben wie ich es machen würde. Aber ich bin ja auch nicht Fehler frei.
Muss ich mir nochmal in Ruhe anschauen. In meiner Zeichnung habe ich damals wahrscheinlich generische Transistoren genutzt und nicht die, die ich am Ende getestet habe.

Antworten