In questo articolo, realizzeremo una semplice configurazione di rete ESP-WiFi MESH composta da quattro dispositivi ESP che comunicheranno tra loro con l'aiuto di una rete WiFi MESH. Ogni dispositivo ESP è collegato ad un sensore, quindi, collegheremo un singolo ESP al nostro computer per ottenere dati da tutti e quattro i sensori della rete. In questo progetto/tutorial, utilizzeremo entrambe le schede ESP32 ed ESP8266 in modo da poter creare una rete MESH ESP8266 o una rete MESH ESP32 utilizzando lo stesso metodo.
Introduzione
L’IoT (Internet of Things) ha registrato una crescita esponenziale negli ultimi anni. Man mano che il numero di dispositivi IoT cresce, la quantità di dati cresce, e di pari passo cresce la necessità di strumenti di rete superiori che possano sostenere questo carico. Se però consideriamo un host comune (come un generico router), esso può connettersi ad un numero limitato di nodi, meno di 32 per l'esattezza, e con un numero crescente di dispositivi IoT che potrebbero trovarsi nelle nostre case o nel nostro ambiente lavorativo, ciò non è sufficiente. Attualmente, esistono due soluzioni a questo problema: la prima è utilizzare un router Mesh in grado di gestire molte più connessioni rispetto ad uno generico, oppure possiamo utilizzare un protocollo di rete noto come Mesh Network.
Secondo la documentazione ufficiale di Espressif, la rete ESP-WiFi-MESH è una rete auto-organizzante e auto-rigenerante, il che significa che la rete può essere costruita e mantenuta in modo autonomo. Per maggiori informazioni sulla rete ESP-WiFi MESH visitate la documentazione ufficiale andando sul sito https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/esp-wifi-mesh.html?highlight=esp%20mesh.
Una rete mesh è un gruppo di dispositivi connessi su una rete che agisce come un'unica rete. La rete ESP-WiFi MESH è molto diversa da una configurazione mesh tradizionale. In un ESP-WiFi MESH, il nodo (un singolo dispositivo) può connettersi simultaneamente al suo vicino. Un singolo nodo può connettersi a più nodi e questi possono trasmettere dati da un nodo ad un altro. Questo processo non è solo efficiente ma è anche ridondante. Se uno dei nodi fallisce, i dati provenienti da altri nodi possono raggiungere la loro destinazione senza problemi grazie alla proprietà di auto-rigenerazione della rete ESP-WiFi MESH. Ciò apre anche la possibilità di realizzare l’interconnessione senza la necessità di un nodo centrale, estendendo significativamente l’area di copertura della rete mesh. Con queste caratteristiche, il numero totale di nodi nella rete non è limitato da un singolo nodo centrale. Per semplicità, in questo progetto abbiamo deciso di utilizzare quattro moduli ESP, ma è possibile utilizzare più dispositivi ESP. Per costruire la rete mesh, utilizzeremo la libreria painlessMesh per Arduino che supporta sia i moduli ESP8266 che ESP32.
Il progetto
Per realizzare la rete ESP-WiFi MESH di sensori, collegheremo un sensore BME280 ad una scheda ESP32, un sensore DHT22 a due schede ESP8266 e il sensore DS18B20 ad un’altra scheda ESP8266. Infine, connetteremo tutti i dispositivi tramite una rete ESP-WiFi MESH. In Figura 1 è mostrato lo schema elettrico dei collegamenti dell'hardware costituente la rete mesh di sensori.
Il sensore BME280
Il modulo sensore BME280 misura la pressione barometrica, la temperatura e l'umidità. Poiché la pressione cambia con l'altitudine, è possibile anche stimare l'altitudine. Esistono diverse versioni di questo sensore. Un sensore comunica utilizzando il protocollo di comunicazione I2C (come nel nostro progetto), quindi il cablaggio è molto semplice. Esistono altre versioni di questo sensore che possono utilizzare protocolli di comunicazione SPI o I2C. La Figura 2 riporta l’immagine di un sensore BME280.
Il sensore DHT22
Il sensore di temperatura e umidità DHT22 è un sensore versatile ed economico utilizzato per misurare la temperatura e l'umidità ambientale per un'ampia gamma di applicazioni. Si basa sulla misura del segnale di uscita digitale e può fornire misurazioni ad alta precisione con una risoluzione di 0,1 gradi Celsius per la temperatura e 0,1% per l'umidità. La Figura 3 mostra il sensore DHT22.
Il sensore DS18B20
Il DS18B20 è un sensore digitale di temperatura che può fornire una risoluzione da 9 bit a 12 bit e può misurare temperature da -55°C a +125°C. Il chip DS18B20, progettato e sviluppato da Maxim, presenta un'interfaccia proprietaria OneWire, che ha la particolarità che non solo può essere alimentato con i pin VCC e massa standard, ma può derivare l'alimentazione direttamente dalla linea dati. Oltre a ciò, questo dispositivo è dotato anche di un ID univoco a 64 bit e di impostazioni di allarme non volatile (NV) definibili dall'utente. E' importante sapere che è necessario collegare una resistenza da 4,7K/10K fra il pin del segnale "DATA" e la 3,3V perchè il sensore funzioni correttamente. La Figura 4 mostra il sensore DS18B20 water proof.
Programmazione dei dispositivi ESP
Utilizzeremo l'IDE di Arduino per programmare le schede ESP32 ed ESP8266. Inoltre, installeremo la libreria Painless Mesh per costruire la rete mesh, e le librerie dei sensori BME280, DHT22 e DS18B20.
Installazione della libreria painlessmesh
Per installare la libreria painlessmesh nell’IDE di Arduino, andate su Strumenti > Gestione librerie, cercate la libreria “painlessmesh” e installatela. Mentre scriviamo, la versione della libreria è la 1.5.0, riguardo Arduino, la versione utilizzata è la 1.8.15.
Installazione della libreria Arduino_JSON
In questo progetto di esempio, i dati delle letture dei sensori vengono trasmessi in formato JSON, quindi viene utilizzata la libreria Arduino_JSON per semplificare la gestione delle variabili JSON.
Per installare questa libreria andate su Strumenti > Gestione librerie e nella barra di ricerca digitate “Arduino_JSON”; una volta trovata installatela. La versione che abbiamo installato è la 0.2.0.
Installazione delle librerie dei sensori
Per realizzare l’hardware della rete ESP-WiFi MESH, oltre alle schede di sviluppo ESP32 ed ESP8266, utilizzeremo un sensore DS18B20, un sensore DHT22 e due sensori BME280. Quindi, per la gestione di questi sensori occorre installare le rispettive librerie. Per installare la libreria del sensore BME280, andate su Strumenti > Gestione librerie e nella barra di ricerca digitate e cercate la libreria “Adafruit BME280” e installatela. Mentre scriviamo, la versione della libreria “BME280” è la 2.2.4.
Per installare la libreria del sensore DHT22, andate su Strumenti > Gestione librerie e nella barra di ricerca digitate e cercate la libreria “DHT sensor” di Adafruit e installatela. La versione della libreria “DHT sensor” che utilizzeremo è la 1.4.3.
Per installare la libreria del sensore DS18B20 andate su Strumenti > Gestione librerie e nella barra di ricerca digitate e cercate la libreria “DallasTemperature” e installatela. La versione della libreria “DallasTemperature” che utilizzeremo è la 3.9.0.
Il codice
Impostazioni preliminari del codice
Come vedremo nella spiegazione del codice, il progetto prevede che il codice sia compatibile con tutti i dispositivi ESP collegati ai rispettivi sensori. Ciò viene ottenuto semplicemente selezionando il sensore associato alla scheda previo decommento del sensore interessato e commento degli altri sensori nelle righe di codice relative alla definizione delle macro dei sensori. Ad esempio, nelle righe elencate di seguito viene scelto il sensore BME280 collegato alle due schede ESP32:
#define BME_280 //#define DHT22 //#define DS18B20 //#define ENABLE_LOG
Inoltre, ad ogni modulo ESP viene associato il numero univoco identificativo di nodo della rete mediante una variabile stringa, ad esempio Node_1 alla scheda ESP32 a cui è collegato il sensore BME280:
String nodeName = "NODE_1";
Quindi, ogni scheda ESP può essere programmata caricando lo stesso file del codice inserendo il sensore ad essa associato e l'identificativo del nodo.
Caricamento del codice nella scheda ESP32 collegata al sensore BME280
Come abbiamo visto nell’esempio sopra, prima di caricare il codice nella scheda ESP32 collegata al sensore BME280, è necessario rimuovere il commento dalla definizione della macro del sensore BME280, rimuovere il commento della definizione della macro ENABLE_LOG e assegnare alla scheda ESP32 il nome di nodo univoco Node_1:
#define BME_280 //#define DHT22 //#define DS18B20 #define ENABLE_LOG
String nodeName = "NODE_1";
Fatte le modifiche del codice per la scheda ESP32, salvate il codice con un nome che volete e caricatelo nella scheda ESP32.
Caricamento del codice nelle schede ESP8266 collegate al sensore DHT22
A due schede ESP8266 viene collegato un sensore DHT22 e in un'altra scheda ESP8266 viene collegato un sensore DS18B20. Per caricare il codice in ognuna delle due schede ESP8266 associate al DHT22, occorre eseguire in ogni codice lo stesso procedimento che è stato fatto per la scheda ESP32 collegata al sensore BME280. Quindi, viene rimosso il commento dalla definizione della macro del sensore DHT22, viene rimosso il commento anche della definizione della macro ENABLE_LOG e devono essere commentate le altre definizioni delle macro dei sensori BME280 e DS18B20. Infine, assegniamo ad una scheda ESP8266 il nome di nodo univoco Node_2 e all’altra scheda ESP8266 il nome di nodo univoco Node_3. Le righe seguenti riguardano l’ESP8266 Node_2:
//#define BME_280 #define DHT22 //#define DS18B20 #define ENABLE_LOG String nodeName = "NODO_2";
Effettuate le modifiche, salvate il codice con un nome che volete e caricatelo nella scheda ESP8266 a cui è collegato il sensore DHT22.
Caricamento del codice nella scheda ESP8266 collegata al sensore DS18B20
Anche per questa scheda il procedimento rimane esattamente lo stesso dei precedenti. Decommentiamo la definizione della macro del sensore DS18B20 e anche della definizione della macro ENABLE_LOG, commentiamo le altre definizioni delle macro dei restanti sensori, poi assegniamo alla scheda ESP8266 il nome di nodo univoco Node_4:
//#define BME_280 //#define DHT22 #define DS18B20 #define ENABLE_LOG String nodeName = "NODO_4";
Nota: in tutti e quattro i codici, se occorre, si possono abilitare/disabilitare le istruzioni di log rimuovendo/inserendo il commento dalla definizione della macro ENABLE_LOG.
Descrizione del codice
Per la spiegazione del codice si fa riferimento al codice relativo al sensore DHT22 della scheda ESP8266 identificata con il nodo Node_2.
Il codice inizia includendo la libreria painlessmesh e la libreria Arduino_JSON.
#include <painlessMesh.h> #include <Arduino_JSON.h>
Successivamente, sono definite alcune macro che utilizzeremo per abilitare o disabilitare parti del codice. Ciò è necessario perché non tutti i nodi utilizzano lo stesso sensore. Quindi, per includere o escludere parti del codice, possiamo inserire quattro codici diversi, uno per ogni scheda ESP, in un unico file.
Di seguito, viene abilitato il sensore DHT22:
//#define BME_280 #define DHT22 //#define DS18B20 #define ENABLE_LOG
Ora, viene definita una variabile di tipo “String nodeName” che verrà utilizzata per identificare in modo univoco i nodi della rete mesh:
String nodeName = "NODE_2"; // Name needs to be unique
Viene definita anche la variabile di tipo float per memorizzare i dati di temperatura, umidità e pressione barometrica.
float temp(NAN), hum(NAN), pres(NAN);
Da questo passaggio in poi, utilizzeremo le macro #ifdef e #endif per includere o escludere parti del codice. La prima sezione del codice riguarda il sensore BME280. Come detto prima, inizieremo con l'istruzione #ifdef BME_280. Successivamente, definiamo tutte le librerie richieste per il sensore BME280.
Il sensore BME utilizza anche la libreria “wire”, quindi definiamo anche quella. Poi creiamo un oggetto “bme” della classe BME280I2C. Quindi, accediamo alla variabile della classe e terminiamo con l'istruzione endif.
#ifdef BME_280 #include <BME280I2C.h> #include <Wire.h> #define I2C_SDA 33 #define I2C_SCL 32 TwoWire I2CBME = TwoWire(0); BME280I2C bme; BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); BME280::PresUnit presUnit(BME280::PresUnit_Pa); #endif
Facciamo lo stesso procedimento anche per la libreria DHT. Iniziamo con l'istruzione #ifdef DHT_22 seguita dall'inclusione della libreria DHT.h. Successivamente, definiamo il PIN per DHT e aggiungiamo un prototipo per DHT22. Poi creiamo un oggetto passando le istruzioni sopra definite, e concludiamo con l'istruzione #endif.
#ifdef DHT_22 #include "DHT.h" #define DHTPIN 4 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); #endif
Facciamo lo stesso anche per il sensore DS18B20 iniziando con l'istruzione #ifdef DS18B20. Poiché il sensore DS18B20 richiede la libreria OneWire, la includiamo insieme alla libreria DallasTemperature. Successivamente, definiamo il PIN per il sensore e creiamo un oggetto OneWire passando la variabile PIN. Poi passiamo l'indirizzo dell'oggetto OneWire all'oggetto DallasTemperature creando un nuovo oggetto DallasTemperature.
#ifdef DS18B20 #include <OneWire.h> #include <DallasTemperature.h> const int oneWireBus = 4; OneWire oneWire(oneWireBus); DallasTemperature ds18b20(&oneWire); #endif
Di seguito, sono definite le credenziali Wi-Fi (che potete scegliere come volete) insieme al numero della porta TCP 5555. Queste credenziali e il numero di porta dovrebbero rimanere gli stessi per tutti i nodi della rete.
#define MESH_PREFIX "xxxxxxxxxxxx" #define MESH_PASSWORD "xxxxxxxxxxx" #define MESH_PORT 5555
Successivamente, creiamo tre istanze. Una è per lo Scheduler, un‘altra è per la painlessmesh e l'ultima è per la libreria JSON JSONVar.
Scheduler userScheduler; // to control your task painlessMesh mesh; JSONVar myVar;
Abbiamo creato un'attività che è come un thread che viene sempre eseguito e chiama una funzione dopo un pò di tempo. L'attività definita di seguito verrà utilizzata per inviare un messaggio broadcast a tutti i nodi. L'attività richiede immediatamente tre parametri. Il primo definisce la frequenza con cui l'attività chiamerà la funzione, successivamente richiede la durata dell'attività e infine richiede un puntatore alla funzione chiamante.
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
La funzione chiamante sendMessage(). Questa funzione chiama un'altra funzione che restituisce una stringa di JSON. Come suggerisce il nome, l'attività sendMessage viene utilizzata per inviare il messaggio a tutti i nodi della rete.
void sendMessage() { String msg = construnct_json(); Task taskSendMessage; mesh.sendBroadcast( msg ); taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 )); }
La funzione ReceiveCallback(). Ogni volta che arriva un nuovo messaggio, questa funzione riceve una chiamata. Se si vuole utilizzare il messaggio ricevuto per eseguire un’azione, occorre modificare questa funzione per portare a termine l’operazione. Questa funzione accetta due argomenti: l'ID del nodo e il messaggio come puntatore.
void receivedCallback( uint32_t from, String &msg ) { Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str()); }
La funzione newConnectionCallback(). Questa funzione riceve una chiamata ogni volta che viene aggiunto un nuovo dispositivo alla rete e invia un'istruzione di stampa al monitor seriale.
ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 3869 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.