Sensori wireless con Raspberry Pi e ESP8266, tramite MQTT


Informatica / mercoledì, Gennaio 29th, 2020

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:

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

sudo apt update; sudo apt install -y mosquitto

Per installare il client in locale sarà sufficiente installare

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

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:

  1. Descrizione del progetto
  2. Definizioni tramite #define
  3. Variabili
  4. Funzioni
  5. Setup (codici eseguiti solo all’avvio)
  6. 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.

/* 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.

#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

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).

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

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.

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.

#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 password12#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

WiFiClient espClient;
PubSubClient client(espClient);

Funzione di connessione ed invio

La funzione per connetterci al nostro broker MQTT, sarà questa

/* 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

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

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

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!