Controllare Relè e Led tramite browser HTTP da remoto
Nel precedente articolo abbiamo spiegato come sia possibile realizzare, tramite l’IDE di Arduino, un firmware personalizzato da poter caricare sulla scheda miniaturizzate RLY-1601 dotata di relè e del modulo WiFi ESP-12E. E’ stato anche descritto come poter connettere la RLY-1601 ad un convertitore USB-seriale a 3.3V per poter caricare il firmware realizzato sulla scheda. In questo articolo sarà fatto un passo deciso verso il mondo del IoT andando ad illustrare come realizzare un semplice firmware, sfruttando le immense librerie per il SoC ESP8266, che permetta il controllo sia del relè che del led, a bordo della RLY-1601, tramite un qualsiasi browser.
Prima di inizare ad analizzare il codice consigliamo, per chi non lo avesse ancora fatto, di leggere l’articolo iniziale di questa serie di articoli sulla possibilità di programmare la RLY tramite l’IDE di Arduino, raggiungibile al link sottostante, poiché in questo articolo ci soffermeremo solo sul codice non ripetendo quanto già scritto riguardo a programmazione ed hardware :
Ricordiamo, inoltre, il link del manuale delle librerie per l’ESP8266 utilizzate nel codice per chi volesse apporfondire o apprendere tutte le altre, e sono moltissime, funzionalità disponibili: Manuale Librerie ESP8266.
Come già accennato, l’obiettivo che vogliamo raggiungere è la possibilità di poter controllare lo stato del relè e del led, a bordo della scheda RLY, tramite un browser. Inoltre, vorremmo anche poterne verificare lo stato ovvero sapere se il relè è aperto o chiuso ed il led è acceso o spento. Volendo precisare meglio cosa vuol dire il termine “tramite browser”, la nostra idea è quella di utilizzare un qualsiasi browser per aprire una pagina web tramite la quale, attraverso dei link, poter comandare la RLY e poter verificare lo stato di relè e led.
Per realizzare questa particolare configurazione è necessario che il modulo ESP8266, a bordo della RLY, funzioni come un server web ovvero rimanga in ascolto sulla porta 80 ed accetti eventuali richieste HTTP di tipo GET da un client che nel nostro caso è il browser. Ogni volta che il browser effettua una richiesta GET al web server, quest’ultimo dovrà rispondere al GET inviando la pagina in HTML che il browser visualizzerà sullo schermo. La pagina web dovrà essere salvata all’interno del modulo ESP8266, dato che sarà il nostro web server, ma a causa delle limitate capacità (rispetto ad un web server per PC) sia in termini di memoria che di velocità sarà possibile realizzare pagine web testuali molto semplici. Poco male poichè più che sufficenti per raggiungere il nostro obiettivo.
Iniziamo ad analizzare il codice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Control the Relay from everywhere with HTTP Web Server ACE Innovation (aceinnova.com) */ #include <ESP8266WiFi.h> // LED of ESP-12E is connected to GPIO2 #define LED_PIN 2 // RELAY is connected to GPIO12 #define RLY_PIN 12 // SSID of the Router const char* ssid = "TUA_SSID"; // WiFi Password const char* password = "TUA_PASSWORD"; // Define RLY as server on Port 80 WiFiServer server(80); // Define Led and Relay Statuses String statusRly = "Off"; String statusLed = "Open"; |
Inizialmente viene inclusa la libreria ESP8266WiFi che contiene le funzionalità per utilizzare la WiFi del modulo ESP8266, successivamente vengono definiti i pin relativi al led ed al relè:
- led connesso a GPIO2 quindi indicato nel codice con il numero 2;
- relè connesso a GPIO12 quindi indicato nel codice con il numero 12.
Successivamente sono definite due constanti. La prima è utilizzata per salvare il nome della rete WiFi (SSID) alla quale il modulo si andrà a connettere mentre nella seconda viene salvata la password della WiFi. All’interno del codice sostituire “TUA_SSID” e “TUA_PASSWORD” con i vostri valori. Continuando con l’analisi del codice, viene definita una variabile server di tipo WiFiServer (necessaria per far diventare la ESP8266 un web server in ascolto sulla porta 80) e due variabili di tipo String.
All’interno della funzione setup() si possono osservare le classiche dichiarazioni delle modalità di funzionamento dei pin (pin come OUTPUT) e della WiFi.
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 |
void setup() { Serial.begin(115200); delay(100); // initialize digital pin LED_PIN as output. pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); // initialize digital pin RLY_PIN as output. pinMode(RLY_PIN, OUTPUT); digitalWrite(RLY_PIN, LOW); // Connect to WiFi network (RLY works in Client Mode) Serial.printf("Connecting to %s\n ", ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); // Wait to establish connection to the router while (WiFi.status() != WL_CONNECTED) { delay(2000); Serial.print("."); } Serial.println(" connected"); // RLY is connected with the router. Start the server server.begin(); // Print the IP address (short version) Serial.printf("Web Server started, open http://%s in a web browser\n", WiFi.localIP().toString().c_str()); } |
Il modulo ESP8266 viene impostato, tramite la funzione WiFi.mode(WIFI_STA), in modalità Station/Client e tenterà di connettersi alla WiFi generata dal router di casa. La funzione WiFi.begin(ssid, password), permette proprio di far avviare la procedura per la connessione alla WiFi. A connessione avvenuta viene chiamata la funzione server.begin() che attiva il web server sul modulo.
Prima di passare alla funzione di loop() dichiariamo una funzione, molto semplice, che permetta la generazione della pagina HTML che il nostro web server invierà al browser.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
String prepareHtmlPage() { String htmlPage = String("HTTP/1.1 200 OK\r\n") + "Content-Type: text/html\r\n" + "Connection: close\r\n" + // the connection will be closed after completion of the response "\r\n" + "<!DOCTYPE HTML>" + "<html>" + "<h2>DEMO - RLY HTTP REQUEST/RESPONSE - by <a href=\"https://www.aceinnova.com\" target=\"_blank\">ACE Innovation</a></h2>" + "LED is now: " + "<span style=\"color:red;\">" + statusLed + "</span><br>" + "RELAY is now: " + "<span style=\"color:red;\">" + statusRly + "</span>" + "<br><br>" + "Click <strong><a href=\"/LED=ON\">here</a></strong> to turn the LED On or <strong><a href=\"/LED=OFF\">here</a></strong> to turn the LED Off<br>" + "Click <strong><a href=\"/RLY=OPEN\">here</a></strong> to Open the RELAY or <strong><a href=\"/RLY=CLOSED\">here</a></strong> to Close the RELAY <br>" + "</html>" + "\r\n"; return htmlPage; } |
Le uniche peculiarità da notare sono i link, “LED=ON” e “RLY=OPEN”, che, come vedremo tra poco, sono utilizzati per far cambiare lo stato del relè e del led.
Infine passiamo ad osservare la funzione di loop:
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 |
void loop() { WiFiClient client = server.available(); // Check if a Client (web browser) has connected if (client) { // Wait until the client (web browser) sends some data Serial.println("\n[Client Connected]"); while(client.connected()) { if(client.available()) { // Some Data is available String request = client.readStringUntil('\r'); Serial.print(request); // Match the request if(request.indexOf("/LED=ON") != -1 && request[0] == 'G') { Serial.print(1); statusLed = "On"; digitalWrite(LED_PIN, LOW); } else if(request.indexOf("/LED=OFF") != -1 && request[0] == 'G') { Serial.print(2); statusLed = "Off"; digitalWrite(LED_PIN, HIGH); } else if(request.indexOf("/RLY=OPEN") != -1 && request[0] == 'G') { Serial.print(3); statusRly = "Open"; digitalWrite(RLY_PIN, LOW); } else if(request.indexOf("/RLY=CLOSED") != -1 && request[0] == 'G') { Serial.print(4); statusRly = "Closed"; digitalWrite(RLY_PIN, HIGH); } if (request.length() == 1 && request[0] == '\n') { Serial.print(5); client.println(prepareHtmlPage()); break; } } } // give the browser time to receive data delay(10); client.flush(); client.stop(); Serial.println("[Client disonnected]"); } } |
La funzione di loop non fa altro che rimanere in attesa di una connessione da parte di un client. Nel momento in cui un client si connette, l’ultimo if viene verificato
1 |
if (request.length() == 1 && request[0] == '\n') |
e viene inviato al client quanto generato dalla funzione prepareHtmlPage() ovvero il codice HTML. Ogni volta che l’utente clicca su uno dei 4 link presenti nella pagina HTML, viene verificato uno dei 4 if a seconda se l’utente ha premuto sul link “LED=OFF”, “LED=ON”, “RLY=OPEN” o “RLY=CLOSED”:
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 |
// Match the request if(request.indexOf("/LED=ON") != -1 && request[0] == 'G') { Serial.print(1); statusLed = "On"; digitalWrite(LED_PIN, LOW); } else if(request.indexOf("/LED=OFF") != -1 && request[0] == 'G') { Serial.print(2); statusLed = "Off"; digitalWrite(LED_PIN, HIGH); } else if(request.indexOf("/RLY=OPEN") != -1 && request[0] == 'G') { Serial.print(3); statusRly = "Open"; digitalWrite(RLY_PIN, LOW); } else if(request.indexOf("/RLY=CLOSED") != -1 && request[0] == 'G') { Serial.print(4); statusRly = "Closed"; digitalWrite(RLY_PIN, HIGH); } |
L’esecuzione del codice all’interno degli if permette l’accensione o lo spegnimento del led e la chiusura o apertura del relè.
Riportiamo, infine, il codice completo da copiare sull’IDE di Arduino per effettuarne la compilazione ed il successivo caricamento sulla scheda RLY-1601.
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
/* Control the Relay from everywhere with HTTP Web Server ACE Innovation (aceinnova.com) */ #include <ESP8266WiFi.h> // LED of ESP-12E is connected to GPIO2 #define LED_PIN 2 // RELAY is connected to GPIO12 #define RLY_PIN 12 // SSID of the Router const char* ssid = "TUO_SSID"; // WiFi Password const char* password = "TUA_PASSWORD"; // Define RLY as server on Port 80 WiFiServer server(80); // Define Led and Relay Statuses String statusRly = "Off"; String statusLed = "Open"; void setup() { Serial.begin(115200); delay(100); // initialize digital pin LED_PIN as output. pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); // initialize digital pin RLY_PIN as output. pinMode(RLY_PIN, OUTPUT); digitalWrite(RLY_PIN, LOW); // Connect to WiFi network (RLY works in Client Mode) Serial.printf("Connecting to %s\n ", ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); // Wait to establish connection to the router while (WiFi.status() != WL_CONNECTED) { delay(2000); Serial.print("."); } Serial.println(" connected"); // RLY is connected with the router. Start the server server.begin(); // Print the IP address (short version) Serial.printf("Web Server started, open http://%s in a web browser\n", WiFi.localIP().toString().c_str()); } void loop() { WiFiClient client = server.available(); // Check if a Client (web browser) has connected if (client) { // Wait until the client (web browser) sends some data Serial.println("\n[Client Connected]"); while(client.connected()) { if(client.available()) { // Some Data is available String request = client.readStringUntil('\r'); Serial.print(request); // Match the request if(request.indexOf("/LED=ON") != -1 && request[0] == 'G') { Serial.print(1); statusLed = "On"; digitalWrite(LED_PIN, LOW); } else if(request.indexOf("/LED=OFF") != -1 && request[0] == 'G') { Serial.print(2); statusLed = "Off"; digitalWrite(LED_PIN, HIGH); } else if(request.indexOf("/RLY=OPEN") != -1 && request[0] == 'G') { Serial.print(3); statusRly = "Open"; digitalWrite(RLY_PIN, LOW); } else if(request.indexOf("/RLY=CLOSED") != -1 && request[0] == 'G') { Serial.print(4); statusRly = "Closed"; digitalWrite(RLY_PIN, HIGH); } if (request.length() == 1 && request[0] == '\n') { Serial.print(5); client.println(prepareHtmlPage()); break; } } } // give the browser time to receive data delay(10); client.flush(); client.stop(); Serial.println("[Client disonnected]"); } } String prepareHtmlPage() { String htmlPage = String("HTTP/1.1 200 OK\r\n") + "Content-Type: text/html\r\n" + "Connection: close\r\n" + // the connection will be closed after completion of the response "\r\n" + "<!DOCTYPE HTML>" + "<html>" + "<h2>DEMO - RLY HTTP REQUEST/RESPONSE - by <a href=\"https://www.aceinnova.com\" target=\"_blank\">ACE Innovation</a></h2>" + "LED is now: " + "<span style=\"color:red;\">" + statusLed + "</span><br>" + "RELAY is now: " + "<span style=\"color:red;\">" + statusRly + "</span>" + "<br><br>" + "Click <strong><a href=\"/LED=ON\">here</a></strong> to turn the LED On or <strong><a href=\"/LED=OFF\">here</a></strong> to turn the LED Off<br>" + "Click <strong><a href=\"/RLY=OPEN\">here</a></strong> to Open the RELAY or <strong><a href=\"/RLY=CLOSED\">here</a></strong> to Close the RELAY <br>" + "</html>" + "\r\n"; return htmlPage; } |
Una volta programmata la scheda RLY-1601 è possibile aprire il monitor seriale dell’IDE di Arduino per osservare tutti i messaggi di debug, ovvero i messaggi inviati tramite la funzione Serial.print(). Al termine della fase di connessione alla WiFi del router e se la connessione è andata a buon fine, verrà stampanto l’IP associato alla scheda RLY.
Tramite un browser, di un dispositivo (PC\Tablet\Smartphone) connesso alla medesima WiFi della RLY, accedere alla pagina web della RLY digitando nella barra degli indirizzi, l’indirizzo osservabile dal debug (in questo esempio http://192.168.1.44).
Si aprirà istantaneamente la pagina web precedentemente scritta nel codice del firmware all’interno della funzione prepareHtmlPage()
La pagina web mostra sia lo stato del led che del relè ed è inoltre possibile pilotare l’accensione e lo spegnimento del led come anche l’apertura e la chiusura del relè cliccando sui vari link.
Questa è solo una piccola applicazione tra le “infinite” possibili ma che, pensiamo, illustri bene le enormi potenzialità della nostra scheda RLY.
Avete realizzato un’applicazione con la RLY anche molto semplice ma utile? Scriveteci cosa avete realizzato e noi saremo ben felici di postare la vostra “creatura” sul nostro Blog.
A presto!!!
molto interessante e completo.
Come posso far comparire sul browser dei pulsanti invece che delle scritte ?
Grazie
Saluti
Salve Ambro,
modificando il codice HTML all’interno della funzione ‘prepareHtmlPage()’ può aggiungere pulsanti e/o modificare l’intero layout della pagina.
Interessantissimo ma io da remoto intenderei fuori dal wifi di casa… la porta può essere diversa dalla 80? Impostando il router un dyndns ad esempio pippo.freedns.com:44444 e impostando il portforwarding sul router il tutto funzionerebbe?
Ciao Marco, certe che funzionerebbe. L’articolo è stato fatto connettendosi direttamente in locale per semplicità ma tutto funziona ugualmente anche da remoto gestendo il “Port Forwmarding” sul router ed utilizzando, se si ha un IP dinamico, un servizio come dyndns per avere un indirizzo statico dove potersi connettere. Per quanto riguarda la porta puoi decidere di cambiarla impostanto sulla riga 20 un valore diverso da 80 oppure gestire anche questa cosa tramite “Port Forwarding”. Nel manuale della RLY puoi trovare una procedura per contattare da remoto la RLY usando il firwmare originario ma le nozioni valgono in generale quindi, se vuoi, puoi leggerlo per qualche info in più: https://drive.google.com/file/d/0Bwzw_XX84ifZd201QUdjc2ZGcEE/view?resourcekey=0-9zMrmvr6L5nUHtipM0wjuA