Mehrere NodeMCU miteinander verbinden: Kommunikation zwischen Server und Client

In diesem Tutorial lernst du, wie du zwei NodeMCU-Module miteinander kommunizieren lassen kannst - eines als Server (Access Point) und eines als Client. Wir zeigen dir Schritt für Schritt, wie du die Verbindung einrichtest und implementierst komplette Code-Beispiele für beide Geräte.

Einführung

NodeMCU ist eine kostengünstige und leistungsstarke IoT-Plattform basierend auf dem ESP8266-Mikrocontroller. Mit integrierter WLAN-Funktionalität eignet sich NodeMCU hervorragend für die Entwicklung vernetzter Projekte. In diesem Tutorial lernst du, wie du zwei NodeMCU-Module miteinander kommunizieren lassen kannst - eines als Server (Access Point) und eines als Client.

Die Kommunikation zwischen NodeMCUs ermöglicht viele spannende Anwendungen wie:

  • Verteilte Sensornetzwerke
  • Fernsteuerung von Geräten
  • Datenaustausch zwischen mehreren Mikrocontrollern
  • Redundante Systeme mit mehreren Kontrollpunkten

Benötigte Hardware und Software

Hardware

  • NodeMCU (ESP8266-basierte Entwicklerboards)
  • 2× Micro-USB-Kabel
  • Optional: Steckbrett und Jumper-Kabel
  • Optional: Sensoren oder Aktoren für praktische Anwendungen (LEDs, Schalter, etc.)

Software

  • Arduino IDE (neueste Version)
  • ESP8266-Boardmanager und Bibliotheken
  • ESP8266WiFi-Bibliothek
  • ESP8266WebServer-Bibliothek

Information

Alle benötigten Software-Komponenten sind kostenlos verfügbar und einfach zu installieren. In den Voraussetzungen weiter unten erklären wir die Installation im Detail.

Grundkonzepte der WLAN-Kommunikation mit NodeMCU

NodeMCU-Module können auf zwei Arten über WLAN kommunizieren:

  1. Über einen bestehenden Router: Beide NodeMCUs verbinden sich mit demselben WLAN-Router und kommunizieren durch diesen.
  2. Direkte Verbindung: Ein NodeMCU wird als Access Point (AP) konfiguriert, während das andere als Client fungiert.

In diesem Tutorial konzentrieren wir uns auf die zweite Methode, die direkte Verbindung. Hierbei agiert ein NodeMCU als Server und erstellt ein eigenes WLAN-Netzwerk, während das andere als Client fungiert und sich mit diesem Netzwerk verbindet.

Die Kommunikation erfolgt über HTTP-Anfragen oder WebSockets, wobei der Server auf eingehende Anfragen reagiert und der Client Anfragen sendet. Für unser Tutorial verwenden wir das HTTP-Protokoll, da es einfacher zu implementieren ist.

Voraussetzungen und Einrichtung

Installation der Arduino IDE

  1. Lade die neueste Version der Arduino IDE von arduino.cc herunter
  2. Installiere die IDE auf deinem Computer

Einrichtung für ESP8266

  1. Öffne die Arduino IDE
  2. Gehe zu "Datei" > "Voreinstellungen"
  3. Füge folgende URL im Feld "Zusätzliche Boardverwalter-URLs" ein:
    http://arduino.esp8266.com/stable/package_esp8266com_index.json
  4. Gehe zu "Werkzeuge" > "Board" > "Boardverwalter"
  5. Suche nach "esp8266" und installiere das Paket "esp8266 by ESP8266 Community"

Wichtiger Hinweis

Achte darauf, dass du die URL für den Boardverwalter exakt wie angegeben kopierst. Ein Fehler in der URL führt dazu, dass die ESP8266-Boards nicht gefunden werden. Hier findest du weitere Informationen zum Einrichten des NodeMCU.

Installation der benötigten Bibliotheken

Die meisten benötigten Bibliotheken sind bereits im ESP8266-Paket enthalten. Falls nicht, kannst du sie über den Bibliotheksverwalter installieren:

  1. Gehe zu "Sketch" > "Bibliothek einbinden" > "Bibliotheken verwalten"
  2. Suche und installiere folgende Bibliotheken:
    • ESP8266WiFi
    • ESP8266WebServer
    • ArduinoJson (optional, aber nützlich für strukturierte Datenübertragung)

Schritt-für-Schritt-Anleitung

Schritt 1: Identifiziere deine NodeMCUs

Markiere deine beiden NodeMCUs, um sie zu unterscheiden (z.B. mit Aufklebern "Server" und "Client").

Schritt 2: Server-NodeMCU einrichten

  1. Verbinde den Server-NodeMCU mit deinem Computer
  2. Öffne die Arduino IDE
  3. Wähle das korrekte Board und den Port unter "Werkzeuge"
  4. Kopiere den Server-Code (siehe Server-Code unten)
  5. Lade den Code auf den NodeMCU hoch

