Multimetro connesso in MQTT

In questo articolo descrivo come il mio multimetro DT-4000ZC pubblica su Internet le misure effettuate, utilizzando un microcontrollore Atmel e un modulo WiFi ESP-01 (basato sul chip ESP8266) ed il protocollo MQTT. Per comprendere meglio le fasi di questo progetto, vi invito a leggere i vari articoli pubblicati precedentemente che sono gli “studi preliminari” per arrivare a questo risultato.

MQTT Client tester per modulo ESP-01
http://ficara.altervista.org/?p=3326
DT-4000ZC logger per Android
http://ficara.altervista.org/?p=3208
Interfacciare il modulo ESP-01 con una porta USB
http://ficara.altervista.org/?p=3041
Single 3.7V Li-ion cell battery back-up for Raspberry Pi
http://ficara.altervista.org/?p=2736

Parte prima: l’alimentatore

Il modulino WiFi ESP-01 funziona a 3.3V, quindi tutto il circuito utilizzerà questa tensione. Ho pensato di usare un alimentatore tipico da carica batterie per telefonini, con uscita a 5V e un regolatore lineare per i 3.3V, ma ho deciso anche di aggiungere una batteria da 3.7V Li-ion di formato AA come backup di alimentazione in caso di mancanza rete. Il circuito è simile a quello già mostrato nell’articolo Single 3.7V Li-ion cell battery back-up for Raspberry Pi, ma in questo caso invece di avere uno step-up in uscita, abbiamo uno step-down (anche se non switching, ma lineare). Di sotto vedete la foto del circuito appena costruito e collaudato.

Alimentatore 3.3V con batteria Li-Ion di backup

Alimentatore 3.3V con batteria Li-Ion di backup

Lo schema è vergognosamente disegnato a mano, perché non credo che metterò “in produzione” questo dispositivo. Eccolo qui (solo la parte di alimentazione) :

lo schema MAD (Manually Aided Design) della sezione di alimentazione

Lo schema MAD (Manually Aided Design) della sezione di alimentazione

Ho utilizzato un modulino carica batterie Li-Ion acquistato su internet (1 Euro, spedizione inclusa…ma come fanno ?) basato sul chip TP4056. Ho modificato la resistenza che stabilisce la corrente di carica, portandola a 5KOhm (due da 10K in parallelo). Nella foto sottostante si vede il punto da modificare.

0501set-resistorLa ragione di questa modifica è che l’alimentatore esterno a 5V deve “reggere” sia la corrente di ricarica della batteria, sia la corrente di funzionamento del resto del circuito. Considerando che tanti alimentatori “very cheap” hanno una corrente di uscita max di 500-750mA, mi è sembrata una scelta razionale. Notate che sullo schema ho aggiunto anche una morsettiera a 2 poli per dare i 5V anche con un alimentatore diverso, senza uscita su connettore Mini-USB. Se alimentate il circuito attraverso questo morsetto, STATE BEN ATTENTI a non superare i 6 Volts ; sul datasheet del TP4056 c’è scritto che la Vin massima è di 8 Volts, ma io sarei prudente, onde evitare “fumate”, scintille e bruciature miste.

Il regolatore low-drop con uscita a 3.3V è di tipo LM3940 ; il link al datasheet è questo: www.ti.com/lit/ds/symlink/lm3940.pdf . Dalle caratteristiche tecniche si vede che con 5V d’ingresso non c’è problema, stabilizza a 3.3V fino ad 1A (a noi serve MOLTO meno). Il problema è quando manca la tensione di rete e invece dei 5V ci si ritrova con i 4.2V che vengono dalla cella Li-Ion a piena carica. Con questa differenza tra Vin e Vout, la stabilizzazione decade un po’, ma per correnti basse (150-200 mA) si dovrebbe restare nel range operativo di tutto il resto del circuito, modulino WiFi e microcontrollore compresi. Eventualmente, per fare le cose a regola d’arte, si può scegliere un altro regolatore che sia very-low-drop e quindi in grado di stabilizzare l’uscita anche con una Vin più bassa oppure, meglio ancora, usare un regolatore step-down switching che prolungherà anche il tempo operativo del circuito quando alimentato a batteria. Se usate un altro tipo di regolatore lineare, fate attenzione al pinout ! Molti regolatori low drop con lo stesso package hanno una disposizione diversa dei pin ! Controllate bene e modificate lo schema di conseguenza. Per quanto riguarda la tensione, teniamo presente che la cella Li-Ion scenderà a 3.7V (la tensione nominale) solo quando la carica residua sarà ormai solo del 10%. Ricaricate la batteria quando si scarica e tenete presente che le celle Li-Ion non devono scendere mai sotto la tensione di 2.75 V circa, pena la perdita della capacità di ricaricarsi (diventano da buttare). Le celle con protezione interna hanno già un circuito che evita questo rischio.

