In questo articolo andremo a progettare e realizzare passo dopo passo un sensore wireless di temperatura. Tale dispositivo potrà essere utilizzato come esempio per sviluppare sensori di natura differenti, sviluppando così un intero sistema domotico.
Per realizzare questo dispositivo utilizzeremo il modulo wifi ESP8266, di cui abbiamo parlato negli scorsi articoli (qui, qui e qui) e il classico sensore di temperatura DHT11.
L’obiettivo finale è quello di ricevere e monitorare dati sulla temperatura ambientale sullo smartphone o sul pc. Uno sviluppo futuro potrà essere quello di utilizzare tali informazioni per controllare automaticamente e dinamicamente condizionatori o attuatori in generale.
Ma facciamo un passo alla volta e concentriamoci sul nostro piccolo dispositivo. Avendo discusso ampiamente del modulo ESP, passiamo ad analizzare l’altro elemento che compone il dispositivo: il sensore di temperatura DHT11.
Il DHT11 è un sensore di temperatura e umidità digitale. È adatto a molteplici applicazioni grazie ai bassi consumi e alle ridotte dimensioni. Le tensioni di lavoro comprese tra 3 volt e 5,5 volt lo rendono facilmente integrabile in un sistema con Arduino e simili. La comunicazione infine avviene tramite un single-bus.
In commercio esistono modelli differenti per forma, struttura e numero di pin, ma il principio di funzionamento è il medesimo per tutti. Di seguito, il pinout di questo sensore:
Il sensore è coperto da un case (quello che vedete in blu chiaro) e saldato su un piccolo pcb. Sulla scheda è già prevista una resistenza di pull up da 10k tra la linea dati e Vcc. Nei modelli sprovvisti di questa resistenza, è consigliabile inserirla manualmente.
Il DHT11 è un sensore estremamente economico e in quanto tale ha una risposta molto lenta. Bisogna infatti lasciarlo qualche secondo (anche 5 secondi vanno bene) per entrare a regime e calibrarsi. Inoltre, non può essere interrogato frequentemente. Consiglio infatti di non scendere sotto il secondo tra una lettura e la successiva. Nonostante ciò permette di ottenere delle misurazioni tutto sommato accurate e precise, soprattutto se il dato misurato viene filtrato, elaborato e processato a dovere.
Per poter alimentare e misurare i dati del DHT11 avremo bisogno di un microcontrollore. Come già discusso, l’ESP-01 integra le funzionalità di un microcontrollore con la possibilità di connessione wireless, oltre che le dimensioni estremamente più ridotte.
Di seguito, lo schematico tra le connessioni dei due dispositivi:
Con i collegamenti visti sopra abbiamo realizzato la connessione dei dati e predisposto l’alimentazione dei due dispositivi. In questo modo però non abbiamo alcuna possibilità di programmare l’ESP-01, visualizzare i dati del DHT11 ma soprattutto alimentare il tutto.
Come visto in un precedente articolo, per poter programmare l’ESP-01 e connetterlo al pc garantendo l’adattamento logico abbiamo bisogno di un convertitore USB-Seriale come un FTDI232R.
Con l’FTDI232R abbiamo inoltre una fonte di alimentazione per il nostro dispositivo. Il circuito aggiornato, comprendendo i collegamenti al convertitore è illustrato in seguito.
Nello schema ho previsto l’utilizzo di uno switch e un push button per permettere una facile gestione delle modalità di bootload e usage per l’ESP-01, oltre che il suo reset. Come visibile dallo schema progettuale infatti, è presente un push button tra il pin RST dell’ESP-01 e GND: quando premuto il pin RST viene portato a massa e, una volta rilasciato, il modulo viene resettato. Al pin GPIO-0 invece è stato collegato uno switch: un’estremità è collegata a GND, permettendo al modulo di entrare in modalità bootload, mentre l’altra estremità è lasciata flottante. Ciò non toglie che sia possibile usare tale pin per progetti futuri, basterà collegarsi all’estremità dello switch qui rimasta flottante.
Ciò non toglie che, in caso di mancanza di switch e push button, si possa comunque realizzare il circuito: basterà spostare i jumper manualmente, soluzione non definitiva ma comunque funzionale.
Predisposto il circuito, concentriamoci ora sulla programmazione del codice, spiegato riga dopo riga.
Avremo a che fare con connessioni wifi, con l’ESP8266, con il sensore di temperatura DHT11, con il protocollo di comunicazione MQTT (ampiamente introdotto e descritto in questi due articoli: parte 1 e parte 2) e il relativo pattern Publish/Subscribe. Tutte queste funzionalità saranno implementate da alcune librerie, di seguito elencate.
- WiFiClient.h;
- ESP8266WiFi.h;
- MQTT.h;
- PubSubClient.h;
- DHT.h.
Le prime due librerie, ovvero WiFiClient e ESP8266WiFi, sono fornite installando e usando correttamente la scheda dell’ESP8266: prestiamo dunque attenzione che nella sezione Strumenti -> Scheda sia selezionato “Generic ESP8266 Module”. Rimando a questo articolo per la configurazione.
Le librerie MQTT e PubSubClient sono scaricabili a questo link github, così come la libreria per il DHT11 su questo altro link. Da notare che l’ultima libreria per il sensore di temperatura si basa su un’altra libreria realizzata da Adafruit, ovvero Adafruit Unified Sensor Library. Dallo stesso link è possibile comunque recuperare tutto il necessario.
Sistemate le librerie, iniziamo a configurare qualche parametro.
#define SERIAL_SPEED 9600
//----WIFI CONFIG ----
#define WIFI_SSID "SSID DEL VOSTRO WIFI"
#define WIFI_PASSWD "PASSWORD DEL VOSTRO WIFI"
#define MAX_WIFI_INIT_RETRY 10
#define WIFI_RETRY_DELAY 500
Impostiamo come velocità della seriale 9600 baud, più che sufficienti per i nostri scopi. Definiamo alcuni parametri per la connessione wifi con l’SSID e la password, il numero massimo di tentativi di connessione e la distanza tra un tentativo e l’altro, espresso in millisecondi. Definiamo alcuni parametri per il protocollo MQTT.
//----MQTT CONFIG ----
#define MQTT_CLIENT_ID "NOME CLIENT MQTT"
#define MQTT_SERVER "xxx.xxx.xxx.xxx"
//#define MQTT_UNAME "UNAME"
//#define MQTT_PASSW "PASSWD"
#define MQTT_BROKER_PORT 1883
#define MQTT_TOPIC "temperatura"
Definiamo il nome del client MQTT, visibile in fase di trasferimento dati, a nostro piacimento. Con MQTT_SERVER definisco l’indirizzo IP del broker server MQTT. Esiste la possibilità di definire delle credenziali con MQTT_UNAME e MQTT_PASSW. In questo esempio saranno omesse. La porta del broker MQTT in ascolto è impostata a 1883, ovvero una porta non crittografata. Per ultimo, ma non per importanza, il topic che nel nostro caso sarà indicato come “temperatura“.
Concludiamo le definizioni iniziali indicando il nome per l’ESP-01 e il ruolo nelle dinamiche MQTT .In questo caso si tratterà di un publisher.
#define ESP_NAME "ESP"
#define ESP_PUB_ROLE
Istanziamo ora gli oggetti WiFiClient e PubSubClient utilizzando i parametri sopra definiti, oltre che una utile variabile booleana rappresentativa dello stato della connessione.
WiFiClient wifi_client;
PubSubClient mqtt_client(wifi_client, MQTT_SERVER, MQTT_BROKER_PORT);
bool mqtt_status;
Inizializziamo la connessione Wi-Fi. La seguente funzione WiFi_init() avvia la connessione e ne verifica lo stato, ritornandolo tramite Wifi.status().
int WiFi_init()
{
const char* wifi_ssid = WIFI_SSID;
const char* wifi_passwd = WIFI_PASSWD;
int retries = 0;
Serial.println("Connessione all'AP WiFi……….");
WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid, wifi_passwd);
while ((WiFi.status() != WL_CONNECTED) &&
(retries < MAX_WIFI_INIT_RETRY)) {
retries++;
delay(WIFI_RETRY_DELAY);
Serial.println("#");
}
Serial.println(String(WiFi.localIP()[0]) + "." +
String(WiFi.localIP()[1]) + "." +
String(WiFi.localIP()[2]) + "." +
String(WiFi.localIP()[3]));
return WiFi.status();
}
Wifi.status() potrà tornare i seguenti stati:
- WL_CONNECTED: assegnato quando è collegato ad una WiFi rete;
- WL_NO_SHIELD: assegnato quando nessun WiFi scudo è presente;
- WL_IDLE_STATUS: è uno stato temporaneo assegnato quando WiFi.begin() viene chiamato e rimane attivo fino al numero di tentativi di scadenza (con conseguente WL_CONNECT_FAILED) o una connessione viene stabilita (con conseguente WL_CONNECTED);
- WL_NO_SSID_AVAIL: assegnato quando nessun SSID sono disponibili;
- WL_SCAN_COMPLETED: assegnato quando la scansione delle reti è completato;
- WL_CONNECT_FAILED: assegnato quando la connessione non riesce dopo tutti i tentativi;
- WL_CONNECTION_LOST: assegnato quando la connessione è persa;
- WL_DISCONNECTED: assegnato quando ci si scollega dalla rete;
Inizializziamo ora la connessione MQTT, tramite la funzione MQTT_init().
int MQTT_init(boolean topic_subscribe)
{
Serial.println("Avvio della comunicazione MQTT………");
mqtt_client.set_max_retries(255);
if (mqtt_client.connect(MQTT::Connect(MQTT_CLIENT_ID).set_keepalive(90))) {
Serial.println("Connessione al broker MQTT: SUCCESS .........."); if (topic_subscribe) { if (mqtt_client.subscribe(MQTT_TOPIC)) { Serial.println("Sottoscrizione al topic MQTT [" + String(MQTT_TOPIC) + "] SUCCESS........."); } else { Serial.println("Impossibile sottoscrivere al topic MQTT [" + String(MQTT_TOPIC) + "] ERROR........."); mqtt_client.disconnect(); return false; } }
} else {
Serial.println("Connessione al broker MQTT ERROR……….");
}
return mqtt_client.connected();
}
Formalizzate le funzioni di connessione del WiFi e di MQTT, possiamo passare alle strutture di setup() e loop(). Nel setup() avremo:
void setup() {
Serial.begin(SERIAL_SPEED);
dht.begin();
delay(5000);
Serial.println();
Serial.println("Avvio MQTT....");
while (true) {
if (WiFi_init() != WL_CONNECTED) {
Serial.println("Connessione WiFi ERROR....");
} else {
break;
}
}
Serial.println("Connessione WiFi OK....");
while (true) {
#ifdef ESP_PUB_ROLE
mqtt_status = MQTT_init(false);
#endif
if (!mqtt_status) {
Serial.println("Connessione MQTT ERROR....");
}
else {
break;
}
}
}
Nel setup() andremo ad attivare e impostare la velocità della seriale e attivare la comunicazione con il sensore DHT11. Inoltre, si avvia la comunicazione WiFi e MQTT richiamando le relative funzioni WiFi_init() e MQTT_init().
Il loop() sarà invece così formato:
void loop() {
if (mqtt_status) {
#ifdef ESP_PUB_ROLE
int h = dht.readHumidity();
int t = dht.readTemperature();
Serial.println(String(h) + "," + String(t));
delay(10);
mqtt_client.publish(MQTT_TOPIC, String(h) + "," + String(t));
Serial.println("Messaggio inviato....");
delay(5000); // 5 sec (la scelta è arbitraria in funzione delle necessità)
#endif
}
}
Viene effettuata la lettura della temperatura e dell’umidità dal DHT11 e stampata sulla seriale (quindi visibile sul monitor seriale dell’IDE di Arduino) sottoforma di stringa. Inoltre, viene pubblicato con il relativo topic la stessa informazione stampata sulla seriale tramite mqtt_client.publish().
Non rimane che scrivere i giusti parametri (SSID, password, IP del broker etc) e caricare l’intero codice sull’ESP-01 in modalità bootloader tramite il convertitore FTDI232R, riavviando poi l’ESP-01. Se tutto è andato a buon fine, dovremmo vedere una schermata simile a questa:
Se invece non si riesce a caricare lo sketch ottenendo una schermata simile a questa:
basterà resettare l’ESP-01 dal relativo pin e riprovare.
Finito il caricamento, il sensore wireless è dunque pronto!
Aprendo il Monitor Seriale possiamo già constatare l’effettivo funzionamento, con i tentativi di connessione alla rete WiFi e al broker MQTT.
Nell’esempio riportato, l’ESP-01 è riuscito a connettersi alla rete WiFi domestica e sta ricercando il broker MQTT, inutilmente. Questo perchè dobbiamo aprirlo manualmente.
Apriamo dunque sul nostro pc un broker MQTT con Mosquitto (qui discusso) e constatiamo l’effettivo inoltro dei messaggi contenenti temperatura e umidità sul broker. Di seguito la schermata con il Monitor Seriale e il terminale su cui gira Mosquitto.
Per garantire che tutto il sistema MQTT sia funzionante, realizziamo un semplice Subscriber. Per fare ciò scarichiamo l’app per Android MyMQTT. Indichiamo l’indirizzo IP del broker e il topic et voilà!
Da notare sul broker la ricezione dei messaggi inviati dal Publisher, nel nostro caso l’ESP-01 e l’invio di tali messaggi all’app sullo smartphone MyMQTT.
Con ciò abbiamo verificato appieno il funzionamento di questo sensore, della connessione WiFi e del protocollo MQTT. Dalle potenzialità che MQTT ci offre possiamo ampliare la rete di sensori e attuatori, realizzando una vera e propria rete domotica. Il procedimento per implementare altri sensori è simile a quello qui esposto. Non rimane altro da fare che realizzare un nodo mediatore capace di gestire e controllare tutti questi nodi sensore e attuatore.
L’intero sketch è disponibile al download qui.
Per questo articolo è tutto.
Per dubbi, errori o semplicemente ringraziamenti, puoi contattarci attraverso i nostri contatti social.