Mikro­con­trol­ler vernetzen

Lese­zeit: 12 Minu­ten


Ziel des Projekts

  • bis zu drei Mikro­con­trol­ler unab­hän­gig von einem bestehen­den Rou­ter in einem eige­nen WLAN-Netz betrei­ben
    alter­na­tiv: die Mikro­con­trol­ler in das vor­han­de­nen WLAN einbinden
  • mit belie­bi­gen Tem­pe­ra­tur­sen­so­ren (hier DHT11/DHT22) an bis zu drei ver­schie­de­nen Orten die Tem­pe­ra­tur messen
  • die ermit­tel­ten Mess­wer­te in einem Web­brow­ser anzeigen

Die bei­den Ansich­ten unter­schei­den sich ledig­lich durch den ver­wen­de­ten Netz­werk­mo­dus und damit der ver­wen­de­ten IP-Adresse:

links wird der ➨Sta­ti­ons­mo­dus, rechts der ➨Access-Point-Modus verwendet

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

Netz­werk­mo­di der ESP-Mikrocontroller

Sta­ti­on-Modus

Sta­ti­on-Modus mit DHCP

Im Sta­ti­ons-Modus (STA) ver­wen­det der Mikro­con­trol­ler das WLAN-Netz der Rou­ters und erhält von dort eine IP-Adres­se. Die­se wird dyna­misch zuge­wie­sen, es kann jedes Mal eine ande­re sein (DHCP Dyna­mic Host Con­fi­gu­ra­ti­on Protocol).

// ESP32
#include "WiFi.h"

// ESP8266
// #include ESP8266WiFi.h"

// Router als AP
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

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

  WiFi.begin(Router, Passwort);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
 
  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.SSID());

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

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

Sta­ti­ons-Modus mit sta­ti­scher IP-Adresse

Für die­ses Pro­jekt wird aber eine sta­ti­sche IP-Adres­se benö­tigt, sie soll ja im Kli­ent auf­ge­ru­fen werden.

// ESP32
#include "WiFi.h"

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

// Router als AP
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// statische IP-Adresse
IPAddress ip(192, 168, 1, 5);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

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

  WiFi.config(ip, gateway, subnet);
  WiFi.begin(Router, Passwort);

  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.SSID());

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

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

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

// 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
}

ESP im AP-Modus verwenden

Auf­bau des AP-Netzes

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 Tem­pe­ra­tur­da­ten. Die Mikro­con­trol­ler Host 1 und Host 2 mes­sen eben­falls die Tem­pe­ra­tur. In regel­mä­ßi­gen Abstän­den fragt der Ser­ver die­se Mess­da­ten ab. Die Kli­en­ten zei­gen die Daten an.

Soll­test du nur zwei Mikro­con­trol­ler zur Ver­fü­gung haben, kannst du das Pro­gramm leicht anpassen.

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 der ande­ren ESPs ein­sam­meln und gleich­zei­tig als Kli­ent eben­falls die Tem­pe­ra­tur mes­sen.
Daher wird für die IP-Adres­se und das Gate­way die glei­che IP 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 DHT11

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

// unterscheiden der Hosts
#define HOST_1 0
#define HOST_2 1

// IP-Adressen der Hosts
const char* host_1 = "192.168.4.2";
const char* host_2 = "192.168.4.3";

// Array für die Messung
String Messung[2] = {"",""};

unsigned long Wartezeit = 15000;

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

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

// ESP32
WebServer Server(80);

// ESP8266
// ESP8266WebServer Server(80);

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

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

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

  // Access-Point starten
  WiFi.softAP(Router, Passwort);

  // / -> Aufruf der URL, SeiteBauen -> Aufruf der Funktion
  Server.on("/", SeiteBauen);
  Server.begin();
  Serial.begin(9600);
  
  // DHT starten
  dht.begin();
}

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

  // auf Anfragen warten
  Server.handleClient();

  // Messdaten einsammeln
  if ((millis() - Startzeit) > Wartezeit)
  {
    // Daten der Hosts einsammeln
    DatenHolen(HOST_1);
    DatenHolen(HOST_2);
    Startzeit = millis();
  }
}

