Stampa

           

Tante versioni del cronotermostato fatto con esp8266, partendo da una base ho ampliato tutte le versioni adattandole alle mie esigenze, tutte con interfaccia web che ci permette di configurarlo da remoto e volendo anche da locale con l'aggiunta di display e potenziometro per regolare temperatura o pulsanti up down a seconda delle porte che ho a disposizione, ne ho fatte tantissime versioni ma la più semplice implica l'aggiunta di uno schermo touch seriale che ci permette di gestire tutte le funzioni della parte termostato mentre per le programmazioni serve il collegamento tramite il serverweb.

Qui sotto lo sketch della versione con 2 relay e sensore temperatura umidità-

/*
* CronoTermostato con 2 relè
* uno per la parte del termostato,
* l'altro per la parte del temporizzatore in modo che posso impostare il tempo
* di accensione che mi comanda un relè e all'interno di tale accensione un altro relè
* si eccita solo in relazione alla temperatura impostata.
* Quindi se il temporizzatore è attivo in on agisce anche il termostato ma con relè
* separati in modo che al rele del termostato posso inserire ad esempio l'accensione
* di un carico tipo luci e al raggiungimento di una soglia di temp eccitare o diseccitare
* l'altro relè(eccitare o diseccitare il relè è in base al void termControl.
* Qui abbiamo la scelta riscaldamento raffrescamento e l'isteresi impostabile.
*
* By iw5ek Andrea www.arezzonair.it
*/


#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <DHT.h>
//#include <OneWire.h> // libreria per sonda ds18b20
//#include <DallasTemperature.h> //libreria Display
// #define ONE_WIRE_BUS 2 //definizione pin sonda gpio2
//OneWire oneWire(ONE_WIRE_BUS);
//DallasTemperature sensors(&oneWire);

#define DHTPIN 2 // GPIO 2 pin of ESP8266
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT11 // DHT 11 decommentare per usare questo e commentare l'altro
#define pinTermOn 0 //definisco il pin per il rele del termostato
#define pinTempOn 5 //defisco il pin per il rele del crono
#define MAX_MILLIS_VALUE 34359738
#define ON 255
#define OFF 254
byte debug;
unsigned long previousMillis = 0;
const long intervalloDisplay = 10000;

unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
unsigned int GdSettimana = 1;
unsigned int secondi = 0;
unsigned int minuti = 0;
unsigned int ore = 1;
unsigned int giorno = 1;
unsigned int mese = 1;
unsigned int anno = 2018;
unsigned int prevSecondi = 0;
bool sinc = true;// scegli se usare l'aggiornamento automatico della data e dell'ora
bool aggioData = false;

byte EEpromData[41];
byte pData[8];
bool progOn = false;

boolean raffrescamento = false; // definizione boolean della variabile raffrescamento
float temperatura;
float umidita;
float isteresi = 0.30; // valore iniziale di isteresi
boolean termOn = false; // definizione boolean della variabile termOn
boolean caldaiaOn; //valore boolean per definire accensione termostato
boolean tempOn; //valore boolean per definire accensione crono
float setTemp = 20.0; // valore iniz. della temperatura
const char* passwordWeb = "maometto"; //password web
const char* ssid = "ASUS"; //ssid ap remoto
const char* password = ""; //password rete ap
const char* ap_ssid = "CronoTerm"; //setto l'ssid della funzione AP
const char* ap_password = "maometto"; //setto la password dell'AP
// Settaggio IP Statici
IPAddress ip(192, 168, 5, 91); //Ip statico lato client
IPAddress gateway(192, 168, 5, 55);
IPAddress subnet(255, 255, 255, 0);
IPAddress ipAP(192, 168, 6, 1);
IPAddress gatewayAP(192, 168, 6, 1); //Ip statico AP
IPAddress subnetAP(255, 255, 255, 0);
WiFiServer server(80);
WiFiClient data;

