Mikro­con­trol­ler im AP-Modus vernetzen

Lese­zeit: 9 Minu­ten


Zie­le des Projekts

  • zwei Mikro­con­trol­ler unab­hän­gig von einem bestehen­den Rou­ter in einem eigen­stän­di­gen WLAN-Netz betreiben
  • mit belie­bi­gen Tem­pe­ra­tur­sen­so­ren (hier DHT11/DHT22) an zwei ver­schie­de­nen Orten Tem­pe­ra­tur und Luft­feuch­tig­keit messen
  • die ermit­tel­ten Mess­wer­te in einem Web­brow­ser anzeigen

Benö­tig­te Bauteile

  • ESP32-Mikro­con­trol­ler oder ESP8266-Mikro­con­trol­ler in belie­bi­ger Kombination
  • DHT11/DHT22 Tem­pe­ra­tur­sen­so­ren
  • Lei­tungs­dräh­te

Kon­fi­gu­ra­ti­on der Mikrocontroller

Acces­s­point-Modus (AP-Modus)

Beim AP-Modus bau­en die ESPs ein vom hei­mi­schen Rou­ter unab­hän­gi­ges eigen­stän­di­ges Netz auf. Neben dem Namen des Rou­ters und dem Pass­wort musst du dem ESP eini­ge Daten mitteilen:

char Router[] = "ESPServer";
char Passwort[] = "espserver";
IPAddress ip(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0)

Der Name des Rou­ters und das Pass­wort sind frei wähl­bar, aller­dings muss das Pass­wort min­des­tens 8 Zei­chen haben.

ip legt die sta­ti­sche IP-Adres­se fest.
gate­way ist das Gerät - in die­sem Fall der ESP selbst - das die Kom­mu­ni­ka­ti­on der ver­bun­de­nen Gerä­te (der Kli­en­ten) unter­ein­an­der regelt.
sub­net ist der Adress­be­reich der zuge­las­se­nen IP-Adres­sen. 255 bedeu­tet, dass die­ser Bereich jeweils unver­än­der­lich ist, 0 am Ende heißt, dass die IP-Adres­sen varia­bel sind. Da die ers­te und die letz­te IP-Adres­se aus orga­ni­sa­to­ri­schen Grün­den nicht ver­ge­ben wer­den darf, blei­ben 254 IP-Adres­sen (192.168.4.1 bis 192.168.4.254).
Die neue­re Schreib­wei­se ist übri­gens in die­sem Fall 192.168.4/24.

Beach­te, dass die Zah­len­blö­cke der IP-Adres­sen durch Kom­ma­ta getrennt wer­den müssen.

Alle IP-Adres­sen, die mit 192.168. begin­nen, sind als pri­vat fest­ge­legt, sie dür­fen im Inter­net nicht ver­wen­det wer­den. Die nächs­te Zif­fer (4) bezeich­net das Sub­netz. Hier sind maxi­mal 256 Sub­net­ze (192.168.0 bis 192.168.255) mög­lich. Die letz­te Zif­fer (1) ist die kon­kre­te IP-Adres­se des Geräts.

ip und gate­way müs­sen gleich sein!
Du darfst kein Sub­netz ver­wen­den, das der Rou­ter für DHCP verwendet.

Du kannst dir mit einem Werk­zeug einen Über­blick über die im pri­va­ten Netz vor­han­de­nen Gerä­te ver­schaf­fen und anhand der ange­zeig­ten IP-Adres­sen das vom Rou­ter für DHCP ver­wen­de­te Sub­netz herausfinden.

  • Win­dows:
    Ein­ga­be­auf­for­de­rung (cmd) öff­nen
    arp -n
  • Linux:
    Kon­so­le öff­nen
    arp -n zeigt alle über Ether­net ver­bun­de­nen Gerä­te
    arp-scan --local­net zeigt alle über WiFi und Ether­net ver­bun­de­nen Geräte

Pro­gramm zum Auf­bau des Netzes

// ESP32
#include "WiFi.h"

// ESP8266
// #include "ESP8266WWiFi.h"

// Netzwerkname und Passwort des ESP
char Router[] = "ESPServer";
char Passwort[] = "espserver";

// Server und Klient
IPAddress ip(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);

void setup() 
{
  Serial.begin(9600);
  
  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // ESP als Access-Point (AP) konfigurieren
  WiFi.softAPConfig(ip, gateway, subnet);

  // Access-Point starten
  WiFi.softAP(Router, Passwort);
   
  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.softAPSSID());

  Serial.print("IP-Adresse: ");
  Serial.println(WiFi.softAPIP());
}

void loop()
{
  // bleibt leer, das Programm läuft nur einmal
}

Ein Smart­phone sucht über das mobi­le Netz im Inter­net nach der IP-Adres­se des ESP­Ser­vers (192.168.4.1). Da kein DNS-Ser­ver erreich­bar ist, kann die Sei­te nicht ange­zeigt wer­den. Ver­wen­de statt­des­sen
http://192.168.4.1