Infine passiamo al mosfet che fa da switch tra l’alimentazione esterna e la cella Li-Ion. Io ho usato un PMV48XP che avevo tra i miei campioni (il datasheet è qui), ma dato che questo ha un package smd SOT-23 (bello piccolo), è un po’ difficile da saldare su una scheda prototipo come quella mostrata in figura. Chi non ha un’esperienza più che buona nella saldatura, farà bene a cercare un altro componente dalle stesse caratteristiche elettriche, ma con un package più “umano”. Comunque, la funzione di questo switch è di mandare al regolatore la 5V presente sul connettore fino a quando c’è. Appena viene a mancare, invece, è la cella Li-Ion a diventare la sorgente di alimentazione. Il mosfet aperto permette al circuito di ricarica di non “vedere” tutto il carico che c’è dietro (regolatore, modulino wifi, microcontrollore) e di eseguire quindi il normale ciclo di carica con le soglie prefissate. Vi invito, per maggiori dettagli a leggere l’articolo Single 3.7V Li-ion cell battery back-up for Raspberry Pi menzionato in precedenza.

Parte seconda: il microcontrollore

Per il micro, ho “riciclato” un vecchio circuito realizzato nel 2011 per collegare degli economici tablet Android “Made in China” ad un bus RS485 per il controllo di unità di potenza in dispositivi biomedicali. A quei tempi i tablet avevano di serie, internamente, la porta seriale TTYS0 con livelli a 3.3V e bastava modificare la Flash di sistema per poterla utilizzare con i propri programmi. Il circuito comprende un micro ATmega48V e un integrato  SP3072E come interfaccia RS485. Il micro dispone di 4KB di Flash, 512Bytes di Ram e 256 Bytes di EEprom. Queste risorse, sebbene limitate, bastano per realizzare il programma.

img_20161119_181150Purtroppo il micro ha solo una UART asincrona, mentre a me ne servono due: la prima per leggere i dati provenienti dal multimetro e la seconda per pilotare il modulino ESP-01 con i comandi AT. La UART “hardware” l’ho usata per il pilotaggio del modulo ESP-01 a 9600 BPS. Per fortuna, il multimetro comunica con un baud rate “basso” (2400 BPS) e così la seconda UART l’ho realizzata in software. Il multimetro non invia i dati “in chiaro”, come caratteri ASCII, ma come una bitmap dei segmenti accesi sul display LCD. Se qualcuno è interessato a come vengono codificati i dati seriali, il protocollo è descritto in un articolo a questo link (paragrafo: Fortune_Semiconductor_FS9721_LP3).

Questo è lo schema della scheda a microcontrollore. L’interfaccia RS485 verrà utilizzata in modo “creativo” per leggere i dati seriali dal multimetro (la resistenza segnata in rosso è stata cambiata proprio per questo scopo). E’ possibile semplificare il circuito ed ottenere lo stesso risultato, ma avendo una scheda già funzionante, ho deciso di usarla senza troppe modifiche.

microcontrollerPer una visione dello schema più nitida e dettagliata, è possibile scaricare il file in formato PDF da questo link: rs485-andro-micro.

Parte terza: mettere tutto insieme

Nello schema seguente (sempre disegnato a mano) potete vedere i vari blocchi (alimentatore, microcontrollore e modulo wifi) interconnessi tra loro.

I tre blocchi del circuito connessi tra loro

I tre blocchi del circuito con le necessarie connessioni

E questa è la realizzazione pratica:

Il circuito completo montato su una scheda per prototipi

Il circuito completo montato su una scheda per prototipi

Per fare un po’ di debug del software, ho aggiunto un altro circuitino che si collega al connettore ICSP (di programmazione) che rimane libero una volta trasferito il firmware nel micro. Il circuito ha due led (uno giallo e uno rosso) e due pulsanti. Uno di questi è per resettare il microcontrollore e l’altro è un generico input per eseguire routines di test. Il circuito è nella figura sottostante:

Il circuitino di debug che si collega al connettore ICSP (schema)

Il circuitino di debug che si collega al connettore ICSP (schema)

Di seguito, come appare il circuito costruito e collegato:

Il circuito costruito e collegato al connettore ICSP

Il circuito costruito e collegato al connettore ICSP

Un altro utilissimo strumento di debug può essere costruito in brevissimo tempo. Si tratta di una “spia” per il traffico dei dati seriali tra il microcontrollore e il modulino WiFi. In generale, si può utilizzare in tutte quelle comunicazioni seriali half-duplex basate su domanda / risposta. Lo schema è il seguente (i diodi devono essere Schottky, low drop)

serialspy-schE questa è la realizzazione pratica :

serialspy-picCon questo piccolo strumento, insieme ad un programma di terminale seriale, si riesce a intercettare tutta la comunicazione tra il micro e l’ESP-01 ed è facile scoprire gli errori. Come programma di terminale seriale, se non lo scrivo personalmente, mi affido all’ottimo RealTerm .

Il software e il firmware