// il void termControl lo ho modificato in modo che agisce escludendo la sonda si attiva il relay mettendo
// termOn su true quindi per testare il rele senza sonda basta decommentare //else if (termOn = true) fino
// alla chiusura della parentesi}
// così posso testarlo anche senza la sonda inserita
// La parte commentata che riguarda il raffrescamento e il riscaldamento era la bozza del programma
// prima che ideassi l'inserimento del tasto raffrescamento riscaldamento quindi lasciarli commentati
// perchè sostituiti da void estate e void inverno
void estate()
{
if (temperatura >= setTemp + isteresi )
{
digitalWrite(pinTermOn, HIGH);
caldaiaOn = true;
}
else if (temperatura <= setTemp - isteresi )
{
digitalWrite(pinTermOn, LOW);
caldaiaOn = false;
}
}
void inverno()
{
if (temperatura <= setTemp - isteresi )
{
digitalWrite(pinTermOn, HIGH);
caldaiaOn = true;
}
else if (temperatura >= setTemp + isteresi )
{
digitalWrite(pinTermOn, LOW);
caldaiaOn = false;
}
}
void termControl() //il punto esclamativo nega il valore dell'espressione come fosse termOn = false
{
if (!termOn)
{
digitalWrite(pinTermOn, LOW);
caldaiaOn = false;
return;
}
//else if (termOn = true)
//{
// digitalWrite(pinTermOn, HIGH);
// caldaiaOn = true;
//}
if (raffrescamento == true )
{
estate();
}
//{
// if (temperatura >= setTemp + isteresi ) // raffrescamento
// {
// digitalWrite(pinTermOn, HIGH);
// caldaiaOn = true;
// }
// else
// {
// digitalWrite(pinTermOn, LOW);
// caldaiaOn = false;
// }
//}
else if (raffrescamento == false)
{
inverno();
}
//{
// if (temperatura < (setTemp - isteresi)) // riscaldamento
// {
// digitalWrite(pinTermOn, HIGH);
// caldaiaOn = true;
// }
// else if (temperatura > setTemp)
// {
// digitalWrite(pinTermOn, LOW);
// caldaiaOn = false;
// }
//}
}

void tempControl()
{
if (!termOn)
{
digitalWrite(pinTempOn, LOW);
tempOn = false;
return;
}
if (termOn = true);
{
digitalWrite(pinTempOn, HIGH);
tempOn = true;
}
}

void programma()
{
byte fineProgramma;
byte readByte[4];
if (progOn)
{
//leggo il programma
fineProgramma = EEPROM.read(0);
EEpromData[0] = (41 - fineProgramma) / 4; // calcolo il numero di programmazioni rimanenti max 10
if (fineProgramma > 1)
{
for (int i = 1; i < fineProgramma; i = i + 4)
{
readByte[0] = EEPROM.read(0 + i);
readByte[1] = EEPROM.read(1 + i);
readByte[2] = EEPROM.read(2 + i);
readByte[3] = EEPROM.read(3 + i);
EEpromData[0 + i] = readByte[0];
EEpromData[1 + i] = readByte[1];
EEpromData[2 + i] = readByte[2];
EEpromData[3 + i] = readByte[3];
if (readByte[3] == GdSettimana || readByte[3] == 0)
{
if (ore == readByte[2] && minuti == readByte[1])
{
if (readByte[0] == ON) //se il crono è attivo on il boolean termOn risulta vero quindi esegue sia il void tempControl che il void termControl
{
termOn = true;
tempControl();
termControl();
}
else if (readByte[0] == OFF) //lo stesso come sopra ma in termOn false (prende sia in TempControll che in termControll la parte che riguarda termOn = false)
// Quindi il cronotermostato funziona con 2 relè uno si attiva quando il crono è on l'altro termostato si attiva quando il crono è on e le condizioni sono di void termContoll
// Oppure se è in manuale funziona solo il relè termostato in modalità termostato puro.
{
termOn = false;
tempControl();
termControl();
}
}
}
}
}
}
}