Schritt 3: Client-NodeMCU einrichten

  1. Verbinde den Client-NodeMCU mit deinem Computer
  2. Wähle das korrekte Board und den Port unter "Werkzeuge"
  3. Kopiere den Client-Code (siehe Client-Code unten)
  4. Passe die SSID und das Passwort an, damit sie mit den Einstellungen des Servers übereinstimmen
  5. Lade den Code auf den NodeMCU hoch

Schritt 4: Testen der Kommunikation

  1. Trenne beide NodeMCUs vom Computer und versorge sie mit Strom (über USB oder externe Stromversorgung)
  2. Beobachte die serielle Ausgabe des Clients (falls angeschlossen), um zu sehen, ob die Verbindung erfolgreich hergestellt wird
  3. Bei erfolgreicher Kommunikation solltest du sehen, wie der Client Daten vom Server empfängt oder sendet

Codebeispiele

Server-Code

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ArduinoJson.h>

// WLAN-Konfiguration für den Access Point
const char* ssid = "NodeMCU-Server";      // Name des WLAN-Netzwerks
const char* password = "12345678";        // Passwort des WLAN-Netzwerks (mind. 8 Zeichen)

// Server auf Port 80 erstellen
ESP8266WebServer server(80);

// Variablen für Sensordaten oder Status
int sensorValue = 0;
bool ledStatus = false;
const int ledPin = D4;  // Integrierte LED des NodeMCU (D4 = GPIO2)

void setup() {
  // Serielle Kommunikation starten
  Serial.begin(115200);
  Serial.println("\n\nNodeMCU Server startet...");
  
  // LED-Pin konfigurieren
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);  // LED ist LOW-aktiv, daher HIGH = aus
  
  // Access Point konfigurieren und starten
  WiFi.softAP(ssid, password);
  
  // IP-Adresse des Access Points anzeigen
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP-Adresse: ");
  Serial.println(IP);
  
  // Routen für die Webserver-Anfragen definieren
  server.on("/", handleRoot);
  server.on("/status", HTTP_GET, handleGetStatus);
  server.on("/control", HTTP_POST, handleControl);
  server.onNotFound(handleNotFound);
  
  // Webserver starten
  server.begin();
  Serial.println("HTTP-Server gestartet");
}

void loop() {
  // Auf Client-Anfragen horchen
  server.handleClient();
  
  // Sensordaten simulieren (durch Inkrementieren)
  if (millis() % 5000 == 0) {  // Alle 5 Sekunden aktualisieren
    sensorValue = random(0, 1024);  // Zufallswert zwischen 0 und 1023
    Serial.print("Neuer Sensorwert: ");
    Serial.println(sensorValue);
    delay(1);  // Verhindern, dass es mehrmals pro Millisekunde ausgeführt wird
  }
}

// Handler für die Wurzel-Seite
void handleRoot() {
  String html = "";
  html += "NodeMCU Server";
  html += "Dies ist der NodeMCU Server.";
  html += "Aktueller Sensorwert: " + String(sensorValue) + "";
  html += "LED-Status: " + String(ledStatus ? "AN" : "AUS") + "";
  html += "";
  
  server.send(200, "text/html", html);
}

// Handler für Status-Abfragen (gibt JSON zurück)
void handleGetStatus() {
  // JSON-Dokument erstellen
  StaticJsonDocument<200> doc;
  doc["sensorValue"] = sensorValue;
  doc["ledStatus"] = ledStatus;
  
  // JSON in String umwandeln
  String jsonString;
  serializeJson(doc, jsonString);
  
  // JSON an Client senden
  server.send(200, "application/json", jsonString);
}

// Handler für Steuerungsanfragen
void handleControl() {
  // Prüfen, ob der Parameter "led" in der Anfrage vorhanden ist
  if (server.hasArg("led")) {
    String ledValue = server.arg("led");
    
    if (ledValue == "1" || ledValue == "on" || ledValue == "true") {
      ledStatus = true;
      digitalWrite(ledPin, LOW);  // LED einschalten (LOW-aktiv)
      Serial.println("LED eingeschaltet");
    } else {
      ledStatus = false;
      digitalWrite(ledPin, HIGH);  // LED ausschalten
      Serial.println("LED ausgeschaltet");
    }
    
    // Erfolg zurückmelden
    server.send(200, "text/plain", "LED-Status geändert: " + String(ledStatus ? "AN" : "AUS"));
  } else {
    // Fehler zurückmelden, wenn der Parameter fehlt
    server.send(400, "text/plain", "Fehler: Parameter 'led' fehlt");
  }
}

// Handler für nicht gefundene Seiten
void handleNotFound() {
  server.send(404, "text/plain", "404: Nicht gefunden");
}

Client-Code

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>

// WLAN-Konfiguration für die Verbindung zum Server
const char* ssid = "NodeMCU-Server";      // Name des Server-WLAN-Netzwerks
const char* password = "12345678";        // Passwort des Server-WLAN-Netzwerks

// Server-Adresse (Standard-IP des NodeMCU im AP-Modus)
const char* serverAddress = "http://192.168.4.1";

// Variablen für die Client-Funktionalität
const int buttonPin = D3;     // Pin für einen Button (falls vorhanden)
bool lastButtonState = HIGH;  // Letzter Status des Buttons (Pull-Up Widerstand, daher HIGH = nicht gedrückt)
bool ledStatus = false;       // Status der LED auf dem Server
unsigned long lastStatusCheck = 0;  // Zeitpunkt der letzten Statusabfrage

void setup() {
  // Serielle Kommunikation starten
  Serial.begin(115200);
  Serial.println("\n\nNodeMCU Client startet...");
  
  // Button-Pin konfigurieren (falls vorhanden)
  pinMode(buttonPin, INPUT_PULLUP);
  
  // Mit dem Server-WLAN verbinden
  WiFi.begin(ssid, password);
  
  Serial.print("Verbinde mit ");
  Serial.print(ssid);
  
  // Warten auf WLAN-Verbindung
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  // Verbindungsinformationen anzeigen
  Serial.println();
  Serial.print("Verbunden! IP-Adresse: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // Prüfen, ob die WLAN-Verbindung noch besteht
  if (WiFi.status() == WL_CONNECTED) {
    
    // Button abfragen (falls vorhanden)
    bool currentButtonState = digitalRead(buttonPin);
    
    // Wenn der Button gedrückt wurde (Flanke HIGH zu LOW)
    if (lastButtonState == HIGH && currentButtonState == LOW) {
      // LED-Status umschalten
      ledStatus = !ledStatus;
      // Steuerbefehl an den Server senden
      sendControlCommand(ledStatus);
      delay(50);  // Entprellung
    }
    
    // Button-Status aktualisieren
    lastButtonState = currentButtonState;
    
    // Regelmäßig den Status vom Server abfragen (alle 5 Sekunden)
    if (millis() - lastStatusCheck > 5000) {
      getServerStatus();
      lastStatusCheck = millis();
    }
  } else {
    // Bei Verbindungsverlust neu verbinden
    Serial.println("WLAN-Verbindung verloren. Versuche neu zu verbinden...");
    WiFi.begin(ssid, password);
    
    // Kurz warten und fortfahren
    delay(5000);
  }
}

// Funktion zum Abrufen des Serverstatus
void getServerStatus() {
  // HTTP-Client-Objekte erstellen
  WiFiClient client;
  HTTPClient http;
  
  // URL für die Statusabfrage
  String url = String(serverAddress) + "/status";
  
  // HTTP-Anfrage vorbereiten
  http.begin(client, url);
  
  // HTTP-GET-Anfrage senden
  int httpCode = http.GET();
  
  // Antwort prüfen
  if (httpCode > 0) {
    // Erfolgreiche Antwort
    if (httpCode == HTTP_CODE_OK) {
      // Antwort als String holen
      String payload = http.getString();
      Serial.println("Status-Antwort vom Server:");
      Serial.println(payload);
      
      // JSON-Antwort parsen
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, payload);
      
      // Prüfen, ob das Parsen erfolgreich war
      if (!error) {
        // Daten aus dem JSON extrahieren
        int sensorValue = doc["sensorValue"];
        bool serverLedStatus = doc["ledStatus"];
        
        // Daten anzeigen
        Serial.print("Sensorwert: ");
        Serial.println(sensorValue);
        Serial.print("LED-Status: ");
        Serial.println(serverLedStatus ? "AN" : "AUS");
        
        // Lokale Variable aktualisieren
        ledStatus = serverLedStatus;
      } else {
        Serial.print("Fehler beim Parsen des JSON: ");
        Serial.println(error.c_str());
      }
    }
  } else {
    Serial.print("Fehler bei der HTTP-Anfrage: ");
    Serial.println(http.errorToString(httpCode).c_str());
  }
  
  // Verbindung beenden
  http.end();
}