La sezione software è divisa in due parti : una è il firmware per il microcontrollore e l’altra è un’applicazione per PC (Windows) che permette di programmare i numerosi parametri necessari per personalizzare la connessione al broker MQTT e quella al router WiFi. Normalmente, i dati di personalizzazione vengono salvati nella EEprom del micro, ma dopo centinaia di progetti fatti con i micro Atmel ho potuto verificare che c’è una certa “debolezza” di questa zona di memoria e in ambienti elettricamente rumorosi o in presenza di circuiti non realizzati “a regola d’arte” è possibile ritrovarsi con dei dati corrotti in memoria. Normalmente, nei prodotti commerciali che realizzo, utilizzo una doppia copia dei dati in EEprom, ognuna delle quali ha un CRC relativo ai dati memorizzati. Ad ogni reset del micro e anche in base ad un timer di verifica integrità, il firmware si occupa di verificare entrambe le copie dei dati in EEprom e se ne trova una corrotta, usa l’altra per ripristinare i dati. Se entrambe le copie hanno un CRC errato, allora il firmware segnala un errore su una delle periferiche disponibili (led, display, cicalino, uscita seriale, eccetera). Questa procedura, ovviamente, richiede una certa quantità di codice e allora, in questo particolare caso in cui ho a disposizione solo 4K di Flash per l’intero firmware, ho deciso di usare un approccio differente : i parametri vengono salvati nella memoria programma (Flash), ma NON sono contenuti nel file sorgente in C, bensì vengono “aggiunti” al file di uscita .hex grazie all’applicazione su PC. Questo permette ad un utente di crearsi un proprio file .hex personalizzato ed utilizzarlo per programmare il microcontrollore. La memoria Flash nei microcontrollori Atmel, per la mia esperienza personale, è “sicura”, cioè non mi è mai capitato, in tanti dispositivi costruiti e attualmente presenti sul mercato, di riscontrare una corruzione dei dati programmati.

Nel sorgente in C, l’area di flash destinata ai parametri programmabili è definita semplicemente così :

mqtt-fw1In pratica, viene creata una costante flashdata che nel sorgente è di soli 2 bytes, ma che servirà solo a creare un riferimento per l’applicativo su PC per aggiungere tutti i dati necessari. L’area è allocata all’indirizzo 0x0F00, quindi all’inizio dell’ultimo blocco da 256 bytes della memoria flash. I dati vengono salvati con uno “header” che contiene l’indirizzo (relativo) di partenza di un messaggio e la sua lunghezza. In pratica, uno header di 2 bytes per ognuno dei messaggi (parametri) disponibili. Ecco un esempio di accesso ai dati:

mqtt-fw2Il sorgente in C così compilato, non contiene quindi alcun parametro / messaggio. Infatti, se andiamo a vedere il file .hex risultante dalla compilazione, troveremo questa situazione:

mqtt-fw3Per chi non conosce lo standard dei file intel-hex, il record alla linea 130 indica esattamente all’indirizzo di Flash 0x0F00 i due bytes {0xFF, 0xFF} definiti come ‘flashdata’ nel sorgente in C e sarà proprio questa “chiave” ad essere utilizzata dall’applicativo su PC per inserire tutti i parametri programmati dall’utente. In sostanza, la riga 130 sarà eliminata e al suo posto saranno inserite 16 righe (nel caso di 256 bytes) con i dati “veri”. Naturalmente, il numero di riga 130 è relativo ad una versione iniziale del firmware. Nella versione definitiva troverete gli stessi dati, ma su un numero di riga successivo. Un esempio (incompleto) della sostituzione operata dal programma MQTTprog.exe su PC è visualizzato nell’immagine sottostante:

mqtt-fw4In pratica, quando programmeremo il microcontrollore attraverso l’apposito connettore, useremo come file di origine questo .hex modificato e poi il firmware andrà a “pescare” i vari messaggi (da 0 a 7) usando questo “indirizzamento indiretto”.

Ed ecco la prima versione del software per PC e del firmware per il microcontrollore. Si noti che quest’ultimo non fa uso di “librerie” per il protocollo MQTT ed è realizzato in linguaggio C a partire dallo studio delle specifiche del  protocollo stesso. Nella cartella zippata si trovano: l’eseguibile per Windows MQTTprog.exe, il file intel-hex mqttclient.hex e un file di testo con la lista dei possibili errori e delle abbreviazioni usate per il multimetro, nominato docs.txt. Il file zip si chiama multimqtt-v5.zip e può essere scompattato usando  la password: eficara. L’occupazione di memoria flash per questa versione è la seguente: programma=0x0000..0x0BE3 ; parametri=0x0F00..0x0FFF.

Per verificare l’integrità del file zippato, controllate che Il codice MD5 del file sia: 0AECDF122EB1B5A1700F9FADE625B438. Se lo MD5 è diverso da quello indicato, non scompattate il file perché non è quello originale oppure è corrotto o scaricato parzialmente.

Clausola di non assunzione di responsabilità:
Il programma o software descritto, liberamente prelevabile dal sito, è da considerarsi una “demo” gratuita e pertanto l’autore Emilio P.G. Ficara non fornirà alcun supporto, né si assumerà alcuna responsabilità per ogni eventuale problema, danno o conseguenza che dovesse presentarsi nel download o nell’esecuzione dell’applicazione.
Cliccando questo link per effettuare il download del file multimqtt-v5.zip implicitamente dichiaro di aver letto e capito la clausola di non assunzione di responsabilità e di accettarla.

La prima operazione da fare per creare un file .hex personalizzato per le nostre esigenze è di avviare il programma MQTTprog.exe. Ci troveremo davanti una schermata fatta così:

mqttprog-ssIl riquadro in alto a sinistra contiene una descrizione del significato di ogni parametro; nel riquadro a destra (editabile) inseriremo i nostri parametri personalizzati, uno per riga.

