|
Einfache Arduino Code mit Kommentaren für beliebige Wifi Relaismodule auf Basis von ESP8266 Modulen.
Smart Home / Internet der Dinge (IOT) im Eigenbau.
Oben sehen Sie 2 Versionen der Steuerungswebseite WebSchalter3.1 mit Buttons und WebSchalter3.2 mit Schiebeschalter.
Diese Version des Arduino Sketches für die intelligente WIFI Steckdose habe ich als Beispiel für Programmierung des ESP8266 Relais Modules konzipiert. Möglichst einfach gehalten und alles ist kommentiert.
Hier wird WLAN Name und Passwort direkt im Arduino Sketch eingetragen, wegen der Einfachheit und Übersichtlichkeit der Code.
Zu Kommunikation zwischen der Steuerung Webseite und des ESP8266 WiFi Relais wird AJAX Technologie verwendet. Dass macht zwar die HTML – Code der Steuerungswebseite komplizierter, ermöglicht aber die Steuerung und Statusabfrage des WiFi Relaismoduls sehr schnell und ohne neu laden der Webseite durchzuführen.
Das Bedeutet, das die Webseite wird einmal vom WiFi Relais geladen und dann kommuniziert die im Hintergrund über AJAX-Objekt und JavaScript mit dem WiFi Relais.
Übrigens Steuerungswebseite muss nicht unbedingt von dem ESP8266 Wifi Relaismodul geladen werden. Die Steuerungswebseite kann zum Beispiel von dem Raspberry Pi oder bei einem Hoster im Internet abgerufen werden. Wichtig ist nur das diese AJAX Steuerungswebseite die IP Adresse des WiFi Relais kennt.
In diesem Beispiel Arduino Sketch habe ich alle meine neuen Erkenntnissen Angewendet.
HTML lässt sich jetzt direkt im Arduino Sketch eingeben. Das sieht so aus:
1 2 3 4 5 6 7 8 9 |
const char indexHTML[] PROGMEM = R"=====( <!DOCTYPE html> <html> <head> <title>Schiebeschalter</title> <body> </body> </html> )=====" ; |
Ich habe 2 Designs an WiFi Relais Steuerungswebseite ausprobiert. Einmal mit Buttons EIN / AUS / Umschalten. Und mit einem Checkbox, der als Schiebeschalter mit Hilfe von CSS getarnt ist.
Der aktueller Schaltzustand des Wifi Relais wird jede Sekunde (ist einstellbar) aktualisiert und als Farbe des Buttons oder der Position und Farbe des Schiebeschalters angezeigt. Wenn Wifi Relais über den Taster oder über Steuerungswebseite umgeschaltet wird, wird innerhalb einer Sekunde der neue Schaltzustand an allen geöffneten Steuerungswebseiten angezeigt. Auch wenn diese Webseite an andere Ende der Welt gerade auf einem Bildschirm ist.
Sonoff Wifi Wireless Smart Switch Taster und Netzteil integriert #define RelaisPin 12 #define TasterPin 0 int active_low = 0; Schaltplan |
ESP-01 Relaismodul Relais Modul für ESP-01 Uin 5V #define RelaisPin 0 #define TasterPin 2 int active_low = 1; |
ESP-01 Relaismodul Relais Modul Uin 7V...30V #define RelaisPin 4 #define TasterPin 5 int active_low = 1; Schaltplan |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include "index_html.h" // In dieser Datei befindet sich die Steuerung Webseite const char* ssid = "MainWlan"; // WLAN-Name, const char* password = "Gehaim"; // WLAN-Passwort #define RelaisPin D4 // Relais #define TasterPin D1 // Aktiv Low (Taster zwischen TasterPin ung GND) int active_low = 1; // "0" Relais schaltet bei +5V , "1" Relais beim schaltet bei 0V ESP8266WebServer server(80); // Serverport hier einstellen int val = 0; // Hier wird der Schaltzustand gespeichert void setup() { pinMode(RelaisPin, OUTPUT); pinMode(TasterPin, INPUT_PULLUP); digitalWrite(RelaisPin, active_low); Serial.begin(115200); // Serielle Schnittstelle initialisieren Serial.println(""); // Neue Zeile Serial.println("Warte auf Verbindung"); WiFi.mode(WIFI_AP); // access point modus WiFi.softAP("astral", "12345678"); // Name des Wi-Fi Netzes und Passwort delay(500); //Abwarten 0,5s Serial.print("IP Adresse "); //Ausgabe aktueller IP des Servers Serial.println(WiFi.softAPIP()); /* // Mit Haus WLAN Verbinden WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); // Warte auf verbindung while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Verbunden mit "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // ENDE Mit Haus WLAN Verbinden */ // Bechandlung der Ereignissen anschliessen server.on("/", Ereignis_Index); server.onNotFound ( handleNotFound ); server.begin(); // Starte den Server Serial.println("HTTP Server gestartet"); } void loop() { server.handleClient(); if (!digitalRead(TasterPin)) // Wenn Taster betätigt "Signal 0" { val = !val; // Umschalten digitalWrite(RelaisPin, active_low ^ val); // Wenn active_low - Variable ist "1", das Zustand "val" wird invertiert Serial.println("Umschalten per Taster auf " + String(val)); delay(500); // Entprellung, Warten bis der Taster Kontakt sich beruhigt hat while (!digitalRead(TasterPin))server.handleClient(); // warten bis der Taster los gelassen wurde } } void Ereignis_Index() // Wird ausgeführt wenn "http://<ip address>/" aufgerufen wurde { if (server.args() > 0) // wenn Argumente im GET Anfrage vorhanden sind z.B http://<ip address>/?zustand=r { if (server.arg("relais") == "0") // prüfen ob "/?relais=0" { Serial.println("Aus"); val = 0; // Ausschalten digitalWrite(RelaisPin, active_low ^ val); } if (server.arg("relais") == "1") // prüfen ob "/?relais=1" { Serial.println("Ein"); val = 1; // Einschalten digitalWrite(RelaisPin, active_low ^ val); } if (server.arg("relais") == "2") // prüfen ob "/?relais=2" Toggle Funktion { val = !val; // Umschalten Serial.println("Umschalten auf " + String(val)); digitalWrite(RelaisPin, active_low ^ val); } // es wird immer Relais Zushtand mitgeteilt server.sendHeader("Cache-Control", "no-cache"); // wichtig! damit Daten nicht aus dem Browser cach kommen server.send(200, "text/plain", String(int(val)) ); // Antwort an Internet Browser senden nur eine Zahl ("0"/"1") } else // wenn keine Argumente im GET Anfrage { Serial.println("Sende Index.html"); server.send(200, "text/html", indexHTML); //dann Index Webseite senden (sehe Datei "index_html.h") } } void handleNotFound() { server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) } |
Die Quellcode unten, das ist die Steuerung Webseite Version 3.1 , mit Buttons.
Das Header ist üblich, wie beim allen Internetseiten. Dem folgt JavaScript Teil, danach style, danach HTML Code für 3 Buttons. Style bestimmen das Aussehen von Buttons. Ich möchte näher JavaScript Teil beschreiben.
Wir haben hier 4 Funktionen: function start (), function aktualisieren (), function LesenAjax(), function httpGet ( sende ).
Funktion start () -hier wird ein AJAX Objekt gebildet. -Ereignis was passieren soll, bei Empfang einer Antwort vom Server, definiert. - Ein Timer im Sekundentakt initialisiert. -und die erste Anfrage über den Relais Zustand an das Server geschickt.
Funktion aktualisieren () -sendet dem WiFi Relais Server eine GET Anfrage "?Zustand=r". Dies passiert jede Sekunde, weil diese Funktion von Timer aufgerufen wird.
Funktion LesenAjax() -wird automatisch ausgeführt, wenn eine Antwort des Servers ankommt. Der Server antwortet mit deinem Text "0" oder "1". Abhängig davon was angekommen ist, werden die Buttons gefärbt.
Funktion httpGet (sende) -wird bei Betätigung des Buttons ausgeführt. Die sendet an das Server in der Variable "sende" enthaltene GET-Anfrage. Das sind "?relais=0", "?relais=1", "?relais=2".
Wenn die Steuerung Webseite nicht vom dem WiFi Relaismodul geladen wird und sollte sich woanders befinden, dann muss man die Variable Url vom "/" auf das "http://192.168.4.1/" ändern. Bei Betrieb im Client Modus die IP sieht natürlich anders aus( fragen Sie Ihre Router, oder schauen Sie die serielle Ausgaben beim Start).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
const char indexHTML[] PROGMEM = R"=====( <!DOCTYPE html> <html> <head> <title>Web Schalter 3.1</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name=viewport content="width=device-width, initial-scale=1"> <script type="text/javascript"> var Url = "/"; window.onload = start; //Funktion nach dem laden des HTMLs ausführen function start () { myAjax = new XMLHttpRequest(); // Bilden anens AJAX objekts myAjax.onreadystatechange=LesenAjax; // Wenn Ereignis vom Server kommt, wird funktion LesenAjax ausgeführt setInterval(aktualisieren,1000); // Initialisiert das Timer-gesteuerte Ausführen von Funktion //aktualisieren(); aktualisieren (); // Relais Zustand holen beim laden der Webseite } function aktualisieren () { myAjax.open("GET",Url+"?Zustand=r",true); // GET-Anfrage an Server senden Asynhron myAjax.send(); } function LesenAjax() //AJAX-Ereignis ist passiert { if (myAjax.readyState==4 && myAjax.status==200) // Wenn antwort volständig und OK { // dann var datenstr=myAjax.responseText; // empfangene Daten als Text if (datenstr == '0') // Button Farben ändern { document.getElementById('aus').style.backgroundColor = '#FFA6D9'; document.getElementById('ein').style.backgroundColor = '#7E00E2'; } if (datenstr == '1') { document.getElementById('aus').style.backgroundColor = '#7E00E2'; document.getElementById('ein').style.backgroundColor = '#FFA6D9'; } } } function httpGet ( sende ) // GET anfrage an Server. { myAjax.open ( "GET", Url + sende, true ) ; myAjax.send() ; } </script> <style type="text/css" media="screen, print, projection"> .button { background-color: #7E00E2; border: 2; color: #FFFF00; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 8px 8px; cursor: pointer; border-radius: 10px; padding: 6px 6px 6px 6px; } </style> </head> <body> <p align=middle> <button id="aus" class="button" onclick="httpGet('?relais=0')">Aus</button> <button id="ein"class="button" onclick="httpGet('?relais=1')">Ein</button> <button class="button" onclick="httpGet('?relais=2')">Umschalten</button> </p> </body> </html> )=====" ; |
Danke an den Dieter Morgenstern. Es hat einen Fehler entdeckt. Und die Lösung vorgeschlagen. Wenn die steuerungs Webseite sich auf anderem Server befindet, dann funktioniert die Steuerung nicht mehr.
Das Browser meldet folgende Fehler "Quellübergreifende (Cross-Origin) Anfrage blockiert: Die Gleiche-Quelle-Regel verbietet das Lesen der externen Ressource auf http://www.xxxx. (Grund: CORS-Kopfzeile 'Access-Control-Allow-Origin' fehlt)."
Ersetzen Sie die Zeile 90 und 91 gegen:
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("pragma","no-cache");
server.sendHeader("Expires", "-1");
server.sendHeader("Access-Control-Allow-Origin","*");
server.send(200, "application/json", String(int(val)) );