Nel nostro Blog e nel forum abbiamo visto come usare i sensori, come creare una bella dashboard fruibile da smartphone e l’invio in tempo reale dei dati tramite protocollo MQTT; tutto questo ha solo uno svantaggio, serve un RaspberryPi per ogni postazione, aumentando l’ingombro ed i costi delle varie postazioni, per fortuna la Cina ci offre una soluzione, al costo di un gelato.
ESP8266 o il più recente ESP32 sono dei SoC (System on Chip) super economici che contengono un microcontrollore, come Arduino, ed un chip Wifi. Ci permettono quindi di leggere i sensori e varie grandezze, e tramite il WiFi, inviarle ad un server remoto MQTT o al nostro RaspberryPi, il quale poi orchestrerà tutti gli ESP con la possibilità di inviargli anche comandi da remoto.
Guide relative a questo articolo
Di seguito troverai tutte le guide che abbiamo già scritto, utili per prepararti alla realizzazione del tuo sistema centralizzato RaspberryPi / ESP:
- Scopriamo insieme Node-RED. Grandi progetti IOT in pochi minuti!
- Crea la tua Dashboard con RaspberryPi
- ESP8266 Guida completa, in italiano!
- ESP8266 Guida Completa – Parte 2: Hardware
- ESP8266 Guida Completa – Parte 3: Collegare ESP al \PC
- ESP8266 Guida Completa – Parte 4: Comandi AT
- ESP8266 Guida Completa – Parte 5: Firmware Arduino
- ESP8266 Guida Completa – Parte 6: Firmware NodeMCU
- [Node-Red] Inviare dati tramite MQTT
- Sensore di temperatura ed umidità AM2320 i2c
Idea
L’idea pratica di questa guida è quella di preparare il nostro RaspberryPi come server MQTT per ricevere i dati da qualsiasi client MQTT, che sia un microcontrollore, il nostro cellulare, un pc o qualsiasi altro sistema che usi questo protocollo.
Successivamente predisporre un modulo ESP8266, nel mio caso ho un NodeMCU Amica ( una dev board che espande e semplifica l’uso del modulo ESP8266 ), che programmeremo tramite Arduino IDE, per una maggiore quantità di guide in rete, ma nulla vieta di usare MicroPython o LUA.
Infine, visualizzare i dati ricevuti su una dashboard web, visibile da smartphone e pc.
Note: La guida è un sistema basilare che, volendo, potrete successivamente implementare con facilità grazie alla vasta community di RaspberryPi, Arduino ed ESP8266/ESP32.
Per eventuali dubbi, discutiamone nel forum.
Preparativi hardware
- RaspberryPi connesso alla rete
- NodeMCU (se usate altri moduli ESP8266/ESP32 i comandi “potrebbero” essere differenti)
- Sensore di temperatura / umidità AM2320
Preparativi software
Cos’è MQTT
MQTT è un protocollo adatto ad inviare una moltitudine di piccoli dati in tempo reale, per esempio solo il valore dei gradi registrati da un sensore. Si sposa quindi perfettamente con le applicazioni IoT.
MQTT usa un server centrale, chiamato broker, il quale riceve i messaggi suddivisi in vari topic, una specie di chat con i gruppi, per fare un parallelo. Si invia un dato in un topic ad esempio sensori/cantina/vini_1 .
In base alle esigenze un client, che sia uno smartphone, RaspberryPi od un servizio online, potrà iscriversi ad un sotto topic o, andando a ritroso, in un topic principale, ad esempio sensori, anche perfino a tutti indistintamente.
Come server MQTT mi piace usare Mosquitto perché l’installazione è semplicissima ed ha un server gratuito per testare i nostri programmi.
MQTT Broker nel RaspberryPi
Installiamo Mosquitto tramite il comando
1 |
sudo apt update; sudo apt install -y mosquitto |
Per installare il client in locale sarà sufficiente installare
1 |
sudo apt update; sudo apt install -y mosquitto-clients |
Si, tutto qui! Fantastico: in un comando abbiamo un server attivo e funzionante pronto a ricevere tutti i nostri dati.
Le alternative sono l’uso di un server online, un paio di esempi sono dweet.io o test.moquitto.org , ma personalmente preferisco tenere i miei dati al sicuro in casa ed, al massimo, accedere a ciò che mi serve tramite VPN o NAT nel router e protezioni sul broker e nel sistema operativo.
Schema NodeMCU ed AM2320
Il sensore AM2320 a differenza dei DHT sfrutta il sistema I²C. Per maggiori dettagli rileggi il topic Sensore di temperatura ed umidità AM2320 i2c .
Il bus I²C, usa i pin SDA e SCL, che nel RaspberryPi sono predeterminati, mentre sul NodeMCU tutti i pin possono essere impostati come I²C, digitali, PWM, 1-wire , cosa che lo rende molto comodo e versatile.
Il sensore accetta tensioni continue da 3.3v a 5v. Per usare i 5V sarà necessario usare un alimentatore esterno che eroghi 5V (nel NodeMCU); in questo caso possiamo usarlo per alimentare direttamente la scheda NodeMCU, perché il pin Vin accetta fino a 10v (mi riferisco alla versione Amica, controlla sempre il datasheet del tuo modello, per non bruciarlo).
I pin I²C andranno collegati su D1 e D2; poi nel codice sarà necessario specificarlo tramite il comando
1 |
sensoreAM2320.begin(D2, D1); |
Anche qui la semplicità la fa da padrona, purtroppo però, ora arriva il difficile, se non conosci Arduino IDE, ma del quale troverai una buona documentazione e migliaia di esempi
ESP8266 ed Arduino IDE
ESP8266 è diventato famoso perché integra un modulo WiFi in grado di rendere smart e connessi quasi tutti gli oggetti. Gli “oggetti intelligenti” sono la base stessa dell’IoT (Internet delle cose, degli oggetti).
Prosegui solo se hai già completato la guida ESP8266 Guida Completa- Parte 5: Firmware Arduino
Facciamo un riassunto molto basilare su Arduino IDE.
Lo Sketch è diviso di solito in varie parti:
- Descrizione del progetto
- Definizioni tramite #define
- Variabili
- Funzioni
- Setup (codici eseguiti solo all’avvio)
- Loop (codice eseguito continuamente dopo il setup)
All’apertura dell’editor viene caricato il file da “C:\Program Files (x86)\Arduino\examples\01.Basics\BareMinimum\BareMinimum.ino” che puoi editare a piacere.
Per prenderci la mano l’ho modificato con questo codice, aggiungendo la disposizione corretta dei pin NodeMCU rispetto ad Arduino.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* DESCRIZIONE */ /* LIBRERIE */ /* DEFINIZIONI */ /* PIN NODEMCU rispetto ad Arduino*/ #define D0 16 #define D1 5 // I2C Bus SCL (clock) #define D2 4 // I2C Bus SDA (data) #define D3 0 #define D4 2 // come "LED_BUILTIN",ma a logica invertita #define D5 14 // SPI Bus SCK (clock) #define D6 12 // SPI Bus MISO #define D7 13 // SPI Bus MOSI #define D8 15 // SPI Bus SS (CS) #define D9 3 // RX0 (console seriale) #define D10 1 // TX0 (console seriale) /*___________________________*/ /* VARIABILI */ /* FUNZIONI */ /* PROGRAMMA */ /*___________________________*/ void setup() { /* Serial.begin(115200); */ } /*___________________________*/ void loop() { } |
Arduino IDE usa librerie scaricabili tramite il menù sketch-> include libreria-> gestore librerie, mentre se te ne serve una non inclusa, scarica lo zip da github o simili, poi da menù importala da sketch -> include libreria-> aggiungi libreria da zip.
Connessione WiFi su ESP8266
La prima cosa da fare nel nostro progetto è collegare i nostri “moduli” Esp8266 al WiFi, che sia il router o un RaspberryPi che fa da Access Point.
Includiamo la libreria dal menù sketch -> include libreria-> Esp8266Wifi , comparirà l’equivalente voce
#include ESP8266WiFi.h
Impostiamo delle definizioni per nome e password wifi, cosi da averle pronte da modificare in alto nello sketch. Uso define e non una variabile cosi risparmio la poca memoria che hanno i microcontrollori.
1 2 |
#define Nome_WIFI "nome del WiFi" #define Pass_WIFI "password del WiFi" |
Nella sezione setup includiamo questo pratico codice per connettersi ed informarci se usiamo il monitor seriale dell’ IDE
1 2 3 4 5 6 7 8 9 10 11 |
Serial.begin(9600); WiFi.begin(Nome_WIFI, Pass_WIFI); Serial.print("Wifi: Connessione..."); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.print("Connesso, IP: "); Serial.println(WiFi.localIP()); |
Se tutto è andato come previsto, collegando NodeMCU tramite cavo usb ed attivando strumenti -> monitor seriale , ci verrà restituito l’ip assegnato dal server DHCP.
Serial.begin(9600); serve ad attivare la comunicazione seriale, consigliano la velocità di 9600, ma anche con 115200 non ho avuto problemi.
Esp8266 leggere temperatura ed umidità dal sensore Am2320
Ora che abbiamo tutto collegato è il turno delle misurazioni vere e proprie. Per farle ci torna utile una libreria che non è presente nel menù gestione librerie, ma è scaricabile dalla repository Github di hibikiledo , scaricandolo tramite il pulsante clone e download -> download zip potremmo importarlo nell’IDE tramite il menù sketch-> include libreria -> includi libreria da zip.
Ora potremmo comodamente richiamarla tramite il menù sketch -> include libreria-> AM2320-master
Inizializzazione Am2320
Procediamo con la creazione del’oggetto sensoreAM2320 e delle variabili float (numeri a virgola mobile).
1 2 3 |
AM2320 sensoreAM2320; float temp = 0; float umidita = 0; |
Dobbiamo inizializzare l’oggetto sensoreAM2320 istruendolo su quali pin usare per SCL ed SDA, tramite il comando
1 |
sensoreAM2320.begin(D2, D1); //NodeMCU non ha un pin SCL e SDA specifico |
Nota come ho usato il termine D1 e D2 che avevamo definito all’inizio, ci torna molto pratico per non ricordarci a memoria la corrispondenza esatta tra i pin arduino e NodeMCU.
Lettura dati
Ora abbiamo un oggetto, sensoreAM2320 pronto, basterà richiedergli di leggere i dati tramite questa funzione da includere nella sezione loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if (sensoreAM2320.measure()) { temp = sensoreAM2320.getTemperature(); umidita = sensoreAM2320.getHumidity(); Serial.print("Temperatura: "); Serial.println(temp); Serial.print("Umidita': "); Serial.println(umidita); } else { // error has occured int errorCode = sensoreAM2320.getErrorCode(); switch (errorCode) { case 1: Serial.println("ERR: sensore AM2320 e' offline"); break; case 2: Serial.println("ERR: CRC validazione fallita."); break; } } |
Finalmente abbiamo i nostri valori temperatura e umidità che potremmo utilizzare a nostro piacimento nello sketch. Adesso puoi implementare l’invio nel modo che preferisci, oppure la visualizzazione in una pagina web locale, dato che ESP8266 può ospitare anche un server web.
E’ necessaria la verifica della ricezione dei dati, perché non è sempre garantito che la lettura vada a buon fine. Per farlo viene eseguito un “check” CRC. In caso di problemi, la funzione restituirà tramite seriale, i relativi errori.
Volendo semplificare lo sketch si possono tranquillamente eliminare tutte le righe che iniziano per Serial.
Invito sempre a leggere i commenti all’interno delle librerie, leggibili tramite un editor di testo, ad esempio Notepad++ . Spesso si trovano informazioni molto utili che il readme.md non contiene.
Invio dei dati tramite MQTT
Abbiamo il broker MQTT, il sensore, i dati pronti, basta solo spedirli! Come? Tramite MQTT.
Esistono varie librerie MQTT, io ho scelto PubSubClient liberamente installabile tramite il menù gestione librerie.
Procediamo all’installazione ed implementazione nel nostro script, trovandoci la voce
#include PubSubClient.h
il passo successivo è la definizione dei valori da assegnare a server, autenticazione e topic tramite la voce #define. Lo faremo all’inizio dello sketch cosi da avere un programma ordinato e rapido da modificare.
1 2 3 |
#define mqtt_server "test.mosquitto.org" #define umidita_topic "sensoreCantina/umidita" #define temperatura_topic "sensoreCantina/temperatura" |
- mqtt_server: ip o nome dns del broker MQTT. Può essere il nostro RaspberryPi o solo in fase di test test.mosquitto.org , non abbiamo implementato l’autenticazione, ma se la vorrete usare, andrà aggiunto utente e password
12#define mqtt_user "your_username"#define mqtt_password "your_password"
- umidita_topic ed temperatura_topic : sono i topic dove scrivere i messaggi, la barra / crea un sotto-topic utile in caso da tanti sensori in un unica area o in questo caso per separare temperatura ed umidità, poi sarà il client a decidere cosa leggere.
Inizializzazione client MQTT
Come per il sensore, andrà creato un oggetto da usare durante la procedura, procediamo cosi
1 2 |
WiFiClient espClient; PubSubClient client(espClient); |
Funzione di connessione ed invio
La funzione per connetterci al nostro broker MQTT, sarà questa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* MQTT */ void mqtt_riconnetti() { // Loop finche' non si connette while (!client.connected()) { Serial.print("connessione mqtt in corso..."); // Attempt to connect if (client.connect("SensoreCantina")) { //se serve, aggiungi autenticazione -> ("SensoreCantina", mqtt_user, mqtt_password)) Serial.println("connesso"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } |
La funzione, una volta chiamata, eseguirà un loop per tentare di connettersi al broker usando l’oggetto client creato in precedenza; in caso di errori, verranno segnalati tramite monitor seriale.
Nella sezione setup sarà necessario impostare il broker nell’oggetto cliente tramite
1 |
client.setServer(mqtt_server, 1883); |
La porta è a discrezione di chi imposta il broker, ma di norma sono
- 1883 : MQTT, non criptata
- 8883 : MQTT, criptata
- 8884 : MQTT, criptata, client certificate necessario
- 8080 : MQTT tramite WebSockets, non criptata
- 8081 : MQTT tramite WebSockets, criptata
Non fa parte dello scopo della guida descrivere come implementare gli altri sistemi di connessione, anche perché fintanto che non si tratta dati sensibili, evitiamo l’inutile aggiunta di lavoro per criptare e decriptare dati veloci come quelli dei sensori.
Una volta arrivati alla sezione loop sarà sufficiente implementare l’invio dei dati
1 2 3 4 5 6 7 8 9 |
if (!client.connected()) { mqtt_riconnetti(); } client.loop(); client.publish(temperatura_topic, String(temp).c_str(), true); client.publish(umidita_topic, String(umidita).c_str(), true); delay(60000); |
Le prime righe si interpretano cosi: se client non è connesso, allora esegui la funzione mqtt_riconnetti, altrimenti prosegui.
Proseguendo il client pubblicherà nel topic da noi scelto, la variabile temp ed umidita, convertita in stringa. Successivamente attenderà due minuti; imposta valori più bassi se misuri temperature possono cambiare molto in fretta.
Extra: almeno un led…
Ok, è tutto attivo, ma quando staccherò la seriale come faccio a sapere se è acceso? La via semplice è accendere il led integrato nella fase di setup tramite il comando
1 |
pinMode(LED_BUILTIN, OUTPUT); |
Visualizzazione dei dati
Ci manca un piccolo particolare… come li vediamo questi dati?
I modi per gestire e visualizzare i dati MQTT sono vari, mi vengono in mente i seguenti, ma se ne conosci altri, consigliali sul forum!
- APP: io uso Iot MQTT Panel, ben fatta e gratuita senza pubblicità
- Dashboard Node-Red: nel parliamo nel nostro Blog. Facilissima, web responsive, e soprattutto orchestra i vari sistemi con semplicità in base hai messaggi ricevuti
- Pagina web locale su RaspberryPi usando un Apache o simili
- Pagina web locale su Esp8266, molto poco smart
- Thinkspeak
- Client MQTT ( ad esempio mosquitto_clients): usando mosquitto_sub -t sensoreCantina/#
Sketch completo
Lo sketch completo lo trovate su BitBucket , basta scaricarlo e personalizzarlo, buon divertimento!
Discutiamone nella pagina dedicata del forum.
Se vuoi restare aggiornato, seguici anche sui nostri social: Facebook , Twitter, YouTube, Google+, Telegram