Io non ho il “telefono fisso” e quindi non ho l’ADSL, ma uso il mio cellulare per fare da hot-spot e per collegarmi ad Internet. Come potete vedere dalla prima riga dei parametri, lo SSID del mio hot-spot è  warmyGun e la password è m2mqtt55. Ovviamente, voi potrete modificare questi dati per accedere al vostro hot-spot personale. I pulsanti Read Param file e Write Param file servono, rispettivamente, a leggere da disco una configurazione pre-salvata e a scrivere su disco la configurazione correntemente mostrata sullo schermo. Il pulsante Modify HEX file serve invece per produrre un nuovo file hex personalizzato partendo dalla base di quello “standard” mqttclient.hex. Il file di uscita prodotto si chiama sempre mqttclient-mf.hex ed è questo che dovrà essere utilizzato per programmare il microcontrollore. Potete copiare la cartella scompattata anche su una chiavetta di memoria usb, perché l’eseguibile non richiede installazione. In ogni caso, copiate la cartella su una directory o un disco con i permessi di scrittura.

Per la programmazione dei microcontrollori Atmel, in generale, io uso il noto programma Avrdude, scaricabile presso il sito: www.nongnu.org/avrdude. La configurazione per i “fuses” del microcontrollore ATmega48V in questo caso è: Hfuse=0xCD Lfuse=0xFC. C’è da tenere presente che alcuni registri interni del micro ATmega48 (o ATmega48V) non sono esattamente identici a quelli dell’ ATmega48P o ATmega48AP. E’ quindi possibile che un circuito che utilizzi uno di questi micro possa presentare qualche problema. Appena avrò il tempo di realizzare un circuito “commerciale”, userò un micro di ultima generazione e compilerò il sorgente in C per una completa compatibilità.

Flusso di programma

Al reset, il led giallo lampeggia 3 volte e poi rimane spento per un paio di secondi, quindi ricomincia a lampeggiare velocemente mentre i vari comandi AT vengono inviati dal micro al modulo WiFi ESP-01 (v0.9.5.2 AT Firmware.bin – 9600 BPS). Le varie fasi successive del programma sono:

1) connessione al router (hot-spot) WiFi
2) attraverso la connessione wifi stabilita, apertura socket TCP su IP:Port del broker
3) invio al broker del comando mqtt CONNECT ; al parametro programmabile ClientId viene aggiunto automaticamente un numero random da 10 a 73, in modo da mantenere una parte fissa e una variabile ad ogni nuova accensione / reset del circuito.
4) attesa dal broker per la risposta CONNACK ; il led rosso si accende in modo fisso.

5) attesa 40 secondi con il led giallo che lampeggia lentamente
6) si spegne il led rosso e viene inviato un comando mqtt PINGREQ
7) attesa dal broker per la risposta PINGRESP ; si riaccende il led rosso fisso

Le fasi da 5 a 7 si ripetono per 2 volte e poi :

8) attesa 40 secondi con il led giallo che lampeggia lentamente
9) si spegne il led rosso e viene inviato un comando mqtt PUBLISH con flag di retain = 1 e QoS = 1. Nel campo Topic verrà inviato il corrispondente paramentro programmato, il Packet Identifier partirà dal valore 0x0101 (incrementato dopo la risposta) e infine nel Payload verrà inviata l’ultima lettura del multimetro, in ASCII, con un limite di 28 caratteri.
10) attesa dal broker per la risposta mqtt PUBACK ; se il Packet Identifier corrisponde a quello inviato, ne viene modificato il valore per la prossima trasmissione.

A questo punto la procedura riprende dalla fase 5. Teoricamente, potremmo spegnere il nostro dispositivo in qualsiasi momento, lasciando che il broker chiuda la connessione per esaurimento del tempo di Keep-Alive (60 secondi, in questa versione), ma per fare le cose in modo “educato”, ho aggiunto anche il comando mqtt DISCONNECT che chiude la connessione in modo canonico. Questo comando può essere attivato premendo il pulsantino TST (TeST, vedi schema) durante le fasi 5 o 8 (attesa 40 secondi). Se il comando viene accettato dal broker, si avrà una immediata disconnessione del socket TCP e i due led rosso e giallo cominceranno a lampeggiare velocemente, alternativamente. Il micro resterà in questa fase finché non toglieremo l’alimentazione o premeremo il pulsantino RST (ReSeT, vedi schema).

Se una delle fasi termina con un errore,  il led rosso farà da “monitor”, indicandoci il numero dell’errore. I vari codici di errore sono contenuti nel file docs.txt ; un lampeggio lungo indica 5 e un lampeggio corto 1. Per esempio, se il codice d’errore fosse 7, avremmo un lampeggio lungo e due brevi. Dopo la visualizzazione dell’errore il micro eseguirà un reset da watchdog e tutto ricomincerà dall’inizio, con i tre lampeggi del led giallo e così via.

Bene, il programma è completo ! Si tratta di una prima versione e forse farò aggiunte o correzioni ; nel caso, pubblicherò le variazioni in un nuovo articolo. That’s all, folks !

MQTT Client tester per modulo ESP-01

L'icona del programma e l'interfaccia USB di prova

L’icona del programma e l’interfaccia USB di prova

