ESP8266- Sensore pressione temperatura Terza parte
I moduli ESP si prestano tutti (più o meno) ad essere utilizzati per progetti a basso consumo energetico. Per maggiori informazioni in merito fare riferimento a questo documento.
Gli stati a basso consumo di ESP sono tre. Nella tabella seguente sono riassunti rispetto ai componenti che rimangono spenti.
Lo stato che è stato utilizzato in questo progetto è il deep sleep in cui solo RTC resta acceso. Lo stato deve essere imposto via codice come vedremo e da esso ESP può essere resettato solo mettendo a low il PIN RST da una causa esterna oppure, come nel nostro caso, collegandolo a GPIO16 e impostando un timer (attivo grazie a RTC) che invia un segnale periodico impostato via software che abbassa il segnale su questo pin e su RST ad esso collegato.
Per programmare ESP si può utilizzare l’ambiente Arduino. Occorre anzitutto aggiungere il link da cui scaricare le librerie ESP in Preferences-> Settings->Additional board
Il link è il seguente
http://arduino.esp8266.com/stable/package_esp8266com_index.json
Una volta fatto questo, verranno installate le librerie relative a ESP e non ci resterà che scegliere la board da noi utilizzata (in questo caso generic ESP8266 module).
Nel codice i dati vengono salvati nella memoria EEPROM tra un risveglio e l’altro. Per quel che riguarda la scrittura sulla EEPROM è bene ricordare che ESP8266 non ha una EEPROM ma la memoria flash può essere utilizzata come se lo fosse o almeno una parte di essa. Maggiori dettagli qui. Tale emulazione è di ben 512 byte(!) che può essere utilizzata per memorizzare ed elaborare piccole quantità di dati come nel nostro caso. L’obiettivo dell’elaborazione per cui viene usata la EPROM è quella di confrontare l’ultima lettura con le due precedenti.
Questo approccio rudimentale (che andrebbe reingegnerizzato anche come struttura del codice introduzcendo una struttura dati vera e propria) è particolarmente adatto a percepire le brusche diminuzioni di pressione che caratterizzano gli eventi atmosferici estremi a cui ultimamente siamo abituati.
Inizialmente vengono lette le prime due locazioni della EEPROM per capire se è già stata fatta una lettura e per collocare il dato nella prima locazione libera. Alla terza accensione la nuova lettura viene comparata con la lettura salvata nella prima cella di memoria. Se la diminuzione di pressione è consistente, lo stato del meteo viene catalogato come molto peggiorato. Di seguito si esegue uno shift dei dati in modo da conservare solo le ultime due letture.
In questo modo questo progetto non è un semplice data logger, ma realizza in pieno il paradigma IoT poichè segnala alla centralina di domotica (in questo caso domoticz su Raspberry) il dato già elaborato.
#include <Adafruit_BMP085.h> #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <EEPROM.h> /** * An example showing how to put ESP8266 into Deep-sleep mode * GPI00 to ground during flashing (without VCC) * GPI00 free and vcc during execution * flashing phase: * 1- OFF VCC ESP * 2- GP00 to ground * 3- plug USB adaptor * 4- FLash * execution PHASE * 1- OFF VCC ESP * 2- GP00 Free * 3- ON VCC ESP * 4- PLUG ESP Adaptor */ // Time to sleep (in minutes): //const int sleepTimeS = 60; //Wi Fi const char* ssid = "SSID"; // The SSID (name) of the Wi-Fi network you want to connect to const char* password = "SSIDpwd"; //DomoticZ const char* host = "192.168.1.112"; //Domoticz, i'm calling you const int httpPort1 = 8080; const int httpPort2 = 80; //Static IP address configuration IPAddress staticIP(192, 168, 1, 41); //ESP static ip IPAddress gateway(192, 168, 1, 1); //IP Address of your WiFi Router (Gateway) IPAddress subnet(255, 255, 255, 0); //Subnet mask IPAddress dns(8, 8, 8, 8); //DNS //Barometer Adafruit_BMP085 bmp; //flag della previsione int prev=0; void setup() { //Force Sleep WiFi.mode( WIFI_OFF ); WiFi.forceSleepBegin(); delay( 1 ); //Serial.begin(115200); delay(100); // Wait for serial to initialize. //while(!//Serial) { } delay(100); //Serial.println('\n'); //Serial.println("I'm awake."); } void loop() { //Hey sensor, give me the data! if (!bmp.begin()) { //Serial.println("Could not find a valid BMP085/BMP180 sensor, check wiring!"); } delay(1); //Serial.println("Temperature = "); //Serial.println(bmp.readTemperature()); //Serial.println(" *C"); //Serial.print("Pressure = "); //Serial.print(bmp.readPressure()); //Serial.println(" Pa"); // Calculate altitude assuming 'standard' barometric // pressure of 1013.25 millibar = 101325 Pascal //Serial.print("Altitude = "); //Serial.print(bmp.readAltitude()); //Serial.println(" meters"); //Serial.print("Pressure at sealevel (calculated) = "); //Serial.print(bmp.readSealevelPressure()); //Serial.println(" Pa"); //Serial.print("connecting to "); //Serial.println(host); float temperature = bmp.readTemperature(); int pressure = bmp.readPressure()/100; int altitude = bmp.readAltitude(); //umbrella or not umbrella? forecast(pressure); // Bring up the WiFi connection WiFi.forceSleepWake(); delay( 1 ); WiFi.mode( WIFI_STA ); WiFi.config(staticIP, gateway, subnet); WiFi.begin(ssid, password); // Connect to the network //Serial.print("Connecting to "); //Serial.print(ssid); Serial.println(" ..."); int i = 0; while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect delay(1000); //Serial.print(++i); Serial.print(' '); } // Use WiFiClient class to create TCP connections WiFiClient client; if (!client.connect(host, httpPort1)) { //Serial.println("connection failed"); sleepWell(); } // We now create a URI for the request for Domoticz String url = "/json.htm?type=command¶m=udevice&idx=29&nvalue=0&svalue="; url += String(temperature, 1); url += ";"; url += String(pressure); url += ";"; url += String(prev); url += ";"; url += "0"; //json string to domoticz http://192.168.1.112:8080/json.htm?type=command¶m=udevice&idx=29&nvalue=0&svalue=65;800;4;0 //Serial.print("Requesting URL: "); //Serial.println(url); // This will send the request to the server client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { //Serial.println(">>> Client Timeout !"); client.stop(); return; } } // Read all the lines of the reply from server and print them to //Serial while (client.available()) { String line = client.readStringUntil('\r'); //Serial.print(line); } //Serial.println(); //Serial.println("closing connection"); WiFiClient client2; //Meteo data archive if (!client2.connect(host, httpPort2)) { sleepWell(); } // We now create a URI for the request for Domoticz url = "/meteostation/insertmeteostation.php?idx=29&tempdata="; url += String(temperature, 1); url += "&pressdata="; url += String(pressure); //Serial.print("Requesting URL: "); //Serial.println(url); // This will send the request to the server client2.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); timeout = millis(); while (client2.available() == 0) { if (millis() - timeout > 5000) { //Serial.println(">>> Client Timeout !"); client2.stop(); return; } } // Read all the lines of the reply from server and print them to //Serial while (client2.available()) { String line = client2.readStringUntil('\r'); //Serial.print(line); } //Serial.println(); //Serial.println("closing connection"); sleepWell(); } void forecast(int analogTemp){ delay(1); //Serial.println('\n'); //Serial.println("looping"); EEPROM.begin(512); delay(1); //Serial.println('\n'); int val0 = int(EEPROM.read(0)); int val1 = int(EEPROM.read(1)); int compare=0; if (val0==0){ //Scrivi su 0 //Serial.println("Scrivo su 0"); EEPROM.write(0, int(analogTemp/4.2)); }else{ if (val1==0){ //Scrivi su 1 //Serial.println("Scrivo su 1"); EEPROM.write(1, int(analogTemp/4.2)); }else{ //previsione compare= analogTemp-(int(EEPROM.read(0)))*4.2; if(compare <=-20){ //Serial.println("PEGGIORAMENTO: "+String(compare)); prev= 4; }else{ if((compare<=-10)&&(compare>-20)){ //Serial.println("PEGGIORAMENTO LIEVE: "+String(compare)); prev= 3; }else{ if((compare<=0)&&(compare>-10)){ //Serial.println("PEGGIORAMENTO molto LIEVE: "+String(compare)); prev= 2; }else{ if(compare>0){ //Serial.println("miglioramento: "+String(compare)); prev= 1; } } } } //Shift //Serial.println("Shift"); EEPROM.write(0, int(val1)); EEPROM.commit(); EEPROM.write(1, int(analogTemp/4.2)); //Serial.println("memory"); //Serial.println("ind 0: "+ String((int(EEPROM.read(0)))*4.2)); //Serial.println("ind 1: "+ String((int(EEPROM.read(1)))*4.2)); } } EEPROM.commit(); } void sleepWell(){ //Serial.println("Going into deep sleep"); WiFi.disconnect( true ); delay(100 ); //sleep for 63 min ESP.deepSleep(3740000000,WAKE_RF_DISABLED); // }
Il codice verrà commentato in dettaglio in un articolo successivo.