Prese comandate IoT controllate da cellulare (ESP8266)
Con questo progetto è possibile comandare 2 prese elettriche da remoto tramite cellulare collegato al WI-FI di casa oppure manualmente tramite 2 pulsanti presenti sulla presa stessa.
Questo è il risultato finale:mentre questa è l'interfaccia web:Per la realizzazione servono:
Per far entrare l'alimentatore USB nella scatola ho dovuto tagliare i contatti dell'alimentatore e sadare i fili:Inolte il cavo USB va tagliato per derivare un positivo e un negativo che vanno alla scheda relè ed un altro negativo che va all'ESP8266.Isola bene tutti i collegamenti con del nastro isolante.
Questo è il cablaggio interno:Ho utilizzato un pezzo di plastica (una vecchia scheda punti del supermercato) per fissare la scheda relè. Gli altri componenti, una volta chiusa la scatola, non possono muoversi quindi non è necessario nessun fissaggio.
Fai solo attenzione quando richiudi il tutto a non schiacciare qualche cavo o piegare i piedini dell'ESP8266.
Il codice per comandare i relè tramite WI-FI e generare l'interfaccia web è il seguente:
La pagina web utilizza la libreria Bootstrap per l'interfaccia grafica. Avendo l'ESP8266 solo 4MB di memoria, la libreria risiede su una CDN e quindi per la corretta visualizzazione è necessario l'accesso a internet.
Questo è il risultato finale:mentre questa è l'interfaccia web:Per la realizzazione servono:
- Nr. 1 contenitore da parete GEWIS 27005
- Nr. 1 pulsante doppio GEWIS 20521
- Nr. 2 prese 10/16A GEWIS 20203
- Nr. 3 tasto copriforo GEWIS 20056
- Nr. 1 ESP8266
- Nr. 1 modulo 2 relè
- Nr. 1 alimentatore USB compatto 800mA
- Nr. 1 cavo micro USB
- Nr. 1 cavo 3G1,5
- Nr. 1 spina 10A
Per far entrare l'alimentatore USB nella scatola ho dovuto tagliare i contatti dell'alimentatore e sadare i fili:Inolte il cavo USB va tagliato per derivare un positivo e un negativo che vanno alla scheda relè ed un altro negativo che va all'ESP8266.Isola bene tutti i collegamenti con del nastro isolante.
Verifica con attenzione le polarità con un tester per evitare di far danni.
Questo è il cablaggio interno:Ho utilizzato un pezzo di plastica (una vecchia scheda punti del supermercato) per fissare la scheda relè. Gli altri componenti, una volta chiusa la scatola, non possono muoversi quindi non è necessario nessun fissaggio.
Fai solo attenzione quando richiudi il tutto a non schiacciare qualche cavo o piegare i piedini dell'ESP8266.
ATTENZIONE: La corrente è molto pericolosa e non si vede, quindi se non sai bene cosa stai facendo, EVITA di mettere mano ai circuiti elettrici.
Comunque quando lavori su un circuito elettrico assicurati che non sia sotto tensione, quindi togli la spina o abbassa l'interruttore generale sul contatore Enel.
In ogni caso non mi assumo nessuna responsabilità per eventuali inesattezze riportate, ogni modifica la fai a tuo rischio e pericolo.
Comunque quando lavori su un circuito elettrico assicurati che non sia sotto tensione, quindi togli la spina o abbassa l'interruttore generale sul contatore Enel.
In ogni caso non mi assumo nessuna responsabilità per eventuali inesattezze riportate, ogni modifica la fai a tuo rischio e pericolo.
Il codice per comandare i relè tramite WI-FI e generare l'interfaccia web è il seguente:
Arduino
#include <ESP8266WiFi.h>
// prese comandate
//----------------------------------------
// configurazione WI-FI
const char WiFiSSID[] = "ssid-xxx";
const char WiFiPSK[] = "password";
// IP statico
IPAddress ip(192, 168, 1, 50);
IPAddress gateway(192,168,1,254);
IPAddress subnet(255,255,255,0);
//----------------------------------------
// Definizione PIN I/O
const int RELE1_PIN = 16; // D0 - GPIO16
const int RELE2_PIN = 5; // D1 - GPIO5
const int BTN1_PIN = 4; // D2 - GPIO4
const int BTN2_PIN = 0; // D3 - GPIO0
String printOnOff(int v){
return String(v == HIGH ? "off" : "on");
}
//----------------------------------------
// gestione relè
int rele1 = HIGH;
int rele2 = HIGH;
void changeRele1(){
rele1 = (rele1 == LOW) ? HIGH : LOW;
digitalWrite(RELE1_PIN, rele1);
Serial.println("Rele1: " + printOnOff(rele1));
}
void changeRele2(){
rele2 = (rele2 == LOW) ? HIGH : LOW;
digitalWrite(RELE2_PIN, rele2);
Serial.println("Rele2: " + printOnOff(rele2));
}
//----------------------------------------
// gestione pulsanti
int button1prev = LOW;
int button2prev = LOW;
void readButtons(){
int button1 = digitalRead(BTN1_PIN);
int button2 = digitalRead(BTN2_PIN);
bool wait = false;
if (button1 != button1prev) {
Serial.println("Button1: " + printOnOff(button1));
if(button1 == LOW){
changeRele1();
}
wait=true;
}
button1prev = button1;
if (button2 != button2prev){
Serial.println("Button2: " + printOnOff(button2));
if(button2 == LOW) {
changeRele2();
}
wait=true;
}
button2prev = button2;
if(wait){
delay(300); //per evitare rimbalzi
}
}
//----------------------------------------
// inizializzazione server
WiFiServer server(80);
void initWiFi() {
// tento di connetermi alla WI-FI
Serial.println();
Serial.println("Attempting to connect to: " + String(WiFiSSID) + " ...");
//attendo la disponibilità del wifi
while ( WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
// Mi connetto alla WIFI ( WPA/WPA2 )
WiFi.begin(WiFiSSID, WiFiPSK);
// setto l'IP statico
WiFi.config(ip,gateway,subnet);
Serial.println();
Serial.print("WiFi connected IP:");
Serial.print(WiFi.localIP());
}
void initServer(){
// avvio il server
server.begin();
// visualizzo l'indirizzo IP
Serial.println();
Serial.print("Use this URL to connect: http://");
Serial.print(WiFi.localIP());
Serial.print("/");
Serial.println();
}
//----------------------------------------
// pagina web
void sendResponse(WiFiClient client){
// invio la risposta
String c1 = String(rele1 == HIGH ? "btn-default" : "btn-success");
String c2 = String(rele2 == HIGH ? "btn-default" : "btn-success");
client.flush();
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println(); // questo è indispensabile
client.println("<!DOCTYPE HTML>");
client.println("<html lang=\"it\">");
client.println("<head>");
client.println("<meta charset=\"utf-8\">");
client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">");
client.println("<title>Prese comandate - Sgart.it</title>");
client.println("<meta name='description' content='Prese comandate - IoT - WiFi - Sgart.it'>");
client.println("<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">");
client.println("<link rel=\"icon\" href=\"http://www.sgart.it/favicon.ico\" type=\"image/x-icon\">");
client.println("<style>body{padding-top:50px;background-color:#fafafa;color: #606060;} .navbar-brand{padding-top:10px;} ");
client.println(".btn-height{height:90px;line-height:76px;margin-bottom:15px;font-size:28px;} .btn-default{background-color:#ffffff;color:#333333;} #box-wait{display:none;position:absolute;top:0;left:0;width:100%;height:5px;background-color:#0f0;z-index:1500;}");
client.println(".footer{position: fixed;width:100%;height:40px;line-height:40px;bottom:0;left:0;background-color:#222;color:#606060;vertical-align:middle;padding-left: 5px;</style>");
//script
client.println("<script>function doCommand(obj,n){");
client.println("var url = /rele/+n;");
client.println("var objWait = document.getElementById(\"box-wait\")");
client.println("objWait.style.display = \"inline\";");
client.println("var xmlhttp = new XMLHttpRequest();");
client.println("xmlhttp.onreadystatechange = function(){");
client.println(" if (xmlhttp.readyState == 4){");
client.println(" if (xmlhttp.status == 200){");
client.println(" var result = xmlhttp.responseText.replace(/^\\s+|\\s+$/gm,'');");
client.println(" obj.className = \"btn btn-block btn-height \" + (result===\"on\" ? \"btn-success\" : \"btn-default\" ); ");
client.println(" }");
client.println(" objWait.style.display = \"none\";");
client.println(" }");
client.println("}");
client.println("xmlhttp.open(\"GET\", url, true);");
client.println("xmlhttp.send();");
client.println("}</script>");
client.println("</head>");
client.println("</body>");
//waiting
client.println("<div id=\"box-wait\"></div>");
//nav bar
client.println("<div class=\"navbar navbar-inverse navbar-fixed-top\"><div class=\"container\"><div class=\"navbar-header\">");
client.println("<a class=\"navbar-brand\" href=\"http://www.sgart.it\"><img width=\"32\" height=\"32\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMxJREFUSEvdVsERgzAM807slJ26Ezu5pr7jCJEDAtP0yunlJFIkB4LInzyqko4qmnR2IwQCWe3w7X5ZYC46l9aBFQ8RraodjBWIetM3RzgYJkCcOjd7ql0E62aqvsQQnqLPKIu6B6ME0vKIIkoWYFMOO9cGfo2aELgYRREFZ3spwjqtEhGBupf6AG/JeQeH7FQUyMEkOoUR2VAHwFnL5uvDr+bTAmz3wXb7DjIERHa/ASzpdr5R7dlA6YZCKOADWajvgzzedX83IvippW8ssVKXGc5FQwAAAABJRU5ErkJggg==\" /></a>");
client.println("</div></div></div>");
//header
client.println("<div class=\"container\"><div class=\"page-header\"><h1>Prese comandate</h1></div></div>");
//body
client.println("<div class=\"container\"><div class=\"row\">");
client.println("<div class=\"col-md-6\"><button id=\"btn1\" type=\"button\" onclick=\"doCommand(this,1)\" class=\"btn btn-block btn-height " + c1 + "\">Presa 1</button></div>");
client.println("<div class=\"col-md-6\"><button id=\"btn2\" type=\"button\" onclick=\"doCommand(this,2)\" class=\"btn btn-block btn-height " + c2 +"\">Presa 2</button></div>");
client.println("</div></div>");
client.println("<div class=\"footer\"><div class=\"content-wrapper\">@2016 <a href=\"http://www.sgart.it/?prese-comandate\">Sgart.it</a> - Prese comandate - v. 1.0.0</div></div>");
client.println("</body></html>");
delay(1);
client.stop();
}
void sendReleStatus(WiFiClient client, int releStatus){
client.flush();
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println(); // questo è indispensabile
client.println(printOnOff(releStatus));
delay(1);
client.stop();
}
//----------------------------------------
// inizio
void setup() {
Serial.begin(9600);
delay(10);
Serial.println("INIT I/O");
// imposto le uscite
pinMode(RELE1_PIN, OUTPUT);
digitalWrite(RELE1_PIN, rele1);
pinMode(RELE2_PIN, OUTPUT);
digitalWrite(RELE2_PIN, rele2);
//imposto gli ingressi
pinMode(BTN1_PIN, INPUT_PULLUP);
pinMode(BTN2_PIN, INPUT_PULLUP);
initWiFi();
initServer();
}
//----------------------------------------
// codice eseguito ciclicamente
void loop() {
readButtons();
// aspetto che un client si connetta
WiFiClient client = server.available();
if (!client) {
return;
}
// attendo che invii qualche dato
while(!client.available()){
delay(1);
}
// leggo la prima linea della richiesta (attenzione è CASE SENSITIVE)
String request = client.readStringUntil('\r');
Serial.println(request);
// routing
if (request.indexOf("/rele/1") != -1) {
changeRele1();
sendReleStatus(client, rele1);
} else if (request.indexOf("/rele/2") != -1) {
changeRele2();
sendReleStatus(client, rele2);
}else{
sendResponse(client);
}
}
Per funzionare va impostato l'SSID e la password della tua rete WI-FI oltre all'IP e netmask.