ESP8266 Webserver

Dein eigener ESP8266 Webserver

Der Microcontroller ESP8266 eignet sich nicht nur perfekt, um Daten aus dem Internet abzurufen und zu verarbeiten. Mit ein paar Zeilen Code baust du dir daraus deinen eigenen ESP8266 Webserver.

So kannst du mit deinem Smartphone oder Computer z.B. auf aktuelle Messdaten von Sensoren zugreifen, oder auch Bauteile an- und ausschalten – Internet of Things pur! 🙂

Weitere Bauteile findest du in unserem Online-Shop.

Der Code für deinen Webserver

Da ein Aufbau auf einem Breadboard bei diesem Projekt entfällt (du benötigst nur deinen Microcontroller), können wir gleich mit dem Sketch starten. Wenn du den ESP8266 bisher noch nicht verwendet hast, lies zunächst dieses Tutorial, um den ESP8266 mit der Arduino IDE programmieren zu können.

Die einzige Bibliothek, die du brauchst, ist die ESP8266WiFi.h – wenn du sie noch nicht installiert hast, hol das gleich in deinem Bibliotheksverwalter nach. Anschließend integrierst du sie ganz am Anfang deines Sketchs:

#include <ESP8266WiFi.h>

Ebenfalls noch vor der Funktion void Setup() hinterlegst du deine Zugangsdaten für dein WiFi-Netzwerk, legst den Port des Servers fest und definierst eine Variable:

// Daten des WiFi-Netzwerks
const char* ssid     = "Dein Netzwerkname";
const char* password = "Dein Passwort";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

// Variable für den HTTP Request
String header;

Grundlegende Informationen darüber, wie ein HTTP Request – also der Abruf von Daten von einem Server – funktioniert, kannst du in diesem Beitrag nachlesen.

Den ESP8266 Webserver mit dem WLAN verbinden

In der Setup-Funktion startest du den Seriellen Monitor und verbindest deinen Server mit dem Internet. Sobald die Verbindung steht, gibt er im Monitor die IP-Adresse aus – diese kannst du in einem Browser auf deinem Computer oder Smartphone wie eine normale Internet-Adresse aufrufen.

