Accendere semaforo con Wemos D1 dal browser

FunduinoUltimo aggiornamento il

Drei LEDs über eine Webseite auf dem Wemos D1 schalten

Der Wemos D1 bringt WLAN mit und kann selbst eine Webseite ausliefern. In dieser Anleitung baust du eine Ampel aus drei LEDs, die du über Buttons im Browser ein- und ausschaltest.

Dabei lernst du, wie sich der Wemos D1 mit deinem WLAN verbindet, wie er eine HTML-Seite an den Browser schickt und wie er die Klicks auf die Buttons auswertet.

Die Webseite der Ampel im Browser mit je einem Button zum Ein- und Ausschalten jeder LED

Die Ampel im Browser

Der Wemos D1 erstellt eine Webseite, die mit CSS (Cascading Style Sheets) gestaltet ist. Ein Klick auf einen Button schaltet die jeweilige LED ein oder aus.

Die IP-Adresse des Wemos D1 kannst du fest vorgeben oder per DHCP vom Router beziehen lassen.

Die Webseite der Ampel im Browser mit je einem Button zum Ein- und Ausschalten jeder LED

Benötigte Bauteile

Falls du den Wemos D1 noch nicht in der Arduino IDE eingerichtet hast, erfährst du in der Anleitung Wemos D1 in der Arduino IDE installieren, wie das geht.

Die Bauteilliste nennt keine Vorwiderstände. Schließe jede LED über einen Vorwiderstand an, zum Beispiel 220 Ω, damit LED und Pin nicht überlastet werden.

Der Schaltplan

Schließe die rote LED an D5, die gelbe LED an D6 und die grüne LED an D7 an.

Schaltplan: rote LED an D5, gelbe LED an D6 und grüne LED an D7 des Wemos D1

Bibliothek einbinden und globale Variablen definieren

Zu Beginn bindest du die Bibliothek ESP8266WebServer ein und legst die Pins der drei LEDs fest. Die Bibliothek gehört zum Boardpaket des ESP8266, du musst sie nicht extra installieren.

Trage bei Router den Namen (SSID) deines WLANs und bei Passwort das WLAN-Passwort ein.

Mit festeIP = false bezieht der Wemos D1 seine IP-Adresse per DHCP vom Router. Setzt du festeIP auf true, verwendet er die IP-Adresse, das Gateway und das Subnetz, die darunter festgelegt sind. Passe diese Werte dann an dein Heimnetz an.

Bibliothek einbinden und globale Variablen definieren
# include "ESP8266WebServer.h"

// Pins der LEDs
int ROT = D5;
int GELB = D6;
int GRUEN = D7;

// Router: SSID des Routers
// Passwort: WLAN-Passwort
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// festeIP = false -> IP-Adresse über DHCP vergeben
// festeIP = true -> IP Gateway und Subnetz festlegen
bool festeIP = false;

// IP, Gateway und Subnetz festlegen
IPAddress ip(192,168,1,200);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

// Webserver Port 80
WiFiServer Server(80);

// Client-Objekt mit dem Namen Client erstellen
WiFiClient Client;

Der setup-Teil

Im setup-Teil stellst du die Pins der LEDs als Ausgänge ein und verbindest den Wemos D1 mit deinem WLAN. Solange die Verbindung noch nicht steht, erscheint im seriellen Monitor alle halbe Sekunde ein Punkt.

Danach startet der Webserver, und der serielle Monitor zeigt den Namen des WLANs und die IP-Adresse des Wemos D1 an. Diese IP-Adresse gibst du in die Adresszeile eines Browsers deiner Wahl ein. Dein Computer oder Smartphone muss dafür im selben WLAN sein.

Der Kommentar „IP des Servers/des verbundenen Computers anzeigen“ passt nicht zu der Zeile darunter: WiFi.SSID() gibt den Namen des WLANs aus, keine IP-Adresse.

Der serielle Monitor zeigt den Namen des WLANs und die IP-Adresse des Wemos D1 an
Die IP-Adresse des Wemos D1 in der Adresszeile des Browsers
1 / 2
Der setup-Teil
void setup()
{
  Serial.begin(9600);
  
  // pinModes der LEDs
  pinMode(ROT, OUTPUT);
  pinMode(GELB, OUTPUT);
  pinMode(GRUEN, OUTPUT);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  // wenn eine statische IP-Adresse verwendet wird
  if (festeIP) WiFi.config(ip, gateway, subnet);

  // verbinden
  while(WiFi.status() != WL_CONNECTED)
  {
    delay(500); 
    Serial.print(".");
  }
  Server.begin();

  // IP des Servers/des verbundenen Computers anzeigen
  Serial.print("Server: ");
  Serial.println(WiFi.SSID());

  // IP des Wemos D1 anzeigen
  if (festeIP) Serial.print("Statische IP Adresse: ");
  else Serial.print("IP Adresse DHCP: ");
  Serial.println(WiFi.localIP());
}

Der loop-Teil

Der loop-Teil wartet darauf, dass sich ein Browser meldet, schickt ihm die HTML-Seite und wertet die Klicks auf die Buttons aus.

