Rothschopf Werner

rowex ganz privat

Angebote

Der Webserver - erste Schritte und behübschen

In dieser mehrteiligen Anleitung werde ich einen kombinierten Webserver - Webclient für den ESP8266 zeigen. Die Arduino IDE kommt zwar mit vielen Beispielen und mit allem was man benötigt aber offenbar haben Einsteiger Probleme bei der Auswahl der richtigen Vorgangsweise.

Das "HelloWorld" Beispiel für einen Webserver am ESP8266 findet sich unter

  • ESP8266Webserver | HelloServer

Im ersten Schritt werden SSID und WIFI Passwort gesetzt. Am besten passt man auch den LED-Pin an seine Hardware an. Ich verwende keinen nackten ESP8266 sondern einen NodeMCU, daher verwende ich pin 2.

const char* ssid = "........";
const char* password = "........";

ESP8266WebServer server(80);

const int led = 2; // GPIO02/D4 on NodeMCU is the (blue) LED on the ESP-12E

Der Upload dieses Sketches soll problemlos funktionieren. Nach dem Upload wird eine WiFi Verbindung hergestellt werden und im seriellen Monitor wird eine IP-Adresse ausgegeben. Mit dieser IP-Adresse kann der Webserver aufgerufen in einem Browser aufgerufen werden.

Auf Basis dieses Sketches arbeite ich schrittweise weiter. Da ich viele Uploads machen werden - kommt als erstes das ArduinoOTA hinzu. ArduinoOTA ermöglicht den Sketch-Upload direkt aus der IDE über die WiFi und ist wesentlich schneller als über die serielle Schnittstelle. ArdinoOTA verdient sich eigentlich ein eigenes Tutorial - daher nur kurz zusammengefasst die wesentlichen Teile

im Deklarationsteil ergänze ich

#include <ArduinoOTA.h> // OTA Upload via ArduinoIDE

im setup()

ArduinoOTA.begin(); // OTA Upload via ArduinoIDE

im loop()

ArduinoOTA.handle(); // OTA Upload via ArduinoIDE

Da wir den Webserver großzügig erweitern werden, wandern alle Server relevante Funktionen wie handleRoot(), handleNotfound() ... in einen neuen IDE-Tab "server". Das hilft später die Übersicht zu behalten.

Dann beginne ich alle Fixtexte aus dem RAM in den Flash /Programmspeicher des ESP8266 zu verschieben. Dazu nehme ich einfach das F-Makro

Serial.println(F(""));
Serial.print(F("Connected to "));
Serial.println(ssid);
Serial.print(F("IP address: "));

Konsequent angewandt wird eine Menge RAM gespart - und Flash haben wir ausreichend am ESP8266 zur Verfügung.

im Tab "server" adaptieren wir nun auch die Seite 404. Testweise lasse ich mir eventuell übergebene Parameter auf der Webseite ausgeben.