Sto per realizzare un nuovo progetto per trasmettere i dati di un multimetro via Internet. Inizialmente avevo pensato di creare un mio piccolo server e qualche script in PHP per gestire i dati in arrivo e smistarli verso gli utenti interessati alla lettura dei dati da remoto. Poi, invece, ho dato un’occhiata al protocollo MQTT ed ho visto che è molto semplice da implementare, almeno per quanto riguarda la parte Client. Ho per prima cosa visitato il “sito ufficiale” a questo link: http://mqtt.org/documentation e da lì ho scaricato il PDF con tutte le specifiche del protocollo: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf . Ho studiato tanti protocolli e letto tante specifiche e devo dire che sono stato piacevolmente impressionato dalla chiarezza e dalla sinteticità di questo documento.

Mi sono messo quindi al lavoro per sviluppare la mia versione di Client senza usare alcuna “libreria” già pronta. Il perché di questo approccio risiede nel fatto che dovrò “far entrare” tutto il software su di un piccolo microcontrollore e perciò voglio essere in grado di implementare nel firmware solo le cose strettamente necessarie. In secondo luogo, scrivere da zero un protocollo significa capirlo profondamente e questo è sempre un bel vantaggio, in prospettiva !

La fase preparatoria ha incluso la messa in opera di un “broker” MQTT (in pratica, il Server). Ho utilizzato un programma open-source ben collaudato che si chiama “mosquitto”. Ho trovato il sito ufficiale “An Open Source MQTT v3.1 Broker” a questo link: https://mosquitto.org/ . Per l’installazione ho usato un computer con Debian 7 e tramite il caricatore di pacchetti “apt-get install” ho caricato tutto il necessario. La personalizzazione è piuttosto semplice e richiede solo una lettura accurata delle istruzioni fornite e reperibili in rete.

Per chi volesse fare delle prove senza installare il broker, c’è la possibilità di collegarsi ad alcuni brokers “free”. Ce ne sono parecchi in rete. Ne cito uno: Host: broker.hivemq.com Port: 1883 , ma cercando su Internet se ne trovano anche altri. Non so quale consigliare, perché personalmente ho scelto di usare il mio.

Infine, mi sono messo a scrivere il software del Client. Come al solito, prima di preparare il firmware in C per il microcontrollore, ho fatto un “tester” sul computer usando il caro, potente e gratuito Freebasic, con il supporto del FireFly per la gestione grafica su Windows. Come hardware ho usato la mia interfaccia USB per il modulino WiFi ESP-01, che ho descritto in un mio precedente articolo “Interfacciare il modulo ESP-01 con una porta USB” a questo link: http://ficara.altervista.org/?p=3041 .

Questa è l’immagine del programma in funzione:

Il programma in funzione, collegato al broker.

Il programma in funzione, collegato al broker.

All’avvio, il programma apre un selettore di files per poter scegliere un file di parametri. In tale file sono contenuti tutti i dati necessari per effettuare il collegamento. Il file di default: MQTT-defaults.txt ha inizialmente questo contenuto:

il file di parametri all'origine; dovrà essere personalizzato dall'utente

il file di parametri all’origine; dovrà essere personalizzato dall’utente

Analizziamo i vari parametri e personalizziamo il file per le nostre esigenze.
Ogni linea contiene un dato ed è composta da due campi; il primo che termina con il carattere ‘:‘ è il nome del parametro e non deve essere modificato; il secondo è il valore che vogliamo attribuire a quel parametro. Vediamoli uno alla volta:

wifi-ssid: qui dobbiamo inserire lo SSID del modem / router WiFi al quale ci vogliamo collegare con il modulo ESP-01 per accedere a Internet, tipicamente qualcosa come “Alice-12345678”.

wifi-pasw: qui dobbiamo mettere la password che usiamo per rendere sicura la nostra connessione WiFi, ad esempio: “123LaMiaPasswordDIFFICILE”

E con questo abbiamo fornito al programma i dati necessari per eseguire l’accesso a Internet. Il mio modulo ESP-01 è un po’ vecchio ed ha la memoria flash da 512KB ; ho caricato al suo interno la versione di firmware per comandi AT di nome: v0.9.5.2 AT Firmware.bin (508 KB), nella versione con baud rate “nativo” di 9600 BPS. Per come è scritta l’applicazione di test, non ci dovrebbero essere problemi anche con altre versioni di firmware AT, modificando opportunamente la velocità della porta seriale. Consiglio, in ogni caso, di forzare il baud rate a 9600 sul modulo e lasciarlo così, perché è più che sufficiente per lo scopo.

Veniamo ora agli altri dati da fornire, quelli relativi al protocollo MQTT.

mqtt-broker: qui inseriamo il nome o l’IP del broker a cui vogliamo collegarci. Se usiamo un nostro broker installato su un PC della rete locale, scriveremo l’IP di quel particolare PC, per esempio: 192.168.1.200 ; se invece vogliamo usare un broker esterno, scriveremo il suo IP (se lo conosciamo) o il nome, ad esempio: broker.hivemq.com

mqtt-port: qui inseriremo la porta di comunicazione usata dal broker. L’impostazione standard per la porta TCP è la 1883 per la connessione normale o la 8883 per connessione SSL. In questo tester non viene usata la connessione SSL perché il dispositivo a microcontrollore che seguirà, non prevede questo grado di sicurezza.