void SeiteBauen() 
{
  // Messwert ermitteln
  // . durch , ersetzen
  String Temperatur = String(dht.readTemperature());
  Temperatur.replace(".", ",");
  
  // Seite zusammen bauen
  String Seite = "";
  Seite += Seitenkopf;
  Seite += "<h1 align=\"left\">Raumtemperatur</h1>";
  Seite += "<div align=\"left\";>";

  Seite += "<div class=\"farbigeBox\">";
  Seite += "Bad: ";
  Seite += Temperatur + "&deg;C";
  Seite += "<br>";
  Seite += "Wohnzimmer:";
  Seite += String(Messung[HOST_1]);
  Seite += "<br>";
  Seite += "Esszimmer:";
  Seite += String(Messung[HOST_2]);
  Seite += "</div>";

  // Button aktualisieren
  Seite += "<hr><input style=\"font-size:16pt; font-weight:bold;";
  Seite += "background-color:#55A96B;";
  Seite += "display:block; cursor:pointer;\"type=\"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 übermitteln
  Server.send(200, "text/html", Seite);
}

void DatenHolen(int hostNo)
{
  WiFiClient client;
  String host = "";
 
  // Namen des Host zuweisen (host_1)
  if(hostNo == HOST_1) 
  {
    host = host_1;

    // wenn der Host nicht verbunden werden kann
    // zurück zur aufgerufenen Funktion
    if (!client.connect(host_1, 80)) return;
  }
  
  // Namen des Host zuweisen (host_2)
  if(hostNo == HOST_2) 
  {
    host = host_2;

    // wenn der Host nicht verbunden werden kann
    // zurück zur aufrufenden Funktion
    if (!client.connect(host_2, 80)) return;
  }

  /*
    GET-Anfrage senden
    /Messung -> Adresse (URL) für die zu übermittelnden Werte
    wird von den Klienten festgelegt
    host -> der jeweilige Klient
    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 zwischen den Abfragen der Klienten
  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
    if(Daten != "")
    {
      Messung[hostNo] = Daten;
      Serial.println(Daten);
    }
  }
}

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

ESP als Host

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

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

// Bibliothek für DHT einbinden
#include "DHT.h"

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

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

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

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

// IP des Klienten ESP als AP
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();

  // DHT starten
  dht.begin();
}

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

void SeiteBauen() 
{
  // Messwerte ermitteln
  // . durch , ersetzen
  String Temperatur = String(dht.readTemperature());
  Temperatur.replace(".", ",");
  
  // Seite zusammenbauen
  String Seite = Temperatur + "&degC";

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

Das Heim­netz verwenden

Das Pro­gramm für den zwei­ten Host unter­schei­det sich in Zei­le 26. Sie muss lauten:

IPAddress ip(192, 168, 4, 3);

Die Mikro­con­trol­ler sol­len direkt ins hei­mi­sche Netz ein­ge­bun­den wer­den. Hier­zu musst du die IP-Adres­se des Rou­ters fest­stel­len und dann die IP-Adres­sen der Mikro­con­trol­ler anpas­sen. Die­se müs­sen sich im glei­chen Adress­be­reich befin­den. Außer­dem musst du beach­ten, dass sich die­se Adres­sen außer­halb des Bereichs befin­den, das vom DHCP-Ser­ver des Rou­ters reser­viert ist. Die IP-Adres­sen der Kli­en­ten wer­den vom Rou­ter dyna­misch vergeben.

ESP als Ser­ver und Klient

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

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

#include "DHT.h"

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

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

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

#define HOST_1 0
#define HOST_2 1

// Router als AP
const char* host_1 = "192.168.1.7";
const char* host_2 = "192.168.1.8";

String Messung[2] = {"",""};
unsigned long Wartezeit = 15000;

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// MCU als Server und Klient
IPAddress ip(192, 168, 1, 6);

// IP-Adresse des Routers
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

// ESP8266
// ESP8266WebServer Server(80);

// ESP32
WebServer Server(80);

// farbiger Button mit CSS
String Seitenkopf =
  "<head><style>"

  // farbiger Button mit CSS
  ".farbigeBox {"
  "background-color: ivory;"
  "color: black;"
  "width: 450px;"
  "padding: 20px;"
  "text-align: left;"
  "font-size: 40px;"
  "font-family: arial;"
  "}"
  "</style>"

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

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

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

  // DHT starten
  dht.begin();
}

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

  // auf Anfragen warten
  Server.handleClient();

  // Messdaten einsammeln
  if ((millis() - Startzeit) > Wartezeit)
  {
    // Daten der Hosts einsammeln
    DatenHolen(HOST_1);
    DatenHolen(HOST_2);
    Startzeit = millis();
  }
}

void SeiteBauen() 
{
    // Messwert ermitteln
  // . durch , ersetzen
  String Temperatur = String(dht.readTemperature());
  Temperatur.replace(".", ",");
  
  // Seite zusammen bauen
  String Seite = "";
  Seite += Seitenkopf;
  Seite += "<h1 align=\"left\">Raumtemperatur</h1>";
  Seite += "<div align=\"left\";>";

  Seite += "<div class=\"farbigeBox\">";
  Seite += "Bad: ";
  Seite += Temperatur + "&deg;C";
  Seite += "<br>";
  Seite += "Wohnzimmer:";
  Seite += String(Messung[HOST_1]);
  Seite += "<br>";
  Seite += "Esszimmer:";
  Seite += String(Messung[HOST_2]);
  Seite += "</div>";

  // Button aktualisieren
  Seite += "<hr><input style=\"font-size:16pt; font-weight:bold;";
  Seite += "background-color:#55A96B;";
  Seite += "display:block; cursor:pointer;\"type=\"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.1.6'\" value=\"aktualisieren\">";
  Seite += "<hr>";
  
  // Seite übermitteln
  Server.send(200, "text/html", Seite);
}

void DatenHolen(int hostNo)
{
  WiFiClient client;
  String host = "";

  // Namen des Host zuweisen (host_1)
  if(hostNo == HOST_1) 
  {
    host = host_1;

    // wenn der Host nicht verbunden werden kann
    // zurück zur aufrufenden Funktion
    if (!client.connect(host_1, 80)) return;
  }
  
  // Namen des Host zuweisen (host_2)
  if(hostNo == HOST_2) 
  {
    host = host_2;

    // wenn der Host nicht verbunden werden kann
    // zurück zur aufgerufenen Funktion
    if (!client.connect(host_2, 80)) return;
  }

  /*
    GET-Anfrage senden
    /Messung -> Adresse (URL) für die zu übermittelnden Werte
    wird von den Klienten festgelegt
    host -> der jeweilige Klient
    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 zwischen den Abfragen der Klienten
  while (!client.available() && ((millis() - LetzteZeit) < 5000))
  {
    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
    if(Daten != "")
    {
      Messung[hostNo] = Daten;
      Serial.println(Daten);
    }
  }
}

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;

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

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

// Router als AP
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// IP des Klienten Router als AP
IPAddress ip(192, 168, 1, 8);

// IP-Adresse des Routers
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

// ESP8266
WebServer Server(80);

// ESP32
// WebServer Server(80);

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

  Server.on("/Messung", SeiteBauen);
  Server.begin();
  dht.begin();
}

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

void SeiteBauen() 
{
  // Messwerte ermitteln
  // . durch , ersetzen
  String Temperatur = String(dht.readTemperature());
  Temperatur.replace(".", ",");
  
  // Seite zusammen bauen
  String Seite = Temperatur + "&deg;C";

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

Quel­len


Letzte Aktualisierung: 10. Okt 2024 @ 10:08