void clientControl()
{
WiFiClient client = server.available();
if (!client)
{
return;
}

delay(10);
String req = client.readStringUntil('\r');
client.flush();

// Match the request
if (req.indexOf(passwordWeb) == -1)
{
client.flush();
client.stop();
return;
}

if (req.indexOf("term=on") != -1)
{
termOn = true;
}
else if (req.indexOf("term=off") != -1)
{
termOn = false;
}
if (req.indexOf("risca=on") != -1)
{
raffrescamento = true;
}
else if (req.indexOf("risca=off") != -1)
{
raffrescamento = false;
}
if (req.indexOf("setTemp=") != -1)
{
setTemp = req.substring(req.indexOf("setTemp=") + 8, req.length()).toFloat();
}
if (req.indexOf("isteresi=") != -1)
{
isteresi = req.substring(req.indexOf("isteresi=") + 9, req.length()).toFloat();
}
if (req.indexOf("cancProg=1") != -1)
{
for (int i = 1; i < 512; i++)
{
EEPROM.write(i, 0);
}
EEPROM.write(0, 1);
EEPROM.commit();
EEpromData[0] = 10;
}

if (req.indexOf("progOn=1") != -1)
{
progOn = true;
termOn = false;
}
else if (req.indexOf("progOn=0") != -1)
{
progOn = false;
}

if (progOn && EEpromData[0] > 0)
{
if (req.indexOf("insProg=1") != -1)
{
int indirizzoEEprom = EEPROM.read(0);// primo indirizzo in EEprom vuoto su cui scrivere

pData[0] = ON;
pData[1] = req.substring(req.indexOf("pMinutiOn=") + 10, req.indexOf("pMinutiOn=") + 12).toInt();
pData[2] = req.substring(req.indexOf("pOreOn=") + 7, req.indexOf("pOreOn=") + 9).toInt();
pData[3] = req.substring(req.indexOf("GdS=") + 4, req.indexOf("GdS=") + 5).toInt();
pData[4] = OFF;
pData[5] = req.substring(req.indexOf("pMinutiOff=") + 11, req.indexOf("pMinutiOff=") + 13).toInt();
pData[6] = req.substring(req.indexOf("pOreOff=") + 8, req.indexOf("pOreOff=") + 10).toInt();
pData[7] = pData[3];
//Scrittura dati in EEprom
for (int indice = 0; indice < 8; indice++)
{
EEPROM.write(indirizzoEEprom, pData[indice]);
indirizzoEEprom++;
}
EEPROM.write(0, indirizzoEEprom);
EEPROM.commit();
}
}
client.flush();
termControl();
programma();
delay(1);

client.println("HTTP/1.1 200 OK");
client.println("Connection: close");
client.println("Content-Type: text/html");
client.println("");
client.println("<html>");
client.println("<head>");
client.println("<meta charset='utf-8'>");
client.println("<link rel='icon' href='http://www.arezzonair.it/favicon.ico'/>");
client.println("<meta name='viewport' content='width=device-width, user-scalable=0, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0'/>");
client.println("</head>");
client.println("<body style='width:100%; background-color: #F7B40D; font:arial;'>");
client.println("<h1 align='center'>EspCronoTermostato</h1>");
client.print("<div id='temp' style='font-size:32px; color:BLACK; background-color:#FFFFFF; width:110px; height:60px; margin:0 auto; text-align:center; line-height:60px; box-shadow:3px 3px 5px #525252; border-radius: 10px;");
if (caldaiaOn)
{
client.print("background-color:#FF0000;");
}
client.print("'>");
client.print(temperatura, 1);
client.println("°");
client.println("</div><br>");

client.print("<div id='temp' style='font-size:32px; color:GREEN; background-color:#FFFFFF; width:110px; height:60px; margin:0 auto; text-align:center; line-height:60px; box-shadow:3px 3px 5px #525252; border-radius: 10px;'>");
client.print(umidita, 1);
client.println("%");
client.println("</div><br>");

client.print("<div id='temp' style='font-size:32px; color:BLACK; background-color:#FFFFFF; width:110px; height:60px; margin:0 auto; text-align:center; line-height:60px; box-shadow:3px 3px 5px #525252; border-radius: 10px;");
if (tempOn)
{
client.print("background-color:#FF0000;");
}
client.print("'>");
client.println("Crono");
client.println("</div>");

client.print("<form action='");
client.print(passwordWeb);
client.print(".html");
client.println("' method='GET'>");
client.println("<p align='center'>Modalita di funzionamento:</p>");
client.println("<p align='center'><input type='radio' name='progOn' value='0' checked='checked'> Manuale");
client.print("<input type='radio' name='progOn' value='1' ");
if (progOn)
{
client.print("checked='checked'");
}
client.println("> Automatico</p>");
if (!progOn)
{
client.println("<p align='center'><input type='radio' name='term' value='off' checked='checked'> OFF");
client.print("<input type='radio' name='term' value='on' ");
if (termOn)
{
client.print("checked='checked'");
}
client.println("> ON</p>");
}
else
{
client.println("<p align='center'>");
client.println("Nuovo Programma<br>");
client.println("<select name='GdS'>");
client.println("<option value='0'>Tutti i giorni</option>");
client.println("<option value='1'>Lun</option>");
client.println("<option value='2'>Mar</option></p>");
client.println("<option value='3'>Mer</option>");
client.println("<option value='4'>Gio</option></p>");
client.println("<option value='5'>Ven</option>");
client.println("<option value='6'>Sab</option></p>");
client.println("<option value='7'>Dom</option>");
client.println("</select><br>");
client.println("ON:");
client.println("<input type='number' name='pOreOn' min='0' max='23' step='1' value='0' style='width:35px;'>");
client.println("<input type='number' name='pMinutiOn' min='0' max='59' step='1' value='0' style='width:35px;'>");
client.println("OFF:");
client.println("<input type='number' name='pOreOff' min='0' max='23' step='1' value='0' style='width:35px;'>");
client.println("<input type='number' name='pMinutiOff' min='0' max='59' step='1' value='0' style='width:35px;'>");
client.println("<input type='checkbox' name='insProg' value='1'> Inserisci programma");
client.println("</p>");
client.println("<p align='center'>Programmazioni rimanenti:");
client.print(EEpromData[0] / 2);
client.println("</p>");
if(EEpromData[0] / 2 < 5)
{
client.println("<p align='center'>");
client.println("Programmi:<br>");
for (int i = 0; i < (10 - EEpromData[0]) * 4; i = i + 8)
{
if (EEpromData[i + 1] == ON)
{
client.print("ON");
}
else
{
client.print("OFF");
}
client.print(" ");
client.print(EEpromData[i + 4]);
client.print(" ");
client.print(EEpromData[i + 3]);
client.print(":");
client.print(EEpromData[i + 2]);
client.print(" - ");
if (EEpromData[i + 5] == ON)
{
client.print("ON");
}
else
{
client.print("OFF");
}
client.print(" ");
client.print(EEpromData[i + 8]);
client.print(" ");
client.print(EEpromData[i + 7]);
client.print(":");
client.print(EEpromData[i + 6]);
client.print("<br>");
}

client.println("<input type='checkbox' name='cancProg' value='1'> Cancella i programmi");
client.println("</p>");
}
}
client.println("<p align=\"center\"><input type=\"radio\" name=\"risca\" value=\"off\" checked=\"checked\"> Riscaldamento");
client.print("<input type=\"radio\" name=\"risca\" value=\"on\" ");
if (raffrescamento)
{
client.print("checked=\"checked\"");
}
client.println("> Raffreddamento</p>");
client.print("<p align='center' id='setTemp'>Set Temp:<input type='number' name='setTemp' min='10' max='50' step='0.1' style='height:50px; width:50px;' value='");
client.print(setTemp);
client.println("'></p>");
client.print("<p align=\"center\" id=\"isteresi\">Isteresi : <input type=\"number\" name=\"isteresi\" min=\"0.1\" max=\"5\" step=\"0.1\" style=\"height:50px; width:50px;\" value=\"");
client.print(isteresi);
client.println("\"></p>");
client.println("<p align='center'><input type='submit' value='SET'></p>");
client.println("</form>");
//Stampa a monitor web la data e ora
client.print(giorno);
client.print(" ");
client.print(mese);
client.print(" ");
client.print(anno);
client.print(" ");
if (ore < 10)
{
client.print("0");
}
client.print(ore);
client.print(":");
if (minuti < 10)
{
client.print("0");
}
client.print(minuti);
client.print(":");
if (secondi < 10)
{
client.print("0");
}
client.print(secondi);
client.println("</body>");
client.println("</html>");
client.stop();
}

