WePaRT: Stazione monitoraggio meteo e polveri sottili

In questo articolo illustro una centralina per il monitoraggio del particolato a cui ho aggiunto un sensore per poter rilevare anche temperatura, umidità e pressione atmosferica. Si tratta quindi di una Stazione meteo che controlla anche le Polveri Sottili. L’ho chiamata WePaRT come acronimo di Weather and Particulate Recorder-Transmitter.

Sponsor

I componenti per realizzare la centralina di monitoraggio del particolato sono stati gentilmente offerti da DigitSpace – Negozio online di componenti elettronici e kit ad ottimi prezzi situato in Cina. Pagamento con paypal e spedizioni con corriere espresso.

Digitspace

Struttura della centralina

I dati vengono rilevati da una stazione posizionata in un punto in cui Internet non è accessibile. Chiamerò questa: stazione base. E’ la stazione sulla quale vengono montati i sensori e che viene posta, ad esempio, in cima ad un palazzo, in una campagna remota ecc. Questa stazione, di per se, visualizza i dati sul display e, volendo, possono essere anche visionati in tempo reale sul proprio cellulare dal momento che genera anche un access point WiFi al quale è possibile collegarsi.

Dal momento che desidero essere aggiornato su questi dati e visualizzarli anche in forma grafica soprattutto quando non sono nei pressi della stazione base, questa, in aggiunta, trasmette i dati rilevati mediante la tecnologia LoRa (quindi via radio), ad un sistema ricevitore. Il ricevitore, che chiamerò stazione remota, viene posizionato a distanza dalla centralina in un luogo in cui è disponibile una connessione ad internet via WiFi. In linea d’aria, senza che siano presenti edifici, si può anche superare la distanza di 1Km.

La stazione remota, oltre a visualizzare i dati ricevuti su un display, li ritrasmette nella rete locale (via MQTT) e ad un servizio che permette, gratuitamente, di realizzare grafici visibili, eventualmente, a tutti e ci permette quindi di condividere le nostre rilevazioni col mondo intero. A questo scopo utilizzeremo Thingspeak. Anche la stazione remota genera una pagina HTML che si aggiorna in tempo reale con la tecnologia Ajax e questa è invece disponibile accedendo alla stessa rete a cui è collegata la centralina.

In un prossimo aggiornamento vedremo anche come far arrivare notifiche push sul cellulare nel momento in cui i valori di particolato superano una certa soglia.

WePaRT – Schema a blocchi

Per evitare perdite di dati che in alcune situazioni possono essere di vitale importanza, sia la stazione base che la stazione remota registrano i dati su microSD in un file CSV ed entrambe le pagine web generate (sia quella accessibile da access-point generata dalla stazione base, sia quella accessibile dalla rete Wi-Fi locale a cui è collegata la stazione remota) danno la possibilità di scaricare i files CSV presenti sulla scheda di memoria. La stazione remota da anche la possibilità di scaricare il file di testo in cui verranno memorizzati i pacchetti ricevuti con errori di trasmissione e quindi non trasferiti nel CSV, a scopo di analisi.

Articoli propedeutici

Prima di continuare è assolutamente necessario che leggiate, se non l’avete ancora fatto, i 3 articoli precedenti in cui ho parlato a fondo dei dispositivi che andremo ad utilizzare, dando delle nozioni che in questo articolo riterrò scontate perchè ne ho già parlato:

  • Il sensore SDS011 – Qui illustro come funziona il sensore di polveri sottili che utilizzo nella centralina.
  • I sensori di pressione BME280 e BMP280 – Le differenze tra i due sensori, come riconoscerli e come utilizzarli.
  • La scheda di sviluppo TTGO LoRa 32, parte 1 – Qui illustro la scheda che andremo ad utilizzare come trasmettitore e ricevitore, dando un’infarinatura generale sulla tecnologia LoRa e in particolare su come va utilizzata correttamente la scheda.
  • La scheda di sviluppo TTGO LoRa 32, parte 2 – Qui do un semplice esempio di comunicazione punto-punto, per cui troverete tutte le nozioni necessarie per poter programmare la scheda da Arduino IDE, passaggi che in questo articolo non ripeterò.

Lo ripeto ancora una volta, se siete capitati su questo articolo cercando un sistema per monitorare la situazione meteo e/o le polveri sottili, è assolutamente necessario che leggiate prima i 4 articoli citati sopra, altrimenti per forza di cose alcune cose saranno incomprensibili.

Componenti utilizzati

Elenco qui i materiali che ho utilizzato io. I seguenti materiali sono stati gentilmente forniti da Digitspace, vi lascio pertanto i link diretti ai prodotti:

Il sensore BMP280 rileva Pressione e Temperatura. Se avete letto gli articoli propedeutici sapete che esiste la variante BME280 che, in aggiunta, rileva anche l’umidità. Nel caso di utilizzo del BME280 il DHT22 diventa quindi apparentemente superfluo, in realtà li utilizzo entrambi e sulle pagine generate mi visualizzo entrambi i valori (ad esempio sia temperatura dal DHT22 che dal BME/BMP280). Dal momento che questi sensori costano poco, consiglio di non fare modifiche anche perchè vorrebbe dire mettere mano al sorgente che è davvero molto complesso e articolato.

La stazione base deve essere alimentata. Io ho utilizzato un modulo HLK-10M05 fornitomi sempre da Digitspace,   su questo mi preme fare due considerazioni:

  • Il modulo in questione è, in realtà, sovradimensionato: è infatti da 10W, il che vuol dire che, fornendo 5V, eroga 2A. Per la sola applicazione in questione va benissimo anche il modello più piccolo, l’ HLK-5M05, che è da 1A. Questi moduli sono, in pratica, degli alimentatori switching incapsulati. Fatti molto bene e con molta cura. Se siete iscritti al nostro canale telegram, potete trovare altre informazioni su questi moduli cercando nei post passati (basta fare la ricerca, ma anche cercare nella galleria media trovando l’immagine dei moduli).
  • L’utilizzo di moduli switching direttamente sulla protoboard è in realtà pericoloso e fattibile solo da utenti esperti per cui lo sconsiglio vivamente dal momento che ci sarebbe la 220V su PCB. Consiglio pertanto di utilizzare un alimentatore da parete 5V da almeno 1A come se ne trovano tanti su Amazon.

Dal momento che l’SDS011 utilizza un connettore JST-XH, io ho comprato un kit di connettori JST-XH su Amazon, che ho utilizzato anche per collegare sul PCB gli altri due sensori. Nella confezione dell’SDS011 sono presenti anche l’adattatore USB, che in questo caso non utilizzeremo, e il cavetto per la connessione del sensore all’adattatore USB: potete utilizzare tale cavetto ma avete comunque poi bisogno del connettore maschio da mettere sul PCB, per cui quel kit di Amazon, secondo me, è molto buono perchè lo riutilizzerete anche per altre cose.

Per la stazione remota, invece, basterà un semplice alimentatore o caricabatterie da parete che esce con il connettore microUSB dato che alimenteremo la scheda LoRa32 direttamente (qui non ci saranno altre cose collegate alla scheda).

C’è bisogno, poi, di una manciata di componenti che in genere abbiamo già a portata di mano:

  • 3 Condensatori multistrato da 100 ÷ 220nF
  • 1 resistenza da 10kΩ

Se volete registrare i file CSV sulla microSD avete quindi bisogno di una oppure di 2 schede microSD : se ne avete una sola, potete montarla nella stazione remota ad esempio. Non sono necessarie schede di capacità elevata dal momento che i files generati sono di pochi kB (per arrivare a 1GB di dati ho stimato circa 9 anni di utilizzo continuo), per cui anche vecchie schede da 1, 2, 4GB vanno più che bene.

In più, è necessario un box in cui alloggiare la stazione base. Io ho scelto un contenitore della Bahar Enclosures: il BWP 10008-A2, che ha le alette laterali per poterlo fissare al muro, è waterproof, ha il coperchio trasparente, è realizzato in ABS e ha dimensioni  260*143*75 mm e si è rivelato molto adatto allo scopo ed in più fornisce un aspetto super-professionale alla realizzazione

Non costa nemmeno molto, il problema è la spedizione, ma vi assicuro che ne vale la pena. Ad ogni modo, all’ultimo paragrafo c’è uno spreadsheet di Google con il riassunto di tutto il materiale necessario.

Circuito stazione base

Questo è lo schema della stazione base:

Come vedete la realizzazione è molto semplice: l’alimentazione a 5V proveniente dall’alimentatore da parete o dal modulo switching verrà fornita direttamente sul pin 5V della scheda e sul pin 5V dell’ SDS011. Dal pin 3V del modulo LoRa32 preleveremo invece l’alimentazione a 3.3V per alimentare sensori DHT22 e BME (o BMP) 280. Sappiamo dagli articoli precedenti che sul pin 3.3V del modulo abbiamo corrente in abbondanza e, ad ogni modo, quei due sensori consumano molto poco.

Da test che ho fatto, tutta la centralina, considerando il modulo SDS011 in attività (che dura comunque solo 30secondi durante i quali la ventola è accesa), assorbe meno di 200mA.

Tutti i sensori hanno un condensatore da 100 ÷ 220nF sull’alimentazione quanto più vicino possibile al pin. Importante non dimenticarsi della resistenza di pullup da 10kΩ sul terminale dati del DHT22.

Il sensore BME/BMP utilizzerà l’I2C Hardware, che è lo stesso bus utilizzato dal display OLED a bordo del modulo. Il sensore SDS011 utilizzerà invece l’UART hardware, per questo motivo, durante la programmazione, il sensore di particolato deve essere disconnesso altrimenti la programmazione non va a buon fine.

Durante la programmazione ricordatevi anche di rimuovere la microSD. Ma avete letto gli articoli precedenti quindi lo sapete già, giusto?

Il DHT22 può utilizzare un normale pin, ho scelto il GPIO4 perchè durante la programmazione non mi da problemi. Prima di questo ho provato a collegarlo al GPIO34, ma il sensore non funzionava affatto, e al GPIO12 che però durante la programmazione mi genera l’errore:

A fatal error occurred: MD5 of file does not match data in flash!

Questo è il circuito come l’ho realizzato io sulla millefori:

Per la realizzazione delle piccole etichette utilizzo una Dymo

Vedete che ho montato il modulo LoRa32 a testa in giù, col connettore SMA verso il basso perchè ho fatto la scelta  di utilizzare l’antenna esterna collegata con una prolunga sul connettore U.FL (più in basso spiego alcune cose/do alcuni consigli), per tale motivo nel codice sorgente della stazione base nel setup ho ruotato la visualizzazione del display di 180°. 

Circuito stazione remota

Non c’è. Viene utilizzato il modulo LoRa32 tal quale senza nient’altro vicino se non l’alimentatore sulla Micro-USB ed eventulamente la MicroSD innestata.

Realizzazione stazione base

Come detto sopra, per il montaggio della circuiteria ho utilizzato il contenitore Bahar BWP 10008-A2. Tale contenitore è stagno ma, chiaramente, facendo dei buchi per montare le varie parti, perde la tenuta: questo per me non è un problema perchè, in ogni caso, la scatola va piazzata in un posto in cui non batte il sole direttamente e non ci piove, altrimenti i sensori si rovinano (soprattutto l’SDS011 che non deve ricevere il sole in maniera diretta), leggono male, entra acqua nel punto di ingresso aria del sensore di particolato ecc.

Personalmente ho montato il box a casa mia in cima all’edificio al di sotto del tetto in modo da essere ben ventilato (per leggere valori corretti di particolato e per un corretto flusso di aria sui sensori meteo) e non ricevere la luce del sole frontalmente e soprattutto non ricevere acqua.

I due sensori meteo li ho chiaramente montati utilizzando dei cavetti e i connettori JST-XH del kit di Amazon di cui vi ho parlato prima:

L’utilizzo di connettori JST-XH dona sicuramente un aspetto più professionale alle realizzazioni. Sebbene abbiano un passo di 2.50mm si adattano perfettamente al passo standard di 2.54mm senza problemi e sono facili da crimpare anche non avendo i tool appositi

Su un lato della scatola ho fatto dei fori: uno rettangolare per far incastrare completamente il DHT22 e uno sottile in cui far passare il solo cavetto del BME/BMP con due fori per il suo fissaggio. Piuttosto che lasciare i sensori all’aria aperta, li ho coperti con uno schermo di Stevenson che ho stampato in 3D:

Trovate questo modello su Thingiverse. L’ho stampato in PLA+ che, per un utilizzo all’aria aperta è sicuramente meglio del normale PLA. Lo spazio sulla base dello schermo di Stevenson consente l’alloggiamento sia del sensore di pressione che del DHT purchè vi organizziate bene con gli spazi e lavoriate in maniera pulita. I sensori in questo modo vengono coperti e lo schermo consente una ottimale circolazione dell’aria. Il sensore di particolato, invece, l’ho collegato verso l’esterno mediante un imbutino che ho disegnato personalmente, collegato con un tubo:

L’imbutino l’ho reso disponibile nel repo Github ed è costituito da due parti: quella che vedete visibile nella foto e una piccola griglia che va all’esterno e che dovrebbe servire a fare in modo che non si infilino insetti. Il diametro del gambo è lo stesso dell’imbocco del sensore: 6mm. Il diametro esterno dell’imbutino è 30mm e il foro da fare sulla scatola è 15mm che corrisponde al diametro dell’incavo interno.

Qui si vedono le parti stampate in 3D all’esterno:

Parti stampate in 3D: schermo di Stevenson al di sotto del quale si trovano il BME280 e il DHT22, e imbutino con griglia per aspirazione aria da parte dell’ SDS011

e qui come appaiono all’interno:

Posizionamento dei sensori nella scatola

Dal momento che l’SDS011 deve anche espellere l’aria, bisogna prevedere anche uno sfiato. Ho realizzato una serie di fori nella direzione del punto di uscita e messo un foglio di plastica per separare la zona sensori dalla zona circuito per fare in modo che eventuale polvere non ricopra il circuito:

Il riquadro rosso indica il punto in cui ho praticato una serie di fori per lo sfiato dell’SDS011 che si trova subito sopra di essi. Tra SDS011 e circuito ho apposto un foglio di plastica per protezione dalla polvere. La plastica arriva fino in cima in modo che aderisca anche al coperchio della scatola quando viene chiusa.

Considerazioni sull’utilizzo dell’antenna da connettore U.FL

Per poter montare il LoRa32 nella scatola è necessario far fuoriuscire l’antenna. Se siete bravi magari riuscite ad utilizzare una scatola più grande in cui inglobare tutta la scheda compresa di antenna o magari potete usare la stessa scatola disponendo tutto in verticale e ottimizzando gli spazi. Io ho preferito montare l’antenna all’esterno e  per fare questa cosa ci sono due soluzioni:

  • Utilizzare una prolunga coassiale da SMA maschio a SMA femmina
  • Utilizzare una prolunga coassiale da U.FL a SMA femmina

Nel primo caso collegherete il maschio al connettore antenna già presente sulla scheda: questa è la soluzione che consiglio se volete tirare l’antenna fuori dal box ed è un consiglio che fornisco col senno di poi. Io ho scelto la seconda soluzione perchè sulla scheda è presente un connettore U.FL e il tipo di cavetto che ci vuole è quello che normalmente si trova anche nei router per collegare le antenne esterne e quindi è più facile da recuperare a costo zero. Ce l’ha comunque in catalogo anche Futura Elettronica. Ma perchè non consiglio questa soluzione? Perchè sulla scheda LoRa32 il connettore U.FL è si presente, ma non è collegato!

Inizialmente avevo fatto le prove con l’antenna direttamente collegata al connettore SMA, così come esce dalla confezione insomma, e andava tutto bene. Il valore di RSSI sul modulo che fungeva da ricevitore era buono: prossimo a zero quando avvicinavo i moduli e scendeva man mano che mi allontanavo, arrivando al valore minimo di -120 quando i moduli erano proprio lontanissimi (un centinaio di metri in linea d’aria chiusi in due case separate). Ricordo che quando il valore di RSSI è molto basso (da -100 a scendere) i pacchetti possono arrivare danneggiati.

Ho quindi fatto le prove utilizzando, sulla stazione base, il cavetto U.FL/SMA con l’antenna: i valori di RSSI erano bassissimi anche con i moduli vicini (con i due moduli distanti nemmeno un metro, avevo un RSSI tra-60 e -80). Inizialmente non ci ho fatto caso, sottovalutando la questione, pensando che comunque l’utilizzo di un cavetto riciclato da un router potesse indurre delle perdite, e così ho lasciato a funzionare il sistema per alcuni giorni: il valore di RSSI era sempre prossimo a -120 con i moduli in due stanze adiacenti, nella stessa casa, e una grossa percentuale di pacchetti arrivava, giustamente, corrotta.

Ho quindi indagato tester alla mano:  per fortuna avevo appena comprato i puntali nuovi e sottili  che mi hanno aiutato tantissimo (pubblicai un video di questi puntali qui, se vi interessano, nella descrizione del video c’è il link per l’acquisto). Il punto centrale del connettore U.FL risultava scollegato! Tale connettore si trova sullo stesso percorso del connettore SMA quindi per forza di cose per me era associato al modulo LoRa piuttosto che al WiFi (per il quale c’è comunque l’antenna metallica saldata che viene usata anche per il Bluetooth). E difatti ci avevo visto giusto!

Sullo schema e sulla documentazione attuale del LoRa32, purtroppo non ci sono informazioni sul connettore U.FL

In un primo momento non ho fatto altro che collegare con un sottile filo il polo “caldo” del connettore U.FL a quello del connettore SMA. Poi, dopo altre indagini più approfondite ho capito che bastava spostare una resistenza SMD e prima di pubblicare l’articolo ho chiesto conferma a LiLyGO, che produce la scheda, la quale mi ha confermato tutto. Nella seguente foto ho quindi riportato la modifica da fare se volete utilizzare il connettore U.FL:

Il rettangolo rosso indica come è posizionata di default la resistenza. Bisogna dissaldarla e ruotarla di 90° fino a metterla nella posizione indicata dal rettangolo giallo: ci sono già i pad a saldare.

Il problema, per me, è che quella resistenza è in formato 0402 (imperiale, 1005 metrico) il che vuol dire che è lunga 1mm e larga circa mezzo mm per cui non me la sono sentita di fare questa modifica e ho lasciato la modifica che avevo fatto col filo, tanto funziona anche se probabilmente non è il massimo (con l’antenna diretta sullo SMA avevo comunque valori di RSSI migliori). Questo sistema di ruotare la resistenza serve, ovviamente, a fare in modo che non possano essere usate due antenne contemporaneamente.

Plottare grafici su internet: Thingspeak

Una volta acquisiti i dati possiamo valutare la possibilità di mostrarli su internet in forma grafica utilizzando il servizio offerto da Thingspeak. Su Thingspeak è possibile creare un account gratuito ma che ha delle piccole limitazioni:

  • Non è possibile inviare più di 3 milioni di messaggi all’anno (vedremo dopo cosa è un messaggio di Thingspeak). Tenendo conto di un anno bisestile (366 giorni), si tratta di circa 5 (5.69) messaggi al minuto, ovvero un messaggio ogni 11 secondi circa (10.54): penso siano più che sufficienti! Questo dato è cumulativo per tutti i canali, Thingspeak consiglia di non superare gli 8219 messaggi al mese.
  • E’ possibile disporre solo di 4 canali, ogni canale supporta 8 campi. Un canale ha lo scopo di raggruppare diversi valori, ovvero nel nostro caso le letture da massimo 8 diversi sensori. Immaginiamo di creare il canale a cui diamo il nome My Own WePaRT e di inviare ad esso le letture di particolato, umidità ecc (nel nostro caso non sfrutteremo nemmeno tutti e 8 i campi).
  • Bisogna necessariamente disporre di un indirizzo email non personale (cioè non @gmail.com ad esempio) per cui, se siete studenti o fate parte di un’organizzazione, dovete utilizzare uno di questi indirizzi email.

To access your organization’s MATLAB license, use your school or work email.

Cosa è, quindi, un messaggio su Thingspeak? E’ una stringa contenente fino a 8 campi di dati: immaginatelo come una riga di un file CSV. Ogni messaggio non può superare 3000bytes. Nel nostro caso un messaggio sarà costituito dai valori di PM2.5, PM10, umidità, temperatura e pressione separati da virgole.

Per registrarsi bisogna andare su questo link e cliccare Create One! Inserire indirizzo email, nazionalità, nome, cognome e premere il tasto Continue. Dopo essersi registrati viene inviata una mail, cliccare sul link nella email per convalidare la registrazione e tornare alla pagina dove c’è il pulsante Continue: premerlo, si viene invitati ad inserire una password. L’account è creato.

Creiamo quindi il notro canale da ChannelsMy ChannelsNew Channel. Diamo un nome ed una descrizione al canale e diamo quindi il nome ai campi che intendiamo inviare. Nella seguente immagine ci sono le impostazioni che ho usato per il mio canale:

Come vedete ho utilizzato soltanto 5 campi (per attivare un campo disattivato, cliccate sul checkbox alla sua destra): difatti come temperatura e umidità invio soltanto quelli di un solo sensore piuttosto che di entrambi. Più in basso c’è anche un campo Tags dove potete mettere delle parole chiave separate da virgola: vi invito a mettere wepart tra le parole chiave. E’ possibile inserire anche altri dati come l’altitudine e le coordinate geografiche relative al sistema che sta inviando i dati. Potete mettere un URL, l’indirizzo Github e anche un video. Quando avete compilato i campi che vi interessano, premete su Save channel.

Venite portati automaticamente alla visualizzazione privata. Mettiamo caso che vogliate fare come me, ovvero rendere i grafici pubblici: cliccate sul tab Sharing e selezionate la seconda opzione: Share channel view with everyone. Cliccate quindi sul tab Public View: vedete che compaiono già dei grafici collegati ai Field (campi) che avete impostato. La stessa cosa compare in private View. I grafici che appaiono di default sono del tipo Linea con 60 valori massimo.

Se cliccate sul simboletto della matita in alto a destra per ogni grafico vedete che potete aumentare il numero di valori mostrati (Results) e cambiare tipo di grafico (Type). Se, come me, volete mostrare anche un indicatore a lancetta che mostri solo l’ultimo valore piuttosto che il grafico dello storico, premete sul tasto Add Widgets : vedete che potete inserire l’indicatore Gauge, un semplice display numerico Numeric Display e una spia luminosa Lamp Indicator utile per mostrare valori booleani. Dopo aver selezionato Gauge premete il tasto Next e compilate le parti che vi interessano: in particolare il campo Field va impostato sul numero di campo dal quale l’indicatore deve prendere i dati, ci sono quindi i valori minimo e massimo, l’opzione per mostrare il valore anche in forma numerica piuttosto che solo con la lancetta, l’unità di misura da mostrare, la graduazione Tick, l’intervallo di aggiornamento e c’è la possibilità di impostare delle fasce di colore per i range (premendo il + è possibile aggiungere più fasce). A titolo di esempio queste sono le impostazioni che ho usato io per la lancetta che indica la temperatura:

Tutte le modifiche che fate ad una vista non vengono replicate per l’altra vista: ovvero se state aggiungendo indicatori, grafici ecc nella visualizzazione pubblica, non vengono aggiunte in automatico anche alla visualizzazione privata. Personalmente nella visualizzazione privata ho eliminato tutto e mostro unicamente lo Status che è un messaggio particolare associato all’invio delle misure. E’ difatti possibile inviare, insieme alle misure, una nota su di esse che finisce appunto in questo campo particolare. Nello stato mostro lo stato di ricezione, ovvero se il pacchetto da parte della stazione remota è stato ricevuto correttamente oppure no segnalando il tipo di errore rilevato. Per aggiungere la finestra con lo stato dovete premere Add Visualization e selezionare quindi l’unica opzione disponibile nella versione Free: Status.

Le finestrelle dei grafici/indicatori/stato potete riposizionarle a piacimento mediante drag’n-drop.

La libreria utilizzata per comunicare con Thingspeak permette di settare separatamente ogni campo che vogliamo inviare, è necessario quindi tenere la corrispondenza tra settaggi che abbiamo appena fatto su Thingspeak e libreria: se abbiamo impostato il campo 1 con la scritta “Temperatura”, allora nella libreria imposteremo il campo 1 sul valore di temperatura. Approfondiremo dopo questo aspetto. Ricordatevi solo la corrispondenza Numero di campo – Valore.

L’ultima parte che ci interessa si trova nella scheda Api Keys: cliccatela. C’è un codice che è necessario per la libreria, ovvero la chiave di scrittura Write Api Key : questo codice (che deve rimanere segreto altrimenti permettete ad altri di inviare dati al vostro grafico) è quello che permette di inviare i valori ai grafici di  Thingspeak del nostro canale. Più in basso c’è la chiave di lettura, ma a noi non serve. Un altro parametro che ci interessa è il codice identificativo del canale. Tale parametro è sempre in bella vista in alto a sinistra, proprio sotto il titolo, scritto affianco a Channel ID. L’indirizzo della nostra pagina Thingspeak sarà sempre:

https://thingspeak.com/channels/[channel_ID]

Se avete impostato il canale come pubblico, dando ad una persona questo indirizzo, questa visualizzerà esclusivamente la scheda Public e nulla più.

Codice sorgente

Il codice sorgente l’ho reso disponibile su Github, il link è all’ultimo paragrafo. Consiglio agli utenti alle prime armi di non fare modifiche perchè è il frutto di mesi di lavoro e messa a punto e per forza di cose risulta molto complicato e a tratti anche un po’ rimaneggiato e forse non perfettamente ottimizzato. Posso sicuramente dire che sta lavorando da oltre un mese senza errori (su Thingspeak ho rimosso i vecchi valori perchè le prove le ho fatte in casa prima di montare definitivamente la stazione base all’esterno).

Allo stato attuale aggiungere/rimuovere sensori al codice può risultare una vera odissea se non siete esperti. Ad ogni modo ho preparato degli spreadsheet che illustrano la struttura dei pacchetti e il link è sempre all’ultimo paragrafo.

Sono presenti due codici sorgente: uno per la stazione base e uno per la stazione remota. I due sorgenti hanno in comune alcune parti che sono:

  • board_defs.h – contiene le definizioni per la scheda LoRa32
  • images.h – contiene il mio logo e il logo del LoRa che però non è utilizzato
  • my_fonts.h – contiene il font che ho generato io e che non troverete mai negli esempi che ci sono in circolazione e che fanno uso del font standard che trovo inguardabile
  • webpage.h – c’è la maggior parte della pagina web mostrata quando vi collegate all’hotspot generato dalla stazione base e quando vi collegate all’IP della stazione remota nella stessa rete. Anche se i due file webpage.h contenuti nelle cartelle delle due stazioni sembrano simili, sono in realtà diversi

Spiego quindi molto velocemente in maniera separata i sorgenti delle due stazioni.

Librerie da installare

Qui c’è l’elenco delle librerie richieste. Sapete già come installarle in Arduino IDE (Strumenti > Gestione Librerie)

Come vedete non compare una libreria per l’SDS011. Non ne ho trovata nessuna buona funzionante con ESP32, o meglio: ci sono ma non gestiscono il setup del sensore e, se avete letto l’articolo sull’SDS011, sapete che è male tenerlo in funzione di continuo altrimenti dura meno di un anno. Ecco, le librerie per ESP32, allo stato attuale, non permettono di settare il periodo di lavoro e quelle che hanno questa funzione sono per Arduino o per porta seriale emulata. Ho scritto così io qualche riga per poter impostare il sensore per lavorare in maniera discontinua e per leggere i dati.

Codice stazione base

C’è da settare ssidpassword ma ricordo che non sono quelli della rete WiFi (perchè ripeto: la stazione base si trova in un posto dove internet non è accessibile) bensì quelli che volete assegnare all’access point generato dall’ESP32. Di default il SSID della stazione base è WePaRT (192.168.4.1) e non c’è password: in questo modo quando vi trovate nei pressi della stazione base, vi collegate col cellulare senza immettere la password, quindi dal browser digitate l’indirizzo 192.168.4.1 e viene visualizzata la pagina web generata dalla stazione. Ho messo l’indirizzo IP tra parentesi nel nome della rete perchè a volte lo dimentico.

Pagina web generata dall’access point della stazione base

Più in basso nel codice dovete selezionare quale sensore di pressione state utilizzando. Di default è usato il BME280 che tira fuori pressione, temperatura e umidità. Se utilizzate il BMP280, che non fornisce il valore di umidità, commentate USE_BME280 e togliete il commento a USE_BMP280.

Più in basso la stringa infourl l’ho usata per mostrare il link da cui uno può prendere i dati di thingspeak o altro, per cui metteteci dentro il vostro URL: è collegato al tasto INFO (needs internet) che compare nella pagina. In realtà quell’url cliccato dalla webpage che visualizzate stando collegati alla stazione base, non può funzionare perchè non c’è l’accesso ad internet. Potete scollegarvi dalla stazione e quindi cliccarlo.

AVERAGE_SENSORS è messo a 200 e rappresenta il numero di misure consecutive fatte sui sensori (tranne quello di particolato) sui cui viene fatta la media prima di mostrare il valore: questo a parte darci dei valori molto stabili fa anche in modo da rallentare un po’ la visualizzazione, quindi consiglio di non modificarlo.

Vedete che il codice fa uso della lettura sul pin batteria incluso sulla scheda e trasmette anche questo dato: in realtà io non ho utilizzato la batteria anche perchè l’SDS011 non potrebbe funzionare dato che richiede 5V, mentre potrebbero funzionare gli altri due sensori. Il codice c’è, se trovate altre soluzioni… avanti.

Il valore SDS_MINUTES serve per impostare, durante il setup, il periodo di lavoro del sensore di particolato. La mia impostazione di default fa entrare in funzione il sensore ogni 10 minuti. Il parametro SDS_TIMEOUT viene utilizzato soltanto durante il setup per rilevare la presenza del sensore, non toccatelo: essendo questo collegato sulla UART hardware ed essendo questa usata anche per la programmazione, il sensore deve essere disconnesso quando carichiamo il codice, quindi se poi dimentichiamo di riconnetterlo, durante l’avvio ci viene segnalato sul display che il sensore non è presente: in pratica invio un comando al sensore ed entro SDS_TIMEOUT secondi mi aspetto una risposta.

Il define ALLOW_DOWNLOAD è commentato di default: decommentandolo è possibile scaricare i files dalla microSD quando ci si collega all’access point.

Il programma fa le letture dei sensori e invia il pacchetto via LoRa. Il pacchetto è costituito dai valori separati da punto e virgola.

Ho scelto il punto e virgola come separatore perchè così il file CSV viene interpretato correttamente anche dalle vecchie versioni di Excel.

Se è presente la scheda microSD (rilevata una volta sola all’avvio), viene anche generato un file CSV. All’accensione del sistema viene generato un nome di file incrementale (funzione setDataFileName) che parte da 00000000.csv e arriva fino a 99999999.csv. Quando viene superato l’ultimo valore del nome file, ricomincia daccapo sovrascrivendo i files precedenti. Un file chiamato id contiene il numero del file attualmente in uso: questo per fare in modo che all’accensione venga aperto tale file e generato un file dati successivo in per non sovrascrivere i  dati precedenti. 

Con la scheda formattata in FAT32, un file può avere dimensioni massime di 2GB: trovo difficile che si arrivi, con valori CSV, a quella dimensione senza che ci sia mai una mancanza di corrente (che porta il sistema a riavviarsi e quindi generare un nuovo nome file). Ma in effetti, se il sistema base viene fatto funzionare a batteria, uno qualche dubbio lo può avere. Facciamo quindi due conti: in linea di massima, una riga del CSV è intorno ai 70Bytes e i dati vengono registrati/inviati mediamente ogni 20 secondi, quindi diciamo 3.5Bytes al secondo. 2GB (inteso come il “moderno” Gibibytes) sono 2147483648 bytes che alla velocità di 3.5b/sec richiedono circa 19anni… Reputate un po’ voi se è necessario introdurre una routine che controlli la dimensione del file per generarne uno nuovo raggiunto il limite… 

Tutti i valori attuali vengono chiaramente mostrati anche sul display OLED di cui è dotata la scheda di sviluppo.

L’attuale codice (prima versione pubblicata su Github), con tutte le funzioni implementate, occupa il 60% della memoria programma e il 13% della RAM.

Codice stazione remota

Nella stazione remota dovete cambiare i parametri presenti nel file secret.h mettendo ssid password della vostra rete Wi-Fi (a cui la stazione si collegherà). Vanno imposati ID canale e Write Key del vostro canale di ThingSpeak ed eventualmente utente e password del vostro server MQTT se usate un sistema di domotica, oppure lasciate questi ultimi due parametri in bianco.

Nel file .ino scegliete se utilizzare o meno un indirizzo IP statico (consigliato) decommentando/commentando USE_STATIC_IP. Commentate USE_THINGSPEAK se non lo utilizzate, commentate USE_MQTT se non usate un server MQTT.

La stazione remota, essendo collegata alla vostra rete WiFi, si collega anche ad un server NTP per ricavare l’orario esatto: tale orario viene aggiunto al pacchetto ricevuto per ottenere un CSV più ricco di informazioni e confrontare l’orario reale con il timestamp inviato dalla stazione base che è unicamente il valore restituito dalla funzione millis() di Arduino.

Anche questa stazione genera la sua pagina web che in questo caso sarà visibile digitando l’indirizzo IP che avete impostato (192.168.1.162 di default), stando collegati alla stessa rete a cui essa è collegata:

Il pulsante Filesystem sulla pagina web permette di visualizzare lo stato della microSD, allo stesso modo della stazione base: tale tasto chiaramente compare solo nel caso in cui la microSD sia presente. In questo codice non c’è il flag ALLOW_DOWNLOAD: i file possono essere scaricati sempre e sono chiaramente quelli salvati sulla SD da tale stazione.

Affianco ad ogni nome di file c’è la dimensione in Bytes tra parentesi e un link [download] che permette di scaricare il file relativo. id è il file che contiene l’indice dell’ultimo numero di file utilizzato per la registrazione, e a voi non serve a nulla, e badpack.txt è il file di testo in cui vengono registrati i pacchetti non validi

La stazione remota riceve il pacchetto via LoRa, lo controlla e genera un nuovo pacchetto aggiungendo altre informazioni: oltre al timestamp appena detto, viene anche aggiunto il valore di RSSI. Anche qui i dati appena ricevuti vengono mostrati sul display e salvati su microSD se presente. In caso il pacchetto ricevuto sia danneggiato viene comunque registrato, ma su un file di testo a parte chiamato badpack.txt con il tipo di errore rilevato.

L’attuale codice (prima versione pubblicata su Github), con tutte le funzioni implementate, occupa il 62% della memoria programma e il 14% della RAM.

Controllo integrità pacchetto ricevuto

Dal momento che con l’aumentare della distanza tra i due moduli diminuisce l’RSSI e ho notato che non appena si arriva a valori di questo parametro inferiori a -100 alcuni pacchetti arrivano danneggiati, ho ideato una serie di sistemi per verificare l’integrità del pacchetto ricevuto che si sono rivelati molto efficaci.

In testa al pacchetto inviato c’è il simbolo di @ e in coda c’è #: questo è il primo sistema, ovvero verificare che siano presenti dei caratteri di delimitazione. L’ultimo valore del pacchetto inviato è il valore di checksum che ho fatto con una mia funzione che somma tutti i bytes del pacchetto (esclusi i caratteri di delimitazione ma inclusi i punti e virgola) e produce un valore a 16bit. Quando la stazione remota riceve il pacchetto esegue quindi 4 controlli e se uno solo va male, il pacchetto viene scartato:

  • Viene controllata la presenza di @ come primo carattere e # come ultimo carattere.
  • Il pacchetto contiene un campo che rappresenta di campi inviati i quali sono separati gli uni dagli altri da un  punto e virgola: se contando il numero di separatori (punto e virgola) questo numero non combacia, il pacchetto viene scartato. Questo perchè come caratteri sbagliati potrebbero anche essere presenti dei punto e virgola che non ho inserito io.
  • Viene chiaramente verificato il valore del Checksum con la stessa funzione utilizzata per crearlo.
  • Viene controllata l’eventuale presenza di caratteri blank ovvero codici ascii da 0 a 31 e codice ascii 127 che io non inserisco mai nel pacchetto. L’unico carattere blank che eventualmente potrei decidere di inserire  è lo spazio (ascii 32) che non rientra nei controlli.

I pacchetti che non superano questi controlli vengono quindi registrati nel file badpack.txt sulla microSD. Aprendolo potete vedere che le stringhe a volte si accavallano proprio perchè nei pacchetti sbagliati possono essere presenti dei caratteri di tabulazione, delete ecc che causano chiaramente uno spostamento del testo.

L’attuale codice (prima versione pubblicata su Github), con tutte le funzioni implementate, occupa il 62% della memoria programma e il 14% della RAM.

Invio dati a Thingspeak

L’invio dei dati a Thingspeak viene eseguito dalla funzione sendDataToThingSpeak(String TSstatus, bool dataisvalid). Questa funzione accetta due parametri:

  • TSstatus è la stringa che contiene il messaggio di stato di cui parlavo prima nel paragrafo relativo a Thingspeak: costruisco in pratica delle note informative che attualmente visualizzo soltanto io nella mia vista privata.
  • dataisvalid è per segnalare che i dati ricevuti sono validi. In caso affermativo, vengono compilati i campi numerici per i grafici di thingspeak e il messaggio di stato contiene una stringa che dice che i dati ricevuti alle ore x sono validi, in caso contrario vuol dire che è stato ricevuto un pacchetto corrotto per cui i campi non vengono compilati e il messaggio di stato contiene invece una descrizione dell’errore rilevato.

Leggendo le note che ho messo nella funzione potete capire qualcosa di più e li potete cambiare anche i valori per fare in modo, ad esempio, di inviare entrambi i dati di temperatura (dal BME/BMP e dal DHT22) ecc. Io verso Thingspeak invio soltanto i dati presi dal BME280 tralasciando quelli del DHT22, questo perchè da ricerche fatte in giro pare che quel sensore sia più accurato sul valore di umidità. Personalmente come temperature leggo sempre le stesse (non c’è mai una differenza superiore al mezzo grado tra i due) mentre i dati di umidità sono effettivamente discordanti a volte di un buon 20%.

Chiaramente se usate il BMP280, che non manda l’umidità, modificherete la riga

ThingSpeak.setField(2, humidityB); // or humidityD

con

ThingSpeak.setField(2, humidityD);

Il 2 nei parametri identifica il numero di campo di Thingspeak. Nelle note del codice è spiegato tutto. I dati vengono inviati a Thingspeak solo nel momento in cui la stazione remota ne riceve di nuovi, per cui la frequenza di aggiornamento di Thingspeak è determinata dalla stazione base. Con la media su 200 valori e un delay nel loop di 150mS ho una frequenza di aggiornamento di circa 22 secondi: l’importante è stare sopra gli 11 secondi per quello che vi dicevo prima, per non superare il limite concesso di messaggi all’anno e quindi ritrovarsi i grafici bloccati prima che sia finito l’anno.

Nel caso in cui nel nostro account Thingspeak dovessimo implementare altri canali, dato che il numero di messaggi a disposizione, ricordo, è cumulativo per tutti i canali, dovremo diminuire la frequenza di aggiornamento aumentando quel ritardo nel loop.

FAQ

  1. [Q] Perchè ottengo l’errore “xyz” durante la programmazione?
    [A] Ricordati di:
    – selezionare la scheda corretta in Arduino IDE (ESP32 Arduino > TTGO LoRa32-OLED v1)
    – selezionare la porta COM corretta
    – installare precisamente le librerie che ho indicato
    – aver rimosso il collegamento seriale verso il sensore SDS011
    – aver rimosso la scheda microSD
  2. [Q] É possibile visualizzare un grafico di Thingspeak da solo/includerlo in una pagina web? 
    [A] SI. Puoi cliccare sul simboletto di finestra-freccia in alto a destra del grafico:

    Il grafico in questione viene visualizzato da solo in un’altra finestra, puoi includere l’url visualizzato in un IFRAME.
  3. [Q] É possibile visualizzare i grafici di Thingspeak più grandi?
    [A] SI. Basta aggiungere ?height=[altezza in pixel]&width=[larghezza in pixel] dopo l’url del grafico per poterlo ridimensionare.
  4. [Q] É possibile visualizzare i valori vecchi inviati a Thingspeak che non vengono più visualizzati sul grafico?
    [A] SI e NO. É possibile recuperare i vecchi valori utilizzando la funzione API Thingspeakread oppure scaricare un CSV con tutti i dati dalle impostazioni del canale, nella scheda Data Import/Export.
  5. [Q] Nell’account di Thingspeak leggo che c’è una expiration date… vuol dire che l’account dura solo un anno?
    [A] NO. Per gli account gratuiti vuol dire che i messaggi rimasti a quella data verranno resettati, non c’è una perdita di dati: leggi qui.
  6. [Q] É possibile aggiungere/rimuovere dei sensori?
    [A] SI. C’è il sorgente: datti da fare e fammi sapere cosa ci hai fatto.
  7. [Q] Durante le registrazioni ho fatto delle prove e verso Thingspeak sono stati inviati dei dati errati. Dal momento che prima delle prove i dati erano buoni e non li vorrei perdere, come faccio ad eliminare solo questi dati sbagliati dal grafico?
    [A] Non c’è un sistema rapido e selettivo per poterlo fare. L’unica soluzione è: fermare momentaneamente la registrazione (spegni la stazione remota), andare alla scheda Data Import/Export e dalla zona Export cliccare sul tasto Download. Così facendo salvi sul tuo PC il CSV con tutti i dati. Aprilo con un editor di testo e rimuovi manualmente le righe che non vuoi più far visualizzare. Salva il file. Adesso vai alla scheda Channel Settings e premi sul tasto Clear Channel: il canale verrà svuotato dei dati e i grafici appariranno puliti, senza dati. Ora ritorna alla scheda Data Import/Export e nella zona Import carica il file CSV che hai appena modificato e premi il tasto Upload. Dai qualche minuto di tempo a Thingspeak per caricare e plottare daccapo tutto il CSV: nel frattempo potresti vedere i grafici che presentano pochi dati anzichè tutti ma dopo un po’ si sistemano.
  8. [Q] Mi potresti aiutar….
    [A] NO
  9. [Q] Non sono esperto e vorr….
    [A] NO
  10. [Q] Questo progetto è bellissimo, lo implementerò pure io! Come posso ringraziarti per aver messo questo popò di roba gratuitamente? (domanda da fantascienza)
    [A] Ho fatto una pagina apposta con la risposta.

Aggiornamenti

Notifiche Push

A breve verrà rilasciato un aggiornamento che prevede l’utilizzo di notifiche push sul cellulare mediante il servizio offerto da Pushover. WePaRT sarà in grado di inviare una notifica nel momento in cui i valori di particolato superano dei limiti preimpostati. Per ulteriori dettagli su come funziona pushover, vi invito a leggere l’articolo in cui ne parlo.

Video presentazione

Abbiamo fatto una Live su Youtube in cui ho parlato di questo progetto. La mia qualità video durante la Live, purtroppo, era molto bassa a causa di problemi tecnici che c’erano nella mia zona dovuti a precipitazioni copiose protrattesi per giorni.

Problemi noti 

Questo paragrafo l’ho aggiunto il 18/11/2020

Reset continuo della scheda

Se la scheda di memoria si danneggia, la stazione (sia essa la base che la remota), si resetta di continuo. Capita che il firmware riesca a rilevare la presenza della microSD ed addirittura segnalare anche la quantità totale di memoria della scheda, ma nel momento in cui bisogna accedere al filesystem (questo avviene subito dopo la segnalazione di memoria), il sistema si resetta se la scheda è danneggiata in qualche modo. Questa cosa mi è capitata personalmente sulla stazione base e difatti sulla mia pagina Thingspeak in cui memorizzo i dati c’è un buco di circa 1 mese perchè non mi sono accorto in tempo dell’anomalia: non controllo tutti i giorni i valori e la stazione remota continua a funzionare mostrando sempre gli ultimi valori a cui. Questo problema mi ha fatto pensare che è meglio mettere una segnalazione timeout sulla stazione remota: se non arrivano dati dopo un certo tempo, magari viene fornita un’indicazione a display, magari lampeggiante.

Parlano di WePaRT

Links

 

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)