Auf­bau des AP-Netzes

Als Kli­en­ten kön­nen alle WLAN-fähi­gen Gerä­te ver­wen­det werden. 

Das Schau­bild zeigt den Auf­bau des Net­zes und die Kom­mu­ni­ka­ti­on der Gerä­te unter­ein­an­der. Ich habe einen ESP32-WROOM gewählt, du kannst aber auch eine belie­bi­ge Kom­bi­na­ti­on von ESP32 oder ESP8266-Mikro­con­trol­lern ver­wen­den.
Der Mikro­con­trol­ler mit der IP 192.168.4.1 baut das WLAN-Netz auf und erhebt gleich­zei­tig auch Daten für Tem­pe­ra­tur und Luft­feuch­tig­keit. Der zwei­te Mikro­con­trol­ler (Host) misst eben­falls Tem­pe­ra­tur und Luft­feuch­tig­keit. In regel­mä­ßi­gen Abstän­den fragt der Ser­ver sei­ne eige­nen Daten und die des Hosts ab. Die Kli­en­ten zei­gen die Daten auf der Web­sei­te an.

Manu­el­le Kon­fi­gu­ra­ti­on des Klienten

Den Kli­en­ten wer­den kei­ne IP-Adres­sen auto­ma­tisch zuge­teilt. Daher muss die Kon­fi­gu­ra­ti­on hän­disch erle­digt wer­den.
Zunächst musst du das als "ESP­Ser­ver" ange­zeig­te WLAN aus­wäh­len und anschlie­ßend die Kon­fi­gu­ra­ti­on anpassen.

Wenn du meh­re­re Kli­en­ten ver­wen­den willst, musst du jeweils eine ande­re IP-Adres­se ver­wen­den (z. B. 192.168.4.5). Die Adres­se des Rou­ters bleibt unverändert.

iOS

Android

Win­dows 10

ESP als Ser­ver und Klient

Ein ESP soll als Ser­ver die Daten des ande­ren ESP ein­sam­meln und gleich­zei­tig als Kli­ent eben­falls Tem­pe­ra­tur und Luft­feuch­tig­keit mes­sen.
Daher wird für die IP-Adres­se und das Gate­way die glei­che IP-Adres­se verwendet.

// ESP8266
// #include "ESP8266WebServer.h"

// ESP32
#include "WebServer.h"
#include "WiFi.h"

#include "DHT.h"

// Pin des DHT-Sensors
int SENSOR_DHT = 19;

// Sensortyp festlegen
// DHT22 oder DHT11
#define SensorTyp DHT22

DHT dht(SENSOR_DHT, SensorTyp);

// Netzwerkname und Passwort des ESP
char Router[] = "ESPServer";
char Passwort[] = "espserver";

// ESP32
WebServer Server(80);

// ESP8266
// ESP8266WebServer Server(80);

// farbige Box mit CSS
String Seitenkopf =
  "<head><style>"
  ".farbigeBox {"
  "background-color: ivory;"
  "color: black;"
  "width: 480px;"
  "padding: 20px;"
  "text-align: left;"
  "font-size: 40px;"
  "font-family: arial;"
  "}"
  "</style>"

  // refresh -> Seite automatisch aktualisieren
  "<meta http-equiv=\"refresh\" content=\"30\"></head>";

// Wartezeit für die sichere Übermittlung der Daten
unsigned long Wartezeit = 5000;

// enthält die Daten des 2. ESPs
String Messung;

// IP-Adresse des 2. ESP
const char* host = "192.168.4.2";

// Konfiguration als Server und Host
IPAddress ip(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);

void setup() 
{
  Serial.begin(9600);
  
  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // ESP als Access-Point (AP) konfigurieren
  WiFi.softAPConfig(ip, gateway, subnet);

  // Access-Point starten
  WiFi.softAP(Router, Passwort);
   
  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.softAPSSID());

  Serial.print("IP-Adresse: ");
  Serial.println(WiFi.softAPIP());

  // Webserver starten
  // / -> Aufruf der URL, SeiteBauen -> Aufruf der Funktion
  Server.begin();
  Server.on("/", SeiteBauen);

  dht.begin();
}

void loop() 
{
  static unsigned long Startzeit = millis();

  // auf Anfragen warten
  Server.handleClient();

  // Messdaten einsammeln
  if ((millis() - Startzeit) > Wartezeit)
  {
    // Daten des 2. ESPs einsammeln
    DatenHolen();
    
    Startzeit = millis();
  }
}