mqtt-user: qui inseriremo il nostro username che verrà inviato al broker nel momento in cui effettueremo una operazione di CONNECT. Se usiamo un nostro broker e abbiamo inserito un elenco di nomi abilitati, la connessione sarà possibile solo se lo username (con la relativa password) verrà riconosciuto. Usando il broker “free” citato precedentemente, potremo usare un nome qualsiasi. Attenzione ai caratteri ! In questa mia versione di prova, è previsto che i caratteri siano solo maiuscole, minuscole e numeri. Inserendo strani simboli, si riceverà un errore o non si riuscirà ad effettuare il CONNECT.

mqtt-pasw: qui inseriremo la nostra password, che sarà inviata insieme allo username. Anche per questo testo, vale la limitazione dei caratteri descritta per lo username. Trattandosi di una connessione non SSL, qualcuno potrebbe “sniffare” i vostri dati usando un analizzatore di protocollo (es: wireshark) con la propria scheda di rete WiFi settata in modo “promiscuo”; ma ricordiamoci che stiamo solo facendo esperimenti ! Non siamo nei servizi segreti…

mqtt-clid: qui inseriremo il “Client Identifier” che è un nome che serve al broker per tenere traccia della nostra connessione. Il nome che inseriremo (sempre con le solite limitazioni) verrà elongato dal programma con 4 caratteri aggiuntivi, che saranno la rappresentazione esadecimale di un numero random da 0 a 0x7FFF. Quindi, se usiamo per esempio: MioTester, al momento di un comando CONNECT verrà inviato un Client Identifier tipo: MioTester6F3C. Questo permette di avere un nome con una parte fissa e un suffisso variabile per le nostre connessioni.

mqtt-keep: qui inseriremo il numero di secondi per i quali il broker deve tenere attiva la connessione anche se il Client non invia nulla. Un valore tipico potrebbe essere 60. Se entro i sessanta secondi il broker non riceverà un comando dal client, chiuderà la connessione. In tal caso, dovremo dare di nuovo il comando di CONNECT per poter effettuare qualsiasi altra operazione.

Ecco come potrebbe risultare il file modificato con i valori indicati:

Un esempio di configurazione.

Un esempio di configurazione.

Iniziamo il nostro esperimento !

Per prima cosa, naturalmente, colleghiamo l’interfaccia USB:ESP-01 ad una porta USB del nostro computer. Prendiamo nota del numero di COM PORT che viene assegnato. Io, di solito vado nelle impostazioni delle periferiche, seleziono la porta COM assegnata e la “forzo” (con le impostazioni avanzate) a diventare la COM3. Ho questa abitudine fin dai tempi in cui nei notebook “di pregio” esistevano due porte COM standard, la COM1 e la COM2. Ora, se abbiamo il firmware del modulo ESP-01 con il baud rate fissato a 9600 BPS, possiamo eseguire la prima operazione, che consiste appunto nell’aprire la porta COM mediante il pulsante OPEN. Se tutto è andato bene, sulla finestra dei messaggi apparirà la scritta: #: Open ; se invece c’è qualche errore, vedremo la scritta: #: Error opening COMx. In questo caso, è possibile che ci sia qualche errore nelle impostazioni delle porta. Quindi, ricontrollare tutto e riprovare…

Se volete modificare il baud rate del modulino WiFi, vi consiglio di usare un mio programmino che trovate su questo sito, col nome: AT-commands tool al seguente link: http://ficara.altervista.org/?p=3158. La lista dei comandi AT per l’ESP8266 si trova con una facile ricerca su Internet, in formato PDF. Sulla mia versione del modulino ESP-01, il comando per modificare il baud rate (stabilmente) è: AT+CIOBAUD=9600^M^J ; naturalmente, questo comando deve essere inviato al modulino con il baud rate che è attualmente in uso. Quindi: se il modulino è fissato a 115200 BPS noi ci connettiamo a quella velocità, diamo il comando e poi chiudiamo la porta seriale, resettiamo il modulo e riapriamo la seriale, stavolta settata a 9600 BPS.

Ora, se la porta COM è aperta, eseguiamo il primo passo, che è quello di connettersi alla rete WiFi. Lo facciamo cliccando il pulsante  WiFi Connect. Se i dati che abbiamo inserito nel file di parametri sono tutti giusti, vedremo sulla finestra una serie di messaggi e dopo una decina di secondi apparirà in fondo allo schermo la scritta: #: Ok, WiFi connected! Bene, la nostra connessione a Internet è stabilita.

wificonn-partIniziamo ora ad usare i comandi MQTT.

Faccio innanzitutto una premessa: in questa versione di prova non vengono gestiti alcuni comandi ed altri sono utilizzati con delle limitazioni. Questo programma, infatti, è nato per fare delle prove in vista della realizzazione di un firmware per un piccolo microcontrollore, con risorse hardware molto limitate.

Consiglio caldamente la lettura della documentazione del protocollo MQTT, che è disponibile sul sito principale http://mqtt.org e su tanti altri siti (anche in italiano) che danno spiegazioni in linea generale o anche approfondita, di come funziona il sistema. Data la gran quantità di pubblicazioni sull’argomento, mi è sembrato inutile ripetere le stesse cose anche in questo mio articolo. Mi limiterò, quindi, ai soli casi in cui ho imposto delle limitazioni alle possibilità offerte dal protocollo, con l’obiettivo di mantenere “minimalista” la struttura del software.

La prima e più importante limitazione è che la lunghezza massima dei comandi è di 127 bytes, più 2 bytes di Fixed Header. Questa vale per ognuno dei comandi implementati nel software di test.