void setup() {
  Serial.begin(115200);

  // Mit dem WiFi-Netzwerk verbinden
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

Der Loop – Server aufrufen und Daten abrufen

Jetzt ist es soweit: Du rufst den ESP8266 Webserver in deinem Browser auf. Dieser empfängt deinen HTTP Request und antwortet darauf mit einer einfachen Webseite. Mit einer sehr einfachen Webseite, wie du gleich sehen wirst. 🙂

Zunächst benötigst du eine Zeile Code, die dafür sorgt, dass dein Server auf Clients (also Aufrufe) wartet:

WiFiClient client = server.available(); 

Wenn das der Fall ist, erscheint eine entsprechende Meldung im Seriellen Monitor. Anschließend benötigst du eine neue Variable für den Text, den der Client mit seinem Request sendet:

if (client) {                        
    Serial.println("Client available");
    String currentLine = "";     

Jetzt folgt ein While Loop, der dafür sorgt, dass sowohl dein Server den HTTP Request empfangen kann als auch eine Antwort an den Client senden kann. Die Anfrage des Clients speicherst du – Byte für Byte – einer Hilfsvariablen (c), die wiederum Stück für Stück die Variable header füllt, die du ganz am Anfang des Sketchs definiert hast.

Sobald ein Zeilenumbruch (\n) kommt und der Client anschließend eine Leerzeile sendet (currentLine. length() == 0), ist die Anfrage beendet. Zeit für eine Antwort!

while (client.connected()) { 

      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        header += c;

        if (c == '\n') {

          if (currentLine.length() == 0) {

Der ESP8266 Webserver antwortet und sendet das HTML für die Webseite

Bevor die Webseite in deinem Browser erscheint, erhält dieser zunächst eine Statusmeldung vom Server: 200 OK steht hierfür für den geglückten Request. Danach kommt die Information, welche Daten gleich gesendet werden, nämlich Text in Form von HTML: Content-type:text/html. Danach noch die Info, dass die Verbindung geschlossen wird, sobald der Request vollständig abgeschlossen wurde – und eine Leerzeile.

client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();

Endlich Zeit für die Webseite. Wie angekündigt ist diese sehr einfach, denn sie besteht nur aus einer einzigen Überschrift. Aber das reicht ja für den Anfang. 🙂

Überschriften sind in HTML hierarchisch geordnet und erhalten ein entsprechendes Tag – von H1 bis H6. Üblicherweise hat jede Webseite (genau) eine H1-Überschrift für den Titel der Webseite.

Die Überschrift steht zwischen dem öffnenden <h1> und dem schließenden HTML-Tag </h1>. Im öffnenden Tag bringst du allerdings noch die Information unter, dass der Text zentriert auf dem Bildschirm erscheinen soll: align=\”center\”.

Noch ein Hinweis: Die umgedrehten Schrägstriche (Backslashes) benötigst du im Code, um die Anführungszeichen zu “maskieren”. Ansonsten würde die Arduino IDE sie als Teil von C++ interpretieren statt als Text, der über die Funktion client.println() von deinem ESP8266 Webserver ausgegeben wird.

Möchtest du mehr über HTML und CSS wissen? In weiteren Verlauf dieses Projekts lernst du die Grundlagen eines schicken Interfaces für den Server.

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\"></head>");
client.println("<body><h1 align=\"center\">Hier spricht dein Server! :)</h1></body></html>");

Alles, was in deinem Sketch jetzt noch folgt, sind Abfragen für die Variable currentLine und etwas Code zum Beenden der Verbindung des Clients mit dem Server. Diese Zeilen findest du hier im vollständigen Sketch unten.

Der vollständige Sketch

// Library für WiFi-Verbindung
#include <ESP8266WiFi.h>

// Daten des WiFi-Netzwerks
const char* ssid     = "Dein Netzwerkname";
const char* password = "Dein Passwort";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

// Variable für den HTTP Request
String header;

void setup() {
  Serial.begin(115200);

  // Mit dem WiFi-Netzwerk verbinden
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop() {
  WiFiClient client = server.available();   // Auf Clients (Server-Aufrufe) warten

  if (client) {                             // Bei einem Aufruf des Servers
    Serial.println("Client available");
    String currentLine = "";                // String definieren für die Anfrage des Clients

    while (client.connected()) { // Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             // Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    // und es im Seriellen Monitor ausgeben
        header += c;
        if (c == '\n') {                    // bis eine Neue Zeile ausgegeben wird

          // Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            // Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\"></head>");
            client.println("<body><h1 align=\"center\">Hier spricht dein Server! :)</h1></body></html>");

            // Die Antwort mit einer Leerzeile beenden
            client.println();
            // Den Loop beenden
            break;
          } else { // Bei einer Neuen Zeile, die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  // alles andere als eine Leerzeile wird
          currentLine += c;      // der Variable hinzugefüht
        }
      }
    }
    // Variable für den Header leeren
    header = "";
    // Die Verbindung beenden
    client.stop();
    Serial.println("Client disconnected");
    Serial.println("");
  }
}

Erweitere deinen Webserver

Im Folgenden lernst, wie du mit deinem ESP8266 Webserver Geräte steuerst und die aktuelle Temperatur auf einer selbst erstellten Webseite ablesen kannst.

  • Einen Temperatursensor anschließen
  • Eine LED anschließen
  • Den Webserver einrichten und steuern
  • Wie warm ist es gerade?
  • Autoreload der Webseite
  • Die LED steuern
  • CSS und HTML für eine schönere Webseite
  • Eine feste IP-Adresse vergeben

EINEN TEMPERATURSENSOR ANSCHLIESSEN

Natürlich gibt es eine Vielzahl von Sensoren, deren Daten du über einen Webserver überprüfen kannst. Wir möchten hier jedoch den wohl beliebtesten Anwendungsfall beschreiben – Temperaturdaten.

Hierfür gibt es auf dem Markt einige günstige Sensoren, die immer wieder zum Einsatz kommen und die sich bewährt haben. Du kannst sie im Handumdrehen anschließen und dank der passenden Bibliotheken ebenso einfach die Temperatur messen.

Schauen wir uns drei der bekanntesten Sensoren an: Den BMP180, den GY-906, den DHT22 und DHT11.

DEN BMP180 ANSCHLIESSEN

Diesen Sensor schließt du per I²C an deinem ESP8266 an. Wie du hier siehst, benötigst du hierfür die Pins D1 und D2.

ESP8266 Pinout

Orientiere dich beim Aufbau an folgender Skizze:

Anschluss BMP180 am ESP8266

DIE PASSENDE BIBLIOTHEK

Neben der bereits vorinstallierten Bibliothek Wire (für die Kommunikation per I²C), benötigst du noch eine weitere, um die Daten des Sensors problemlos auslesen zu können.

Öffne also den Bibliotheksmanager in der Arduino IDE und suche nach BMP180. Du findest nun eine Bibliothek namens Adafruit BMP085 Library – das ist die richtige, auch wenn sie ein anderes Modell im Namen trägt. Der BMP085 war das Vorgängermodell des BMP180, was die Kommunikation angeht, jedoch mehr oder weniger baugleich.

Die richtige Bibliothek: Adafruit BMP085 Library

Installiere nun diese Bibliothek und schließe den Bibltiotheksmanager.

DIE TEMPERATUR MESSEN

Jetzt kann es mit der Messung auch schon losgehen. Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include <Wire.h>
#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;
 
void setup() {
  Serial.begin(115200);
  if (!bmp.begin()) {
Serial.println("Sensor nicht gefunden!");
while (1) {}
  }
}
 
void loop() {
    Serial.print("Temperatur = ");
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");
   
    Serial.println();
    delay(2000);
}

In deinem Seriellen Monitor sollten jetzt alle 2 Sekunden die Messwerte für die Temperatur in °C erscheinen. Sollte nichts erscheinen, überprüfe, ob die Baudrate im Sketch und im Seriellen Monitor übereinstimmt oder du SCL und SDA versehentlich verwechselt hast.

DEN GY-906 ANSCHLIESSEN

Im Prinzip schließt du diesen Sensor genauso an wie den BMP180 – er kommuniziert ebenfalls über I²C. Die Skizze für den Anschluss sieht also ganz ähnlich aus:

DIE PASSENDE BIBLIOTHEK

Auch für den GY-906 gibt es eine Bibliothek, die dir das Leben einfacher macht. Suche im Bibliotheksmanager nach Adafruit_MLX90614 und installiere die aktuelle Version.

MLX90614 bezieht sich auf den Sensor selbst – GY-906 ist hingegen die Bezeichnung des ganzen Bauteils.

DIE TEMPERATUR MESSEN

Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include <Adafruit_MLX90614.h>
#include <Wire.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

void setup() {
  Serial.begin(115200);
  mlx.begin(); 
}

void loop() {
  Serial.print("Umgebung = "); Serial.print(mlx.readAmbientTempC());
  Serial.print("*C\tObjekt = "); Serial.print(mlx.readObjectTempC());       
  Serial.println("*C");

  Serial.println();
  delay(2000);
}

Wie du siehst, bindest du zu Beginn des Sketchs die Bibliotheken für den Sensor und die Kommunikation per I²C ein. Anschließend erstellst du ein Objekt der Bibliothek mit dem Namen mlx.

Sicherlich weißt du, dass der GY-906 eine Besonderheit hat (was ihn auch etwas teurer als andere Sensoren macht): Er misst nicht nur die Umgebungstemperatur, sondern per Infrarot auch jene von Objekten.

Deshalb befinden sich im Sketch zwei Abfragen – eine für die Temperatur um den Sensor herum – mlx.readAmbientTempC() – und eine für das Objekt “vor seiner Nase” – mlx.readObjectTempC. Welche Temperatur später bei deinem Webserver zum Einsatz kommen soll, ist natürlich dir überlassen.

DEN DHT22 ANSCHLIESSEN

Etwas aufwändiger ist der Anschluss des Sensors DHT22, denn hierfür benötigst du einen 10 kΩ Widerstand. Orientiere dich beim Anschluss an dieser Skizze:

Anschluss DHT22 am ESP8266

DIE PASSENDEN BIBLIOTHEKEN

Für den DHT22 musst du zwei Bibliotheken installieren, von denen du jedoch nur eine im Sketch einbinden musst. Öffne deinen Bibliotheksmanager. Suche dort zunächst nach Adafruit Unified Sensor und installiere die aktuelle Version. Die Versionsnummer in den folgenden Screenshots können abweichen.

Suche anschließend nach DHT22 und installiere die Bibliothek DHT sensor library.

DHT Sensor Library

DIE TEMPERATUR MESSEN

Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include "DHT.h"

#define DHTPIN 4  
#define DHTTYPE DHT22

float temp;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {

  temp = dht.readTemperature();
 
  Serial.print("Temperatur: ");
  Serial.print(temp);
  Serial.println("*C");

  Serial.println();
  delay(2000);

}

Nachdem du die Bibliothek eingebunden hast, legst du den Pin fest, an dem der DHT22 angeschlossen ist. In unserem Sketch ist das der Pin 4. Der Sensor ist allerdings am ESP8266 an Pin D2 angeschlossen. Wieso dann die unterschiedlichen Zahlen?

Scrolle noch einmal nach oben zum Pin-Diagramm des ESP8266. Wie du dort sehen wirst, entspricht der Pin D2 dem GPIO 4 – diese Ziffer kommt im Sketch zum Einsatz.

In der nächsten Zeile legst du das Modell des Sensors fest – in unserem Fall also ein DHT22. Anschließend erstellst du ein Objekt der Bibliothek names dht, das später bei der Messung mit der Funktion dht.readTemperature() zum Einsatz kommt.

Der Rest des Sketchs dürfte für dich kein Problem sein. Achte jedoch darauf, dass die Baudrate von Sketch und Seriellem Monitor übereinstimmt.

DEN DHT11 ANSCHLIESSEN

Der Sensor DHT11 ist so etwas wie der “kleine Bruder” des DHT22. Er hat einen kleineren Messbereich und ist auch etwas ungenauer. Trotzdem ist er gerade bei Einsteigern beliebt. Und leichter anzuschließen ist er auch:

In obigen Beispiel-Sketch musst du für den DHT11 nur eine Zeile anpassen:

#define DHTTYPE DHT11

EINE LED ANSCHLIESSEN

Im vorangegangenen Abschnitt hast du einen Temperatursensor angeschlossen, dessen Messdaten du später über deinen Webserver auslesen wirst. Aber so ein Webserver soll natürlich keine Einbahnstraße sein: Ebenso hast du die Möglichkeit, an deinen ESP8266 ein Gerät anzuschließen, das du vom Smartphone aus steuerst.

Hier sind deiner Phantasie kaum Grenzen gesetzt. Vielleicht möchtest du die Rollläden hoch- und herunterlassen oder die Heizung an- und ausschalten. Oder einfach nur das Licht.

In diesem Abschnitt und im weiteren Verlauf des Kurses beschäftigen wir uns mit einem “Gerät”, das du sicherlich schon oft verwendet hast: eine LED. 🙂 Erweitere also zunächst dein Projekt auf dem Breadboard um eine LED samt Vorwiderstand. Orientiere dich hierbei an folgender Skizze:

ESP8266 mit BMP180 und LED

Als Beispiel soll uns eine rote Standard-LED mit einer Spannung von 2,3 V und 20 mA Stromfluss dienen. Da dein ESP8266 3,3 V “liefert”, ergibt sich hieraus ein Vorwiderstand von 51 Ω.

Verbinde die Anode (langes Bein) der LED mit dem Pin D7 des ESP8266, damit du sie mit den späteren Sketches dieses Kurses ohne Bearbeitungen steuern kannst. Die Kathode kommt mit dem Vorwiderstand dazwischen an GND.

Hast du eine andere LED im Sinn? Mit diesem Rechner kannst du den richtigen Vorwiderstand berechnen.

SO STEUERST DU “GROSSE” GERÄTE

Die LED in diesem Abschnitt dient natürlich nur dem Verständnis. Sicherlich möchtest du stattdessen Geräte steuern, die mit 230 Volt versorgt werden. Auch das kannst du mit deinem ESP8266 umsetzen – allerdings benötigst du hierfür ein Relais.

Achte beim Kauf darauf, dass dieses mit den 3,3 V des ESP8266 funktioniert. Viele der erhältlichen Relais benötigen 5 V. Solltest du einen Wemos D1 Mini verwenden, kannst du sogar ein praktisches Relais-Shield darauf montieren.

Damit hast du die Grundlagen abgeschlossen. In den nächsten Abschnitten beschäftigen wir uns mit dem eigentlichen Webserver.

DEN WEBSERVER EINRICHTEN UND STEUERN

WAS IST EIN SERVER?

Was ist eigentlich ein Server und was macht er? Lass uns dieses Thema zunächst ganz kurz betrachten.

Ein Server ist ein Computer – oder in unserem Fall ein Microcontroller – der von einem anderen Computer Anfragen nach Informationen erhält. Diese Anfragen bearbeitet er und wenn er die angeforderten Informationen besitzt, sendet er sie zurück an den Client.

Funktion eines Servers

In diesem Projekt dient bekanntlich dein ESP8266 als Server. Dein Client kann dann zum Beispiel das Gerät sein, auf dem du diesen Text gerade liest – also ein PC, Laptop, Tablet oder Smartphone.

Informationen können dann zum Beispiel “bloße” Messdaten sein oder auch eine Webseite, die diese Messdaten enthält.

Aber nicht nur das: Dein Webserver kann ebenso Befehle erhalten, die deinen ESP8266 dann etwas steuern lassen. So kannst du zum Beispiel die im vorherigen Abschnitt erwähnte LED an- oder ausschalten. Den neuen Status der LED (also AN oder AUS) kannst du dir dann zurücksenden lassen.

In den folgenden Abschnitten tasten wir uns langsam an dieses Thema heran. Zunächst starten wir, wie man jedes ordentliche Projekt startet: Mit einem “Hello world!” Danach fragen wir die Temperatur als blanke Zahl ab. Anschließend hübschen wir diese Messdaten mithilfe von HTML auf und bauen uns ein Interface.

Zuletzt wirst du selbst aktiv und schaltest das Licht über dieses Interface an und aus.

Los geht’s! 🙂

HELLO WORLD!

Zeit, um mit unserem Webserver zu beginnen. Zunächst lassen wir den Temperatursensor und die LED noch links liegen. Stattdessen stellt dein ESP8266 auf Anfrage eine Website bereit, die erst einmal nichts als ein einfaches “Hello World” enthält.

Hello World

Damit du diese Webseite aufrufen kannst, teilt dir dein ESP8266 im Seriellen Monitor die IP-Adresse mit, die du in einem Browser deiner Wahl aufrufen kannst.

Hinweis: Beachte bitte, dass du auf deinen Webserver nur zugreifen kannst, wenn sich dein Client im gleichen WLAN-Netzwerk befindet wie dein ESP8266. Darüber, wie du von überall auf der Welt auf deinen Server zugreifen kannst – und ob du das überhaupt solltest, sprechen wir am Ende dieses Artikels.

DER ANFANG DES SKETCHS

Du hast sicherlich schon gelernt, wie du deinen ESP8266 mit dem Internet verbindest. Ohne Netzwerk kein Server – deshalb benötigen wir auch in allen folgenden Sketches dieses Kurses eine Verbindung zu deinem WLAN.

Hier noch einmal in aller Kürze. Diesen Code benötigst du am Anfang des Sketchs:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Zugangsdaten zu deinem WLAN-Netzwerks
const char* ssid     = "SSID";
const char* password = "PASSWORT";

Anschließend legst du den Port deines Webservers auf 80 fest. Dieser Port ist der Teil der Netzwerk-Adresse, an der dein Webserver auf eingehende Anfragen von Clients wartet.

//Port des Webservers auf 80 setzen
WiFiServer server(80);

DAS SETUP

Hier startest du zuerst den Seriellen Monitor. Achte später darauf, dass du dort dieselbe Baudrate eingestellt hast wie im Sketch.

Serial.begin(115200);

Anschließend stellt dein ESP8266 die Verbindung zu deinem WLAN-Netzwerk her:

WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

Da dein ESP8266 nun mit dem Netzwerk verbunden ist, hat er dort auch eine IP-Adresse. Diese benötigst du später, um eine Anfrage an den Server zu schicken. Damit du weißt, wie sie lautet, gibst du sie im Seriellen Monitor aus und startest danach den Server:

Serial.println("IP-Adresse: ");
Serial.println(WiFi.localIP());
 
server.begin();

DER LOOP

Die bisherigen Einstellungen und Funktionen waren noch recht überschaubar. Im Loop findet nun die gesamte Kommunikation zwischen Server und Client statt.

Zunächst benötigen wir eine Zeile Code, mit der der ESP8266 nach eingehenden Anfragen “horcht”:

WiFiClient client = server.available();

Ob eine Anfrage eintrifft, fragst du mit einem If-Statement ab:

if (client) {

Nur dann – also wenn du die IP-Adresse in deinem Browser aufrufst – wird der weitere Code in void loop() ausgeführt. Zunächst gibst du eine entsprechende Meldung im Seriellen Monitor aus und erstellst einen String, in dem du die ankommenden Daten der Anfrage zeilenweise speicherst und prüfen wirst, ob sie zu Ende ist.

Serial.println("Anfrage von Client erhalten.");
String currentLine = ""; 

Solange der Client mit dem Server verbunden ist und Daten von ihm “reinkommen”, speicherst du diese Byte für Byte in der Variablen c und gibst sie im Seriellen Monitor aus.

while (client.connected()) {

  if (client.available()) {
    char c = client.read();
    Serial.write(c);

Dort kannst du die Anfrage Zeile für Zeile nachverfolgen. Apropos Zeilen: Interessant sind hier die Zeilenumbrüche und Leerzeilen. Wenn dein Server das Zeichen für eine New Line \n erhält, prüfst du, ob die Anfrage zu Ende ist.

Das ist etwas kompliziert, denn eine Anfrage endet immer mit einer Leerzeile, was nicht nur einem \n, sondern der Zeichenkombination \n\n entspricht. Aber eins nach dem anderen. Zunächst prüfst du ob ein \n hereinkommt:

if (c == '\n') {

oder etwas anderes außer einem Carriage Return \r. All diese “anderen” Bytes (also alles außer \n und \r) speicherst du in deiner Variablen für die aktuelle Zeile currentLine.

else if (c != '\r') {
  currentLine += c;
  }

Wenn das aktuelle Byte c der Anfrage jedoch \n lautet, greift das oben erwähnte If-Statement. Gleich danach folgt eine weitere Prüfung, ob die Variable currentLine einen Inhalt hat:

if (currentLine.length() == 0) {

Ist das nicht der Fall, kam offensichtlich noch kein \n\n – also noch keine Leerzeile. Deshalb wird die Variable currentLine wieder gelöscht und der Sketch springt zurück zur nächsten Zeile der Anfrage des Clients:

else {
  currentLine = "";
  }

Wenn jetzt jedoch wieder ein \n kommt, haben wir unsere Leerzeile – oder anders gesagt: Die Anfrage des Clients ist zu Ende! Dieses Prozedere mit den verschiedenen Schleifen ist auf den ersten Blick recht kompliziert – nimm dir deshalb ruhig Zeit und verfolge die Durchgänge im gesamten Sketch.

DER SERVER ANTWORTET

Nun ist also der Server mit seiner Antwort an den Client dran. Da mit deinem ESP8266 Webserver alles in Ordnung ist, lässt du ihn mit einem entsprechenden Status-Code antworten – nämlich 200:

client.println("HTTP/1.1 200 OK");

Es folgen Informationen zur Art des Contents, der gleich geliefert wird und darüber, dass der Server die Verbindung zum Client kappen wird, sobald er mit seiner Antwort fertig ist. Gefolgt von einer Leerzeile:

client.println("Content-type:text/html");
client.println("Connection: close");
client.println();

Nun kommt endlich unser “Hello world!”. Und zwar als HTML:

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
client.println("<body><h1 align=\"center\">Hello world!</h1></body></html>");

Sehr reduziertes HTML – abgesehen vom <head> befindet sich im <body> nur eine in deinem Browser zentrierte Überschrift <h1> mit unserer Nachricht.

Später erfährst du mehr über HTML ein und baust dir damit ein ansprechendes Interface, über das du mit deinem ESP8266 interagieren kannst.

An dieser Stelle war es das jedoch. Fast. Fehlt nur noch das Ende der Verbindung und eine Info hierüber in deinem Seriellen Monitor:

client.stop();
Serial.println("Verbindung beendet.");
Serial.println("");

Hier noch einmal der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Daten deines WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Dein WLAN-Passwort";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  // Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             // Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    // und es im Seriellen Monitor ausgeben
        if (c == '\n') {                    // bis eine Neue Zeile ausgegeben wird

          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
            client.println("<body><h1 align=\"center\">Hello world!</h1></body></html>");

            //Die Antwort beenden
            client.println();
            //Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile) die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefügt
        }
      }
    }
    //Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

WIE WARM IST ES GERADE?

Im letzten Abschnitt hast du einen Webserver in seiner einfachsten Form erstellt und ein einfaches Hello world! auf einer ebenso einfachen Webseite ausgegeben.

Lass uns nun einen Schritt weiter gehen. In diesem Abschnitt ermittelst du mithilfe deines Sensors die aktuelle Raumtemperatur. Wenn du die die IP-Adresse des Servers aufrufst erscheint diese dann auf der Webseite.

Die aktuelle Temperatur

PASSE DEN SKETCH AN

Die gute Nachricht: Du kannst den Großteil des Sketchs aus dem letzten Abschnitt einfach übernehmen. Hinzufügen musst du lediglich etwas Code für die Messung der Temperatur. Ebenso bedarf es ein paar Anpassungen der Webseite, die dein Server an deinen Client übermittelt.

Zunächst zur Temperatur. In diesem Abschnitt arbeiten wir weiter mit dem Sensor BMP180. Füge zu Beginn des Sketchs folgende Zeilen hinzu:

#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

Mit der ersten Zeile integrierst du die Bibliothek für den Sensor. Die zweite erstellt das Objekt bmp. Anschließend benötigen wir noch eine Variable für die gemessene Temperatur.

Im Setup prüfst du, ob der Sensor verfügbar ist. Ist das nicht der Fall, begibt sich dein Sketch in eine Endlosschleife und wird nicht weiter ausgeführt:

if (!bmp.begin()) {
  Serial.println("Sensor nicht gefunden!");
  while (1) {}
}

Wir gehen natürlich davon aus, dass das nicht der Fall ist. Deshalb folgt nun die eigentliche Messung. Diese integrierst du im Loop – mitten in der Antwort des Servers an den Client. Das hat den Vorteil, dass du immer die aktuelle Temperatur erhältst, sobald du eine neue Anfrage stellst, also zum Beispiel einen Refresh im Browser machst.

temp = bmp.readTemperature();
Serial.print("Temperatur = ");
Serial.print(temp);
Serial.println(" *C");

ETWAS MEHR HTML FÜR DEINE WEBSEITE

Jetzt musst du nur noch die Antwort des Servers – also die Webseite etwas anpassen. Zunächst fügst du dem <head> der Webseite die Zeichencodierung UTF-8 hinzu, damit das Grad-Zeichen ° korrekt dargestellt wird:

client.println("<meta charset=\"utf-8\"></head>");

Anschließend ersetzt du Headline Hello world! durch Die aktuelle Temperatur und fügst direkt darunter einen neuen Absatz hinzu, der den Messwert deines Temperatursensors in der Variablen temp enthält:

client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>")
client.println("<p align=\"center\">");
client.println(temp);
client.println("°C</p>");
client.println("</body></html>");

TESTE DEINE NEUE WEBSEITE

Den gesamten Sketch findest du oben im Reiter Downloads. Lade ihn auf deinen ESP8266 und rufe die die IP-Adresse im Browser auf. Siehst du die aktuelle Temperatur?

Teste auch, ob sich die Temperatur verändert, wenn du deinen ESP8266 samt Sensor an einen anderen Ort stellst und eine neue Anfrage schickst.

Im nächsten Abschnitt integrierst du eine Funktion, die dir die “Arbeit” abnimmt – statt manuell die Webseite zu aktualisieren macht sie das von alleine.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    //und es im Seriellen Monitor ausgeben
        if (c == '\n') {                    //bis eine Neue Zeile ausgegeben wird

          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\"></head>");
            client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>");
            client.println("<p align=\"center\">");
            client.println(temp);
            client.println("°C</p>");
            client.println("</body></html>");

            //Die Antwort beenden
            client.println();
            // Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile), die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    // Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

AUTORELOAD DER WEBSEITE

Wie wäre es, wenn du die Webseite mit der Antwort des Servers nicht selbst neu laden müsstest, um die aktuelle Temperatur zu erfahren? Kein Problem!

In diesem Abschnitt lernst du zwei Methoden kennen, die genau das für dich übernehmen.

AUTOREFRESH MIT EINEM META-TAG

Die erste Methode erfordert nur eine kleine Anpassung im HTML der Antwort deines Servers. Erweitere einfach den Head des HTML um folgende Information:

<meta http-equiv=\"refresh\" content=\"5\">

Der gesamte Head sollte dann wie folgt aussehen:

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta charset=\"utf-8\"><meta http-equiv=\"refresh\" content=\"5\"></head>");

Jetzt lädt deine Webseite alle 5 Sekunden neu – und stellt somit eine neue Anfrage an deinen ESP8266, der daraufhin die Temperatur ermittelt und zurückgibt.

Das funktioniert im Prinzip ganz gut – allerdings kannst du damit einen Refresh höchstens einmal pro Sekunde ausführen. Wenn du häufigere Anfragen möchtest, um deine Daten quasi in Echtzeit zu erhalten, eignet sich ein kleines Script besser.

AUTOREFRESH MIT JAVASCRIPT

Mit dem folgenden Script kannst du deine Webseite häufiger als einmal pro Sekunde neu laden – theoretisch sogar jede tausendstel Sekunde. Das wäre jedoch sicherlich etwas zu viel des Guten.

Füge also statt des Meta-Tags von oben folgendes Script deinem Head hinzu:

<script>
  function refresh(refreshPeriod)
  {
      setTimeout('location.reload(true)', refreshPeriod);
  }
  window.onload = refresh(5000);
</script>

Der Head sollte dann in deinem Sketch so aussehen:

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta charset=\"utf-8\">");
client.println("<script>function refresh(refreshPeriod){setTimeout('location.reload(true)', refreshPeriod);}");
client.println("window.onload = refresh(500);</script></head>");

Jetzt aktualisiert sich deine Webseite alle 500 Millisekunden von alleine. Diese Information findest du in refresh(500) – probiere es gleich einmal aus und ersetze diesen Wert durch andere. Siehst du, wie schnell sich die Temperatur im Browser verändert (vorausgesetzt sie verändert sich wirklich um deinen Sensor herum)?

DIE LED STEUERN

Du kannst nun also die aktuelle Raumtemperatur auf der Webseite sehen, die dein Server dir unter seiner IP-Adresse zur Verfügung stellt. Wie wäre es, wenn du von dort aus auch das Licht – also deine LED – ein- und ausschalten könntest? Genau das setzen wir jetzt um.

Zunächst benötigen wir etwas Code für die LED. Zu Beginn des Sketchs legst du den Pin fest, an dem sie angeschlossen ist. Wir bleiben hier bei Pin D7 – den wir im Sketch mit der Zahl 13 ansteuern. Ebenso benötigen wir eine Variable für den Status der LED, also ob sie an oder aus ist:

const int led = 13;
String ledState = "aus";

Falls du noch nicht mit den verschiedenen Pins des ESP8266 und der Unterschiede in ihrer Bezeichnung vertraut bist, wirf einen kurzen Blick auf folgende Skizze. Hier findest du die wichtigsten Pins und ihre Nummer, mit der du sie in deinem Sketch ansteuerst.

ESP8266 Pinout

Im Setup des Sketchs legst du nun noch schnell den pinMode fest und schaltest die LED zu Beginn aus, so wie du es oben in der Variablen ledState auch festgehalten hast.

pinMode(led, OUTPUT);
digitalWrite(led, LOW);

Wie kannst du nun die LED von der Webseite aus an- und ausschalten? Hierfür bringst du dort zunächst einen Link unter, der deinen Befehl weiterleitet. Wenn die LED aus ist (also ledState auf “aus” steht), lautet der Ankertext des Links ANSCHALTEN. Wenn sie an ist entsprechend AUSSCHALTEN.

if (ledState == "aus") {
  client.println("<p align=\"center\"><a href=\"/led/on\">ANSCHALTEN</a></p>");
} else {
  client.println("<p align=\"center\"><a href=\"/led/off\">AUSSCHALTEN</a></p>");
  }

Ein kurzer Exkurs zu HTML: Ein Link wird hier mit dem Tag <a> begonnen und mit </a> wieder geschlossen. Zwischen diesen beiden Tags befindet sich der Ankertext, also das Wort, das du anklicken kannst.

Das Ziel des Links befindet sich im öffnenden Tag <a> hinter href= und wird mit Anführungsstrichen markiert. Im Code oben heißt das Linkziel also entweder “/led/on” oder “/led/off”.

Übrigens, sind dir die umgedrehten Schrägstriche (Backslashes) aufgefallen? Diese benötigst du in deinem Sketch, um die Anführungszeichen zu maskieren. Ansonsten würde z.B. im Befehl client.println() oben zu viele Anführungszeichen stehen, was unweigerlich zu einem Fehler führen würde.

Wenn du die IP-Adresse deines Servers nun aufrufst, sieht du folgende Webseite:

Aber noch einmal zurück zum Linkziel: Wenn du also den Link ANSCHALTEN klickst, wird “/led/on” hinter die IP-Adresse des Servers geschrieben, sodass sie z.B. so lautet:

http://192.168.0.242/led/on

Das können wir uns zunutze machen, wenn dein Server die Anfrage des Clients liest.

DEINEN BEFEHL IM HEADER AUSLESEN

Wie du ja bereits weißt, sendet dein Client eine ganze Reihe Informationen an deinen Server, wenn er eine Anfrage an ihn stellt. Nach deinem Klick auf den Link auch den Befehl /led/on bzw. /led/off.

Um diese Befehle zu empfangen, benötigst du zunächst zu Beginn des Sketchs eine gleichnamige Variable für den Header:

String header;

Wenn eine Anfrage reinkommt, verwendest du ja bereits die Variable c, um zu ermitteln, wann die Anfrage zu Ende ist. Hier integrierst du nun auch deinen String header, den du mit den übertragenen Daten füllst:

if (client.available()) {
  char c = client.read();
  Serial.write(c);
  header += c;
  if (c == '\n') {

Nun befindet sich im String header (nach deinem Klick auf den Link) entweder der Befehl /led/on oder /led/off.

Um herauszufinden welcher, machst du eine kleine Abfrage:

if (header.indexOf("GET /led/on") >= 0) {
  Serial.println("Die LED ist an");
  ledState = "an";
  digitalWrite(led, HIGH);
} else if (header.indexOf("GET /led/off") >= 0) {
  Serial.println("Die LED ist aus");
  ledState = "aus";
  digitalWrite(led, LOW);
}

Hier benutzt du die Funktion indexOf() – diese prüft, ob sich ein bestimmter String (hier z.B. “GET /led/on”) in einem anderen String befindet. Ist das nicht der Fall, ist ihr Ergebnis -1. Wenn sie ihn jedoch findet, gibt sie seine Position zurück. Diese ist uns eigentlich egal, Hauptsache das Ergebnis ist nicht -1, sondern >= 0. 🙂

Wenn du also die LED mit einem Klick angeschaltet hast, steht im header der String “GET /led/on”. In diesem Fall schaltest du die LED mit digitalWrite() an und setzt die Variable ledState auf “an”.

Das wiederum verändert den Ankertext des Links: Dieser wechselt von ANSCHALTEN auf AUSSCHALTEN. Und damit wirklich klar ist, was Sache ist, schreibt dein Server noch den Status der LED über den Link:

client.println("<p align=\"center\">Die LED ist " + ledState + ".</p>");

Und das war es auch schon. Probiere es gleich mal aus. Kannst du die LED über die Webseite an- und ausschalten?

Im nächsten Abschnitt hübschst du die Webseite etwas auf.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

//String für den Header
String header;

//Pin und Status der LED
const int led = 13; //Pin D7 am ESP8266
String ledState = "aus";


void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);
        header += c;
        if (c == '\n') {


          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //die Led an- und ausschalten
            if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("Die LED ist an");
              ledState = "an";
              digitalWrite(led, HIGH);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("Die LED ist aus");
              ledState = "aus";
              digitalWrite(led, LOW);
            }

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            //Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\"></head>");
            client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>");
            client.println("<p align=\"center\">");
            client.println(temp);
            client.println("°C</p>");

            client.println("<p align=\"center\">Die LED ist " + ledState + ".</p>");

            if (ledState == "aus") {
              client.println("<p align=\"center\"><a href=\"/led/on\">ANSCHALTEN</a></p>");
            } else {
              client.println("<p align=\"center\"><a href=\"/led/off\">AUSSCHALTEN</a></p>");
            }

            client.println("</body></html>");

            //Die Antwort beenden
            client.println();
            //Den Loop beenden
            break;
          } else { // Bei einer neuen Zeile (keine Leerzeile), die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    //Variable header leeren
    header = "";
    // Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

CSS UND HTML FÜR EINE SCHÖNERE WEBSEITE

Du hast nun eine einfache Webseite, auf der du die aktuelle Temperatur siehst und die LED steuern kannst. Allerdings sieht sie sehr nach den Anfängen des World Wide Webs aus. Lass uns also ein paar Minuten Zeit investieren und sie etwas aufmöbeln.

Am Ende dieses Abschnitts sieht deine Webseite folgendermaßen aus:

Webseite mit neuem Layout

Du siehst zwei Karten – eine für die Temperatur und eine für die Steuerung der LED. Statt eines einfachen Links befindet sich auf letzterer ein Button. Beachte bitte, dass sich das Aussehen des Buttons je nach Browser verändern kann.

DAS CSS

Bisher haben wir kaum CSS (Cascading Style Sheets) verwendet. Das ändert sich jetzt, aber keine Angst – es hält sich trotzdem im Rahmen. 🙂 Folgende Informationen benötigen wir für die Webseite:

<style>
    html {
      font-family: Helvetica;
    }

    h1,
    p {
      text-align: center;
    }

    a {
      color: black;
      text-decoration: none;
    }

    div {
      margin: 10px auto 10px auto;
      padding: 10px;
      height: 80px;
      width: 200px;
      background-color: aliceblue;
      border: 1px solid lightgray;
    }
  </style>

Allerdings ahnst du es vielleicht bereits, diese Informationen zum Styling der Webseite musst du im Sketch etwas anders unterbringen – nämlich so wie du es mit den anderen HTML-Tags auch gemacht hast: Innerhalb der verschiedenen client.println() Funktionen. Achte bitte darauf, folgende Zeilen noch vor dem schließenden </head> Tag unterzubringen.

client.println("<style>");
client.println("html { font-family: Helvetica;} h1, p {text-align: center;}");
client.println("a { color: black; text-decoration: none;}");
client.println("div { margin: 10px auto 10px auto; padding: 10px; height: 80px; width: 200px; background-color: aliceblue; border: 1px solid lightgray;}");
client.println("</style>");

DAS HTML

Den Head der Webseite hast du nun um das neue Styling erweitert. Nun kommt der Body dran. Folgendes HTML musst du hier integrieren:

<div>
  <p>Raumtemperatur</p>
  <p> (temp) </p>
</div>
<div>
  <p>LED</p>
  <button style="margin-left:50px;"><a href="/led/on">ANSCHALTEN</a>
  </button>
  <button style="margin-left:45px;"><a href="/led/off">AUSSCHALTEN</a>
  </button>
</div>

Die Variable temp siehst du im obigen Code fett gedruckt – dort dient sie nur als Erinnerung, dass sie dort hinein muss. In deinem Sketch sieht dieses HTML dann so aus:

client.println("<body><div><p>Raumtemperatur</p>");
client.println("<p>");
client.println(temp);
client.println("°C</p></div>");

client.println("<div><p>LED</p>");

if (ledState == "aus") {
  client.println("<button style=\"margin-left:50px;\"><a href=\"/led/on\">ANSCHALTEN</a></button>");
} else {
  client.println("<button style=\"margin-left:45px;\"><a href=\"/led/off\">AUSSCHALTEN</a></button>");
}

client.println("</div></body></html>");

Wie du siehst, befindet sich hier wieder die If-Abfrage, die je nachdem, ob die LED an oder aus ist, einen anderen Button ausspielt. Das Styling für die Buttons – genauer gesagt ihre Abstände nach links – befinden sich direkt im <button> Tag. Achte in diesem Fall bitte auf die korrekte Maskierung der Anführungsstriche mit dem Backslash \.

Und das war es schon. Lade den Sketch mit dem aktualisierten CSS und HTML auf deinen ESP8266 und schau dir deine neue Webseite gleich einmal an.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

//String für den Header
String header;

//Pin und Status der LED
const int led = 13; //Pin D7 am ESP8266
String ledState = "aus";


void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   // uf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);
        header += c;
        if (c == '\n') {


          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //die Led an- und ausschalten
            if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("Die LED ist an");
              ledState = "an";
              digitalWrite(led, HIGH);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("Die LED ist aus");
              ledState = "aus";
              digitalWrite(led, LOW);
            }

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\">");
            client.println("<style>");
            client.println("html { font-family: Helvetica;} h1, p {text-align: center;}");
            client.println("a { color: black; text-decoration: none;}");
            client.println("div { margin: 10px auto 10px auto; padding: 10px; height: 80px; width: 200px; background-color: aliceblue; border: 1px solid lightgray;}");
            client.println("</style>");
            client.println("</head>");
           
            client.println("<body><div><p>Raumtemperatur</p>");
            client.println("<p>");
            client.println(temp);
            client.println("°C</p></div>");

            client.println("<div><p>LED</p>");
            if (ledState == "aus") {
              client.println("<button style=\"margin-left:50px;\"><a href=\"/led/on\">ANSCHALTEN</a></button>");
            } else {
              client.println("<button style=\"margin-left:45px;\"><a href=\"/led/off\">AUSSCHALTEN</a></button>");
            }

            client.println("</div></body></html>");

            //Die Antwort beenden
            client.println();
            // Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile) die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    //Variable header leeren
    header = "";
    //Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

EINE FESTE IP-ADRESSE VERGEBEN

Wechselt die IP-Adresse deines ESP8266 nach jedem Neustart? Das kannst du leicht beheben, indem du ihm in deinem eine feste IP zuweist. Hierfür benötigst du nur ein paar Zeilen Code.

Hinweis: Die IP-Adresse, die du verwenden möchtest, muss in deinem Netzwerk natürlich noch verfügbar sein und sich im entsprechenden Gateway befinden.

Nehmen wir an, dein ESP8266 hat bisher die Adresse 192.168.0.242 zugewiesen bekommen und ist darunter erreichbar. Du möchtest diese nun jedoch manuell auf 192.168.0.171 festlegen.

Feste IP-Adresse im Seriellen Monitor

Um diese IP-Adresse festzulegen, füge deinem Sketch noch vor der Setup-Funktion folgende Zeilen hinzu. Hier legst du die IP-Adresse 192.168.0.171 im Gateway 192.168.0.1 fest:

IPAddress local_IP(192, 168, 0, 171);
IPAddress gateway(192, 168, 0, 1);

IPAddress subnet(255, 255, 0, 0);

Innerhalb der Setup-Funktion verwendest du diese Daten nun für die Konfiguration. Achte hierbei darauf, folgende Zeile noch vor der Funktion WiFi.begin() unterzubringen:

WiFi.config(local_IP, gateway, subnet);

Nach dem Upload besitzt dein ESP8266 nun die oben festgelegte IP-Adresse in deinem Netzwerk. Möchtest du mehr über dieses Thema wissen? In diesem Wiki-Beitrag erfährst du mehr.

HINWEISE ZUR IT-SICHERHEIT

Zum Ende möchten wir noch auf ein wichtiges Thema hinweisen: IT-Sicherheit.

Den Webserver, den du gebaut hast, kannst du zunächst nur aus deinem eigenen WLAN-Netzwerk ansteuern. Und das ist auch erstmal ganz gut so. Denn so können nur Menschen mit dem passenden Schlüssel auf die Daten des Servers zugreifen – vorausgesetzt dein WLAN-Netzwerk ist sicher.

Zunächst möchten wir dich darauf hinweisen, dass die gängigen ESP8266-Module nur für Hobbyprojekte ausgelegt sind. Das heißt im Umkehrschluss, dass du niemals sicherheitsrelevante Informationen damit verarbeiten solltest.

Das gilt insbesondere, wenn du auf deinen Webserver auch von außerhalb deines eigenen WLAN-Netzes zugreifen möchtest. Dann könnte jeder auf ihn zugreifen – nicht nur du. Natürlich gibt es auch hierfür diverse Sicherheitsmaßnahmen, mit denen du das zumindest erschweren kannst – aber dennoch, diese solltest du nur umsetzen, wenn du genau weißt, was du tust.

An dieser Stelle können wir dir leider keine weiteren Hinweise und Sicherheitslösungen an die Hand geben, da dieses Thema den Rahmen dieses Artikels sprengen würde und sich auch rasant weiterentwickelt.

Für den Einstieg in dieses Thema können jedoch diese zwei Artikel dienen:

Sicherheit? Sicherheit!

Sicherheit in der IoT

Letzte Aktualisierung am 2024-11-21 / Affiliate Links / Bilder von der Amazon Product Advertising API

Bausätze für dein nächstes Projekt

Alles, was du für dein nächstes Projekt brauchst – Bausätze inklusive Anleitung als E-Book und der benötigten Hardware.

ESP8266 Projekt

Wetterstation & Vorhersage

Miss die aktuelle Temperatur und Luftfeuchtigkeit und zeige dazu die Wettervorhersage auf einem OLED-Display an.

Bausatz anschauen

Arduino Projekt

Pflanzenwächter

Braucht deine Pflanze Wasser? Dieses Arduino Projekt gibt dir Bescheid, wenn es so weit ist.

Bausatz anschauen

ESP8266 Projekt

Webserver

Lerne, wie du mit deinem Webserver Messdaten ausgibst, Geräte steuerst und dir mit HTML und CSS ein Interface erstellst.

Bausatz anschauen

Arduino Projekt

Wetterstation

Baue deine eigene Wetterstation, die dir Temperatur und Luftfeuchtigkeit anzeigt.

Bausatz anschauen

Auch interessant

Mehr Projekte für Arduino, Raspi & Co
Werde Mitglied bei Pollux Labs und entdecke spannende Projekte und Tutorials, wie: - ESP8266 Webserver - Arduino Schnarchstopper - ESP32-CAM Fotofalle - ESP32 Internetradio ... und viele mehr!
Finde dein nächstes Projekt!
Als Mitglied von Pollux Labs erhältst du Zugang zu allen Projekte und Tutorials. Von der Arduino Wetterstation bis zum ESP8266 Webserver.
Werde Mitglied