void SeiteBauen()
{
  // Seite "zusammenbauen"
  String Seite = "";
  Seite += Seitenkopf;
  Seite += "<h1>Messdaten</h1>";
  Seite += "<hr>";
  
  /*
    Messung enthält die mit / getrennten Daten
    String Messung mit substring am / trennen
    Temperatur: von Position 0 bis zum / (indexOf)
    Luftfeuchtigkeit von /+1 bis zur Länge des Strings (length)
  */
  String TemperaturKlient = Messung.substring(0, Messung.indexOf("/"));
  String LuftfeuchtigkeitKlient = Messung.substring(Messung.indexOf("/") + 1, Messung.length());
  
  Seite += "<h2>Daten vom Klienten ...</h2>";
  Seite += "<div class=\"farbigeBox\">";
  Seite += "Temperatur: ";
  Seite += TemperaturKlient;
  Seite += "<br>";
  Seite += "Luftfeuchtigkeit: ";
  Seite += LuftfeuchtigkeitKlient;
  Seite += "<br>";
  Seite += "</div>";

  // Messwerte des Servers ermitteln
  // . durch , ersetzen
  String TemperaturServer = String(dht.readTemperature());
  TemperaturServer.replace(".", ",");
  
  String LuftfeuchtigkeitServer = String(dht.readHumidity());
  LuftfeuchtigkeitServer.replace(".", ",");
  
  Seite += "<h2>Daten vom Server ...</h2>";
  Seite += "<div class=\"farbigeBox\">";
  Seite += "Temperatur: ";
  Seite += TemperaturServer + "&degC";
  Seite += "<br>";
  Seite += "Luftfeuchtigkeit: ";
  Seite += LuftfeuchtigkeitServer + "%";
  Seite += "</div>";

  // Button aktualisieren
  Seite += "<hr><button style=\"font-size:16pt; font-weight:bold;";
  Seite += "background-color:#55A96B;";
  Seite += "display:block; cursor:pointer;\">";
  Seite += "</button>";

  // IP für den Button aktualisieren (location.href)
  // muss mit dem Wert für IPAdress übereinstimmen (. statt ,)
  Seite += " onClick=\"location.href='http://192.168.4.1'\" value=\"aktualisieren\">";
  Seite += "<hr>";

  // Seite anzeigen
  Server.send(200, "text/html", Seite);
}

void DatenHolen()
{
  WiFiClient client;

  // wenn Klient erfolgreich auf Port 80 verbunden wurde
  // wenn nicht return -> neuer Versuch
  if (!client.connect(host, 80)) return;
  
  /*
    GET-Anfrage senden
    /Messung -> Adresse (URL) für die zu übermittelnden Werte
    wird von den Klienten festgelegt
    host -> IP-Adresse des 2. ESPs
    HTTP/1.1 -> Abfrageprotokoll
    \r\n -> return mit anschließender neuer Zeile
  */
  client.print(String("GET ") + "/Messung" + " HTTP/1.1\r\n" + host + "\r\n");
  unsigned long LetzteZeit = millis();

  // Wartezeit 
  while (!client.available() && ((millis() - LetzteZeit) < 3000))
  {
    delay(1);
  }  

  // der Klient ist verfügbar
  while (client.available()) 
  {
    // den mit GET erhaltenen String bis zum return (\r) lesen
    String Daten = client.readStringUntil('\r');

    // wenn Daten vorhanden sind
    // Messung enthält die vom 2. ESP übermittelten Daten
    if(Daten != "")
    {
      Messung = Daten;
      Serial.println(Daten);
    }
  }
}

Dar­stel­lung der GET-Anfra­ge im Seri­el­len Monitor

ESP als Host

// ESP8266
// #include "ESP8266WebServer.h"

// ESP32
#include "WebServer.h"
#include "WiFi.h"

#include "DHT.h"

// Pin des DHT-Sensors
int SENSOR_DHT = 19;

#define SensorTyp DHT22

// Sensor DHT einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

// ESP als AP
char Router[] = "ESPServer";
char Passwort[] = "espserver";

// IP des 2. ESPs
IPAddress ip(192, 168, 4, 2);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);

// ESP32
WebServer Server(80);

// ESP8266
// ESP8266WebServer Server(80);

void setup() 
{
  // WiFi starten
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(Router, Passwort);

  // Adresse (URL)festlegen (/Messung)
  // SeiteBauen -> zu übermittelnde Daten
  Server.on("/Messung", SeiteBauen);
  Server.begin();
  Serial.begin(9600);
  
  // DHT starten
  dht.begin();
}

void loop() 
{
  // auf Anfragen warten
  Server.handleClient();
}

void SeiteBauen() 
{
  String Seite ="";

  // Messwerte ermitteln
  // . durch , ersetzen
  String Temperatur = String(dht.readTemperature());
  Temperatur.replace(".", ",");
  
  String Luftfeuchtigkeit = String(dht.readHumidity());
  Luftfeuchtigkeit.replace(".", ",");
  
  // Seite zusammenbauen
  // / Trennzeichen zwischen Temperatur und Luftfeuchtigkeit
  Seite = Temperatur + "&degC/";
  Seite += Luftfeuchtigkeit + "%";

  // Seite übermitteln
  Server.send(200, "text/html", Seite);
}

Quel­len


Letzte Aktualisierung: Nov 18, 2024 @ 7:15