// Funktion zum Senden eines Steuerbefehls
void sendControlCommand(bool ledOn) {
  // HTTP-Client-Objekte erstellen
  WiFiClient client;
  HTTPClient http;
  
  // URL für die Steuerung
  String url = String(serverAddress) + "/control";
  
  // HTTP-Anfrage vorbereiten
  http.begin(client, url);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  
  // Parameter für die LED-Steuerung
  String httpRequestData = "led=" + String(ledOn ? "1" : "0");
  
  // HTTP-POST-Anfrage senden
  int httpCode = http.POST(httpRequestData);
  
  // Antwort prüfen
  if (httpCode > 0) {
    // Erfolgreiche Antwort
    if (httpCode == HTTP_CODE_OK) {
      String response = http.getString();
      Serial.println("Server-Antwort:");
      Serial.println(response);
    }
  } else {
    Serial.print("Fehler bei der HTTP-Anfrage: ");
    Serial.println(http.errorToString(httpCode).c_str());
  }
  
  // Verbindung beenden
  http.end();
}

Fehlersuche und Tipps

Häufige Probleme und Lösungen

  1. Verbindungsprobleme:
    • Überprüfe, ob die SSID und das Passwort in beiden Codes übereinstimmen
    • Das Passwort muss mindestens 8 Zeichen lang sein
    • Stelle sicher, dass die NodeMCUs nicht zu weit voneinander entfernt sind
  2. Fehlermeldung "IP-Adresse des Servers nicht gefunden":
    • Die Standard-IP-Adresse eines NodeMCU im AP-Modus ist 192.168.4.1
    • Wenn du mehrere NodeMCUs als Server verwendest, können IP-Konflikte auftreten
  3. Keine Reaktion auf HTTP-Anfragen:
    • Überprüfe, ob der Server korrekt gestartet wurde (serielle Ausgabe)
    • Stelle sicher, dass die korrekten Routen im Server definiert sind
    • Verwende einen Webbrowser, um die Server-Schnittstelle zu testen (http://192.168.4.1)

Tipp zur Fehlersuche

Die serielle Konsole ist dein bester Freund bei der Fehlersuche. Stelle sicher, dass du bei beiden NodeMCUs Serial.begin(115200) aufgerufen hast und überwache die Ausgabe, um Probleme zu identifizieren.

  1. Instabile Verbindung:
    • Verwende eine stabile Stromversorgung für beide NodeMCUs
    • Implementiere eine Wiederverbindungslogik im Client (im Beispielcode bereits enthalten)
    • Reduziere die Häufigkeit der Anfragen, um Überlastung zu vermeiden

Leistungsoptimierung

  1. Energiesparmodus:
    • Verwende ESP.deepSleep() im Client, um Strom zu sparen, wenn keine Kommunikation erforderlich ist
    • Reduziere die Häufigkeit der Statusabfragen
  2. Zuverlässigkeit:
    • Implementiere Timeouts und Wiederholungsversuche für fehlgeschlagene Anfragen
    • Füge Fehlerprüfungen hinzu, um robustere Kommunikation zu gewährleisten

Erweiterungsmöglichkeiten

  1. Mehr NodeMCUs hinzufügen:
    • Der Server kann mehrere Clients gleichzeitig verwalten
    • Jeder Client benötigt eine eindeutige ID für die Identifizierung
  2. Bidirektionale Kommunikation verbessern:
    • Implementiere WebSockets für Echtzeit-Datenaustausch
    • Verwende MQTT für effiziente Publish-Subscribe-Kommunikation
WebSockets bieten eine persistente Verbindung zwischen Server und Client, was ideal für Anwendungen ist, die häufige Aktualisierungen benötigen.
  1. Sicherheit erhöhen:
    • Implementiere eine einfache Authentifizierung für die HTTP-Anfragen
    • Verwende HTTPS, wenn möglich (erfordert mehr Ressourcen)
  2. Praktische Anwendungen:
    • Verbinde Sensoren mit dem Client und sende die Daten an den Server
    • Implementiere einen ferngesteuerten Schalter mit dem Server als Steuereinheit
    • Erstelle ein verteiltes Sensornetzwerk mit mehreren Clients

Fazit

In diesem Tutorial hast du gelernt, wie du zwei NodeMCU-Module miteinander kommunizieren lassen kannst, wobei eines als Server und eines als Client fungiert. Du hast gesehen, wie du einen Webserver auf dem NodeMCU einrichten, HTTP-Anfragen senden und empfangen und JSON für den Datenaustausch verwenden kannst.

Die möglichen Anwendungen dieser Technologie sind vielfältig, von einfachen Fernsteuerungsprojekten bis hin zu komplexen IoT-Netzwerken. Mit den bereitgestellten Grundlagen kannst du nun deine eigenen Projekte entwickeln und erweitern.

Wichtiger Hinweis

Vergiss nicht, dass die NodeMCU eine leistungsstarke, aber ressourcenbeschränkte Plattform ist. Optimiere deinen Code für Stabilität und Energieeffizienz, besonders wenn deine Projekte mit Batteriestrom betrieben werden sollen.

Viel Erfolg bei deinen NodeMCU-Projekten!

Zurück zu den Artikeln