Aufbau der HTML-Seite: Alle HTML-Anweisungen in spitzen Klammern schickst du mit print oder println an den Browser. Anführungszeichen innerhalb eines Strings maskierst du mit einem Backslash (\"). Für das ü in „grün“ steht im Sketch die HTML-Schreibweise ü, damit der Browser den Umlaut richtig anzeigt.

Formatierung der Buttons mit CSS:

  • font-size: Schriftgröße
  • font-weight:bold: fette Schrift
  • background-color: Hintergrundfarbe
  • width: Breite des Buttons
  • cursor: Form des Mauszeigers über dem Button, hier pointer
  • border-radius, border: Gestaltung des Rahmens

Aufruf der Seite mit JavaScript: onClick="location.href='RotEin'" sorgt dafür, dass der Browser beim Klick auf den Button die Adresse RotEin aufruft.

Auswertung der Buttons: Der Browser sendet dabei einen sogenannten GET-Request, den du im seriellen Monitor siehst, zum Beispiel GET /RotEin. indexOf prüft, ob der gesuchte Text im Request enthalten ist, und schaltet dann die passende LED.

Der loop-Teil
void loop()
{
  // auf Clienten warten ...
  Client = Server.available();
  if (Client)
  {
    boolean SeiteAufbauen = true;

    // SchaltungLesen enthält den Schaltbefehl
    String SchaltungLesen;

    // solange der Client verbunden ist ...
    while (Client.connected())
    {
      if (Client.available())
      {
        // Anforderung vom Clienten lesen ...
        char Zeichen = Client.read();

        // get-Request anzeigen
        Serial.print(Zeichen);

        // new line (\n) gesendet
        if (Zeichen == '\n')
        {
          // wenn SeiteAufbauen den Wert true hat
          if (SeiteAufbauen)
          {
            /*
              HTML-Seite aufbauen
              die folgenden Anweisungen müssen
              mit print oder println gesendet werden
              println "verschönert" den Quelltext
              (erzeugt einen Zeilenumbruch im Quelltext)
              " müssen mit \ maskiert werden " -> \"
            */
            // HTML-Seite aufbauen
            Client.println("HTTP/1.1 200 OK");
            Client.println("Content-type:text/html");

            // Leerzeile zwingend erforderlich
            Client.println();
            Client.println("<!doctype html>");
            Client.println("<html>");
            Client.println("<body>");
            Client.println("<h2>Ampel mit WiFi schalten</h2>");
            Client.println("<hr />");
            Client.println("<table><tr>");

            // Button rot ein
            Client.println("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print(" background-color:#FF6565;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='RotEin'\"");
            Client.println(" value='rot einschalten'>");
            Client.println("</td>");

            // Button rot aus
            Client.print("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print("background-color:white;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='RotAus'\"");
            Client.println(" value='rot ausschalten'>");
            Client.println("</td></tr>");

            // Button gelb ein
            Client.print("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print(" background-color:#FFFB65;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='GelbEin'\"");
            Client.println(" value='gelb einschalten'>");
            Client.println("</td>");

            // Button gelb aus
            Client.print("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print(" background-color:white;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='GelbAus'\"");
            Client.println(" value='gelb ausschalten'>");
            Client.println("</td></tr>");

            // Button grün ein
            Client.print("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print(" background-color:#76FA5F;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='GruenEin'\"");
            Client.println(" value='gr&uuml;n einschalten'>");
            Client.println("</td>");

            // Button grün aus
            Client.print("<td><input style='font-size:14pt;");
            Client.print("font-weight:bold;");
            Client.print(" background-color:white;");
            Client.print(" width:200px; cursor:pointer;");
            Client.print(" border-radius:5px;border: 2px solid black;'");
            Client.print(" type='button'");
            Client.println(" onClick=\"location.href='GruenAus'\"");
            Client.println(" value='gr&uuml;n ausschalten'>");
            Client.println("</td></tr>");
            Client.println("</table>");
            Client.println("<hr />");

            // IPs anzeigen
            Client.print("<b>Eigene IP: ");
            Client.print(Client.remoteIP());
            Client.print("</b>");
            Client.print("<br><b>IP D1: ");
            Client.print(WiFi.localIP());
            Client.print("</b>");
            Client.println("</body>");
            Client.println("</html>");

            // HTTP-Antwort endet mit neuer Zeile
            Client.println();

            // Seite vollständig geladen -> loop verlassen
            break;
          }

          // wenn new line gesendet wurde -> Seite aufbauen
          if (Zeichen == '\n') SeiteAufbauen = true;

          else if(Zeichen != '\r') SeiteAufbauen = false;
          delay(1);
          Client.stop();
        }

        // bei einem anderen Zeichen als return (\r)
        // -> Zeichen dem String SchaltungLesen hinzufügen
        else if (Zeichen != '\r') SchaltungLesen += Zeichen;

        // indexOf überprüft, ob die Zeichenfolge im String SchaltungLesen enthalten ist
        if (SchaltungLesen.indexOf("RotEin") > 0) digitalWrite(ROT, HIGH);
        if (SchaltungLesen.indexOf("RotAus") > 0) digitalWrite(ROT, LOW);
        if (SchaltungLesen.indexOf("GelbEin") > 0) digitalWrite(GELB, HIGH);
        if (SchaltungLesen.indexOf("GelbAus") > 0) digitalWrite(GELB, LOW);
        if (SchaltungLesen.indexOf("GruenEin") > 0) digitalWrite(GRUEN, HIGH);
        if (SchaltungLesen.indexOf("GruenAus") > 0) digitalWrite(GRUEN, LOW);
      }
    }
  }
}
Valuta le istruzioni

Commenti

Fare una domanda o condividere un'esperienza

Scrivici se qualcosa non funziona. Indica la tua scheda e il messaggio di errore.

Controlliamo ogni commento prima della pubblicazione. Il tuo indirizzo e-mail rimane presso di noi.