Ziel des Projekts
- bis zu drei Mikrocontroller unabhängig von einem bestehenden Router in einem eigenen WLAN-Netz betreiben
alternativ: die Mikrocontroller in das vorhandenen WLAN einbinden - mit beliebigen Temperatursensoren (hier DHT11/DHT22) an bis zu drei verschiedenen Orten die Temperatur messen
- die ermittelten Messwerte in einem Webbrowser anzeigen
Die beiden Ansichten unterscheiden sich lediglich durch den verwendeten Netzwerkmodus und damit der verwendeten IP-Adresse:
links wird der ➨Stationsmodus, rechts der ➨Access-Point-Modus verwendet
Benötigte Bauteile
- ESP32-Mikrocontroller oder ESP8266-Mikrocontroller in beliebiger Kombination
- DHT11/DHT22 Temperatursensoren
- Leitungsdrähte
Konfiguration der Mikrocontroller
Netzwerkmodi der ESP-Mikrocontroller
Station-Modus
Station-Modus mit DHCP
Im Stations-Modus (STA) verwendet der Mikrocontroller das WLAN-Netz der Routers und erhält von dort eine IP-Adresse. Diese wird dynamisch zugewiesen, es kann jedes Mal eine andere sein (DHCP Dynamic Host Configuration 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
}
Stations-Modus mit statischer IP-Adresse
Für dieses Projekt wird aber eine statische IP-Adresse benötigt, sie soll ja im Klient aufgerufen 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 (Accesspoint-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
Aufbau des AP-Netzes
Das Schaubild zeigt den Aufbau des Netzes und die Kommunikation der Geräte untereinander. Ich habe einen ESP32-WROOM gewählt, du kannst aber auch eine beliebige Kombination von ESP32 oder ESP8266-Mikrocontrollern verwenden.
Der Mikrocontroller mit der IP 192.168.4.1 baut das WLAN-Netz auf und erhebt gleichzeitig auch Temperaturdaten. Die Mikrocontroller Host 1 und Host 2 messen ebenfalls die Temperatur. In regelmäßigen Abständen fragt der Server diese Messdaten ab. Die Klienten zeigen die Daten an.
Solltest du nur zwei Mikrocontroller zur Verfügung haben, kannst du das Programm leicht anpassen.
Manuelle Konfiguration des Klienten
Den Klienten werden keine IP-Adressen automatisch zugeteilt. Daher muss die Konfiguration händisch erledigt werden.
Zunächst musst du das als "ESPServer" angezeigte WLAN auswählen und anschließend die Konfiguration anpassen.
Wenn du mehrere Klienten verwenden willst, musst du jeweils eine andere IP-Adresse verwenden (z. B. 192.168.4.5). Die Adresse des Routers bleibt unverändert.
iOS
Android
Windows 10
ESP als Server und Klient
Ein ESP soll als Server die Daten der anderen ESPs einsammeln und gleichzeitig als Klient ebenfalls die Temperatur messen.
Daher wird für die IP-Adresse und das Gateway die gleiche 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 + "°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);
}
}
}
Darstellung der GET-Anfrage im Seriellen 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 + "°C";
// Seite übermitteln
Server.send(200, "text/html", Seite);
}
Das Heimnetz verwenden
Das Programm für den zweiten Host unterscheidet sich in Zeile 26. Sie muss lauten:
IPAddress ip(192, 168, 4, 3);
Die Mikrocontroller sollen direkt ins heimische Netz eingebunden werden. Hierzu musst du die IP-Adresse des Routers feststellen und dann die IP-Adressen der Mikrocontroller anpassen. Diese müssen sich im gleichen Adressbereich befinden. Außerdem musst du beachten, dass sich diese Adressen außerhalb des Bereichs befinden, das vom DHCP-Server des Routers reserviert ist. Die IP-Adressen der Klienten werden vom Router dynamisch vergeben.
ESP als Server 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 + "°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 + "°C";
// Seite übermitteln
Server.send(200, "text/html", Seite);
}
Quellen
- Tablet/Smartphone von Pixaline
- Router/Laptop: openclipart.org
- ESP32 von fritzing
- Beitrag von Wolfgang Ewald zu vernetzten Mikrocontrollern
- Espressif WiFi-API
Letzte Aktualisierung: