Inviare dati da un sensore di umidità del suolo ad un db con ESP8266

La versatilità dell’ESP8266 ha come confini solo la nostra fantasia. Come per qualsiasi Arduino, anche con il nostro micro-controllore possiamo collegare una vasta gamma di sensori e, in più, inviare i dati letti ad un database per essere poi utilizzati in svariati modi. Vediamo come.

L’idea è quella di usare il nostro ESP8266 come lettore di sensori. Ovviamente l’esempio è puramente didattico e generico, ma con poco sforzo può essere replicato per altri sensori.

Cosa ci occorre

  • una basetta ESP8266
  • un cavetto micro-usb
  • un sensore di umidità FC-28
  • due cavetti dupont femmina-maschio (colore a piacere) per collegare da sonda a sensore
  • quattro cavetti dupont femmina-maschio per collegare da sensore a ESP8266
  • software Arduino (scarica qui la versione del nostro test 1.8.12)

Prepariamo l’IDE

Prepariamo prima l’ambiente di sviluppo ovvero il nostro IDE Arduino per riconoscere la scheda. Se non lo abbiamo fatto in altre esercitazioni, ci occorre aggiungere al nostro IDE la il software della scheda. Andiamo in File->Impostazioni->URL Aggiuntive per il gestore Schede e incolliamoci questo URL ufficiale e sempre aggiornato:

https://arduino.esp8266.com/stable/package_esp8266com_index.json

Selezioniamo la porta. Su linux la porta di default è la /dev/ttyUSB0. Su Windows, a second della versione che usate, potrebbe essere una tra le COM1, COM2 o la più probabile COM3. Selezionatela nella voce di menù Strumenti->Porta avendo cura di provare anche le altre se lo sketch desse errore in fasi di upload. In genere, su Windows, la porta viene riconosciuta automaticamente o compare una voce di fianco nella tendina che indica il nome del dispositivo.

Selezioniamo il dispositivo, ovvero scheda, corretto. Qui ci sono due possibilità: o usiamo la versione ESP8266 nuda e creda che fa uso di una architettura GPIO per la numerazione dei pin oppure ricorriamo ad una semplificazione con scheda NodeMCU 1.0 (ESP12E-Module) che nomina i pin con le lettere che sono stampate direttamente sulla basetta. Lasciamo ad altri post la spiegazione, vantaggi e svantaggi dei due approcci.

Per la nostra esperienza ci basta configurare al meglio il tutto in modo semplice. Usate la voce di menù sull’IDE Strumenti->Scheda e cercate nella tendina la voce indicata NodeMCU 1.0 (ESP12E-Module). Notiamo che alcune librererie aggiuntive sono spesso scritte per ragionare con la scheda ESP8266, altre volte con la NodeMCU: il discrimine si evidenzia in fase di compilazione poiché avremo un errore sul nome utilizzato per pilotare i pin. Se tra le schede non compare il nome indicato, niente paura, dobbiamo aggiungerlo da libreria. Andate quindi  Strumenti->Scheda->Gestore Schede e nella finestrella in alto a destra cercate ESP8266, vi comparirà un risultato ESP8266 by ESP8266 Community che, mentre scriviamo, è arrivata alla versione 2.6.3.

In Strumenti->Gestione librerie assicuriamoci che sia installata la libreria che ci fornisce funzioni e strumenti vari per gestire le connessioni senza fili. Scorrete la lista fino a trovare WiFi built-in Arduino, giunto alla versione 1.2.7. Stessa cosa, cercate ed installate Arduino Uno WiFi Dev ed by Arduino.

Assemblaggio

L’assemblaggio è molto semplice, non richiede particolari abilità manuali o in campo elettronico. La maggior parte dei sensori in commercio hanno quattro pin: due son oda collegare all’alimentazione VCC 3.3 ed uno al G/GND per l’alimentazione. I dati possono poi essere mandati in formato analogico mentre il pin digitale serve semplicemente a rilevare se la misurazione è o no al di sopra del valore di “threshold”, il valore limite di soglia che può essere regolato con il potenziometro, ovvero la vitarella sul sensore. Dati dei sensori è sempre bene acquisirli in modo analogico, quindi assicuriamoci di collegare il pin A0 sul sensore al pin A0 o simile sul nostro ESP8266. Collegarne tre o quattro, sia lettura analogica che digitale, non pregiudica la misurazione.

Il codice

Il codice per la gestione del sensore è piuttosto banale. Eseguiamo una lettura analogica con la funzione standard dedicata. Il valore senza umidità tornato è 1024,00, mentre mano a mano che si inumidisce la sonda, ad esempio con una spugna o immergendo in un terriccio umido, il valore letto diminuisce. Le letture possono quindi essere ripetute periodicamente scegliendo un intervallo di ritardo. Stampiamo sull’interfaccia seriale il valore letto. Manteniamo semplice il nostro esercizio con un solo sensore, ma facciamo mente locale alle potenzialità degli 8 pin digitali e 1 analogico. L’analogico è dotato di un convertitore ADC a 10bit con valori a decimali a due cifre e parte intera compresa tra 0 e 1023 che può essere multiplexato per ricevere segnali da svariati sensori (ne accendo/invio uno alla volta, per capirci)

float value = 0;

void setup() {
pinMode(A0, INPUT); 

Serial.begin(9600);
}

void loop() {
value = analogRead(A0);
Serial.print("Umidità rilevata= ");
Serial.println(value);  
delay(5000); //ogni 5 secondi fai una misurazione
}

Le funzionalità di rete

Siamo pronti ora a vedere come scrivere questi dati catturati su un database. ESP8266 non scrive pagine PHP, ma può sempre collegarsi ad una pagina PHP esistente su qualche dominio esterno e mandargli dei dati col GET nell’URL o POST. I dati possono essere sotto forma di semplici parametri, o addirittura stringhe JSON, molto utili se alla ESP ci fossero collegati sensori multipli.

Sensore -> ESP8266 -> Access Point/Router -> Sito in Hosting con Apache -> pagina  in PHP raccogli dati GET/POST -> Database MySQL -> esposizione dati JSON con PHP

Per questo esercizio predispongo gli script PHP e il database qui sul dominio che ospita questo sito web. Potete trovare in rete numerosi servizi gratuiti che mettono a disposizione un server Apache con PHP e un db MySQL. Su quest’ultimo creiamo una tabella dove andremo a raccogliere i dati del sensore. La struttura, al momento semplice e autodescrittiva, potrebbe essere simile a questa:

CREATE TABLE IF NOT EXISTS `Sensore` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nome` varchar(60) NOT NULL,
  `valore` float NOT NULL,
  `lettura` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Nel campo nome inseriremo un identificativo del sensore, il valore che ha inviato ed in automatico stacchiamo un valore progressivo come chiave della tabella e la data/ora automatica in cui è stato inserito il record.

Occupiamoci ora del nostro codice sulla basetta ESP8266. Creiamo un nuovo scketch nel nostro Arduino IDE. Ci servono prima un po’ di librerie e qui andiamo ad utilizzare quelle standard ESP8266 con i primi include. Come in tutte le esperienze  con funzionalità di rete/WiFi, ci andiamo ad impostare due stringhe con SSID e password del nostro Access Point o modem di casa. Ci serviranno poi una variabile reale per gestire i valori del sensore e una variabile stringa dove possiamo inserire un nome identificativo del sensore.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

float value = 0;

String ssid     = "SSIDdellaTUArete";
String password = "PASSWORDdellaTUArete";
String nomesensore = "FC28"; 

Il secondo frammento è quello del setup dove andiamo a predisporre il sensore e il suo pin seria, la console seriale per la stampa dei messaggi di debug (che vi ricordo si apre col menu Strumenti->Monitor seriale e si imposta la medesima velocità/banda in fondo del valore del codice qui sotto). Segue quindi la connessione effettiva alla rete Wi-Fi con tanto di configurazione/IP fisso. Se usate il DHCP, potete eliminare o commentare le righe IPAddress* e WiFi.config.

void setup() 
{
  //GESTIONE PIN
  pinMode(A0, INPUT); 

  //GESTIONE MONITOR SERIALE
  Serial.begin(115200);

  //GESTIONE WI-FI
  IPAddress ip(192, 168, 1, 108); 
  IPAddress gateway(192, 168, 1, 1); 
  IPAddress subnet(255, 255, 255, 0); 
  WiFi.config(ip, gateway, subnet);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Sei collegato alla rete LAN");
  Serial.println(WiFi.localIP());
}

Non ci rimane che creare il nostro codice principale che a loop leggerà il sensore e predisporrà un URL per raggiungere una pagina PHP e consegnargli quindi i dati letti. Nel nostro caso la pagina si trova su questo dominio e la chiameremo soilmoisture.php. Inserite l’url del dominio che ospita il file. Il codice per inviare l’URL è piuttosto semplici ed intuitivo, utilizzando le funzioni messeci a disposizione dalle librerie. Ci colleghiamo ad una pagina, gli inviamo un header che sia un GET, un POST o JSON, qui un POST da form simulato e quindi  si preparano i dati da inviare come un URL con GET

  HTTPClient http;
  http.begin("https://www.unsito.it/soilmoisture.php"); //l'URL HTTP a cui ci collegheremo
  http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 
  String httpPost = "sensore=" + nomesensore
                  + "&valore=" + String(value)

 Inviare i dati appena costruiti allo script è semplicissimo e la stessa chiamata restituisce una risposta con il classico valore 200 se positivo, o uno della serie 300, 400, 500 per errori vari  o -1 se la connessione non si innesca.

  int httpResponse = http.POST(httpPost);

La risposta e il payload può essere usata per debug. Sicuramente se httpResponse dovesse essere -1, allora ci troviamo davanti ad un bel problema che la nostra basetta non raggiunge la pagina per problemi di rete o un link sballalo.

Il codice completo:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

float value = 0;

String ssid     = "SSIDdellaTUArete";
String password = "PASSWORDdellaTUArete";
String nomesensore = "FC28"; 

void setup() 
{
  //GESTIONE PIN
  pinMode(A0, INPUT); 

  //GESTIONE MONITOR SERIALE
  Serial.begin(115200);

  //GESTIONE WI-FI
  IPAddress ip(192, 168, 1, 108); 
  IPAddress gateway(192, 168, 1, 1); 
  IPAddress subnet(255, 255, 255, 0); 
  WiFi.config(ip, gateway, subnet);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Sei collegato alla rete LAN");
  Serial.println(WiFi.localIP());
}

void loop() 
{
  //LETTURA SENSORE
  value = analogRead(A0);
  Serial.print("Umidità rilevata= ");
  Serial.println(value);  

  //PREPRAZIONE URL
  HTTPClient http;
  
  //l'URL HTTP a cui ci collegheremo
  http.begin("https://www.unsito.it/soilmoisture.php"); 
  http.addHeader("Content-Type", "application/x-www-form-urlencoded"); 
    
  //Aggiungo le variabili da passare col POST
  String httpPost = "sensore=" + nomesensore
               + "&valore=" + String(value)
               +"";
  Serial.print("HTTP Post: ");
  Serial.println(httpPost);
  

  // Invia richiesta HTTP POST
  int httpResponse = http.POST(httpPost);

  //Feedback del server per debug
  String payload = http.getString();  
  Serial.print("Risposta Server: ");
  Serial.println(httpResponse);
  Serial.print("Payload: ");
  Serial.println(payload);  

  delay(1000 * 60); //ogni minuto fai una misurazione
}
Il nostro sensore collegato ed appoggiato su una spugna bagnata per simulare il terreno ma senza sporcare!

La pagina PHP

Lo script PHP in realtà non ha nulla di particolare per il lettore appassionato di queste pagine. Si tratta di uno script che riceve i dati $_POST e li elabora per inserirli con una query su db. Vediamo qui sotto un esempio. Il file config.php contiene le variabili da inizializzare e passare al db per la connessione.

<?php
require_once("config.php");

if (isset($_POST['sensore']) && isset($_POST['valore']))
{
	$sensore     = $_POST['sensore'];
	$valore      = $_POST['valore']; 
	$connessione = mysqli_connect($mysql_host,$mysql_user,$mysql_pass,$mysql_db);
	if (mysqli_connect_errno())
	die("Connessione non riuscita: " . mysqli_error($connessione));
  
  	$query = "INSERT INTO Sensore (id, nome, valore, lettura) VALUES (null, $sensore, $valore,CURRENT_TIMESTAMP)";
	$res = mysqli_query($connessione,$query) or die("Errore nella query: " . mysqli_error($connessione));
	mysqli_close($connessione); 

}
else
	echo "Script invocato senza parametri POST";

?>
Uno screen del database con le righe scritte dallo script PHP

Come migliorare il nostro applicativo

  • Scritti i dati su un database, il lettore può graficarli con la più classica delle pagine PHP/HTML/CSS, oppure semplicemente esporli in formato JSON per renderli disponibili per altri applicativi web o app mobile.
  • Un dettaglio di cui non abbiamo tenuto conto in questa guida è l’uso del protocollo HTTPS basato su TLS. Questa considerazione ci obbliga a modificare il codice per aggiungere un certificato una impronta del sito a cui ci colleghiamo per permettere alla basetta di creare una connessione sicura.
  • Abbiamo scartato l’invio dei dati col GET ma applicazione più interessante potrebbe essere quella di mandare alla pagina PHP i dati sono forma di JSON, decisamente utile nel caso si debbano inviare oggetti complessi e multipli e soprattutto se dobbiamo inviare dati a sistemi strutturati di cui abbiamo delle specifiche API in tal senso.

Ultima modifica 27 Marzo 2024