void handleNotFound() {
// Output a "404 not found" page. It includes the parameters which comes handy for test purposes.
Serial.println(F("D015 handleNotFound()"));
String message;
message += F("404 - File Not Found\n\n"
             "URI: ");
message += server.uri();
message += F("\nMethod: ");
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += F("\nArguments: ");
message += server.args();
message += F("\n");
for (uint8_t i = 0; i < server.args(); i++)
{
 message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
 server.send(404, "text/plain", message);
}

Der Beispiel-Sketch hat noch relativ wenige Seiten. Ich lege daher im Setup einige weitere Seiten an: 0.htm, 1.htm, 2.htm, x.htm
und weil es "hübsch" aussehen soll, ein Stylesheet f.css

server.on("/0.htm", handlePage);
server.on("/1.htm", handlePage);
server.on("/2.htm", handlePage);
server.on("/x.htm", handleOtherPage); // just another page to explain my usage of HTML pages ...
server.on("/f.css", handleCss); // a stylesheet

x.htm ist ein Beispiel, wie man grundsätzlich eine Seite gestaltet: Seite definieren und einen Handler dazu definieren - den wir dann im Tab "server" ablegen

0.htm, 1.htm, 2.htm rufen den gleichen Handler auf, was in meinem Fall gewollt ist, da auf den Seiten meines Webservers sich große Teile gleichen. Der HTML-Header, Die Überschrift, die Navigationsleiste, der Footer. All das wiederholt sich auf den einzelnen Seiten. Nur der eigentliche Content unterscheidet sich, daher gibt es EINEN Handler - der abhängig von der Seite nur anderen Content ausgibt.

Klingt komplizierter als es ist. Schauen wir uns den Code-Schnipsel an:

void handlePage()
{
String message;
message = F("<!DOCTYPE html>\n"
"<html>\n<head>\n<title>" TXT_BOARDNAME " - Board " TXT_BOARDID "</title>\n"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n"
"<meta name=\"viewport\" content=\"width=device-width\">\n"
"</head>\n");
message += F("<body onload='GetSwitchState(0)'>\n"
"<header>\n<h1>" TXT_BOARDNAME " - Board " TXT_BOARDID "</h1>\n"
"<nav><p><a href=\"0.htm\">Home</a> <a href=\"1.htm\">[Page 1]</a> <a href=\"2.htm\">[The Webclient]</a> <a href=\"r.htm\">[Remote Module]</a> <a href=\"x.htm\">[Page X]</a></p></nav>\n</header>\n"
"<div id='cont'>\n");

if (server.uri() == "/0.htm") // *** HOME *** 0.htm
{
 message += F("<h2>Homepage</h2>\n" // here you write your html code for your homepage. Let's give some examples...
 "<p>This is an example for a webserver on your ESP8266.<p>\n"
 "<p>Values are getting updated with AJAX/JSON. "
 "I'm still using old style XMLHttpRequest instead of fetch-API. It's up to "
 "the reader to update - but old style works fine for me ;-P</p>\n");

 message += F("<h2>Values (with update)</h2>\n");
 message += F("<p>Internal Voltage measured by ESP: <span id='internalVcc'>"); // example how to show values on the webserver
 message += ESP.getVcc();
 message += F("</span>mV</p>\n");

 message += F("<p>Button 1: <span id='button1'>"); // example how to show values on the webserver
 message += digitalRead(BUTTON1_PIN);
 message += F("</span></p>\n");
}
else if (server.uri() == "/1.htm") // *** Page 1 *** 1.htm
{
 message += F("<h2>Page 1</h2>\n"
             "<p>This is example content for [Page 1]<p>\n");
}
else if (server.uri() == "/2.htm") // *** Page 2 *** 2.htm
{
 message += F("<h2>The webclient</h2>\n"
 "<p>Some words about the weblient ('client'): The client will send data to a server.<p>\n"
 "<p>To be precise, the client on this module will send each ");
 message += clientIntervall;
 message += F(" seconds to a resource at<br>");
 message += sendHttpTo;
 message += F("<br>which you can set up in the configuration part. It consists of the webserver adress and a page. You must ensure, that the webserver and the called page is available, otherwise the request will fail.<p>\n"
 "<p>Optionally you can send a command to force the webclient to send <a href='c.php?CMD=CLIENT' target='i'>imidiatly</<a>.</p>\n"
 "<iframe name='i' style='display:none' ></iframe>\n"
 "<p>If the other webserver shares the same source code like this module - it should be able to collect the data from this module.</p>\n"
 );
}
}

Die Funktion beginnt mit der Ausgabe des HTML-Headers, der Navigation und dann abhängig vom Parameter kommt der eigentliche Inhalt der Seite 0.htm. Ähnliche IF's gibt es für 1.htm und 2.htm.

Im Code (blau markiert) sieht man nun auch, wie man "dymamisch" Werte aus Variablen einfügt. Einfach den Fixtext beenden, die Variable hinzufügen und wieder mit Fixtext fortsetzen. Die verteufelte String Klasse macht das eigentlich - in diesem speziellen Fall - ganz gut.

Ich schrieb von "den Webserver behübschen". Also brauchen wir noch die Funktion für den CSS Handler. Im Prinzip ist ein CSS auch nur eine Text-Ausgabe mit einem eigenen MIME-Type

void handleCss()
{
// output of stylesheet
// this is a straight forward example how to generat a static page from program memory
String message;
message = F("*{font-family:sans-serif}\n"
"body{margin:10px}\n"
"h1, h2{color:white;background:" CSS_MAINCOLOR ";text-align:center}\n"
"h1{font-size:1.2em;margin:1px;padding:5px}\n"
"h2{font-size:1.0em}\n"
"h3{font-size:0.9em}\n"
"a{text-decoration:none;color:dimgray;text-align:center}\n"
".small{font-size:0.6em}\n"
".value{font-size:1.8em;text-align:center;line-height:50%}\n"
"footer p, .infodaten p{font-size:0.7em;color:dimgray;background:silver;text-align:center;margin-bottom:5px}\n"
"nav{background-color:silver;margin:1px;padding:5px;font-size:0.8em}\n"
"nav a{color:white;padding:10px;text-decoration:none}\n"
"nav a:hover{text-decoration:underline}\n"
"nav p{margin:0px;padding:0px}\n"
".btn{background-color:#C0C0C0;color:dimgray;text-decoration:none;border-style:solid;border-color:dimgray}\n" //fake style for button
".on, .off{margin-top:0;margin-bottom:0.2em;margin-left:3em;font-size:1.4em;background-color:#C0C0C0;border-style:solid;width:5em;height:1.5em;text-decoration:none;text-align:center}\n"
".on{border-color:green}\n"
server.send(200, "text/css", message);
}

Obiges konsequent angewendet bringt uns schon einen lauffähigen webserver - der je nach Fertigkeit auch schon mal besser bzw. bunter aussieht als eine reine Textseite.

Wer tapfer bis hier her durchgehalten hat, der bekommt unten bei den Links auch meinen fertigen Sketch

Es geht weiter mit "Webserver - Seite Aktualisieren mittes AJAX/JSON".

 


Links

  • Amazon (Suchlink für NodeMCU V2 mit CP2102)
  • Amazon (Alternativ: Wemos D1 pro Mini)
  • Download des finalen Sketch ESP8266 Webserver WebClient

 


Protokoll

erstellt: 2018-09-02 | Stand: 2018-09-05