void displayRefresh()
{
//scrive le temperature sul display
Serial.print("t0.txt=");
Serial.write(0x22);
Serial.print(temperatura, 1);
Serial.write(0x22);
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);

Serial.print("t3.txt=");
Serial.write(0x22);
Serial.print(setTemp, 1);
Serial.write(0x22);
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);

Serial.print("t6.txt=");
Serial.write(0x22);
Serial.print(umidita, 1);
Serial.write(0x22);
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);

Serial.print("t9.txt=");
Serial.write(0x22);
if (giorno < 10)
{
Serial.print("0");
}
Serial.print(giorno);
Serial.print("/");
if (mese < 10)
{
Serial.print("0");
}
Serial.print(mese);
Serial.print("/");
Serial.print(anno);
Serial.print(" ");
if (ore < 10)
{
Serial.print("0");
}
Serial.print(ore);
Serial.print(":");
if (minuti < 10)
{
Serial.print("0");
}
Serial.print(minuti);
Serial.print(":");
if (secondi < 10)
{
Serial.print("0");
}
Serial.print(secondi);
Serial.write(0x22);
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);

//setta il colore del carattere della temperatura
if (caldaiaOn)
{
Serial.print("t0.pco=RED");
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);
}
else
{
Serial.print("t0.pco=GREEN");
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);
}
Serial.print("ref t0");
Serial.write(0xff);
Serial.write(0xff);
Serial.write(0xff);
}

