Hello, world!

Lektion
Downloads

Zeit, um mit unserem Web Server 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 Kursabschnitts.

Der Anfang des Sketchs

Du hast bereits 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:

___STEADY_PAYWALL___

//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 Web Servers auf 80 fest. Dieser Port ist der Teil der Netzwerk-Adresse an der dein Web Server auf eingehende Anfragen von Clients wartet.

//Port des Web Servers 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 Web Server 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 im Kurs gehen wir genauer auf HTML ein und bauen uns 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("");