Il primo comando da dare è il CONNECT, quindi clicchiamo il pulsante MQTT Connect. Con questo comando instauriamo un collegamento con il broker. Vengono inviati il Client Identifier, lo username e la password (quelli inseriti nel file dei parametri) e il flag di Clean Session attivo. Se il comando viene ricevuto correttamente dal broker, questo ci spedirà una risposta di CONNACK, che indica che siamo connessi e che è stata creata una nuova sessione per noi. Vedremo la risposta apparire nella finestra dei messaggi. Se la risposta non c’è, verifichiamo che non ci siano errori nei dati impostati sul file dei parametri (indirizzo del broker, porta di comunicazione) ed eventualmente, ripetiamo tutte le procedure dopo aver corretto gli errori.

connack-partCome si vede dai pulsanti presenti sulla finestra del programma, mancano alcuni comandi che invece fanno parte del protocollo. I controlli “mancanti” sono: PUBREC, PUBREL e PUBCOMP, perché sono legati alla assured delivery (consegna assicurata) disponibile tra le possibilità del QoS (Quality of Service).

Nel protocollo MQTT il QoS ha tre possibili opzioni:
0 – at most once (al massimo una volta) che significa che qualche messaggio può essere perso ed è adatto per applicazioni tipo quella di un sensore che manda continuamente il proprio stato e quindi anche se un pacchetto “si perde” non è un dramma.
1 – at least once (almeno una volta) che significa che il messaggio arriva sicuramente almeno una volta, ma che è possibile che ne arrivino anche dei duplicati.
2 – exactly once (esattamente una volta) che significa che il messaggio arriverà sicuramente solo una volta, senza duplicati.

Nel mio programma, sul comando PUBLISH, attivato dal pulsante MQTT Publish, uso l’opzione 1 – at least once. Quando si riceve un messaggio PUBLISH dal broker (sempre con QoS = 1), bisogna “rispondere” con un PUBACK, cliccando il pulsante MQTT Puback, altrimenti il broker continuerà a tentare di inviarci lo stesso messaggio, attivando il flag DUP che sta appunto a indicare che si tratta di un messaggio ripetuto.

Proviamo, una volta ricevuta la conferma di connessione dal broker con il messaggio di CONNACK, ad inviare un comando di PINGREQ. Clicchiamo quindi il pulsante MQTT Ping e vedremo comparire sulla finestra dei messaggi prima l’invio del comando e poi la risposta del broker: PINGRESP, che ci conferma che il comando è stato accettato. Il ping può essere convenientemente utilizzato per mantenere attiva la comunicazione anche quando non si inviano altri comandi. Per esempio, se inviamo i dati di un multimetro che sta misurando la tensione di una batteria, useremo un PUBLISH quando c’è una variazione importante della misura da comunicare ai vari subscribers, ma per tenere attiva la comunicazione manderemo dei PINGREQ a intervalli di durata inferiore a quella che abbiamo definito nel parametro mqtt-keep:.

pingresp-partOra proviamo il comando DISCONNECT, cliccando il pulsante MQTT Disconnect. Sulla finestra dei messaggi vedremo l’invio del comando, ma non ci sarà alcuna risposta da parte del broker. Vedremo, invece, un messaggio dal modulo ESP-01 che ci conferma che il socket #0, che avevamo aperto al CONNECT, è stato chiuso. Ciò ci conferma che il broker ha terminato la sessione chiudendo la connessione TCP.

disconnect-partNotiamo, tra i vari pulsanti, un TCP Close, che normalmente non dovrebbe essere usato. La sua funzione è quella di chiudere il socket #0 nel caso si verificasse un blocco di qualsiasi genere nella comunicazione TCP. E’ stato utile nella fase di messa a punto del protocollo (sperimentando, si fanno errori !) e allora ho deciso di lasciarlo, anche se probabilmente non servirà. E’ da notare che interrompendo con questo pulsante una connessione in atto, sul broker la “stranezza” verrà riportata sul log come errore. Se avete installato il vostro broker mosquitto, potete andare a vedere il file di log e lì troverete la segnalazione di un Client (il vostro) che ha chiuso inaspettatamente la connessione.

Adesso passiamo al comando SUBSCRIBE, attivato dal pulsante MQTT Subscribe. Come possiamo vedere nell’immagine sottostante, i dati coinvolti in questa operazione sono il Topic filter e il Packet Identifier. Da notare, nel Topic Filter, il carattere ‘#‘ che viene definito wildcard e che in pratica si comporta come il .* quando chiediamo l’elenco dei files in una directory. Facciamo un esempio pratico: se ho due dispositivi che pubblicano (PUBLISH) dei dati, uno con il Topic multimeter/home e l’altro con multimeter/roulotte , facendo una sottoscrizione (SUBSCRIBE) con il Topic filter multimeter/# dirò al broker di inviarmi tutti gli eventi che arrivano sia dal dispositivo che pubblica su multimeter/home, sia da quello che lo fa su multimeter/roulotte.
Il broker, una volta ricevuta la nostra richiesta, ci risponde con un messaggio di SUBACK, per confermare di aver ricevuto ed accettato il comando. Vedremo questa risposta sulla solita finestra dei messaggi.

un esempio di SUBSCRIBE

un esempio di SUBSCRIBE

La finestra dei messaggi dopo aver inviato il comando SUBSCRIBE