void serialControl()
{
if (Serial.available())
{
byte x;
x = Serial.read();
if (x == 101)
{
x = Serial.read();
x = Serial.read();
}
else
{
while (Serial.available())
{
x = Serial.read();
}
return;
}
switch (x)
{
case 10:
setTemp = setTemp + 0.1;
break;

case 11:
setTemp = setTemp - 0.1;
break;

case 12:
termOn = false;
break;

case 13:
termOn = true;
break;
}
termControl();
displayRefresh();
while (Serial.available())
{
x = Serial.read();
}
}
}

void sincDate()
{
String M;
String GdS; // Setto il server dove sincronizzare la data e l'ora
if (!data.connect("192.168.5.131", 8087)) {
return;
}
delay(500);
data.print("HEAD / HTTP/1.1\r\n\r\n");
delay(500);
//Andiamo a cercare all'interno della pagina html la stringa Date: seguita dal giorno della settimana
//poi seguita dal giorno poi dal mese e l'anno poi l'ora:minuti:secondi e le sincronizza
while (data.available()) {
if (data.read() == '\n') {
if (data.read() == 'D') {
if (data.read() == 'a') {
if (data.read() == 't') {
if (data.read() == 'e') {
if (data.read() == ':') {
data.read();
GdS = (char) data.read();
GdS += (char)data.read();
GdS += (char)data.read();
if (GdS == "Mon")
{
GdSettimana = 1;
}
else if (GdS == "Tue")
{
GdSettimana = 2;
}
else if (GdS == "Wed")
{
GdSettimana = 3;
}
else if (GdS == "Thu")
{
GdSettimana = 4;
}
else if (GdS == "Fri")
{
GdSettimana = 5;
}
else if (GdS == "Sat")
{
GdSettimana = 6;
}
else if (GdS == "Sun")
{
GdSettimana = 7;
}
data.read();
data.read();
giorno = (data.read() - '0') * 10;
giorno += data.read() - '0';
data.read();
M = (char) data.read();
M += (char)data.read();
M += (char)data.read();
if (M == "Jan")
{
mese = 1;
}
else if (M == "Feb")
{
mese = 2;
}
else if (M == "Mar")
{
mese = 3;
}
else if (M == "Apr")
{
mese = 4;
}
else if (M == "May")
{
mese = 5;
}
else if (M == "Jun")
{
mese = 6;
}
else if (M == "Jul")
{
mese = 7;
}
else if (M == "Aug")
{
mese = 8;
}
else if (M == "Sep")
{
mese = 9;
}
else if (M == "Oct")
{
mese = 10;
}
else if (M == "Nov")
{
mese = 11;
}
else if (M == "Dec")
{
mese = 12;
}
data.read();
anno = (data.read() - '0') * 1000;
anno += (data.read() - '0') * 100;
anno += (data.read() - '0') * 10;
anno += (data.read() - '0');
data.read();
ore = (data.read() - '0') * 10;
ore += (data.read() - '0') + 2; //Il più uno aumenta di un ora o 2(ora legale estiva) l'ora del server nel mio caso il sever solarlog locale.
if (ore == 24)
{
ore = 0;
}
else if (ore == 25)
{
ore = 1;
}
data.read();
minuti = (data.read() - '0') * 10;
minuti += (data.read() - '0');
data.read();
secondi = (data.read() - '0') * 10;
secondi += (data.read() - '0');
sinc = false;
data.stop();
}
}
}
}
}
}
}
}

