Ciao ragazzi, benvenuti in un nuovo tutorial!
Finalmente ho trovato il tempo di mettermici
su e quindi eccoci qui oggi a vedere come
costruirsi la propria stazione meteorologica
in casa. Nello specifico quello che vedremo
sarà come sfruttare un raspberry pi (io ho
usato il modello zero, ma va bene un qualsiasi
altro modello) per tenere monitorate temperatura
ed umidità all'interno di una stanza. Ovviamente
il prodotto finito può anche essere utilizzato
in altre situazioni, all'esterno o in altri
luoghi, chiaramente proteggendo dispositivo
ed i sensori di conseguenza. Per il momento concentriamoci però sull'uso domestico.
Proprio qualche giorno fa ho pubblicato un
video sulla piattaforma Bolt (video che come
al solito se l'aveste perso lo trovate linkato
qui in alto tra le schede e nella descrizione
in basso), dicevo piattaforma IoT che consente
con veramente due passaggi di realizzare grosso
modo praticamente questo stesso progetto (e
rimando nuovamente a quel video qualora foste
interessati al suo funzionamento). Visto che
in molti nei commenti a quel focus avete sollevato
dubbi sul fatto che Bolt possa o meno avere
senso, soprattutto in base al prezzo richiesto
etc, ho deciso di realizzare questo tutorial
per farvi capire come per ottenere lo stesso
risultato e quindi costruire praticamente
da zero (ok utilizzando alcune librerie di
supporto) ma fondamentalmente come ideare
tutta la stazione di monitoraggio meteo non
sia una cosa così banale come potrebbe sembrare
proprio grazie all'uso di Bolt. Probabilmente
ci saranno soluzioni già pronte out-of-the-box
anche per il pi o alternative/sistemi di vario
genere su cui è possibile appoggiarsi, ma
non è quello lo scopo di questo focus.
Che cos'è e che cosa deve fare la nostra
stazione meteorologica? Essa è composta da
diversi attori: abbiamo uno o più sensori
che rilevano i dati; un dispositivo a cui
questi sensori sono collegati (banalmente
nel nostro caso il pi) che li interpreta ed
immagazzina; un sistema che sia in grado poi
di ritirare fuori questi dati e mostrarli
a chi li richiede; ed infine qualcuno che
sia interessato a leggere queste informazioni
e che quindi esse possano essergli mostrate
in modo utile. Ognuno di questi passaggi non
è completamente banale, poiché ci sono vari
dettagli da specificare con cura.
Partendo dalla cattura dei dati, per iniziare
ci "accontentiamo" di un unico sensore in
grado di catturare sia i dati relativi alla
temperatura, sia quelli relativi all'umidità.
Ovviamente si possono aggiungere innumerevoli
altre variabili, come la pressione atmosferica,
la velocità del vento, servizi di previsioni
via API e quant'altro. Al momento quello che
ci interessa fare è creare un punto di inizio
che è quello che cattura i dati locali.
In futuro si potrà eventualmente ampliare il
progetto aggiungendo tutti i sensori e servizi desiderati
Quindi, come catturare temperatura ed umidità?
Questo sensore che sto utilizzando fa proprio
ciò: ne esistono diverse varianti, quelle
più diffuse hanno 3 o 4 PIN e a seconda di
tale fattore la connessione tra sensore e
raspberry pi può richiedere o meno la presenza
di resistenze. Nella versione a 3 PIN che
è quella che sto utilizzando non è richiesto
alcun resistore e il primo PIN (a sinistra)
è dedicato al segnale catturato, il secondo
PIN (centrale) alimenta a 5V il sensore stesso,
infine il terzo PIN (a destra) è il ground
e chiude il circuito. Volendo è possibile
collegare direttamente il sensore al pi, ma
come mio solito preferisco utilizzare una
breadboard di supporto, anche con la previsione
di aggiungere nuove componenti in futuro.
Basterà quindi collegare il PIN centrale
con una riga esterna della breadboard alimentata
a 5V dal pi, il ground con la relativa a cui
è connesso il ground del pi, ed il PIN per
il segnale con una colonna qualsiasi a cui
abbineremo ad esempio il PIN numero 4 del pi.
Questo rappresenta il nostro primo attore:
cioè lo strumento che cattura i dati. Ovviamente
questa è solo la parte hardware, occorre
il software di controllo. E in ciò ci viene
in aiuto una libreria rilasciata da Adafruit
che consente proprio di gestire i segnali
inviati da sensori come questo. Sia che abbiate
il modello a 4 PIN che il modello a 3 PIN,
la libreria può essere utilizzata indifferentemente
poiché li supporta entrambi. Inoltre, la
stessa libreria funziona sia con python2 che
python3, quindi abbiamo già un ottimo punto
di partenza. Il mio consiglio -al solito-
è quello di utilizzare Raspbian OS Lite perché
è uno dei sistemi più leggeri per raspberry
pi (soprattutto il modello zero) ed offre
già out-of-the-box gran parte di quello che
servirà per la realizzazione di questo progetto.
Una volta copiato l'OS su microSD, abilitato
l'ssh, cambiata la password dell'utente, aggiornato
il sistema e tutte le classiche operazioni
iniziali del caso, assicuratevi di avere installato
il comando pip. Infatti digitando sudo pip
install Adafruit_DHT si avvierà il download
ed installazione automatica della libreria
(se non avete pip potete facilmente prelevarlo
dai repository di Raspbian OS tramite sudo
apt-get install python-pip). Se utilizzate python3
ovviamente dovrete usare pip3.
Una volta scaricata la libreria, utilizzarla
sarà un gioco da ragazzi: come potete vedere
nel codice a video sarà sufficiente importare
la libreria Adafruit_DHT e, per fare una prova
veloce di cattura dei dati dal sensore, creare
un ciclo infinito quindi indicare due variabili
(la prima per l'umidità e la seconda per
la temperatura) a cui assegnare il risultato
della funzione Adafruit_DHT.read_retry(11,4),
dove 11 è il modello del sensore e 4
è il PIN a cui esso è collegato. Come dicevo
sono supportati sia i sensori modello 22 che
modello 11, basta indicare qui quello in nostro
possesso e il pin del raspberry pi
a cui lo abbiamo collegato.
A questo punto stampando i valori
di umidità e temperatura avremo a video i
dati catturati. Niente di più semplice.
Adesso entra in gioco il secondo attore: un
sistema in grado di immagazzinare questi dati
rilevati nel corso del tempo cosicché possano
essere poi visualizzati. Ovviamente, essendo
il pi a fare le misurazioni di umidità e
temperatura, trovo sensato che sia lo stesso
dispositivo a tenerne traccia. Per fare ciò
può aver senso sfruttare un database locale
in cui archiviare tutto e da cui in futuro
estrapolare le informazioni. Visto che vogliamo
fare una cosa che assomigli o magari sia anche
migliore di ciò che fa Bolt out-of-the-box,
sfruttiamo mongodb poiché questo particolare
database non relazionale memorizza i dati
tramite oggetti JSON (la cosa ci tornerà
particolarmente utile in seguito). E non essendo
relazionale, appunto, è fondamentalmente
un repository documentale in cui buttare dati
senza preoccuparci di gestirne formati e quant'altro.
Per questo motivo possiamo installare con
un semplice sudo apt-get install mongodb il
nostro database. Ma non è tutto: mongodb
ci permetterà sì di salvare i dati rilevati
ed ovviamente anche di recuperarli, ma servirà
necessariamente un orchestratore che sia in
grado di essere richiamato per salvare i dati
sul db ma allo stesso tempo capace di avvisare
chi sta guardando questi dati che è presente
una nuova rilevazione.
Vi ricordate quando ho pubblicato il focus
su come costruire applicativi web in tempo
reale? Se vi foste persi quel video chiaramente
lo trovate qui tra le schede e in descrizione,
ma comunque sfrutteremo quello stesso approccio
per la nostra stazione meteo.
L'idea quindi è quella di utilizzare node.js
e socket.io lato server più una semplice
web-app lato client per tirar su una dashboard
visuale che mostri all'utente le rilevazioni
effettuate sottoforma di grafico. Per questo
motivo dovremo installare un altro po' di
roba, fondamentalmente sarà necessario dare
un sudo apt-get install nodejs npm git, così
da avere questi tre tool a bordo. E una volta
installato il tutto, potete scaricare dal
mio account github il progetto weather_station
con il comando che vedete a video.
Il progetto comprende praticamente
già tutto al suo interno,
ma non preoccupatevi perché
ora andremo passo passo
a vederne il funzionamento. Inoltre,
chiaramente, rimando all'articolo sul blog
linkato tra le schede qui in alto e in descrizione
per la guida testuale più dettagliata abbinata
a questo focus.
Una volta clonato il progetto da github, potete
entrare nella cartella weather_station e lanciare
il comando npm install che si occuperà di
scaricare sul pi tutte le librerie aggiuntive
che io ho utilizzato per la costruzione dell'applicativo
di monitoraggio. Le librerie fondamentalmente
non sono altro che lato server il driver per
accedere a mongodb, socket.io come avevamo
detto, il framework express e per la parte
client altre librerie che vedremo in seguito.
Una volta completato il download di tutto
il necessario, lanciate il comando npm start
che avvierà node.js e la nostra applicazione
di monitoraggio. A questo punto se aprite
il browser web da PC o smartphone/tablet collegato
alla stessa rete a cui è connesso il raspberry pi,
andando sull'indirizzo IP del pi:8080
accederete alla dashboard che mostrerà
i dati finora catturato dal sensore. E ovviamente
al primo avvio essa sarà completamente vuota.
Ora abbiamo tutti gli attori del nostro progetto:
chi cattura i dati (il sensore), chi li immagazzina
(mongodb sul pi), chi è in grado di leggere
e scrivere i dati (node.js + socketio), e
chi li mostra all'utente (la dashboard).
Ma aldilà di mongodb che alla fine -essendo
un database- è grosso modo trasparente per
noi, come funzionano le altre 3 componenti?
Allora direi di partire da node.js che poi
è il cuore di tutto e il collante che dà
un senso alla presenza dei vari attori. Il
codice è scritto chiaramente in javascript
e quello che fa è creare una nuova applicazione
e cioè un server web in ascolto sulla porta
8080. Questo server è in grado di collegarsi
a mongodb che è installato sul pi ed attivo
sulla URL qui indicata. Verrà utilizzato
il DB weather_station con una sola collection
di dati che conterrà tutte assieme le misurazioni
effettuate sia di umidità che temperatura.
La prima cosa che viene fatta quando si avvia
questo server è accedere a mongodb e se non
esistono creare il DB weather_station e la
collection per le misurazioni. E poi esso
rimane in ascolto per eventuali richieste
che possono arrivare.
Le richieste possibili sono 3: start (un nuovo
client si aggancia al server e cerca di capire
se il database è attivo oppure no), insert
(un client invia una nuova misurazione da
inserire sul database secondo il formato mostrato,
cioè un oggetto JSON che abbia tre proprietà:
tempo, tipo di rilevazione e valore rilevato),
e infine find (cioè un client chiede al server
di trovare ed inviare le misurazioni presenti
sul database).
Nello specifico: la insert una volta eseguita
risponde a chi l'ha richiamata dicendo "OK
dato inserito" e lancia un evento "inserted"
che oltretutto avviserà ogni altro client
connesso che c'è un nuovo dato potenzialmente
interessante da tenere in considerazioni (e
poi vedremo che cosa ne farà il client di
ciò).
La find, invece, accetta in ingresso un parametro
che porta con sé le date di inizio e fine
dell'intervallo in cui siamo interessati circa
le misurazioni da vedere (ad esempio le ultime
12 ore). Misurazioni che verranno restituite
in ordine temporale a chi le ha richieste.
Questa è la logica della parte server della
nostra stazione meteorologica, quella quindi
che si occupa di inserire nuovi dati e di
fornire quelli che ha a disposizione a chi
li richiede. Quindi ora occorre analizzare
chi è che effettivamente inserisce le misure
e chi è effettivamente le cerca.
Partendo dall'inserimento, chi lo farà sarà
una piccolissima applicazione python che sfrutta
da una parte la libreria Adafruit_DHT che
abbiamo visto ad inizio video per catturare
i dati dal sensore, e dall'altra la libreria
socketIO_client che consente al nostro codice
python di dialogare con node.js via socket.io;
e sarà proprio tramite questa libreria che
i dati di umidità e temperatura rilevati
arriveranno al server il quale, poi come abbiamo
già visto, li memorizzerà sul database.
Questa seconda libreria va installata sempre
tramite pip, con sudo pip install socketIO_client
e una volta scaricata potrà essere semplicemente
usata come vedete a video. Una volta importato
SocketIO da tale libreria, l'unica cosa che
dovremo usare sarà il metodo emit che scatena
un evento, insert in questo caso (che abbiamo
visto descritto nella parte server), evento
a cui viene passato l'oggetto JSON con i tre
attributi tempo di rilevazione, tipo di rilevazione
e valore rilevato dal sensore.
Infine, visto che non ha molto senso misurare
temperatura ed umidità ogni pochi secondi
(o almeno non in casa), il ciclo di cattura
ed inserimento verrà effettuato ogni 30 minuti
(cioè 1800 secondi), così da avere un massimo
di 48 rilevazioni al giorno.
Perfetto, l'ultimo tassello che rimane (il
quarto attore) è il client web, cioè colui
che si occupa di mostrare a video all'utente
i dati rilevati sottoforma di grafico (quindi
utili e leggibili all'occhio umano). Anche
il lato client della nostra web-app è servito
da node.js e consiste fondamentalmente in
una somma di librerie più un pochino di logica
per tenerle assieme. Per velocizzare lo sviluppo
ho utilizzato jQuery come collante, poi c'è
chiaramente il client di socket.io che come
succede nel python anche qui consente di parlare
con il server node.js, abbiamo poi bootstrap
per la resa grafica ed infine l'accoppiata
chart.js + moment.js per mostrare i dati sottoforma
di grafico con la trasformazione delle date
ed orari di rilevazione secondo il nostro
fuso orario.
Allora, tutta la webapp si trova all'interno
della cartella public che node.js espone ai
client che richiamano l'IP del raspberry pi
sulla porta 8080, come avevamo visto prima
sul browser del PC o smarthone/tablet. Escludendo
le librerie boostrap, chart, jquery, moment,
e qualche istruzione css custom, tutta la
logica applicativa risiede solamente nei file
index.html e script.js.
Il file HTML contiene lo scheletro della nostra
web app: include tutte le librerie usate,
è composto da una sezione superiore con i
controlli che consentono di spostarsi indietro
ed avanti nel tempo per leggere le misurazioni,
ed ovviamente il grafico che mostra l'andamento
temporale delle stesse.
Il file JS invece è l'effettivo client che
tiene aggiornato in tempo reale il grafico
(opzione che l'utente può o meno attivare)
e gestisce le varie interazioni. E come fa?
Al caricamento della pagina viene lanciato
un evento di start, che avevamo visto essere
una richiesta al server per sapere o meno
se il database sia pronto; dopodiché troviamo
tutti i parametri di configurazione del grafico,
con: l'intervallo temporale di interesse impostato
su mezza giornata (cioè 12 ore), le etichette
da mostrare sul grafico con i relativi colori
per distinguere umidità e temperatura, la
configurazione di chart (cioè un grafico
lineare con le etichette specificate e sulla
X il tempo e sulla Y le misurazioni relative),
e poi tutte le azioni che l'utente può fare
cioè cercare le misurazioni in un intervallo
specifico tramite l'evento find oppure muoversi
avanti ed indietro di quanto è stato configurato
l'intervalllo (cioè 12 ore o mezza giornata).
A seguire abbiamo le funzioni che vengono
automaticamente richiamate in tempo reale
da socket.io quando il server emette il relativo
evento: la started viene richiamata quando
il server risponde all'evento start (e qui
il client non fa molto se non istanziare il
grafico e subito dopo richiedere i dati delle
ultime 12 ore, che poi è esattamente la stessa
cosa che viene fatta anche quando l'utente
clicca sul bottone reset). L'evento inserted,
invece, viene rilanciato ogni qual volta,
come avevamo visto sul python, viene inserito
un nuovo dato sul DB: in questo caso se è
attiva l'opzione real-time il grafico si auto
aggiorna richiedendo al server gli ultimi
dati rilevati (se l'opzione non è attiva,
invece, l'evento viene scartato).
Infine l'evento found viene rilanciato quando
la ricerca sul server ha effettivamente restituito
nuovi dati, quindi il client deve analizzarli
ed inserirli nel grafico sostituendo quelli
presenti ed aggiornandolo.
Queste che vedete sono alcune misurazioni
di esempio che ho effettutato negli ultimi
giorni. Possiamo vedere che la temperatura
in un certo orario era di TOT gradi centigradi
mentre l'umidità aveva una data percentuale,
e così per ogni rilevazione effettuata, anche
andando indietro nel tempo. Il grafico può
anche essere istruito per mostrare solo umidità
o solo temperatura.
Ho scelto questa visualizzazione lineare,
che potrebbe anche essere un po' forzata visto
che le unità di misura sono differenti, ma
era per ottenere un qualcosa di tangibile
rapidamente. Chart.js ovviamente può essere
configurato in modo più puntuale e farci
ottenere tante altre tipologie di grafico.
Inoltre, chiaramente, tutta l'interfaccia
e le operazioni che l'utente può compiere
possono essere ampliate, modificate e quant'altro
poiché a questo punto abbiamo il giro completo
con tutti gli attori.
Se sul python modifichiamo al volo il tempo
di rilevazione, portandolo a pochi secondi,
e avviamo il nostro rilevatore di temperatura
ed umidità, possiamo vedere come il server
aggiunga i nuovi dati misurati sul database,
e come il grafico sul browser venga aggiornato
in tempo reale senza necessità di azione
da parte dell'utente. Personalmente sconsiglio
di accumulare rilevazioni così vicine, visto
che come potete anche vedere dal grafico la
variazione di temperatura ed umidità in casa
generalmente non varia molto, per lo meno
non in questa stagione... Sarà interessante
vedere cosa succederà in inverno con gli
sbalzi tra accensioni e spegnimenti dei termosifoni
durante la giornata.
Bene, spero di avervi mostrato un valido e
possibile approccio per la creazione di una
stazione meteorologica domestica e anche fatto
capire la differenza che c'è nel crearsi
da sé tutta l'infrastruttura piuttosto che
utilizzarne una -come Bolt- che viene fornita
già funzionante out-of-the-box. Chiaramente
io in quanto smanettone mi sono sicuramente
molto più divertito a realizzare il mio progetto
invece che usare delle API o wizard già pronti,
ma non tutti sono come me e non sempre ha
senso reinventare la ruota...
Ah ovviamente, al momento, tutto questo non
è esposto su internet e quindi non è possibile
accedere alla dashboard da remoto... ma con
il classico giro di configurazione del router
affinché ruoti le richieste dall'esterno
verso il pi, ddns e quant'altro (che abbiamo
visto varie volte nei tutorial) è chiaramente
possibile esporre tutto sul web. Allo stesso
modo è anche possibile separare la conservazione
dei dati (quindi mongodb) dalla rilevazione
(cioè i sensori) e visualizzazione (cioè
node.js + webapp), magari predisponendo uno
o più pi in giro per la casa (o dove volete)
che spediscono le proprie rilevazioni verso
un server centralizzato installato su un altro
raspberry pi, e poi questi dati possano essere
interrogati dall'utente che volendo passa
per un altro dispositivo ancora...
Insomma potete complicare
l'architettura a piacere! :-D
E forse tutto questo potrà essere argomento
di futuri focus: fatemi sapere che ne pensate
nei commenti. Io intanto mi fermo qui, lasciate
un like se il video vi è piaciuto, ed iscrivetevi
al canale qualora non lo foste già attivando
le notifiche per essere subito avvisati quando
pubblicherò nuovi tutorial.
Non mi resta altro che salutarvi, a presto!
Ciaoo :)