La finestra dei messaggi dopo aver inviato il comando SUBSCRIBE

L’operazione opposta a quella appena vista è quella di UNSUBSCRIBE. Con questo comando, attivato dal pulsante MQTT Unsubscribe, si chiede al broker di cancellare la nostra sottoscrizione a uno o più “publisher”. Nonostante il comando permetta di inviare anche più Topic Filters successivi, in questa versione ne viene inviato sempre e soltanto uno. E’ da ricordare che il campo non può essere vuoto, perché questo verrebbe considerato come violazione del protocollo. I campi coinvolti nell’invio del comando sono quelli indicati nella figura sottostante. Il broker risponderà con un messaggio UNSUBACK per avvisarci di aver recepito il comando e smetterà di mandarci messaggi del publisher che abbiamo cancellato. Nell’immagine sottostante vediamo un esempio in cui chiediamo di non essere più iscritti ai messaggi pubblicati da multimeter/home. Alcuni messaggi che erano già in coda, verranno comunque trasmessi, ma dopo non ne riceveremo più. La risposta UNSUBACK apparirà, come di consueto, nella finestra dei messaggi.

Un esempio di UNSUBSCRIBE

Un esempio di UNSUBSCRIBE

La finestra dei messaggi dopo l'invio del comando UNSUBSCRIBE

La finestra dei messaggi dopo l’invio del comando UNSUBSCRIBE

Per concludere, diamo un comando di PUBLISH, tramite il pulsante MQTT Publish. Dando questo comando, trasmettiamo un messaggio al broker e questo si preoccuperà di reinviarlo a tutti i subcribers che sono iscritti al Topic in questione. Nel comando di PUBLISH non è possibile usare caratteri wildcard. Quando il comando è inviato con QoS = 1 (Il nostro caso), è obbligatorio inviare anche il Packet Identifier, che invece non è necessario in caso di QoS = 0. Una volta ricevuto il messaggio, il broker ci risponderà con un PUBACK per confermare di averlo ricevuto. Se in precedenza avevamo dato un comando di SUBSCRIBE per lo stesso Topic, dopo qualche istante riceveremo dal broker lo stesso dato che abbiamo inviato, in quanto facciamo parte di coloro i quali sono destinatari di questi eventi di publish. E’ da notare che il messaggio di PUBLISH inviato dal broker contiene uno specifico Packet Identifier. Durante la ricezione, questo dato viene mostrato nella finestra dei messaggi e inoltre viene copiato nel TextBox riservato a questo scopo, in modo che quando cliccheremo il pulsante MQTT Puback, il nostro PUBACK avrà lo stesso Packet Identifier del messaggio ricevuto e quindi il broker smetterà di reinviarcelo. Nella figura sottostante potete vedere i campi utilizzati nell’invio del messaggio.

Un esempio di PUBLISH

Un esempio di PUBLISH

La finestra dei messaggi dopo aver inviato il comando PUBLISH

La finestra dei messaggi dopo aver inviato il comando PUBLISH

Se avevamo fatto un SUBSCRIBE a multimeter/# o a multimeter/home, riceveremo anche noi il messaggio appena pubblicato, come si legge nelle ultime righe della finestra dei messaggi. A questo punto daremo il comando di PUBACK tramite il pulsante MQTT Puback e vedremo questo risultato:

Dopo aver ricevuto un PUBLISH dal beroker, inviamo un PUBACK per conferma (se IoS è diverso da zero)

Dopo aver ricevuto un PUBLISH dal broker, invieremo un PUBACK per conferma (se Q0S = 1)

Questo è tutto. Spero che il programma e l’articolo possano essere di aiuto a chi volesse cimentarsi nella sperimentazione di questo protocollo.
Buon lavoro !

Clausola di non assunzione di responsabilità:

Il programma o software descritto, liberamente prelevabile dal sito, è da considerarsi una “demo” gratuita e pertanto l’autore Emilio P.G. Ficara non fornirà alcun supporto, né si assumerà alcuna responsabilità per ogni eventuale problema, danno o conseguenza che dovesse presentarsi nel download o nell’esecuzione dell’applicazione.

Cliccando questo link per effettuare il download del file MQTT8266_161111.zip implicitamente dichiaro di aver letto e capito la clausola di non assunzione di responsabilità e di accettarla.

Verificate il checksum MD5 del file MQTT8266_161111.zip scaricato ! Questo deve essere: 6451A7F02C4821C0A14D774D8DE9B623 ; se è diverso, il file è corrotto o non è quello originale. In questo caso, non scompattatelo e buttatelo via !

Se invece è tutto ok, potete scompattarlo (è richiesta una password che è: eficara) e troverete l’eseguibile e il file dei parametri da personalizzare. Potete usare il programma anche su una chiavetta di memoria USB, in quanto non ha bisogno di installazione, essendo un eseguibile puro.

Ultima modifica 2016,Nov,11 : lasciando vuoti i parametri mqtt-user: e / o mqtt-pasw: nel file delle impostazioni, l’operazione di CONNECT avverrà in modo anonimo (Connection Flags = 0x02), quindi nel pacchetto inviato al broker non compariranno i campi username e password. Ovviamente, il broker deve concedere questo tipo di accesso, altrimenti si riceverà un errore o comunque non sarà possibile effettuare alcuna operazione.