void orologio()
{
cli(); // disable interrupts
current_millis_value = millis();
sei(); // enable interrupts

// overflow millis()
if (current_millis_value < previous_millis_value)
m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
else m += current_millis_value - previous_millis_value;

secondi += m / 1000;
m = m % 1000;
minuti += secondi / 60;
secondi = secondi % 60;
ore += minuti / 60;
minuti = minuti % 60;
ore = ore % 24;
if (ore == 00 && minuti == 00)
{
if (!aggioData)
{
aggioData = true;
giorno++;
if (giorno > 28)
{
if (mese == 2)
{
if (anno % 4 == 0 && anno % 100 != 0)
{
//bisestile
}
else if (anno % 400 == 0)
{
//bisestile
}
else
{
mese++;
giorno = 1;
}
}
}
if (giorno > 30)
{
if (mese == 4 || mese == 6 || mese == 9 || mese == 11)
{
mese++;
giorno = 1;
}
}
if (giorno > 31)
{
if (mese == 12)
{
mese = 1;
anno++;
giorno = 1;
}
else
{
mese++;
giorno = 1;
}
}
}
}
else
{
aggioData == false;
}
previous_millis_value = current_millis_value;
if (secondi != prevSecondi)
{
prevSecondi = secondi;
displayRefresh();
}
}

 

DHT dht(DHTPIN, DHTTYPE);

void setup() {
EEPROM.begin(512);
Serial.begin(9600);
dht.begin();
delay(10);

// prepare GPIO
pinMode(pinTermOn, OUTPUT);
digitalWrite(pinTermOn, LOW);

// Connect to WiFi network
WiFi.mode(WIFI_AP_STA); // Setto la modalità AP e Station
WiFi.softAPConfig(ipAP, gatewayAP, subnetAP); //Configuro AP locale
WiFi.softAP(ap_ssid, ap_password); //Configuro ssid e password
WiFi.begin(ssid, password);
WiFi.config(ip, gateway, subnet);

while (WiFi.status() != WL_CONNECTED) {
delay(700);
}

// Start the server
server.begin();

ArduinoOTA.begin();
}

void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= intervalloDisplay)
{
previousMillis = currentMillis;
umidita = dht.readHumidity();
temperatura = dht.readTemperature();
termControl();
displayRefresh();
if (sinc)
{
sincDate();
}
else if (ore == 3 && minuti == 0)
{
sinc = true;
}
}
delay(100);//non togliere!
serialControl();
clientControl();
orologio();
if (progOn)
{
programma();
}
ArduinoOTA.handle();
}