18 novembre 2018

tutorial: come accertarsi che porte e finestre siano aperte o chiuse via raspberry pi (e notifiche push)


Benvenuti!
Questo tutorial vi fornirà una guida su come costruire un piccolo centro di controllo casalingo che consente di tenere monitorate porte e finestre al fine di conoscerne lo stato di apertura o chiusura con aggiornamenti in tempo reale. Il tutto sfruttando un Raspberry Pi ed uno o più sensori digitali Hall.

Nota: il presente articolo contiene una infarinatura generale ed alcuni dettagli sono stati tralasciati. Se volete approfondire, non esitate a lasciare un commento o a contattarmi sui canali social.

Prima di addentrarci, vi riporto il video di supporto a questa guida che ho pubblicato sul mio canale YouTube:


Inoltre vi segnalo che nella pagina dedicata troverete tutti i tutorial da me pubblicati.


1. l'attrezzatura minima per iniziare


Per creare il nostro centro di controllo occorrono:
  • uno o più Raspberry Pi (il modello è indifferente, basta che abbia possibilità di essere connesso alla rete e in questo tutorial viene utilizzato il modello Zero) + una o più microSD (una per Pi) + uno o più alimentatori o fonti di corrente da almeno 2.1A (uno per Pi)
  • Raspbian OS Lite
  • un PC per accedere via SSH ai Pi per sviluppare (oppure mouse + tastiera + monitor da collegare ai vari dispositivi per la configurazione iniziale)
  • un router (e quindi una connessione ad Internet) a cui connettere i Pi ed i dispositivi che si vogliono utilizzare per accedere da remoto alla dashboard
Per quanto riguarda il primo punto i Raspberry Pi verranno tendenzialmente acceduti via SSH per la configurazione generale quindi non occorre altro hardware aggiuntivo, in alternativa è chiaramente sempre possibile collegare mouse + tastiera + monitor e lavorare direttamente sui device. Sarà in ogni caso indispensabile avere un alimentatore per ogni Pi impiegato che eroghi in uscita almeno 2.1A di corrente.
Raspbian OS Lite è probabilmente la scelta migliore poiché è un sistema leggero, consuma poche risorse ed ha la possibilità di farci installare dai repository tutto il necessario.
Il PC sarà lo strumento con cui interagiremo da remoto con i Pi, quindi un router sarà necessario per accedere da remoto ed interagire con i sensori.


2. l'idea e gli attori in gioco


L'idea è quella di creare una architettura composta da:
  1. un sistema centrale capace di mostrare in real-time lo stato di porte e finestre che stiamo monitorando
  2. una memoria storica di tutte le aperture/chiusure avvenute
  3. uno o più rilevatori collegati ad ogni porta o finestra di interesse che capiscono quando il serramento viene manipolato
  4. un dispositivo client che può ricevere aggiornamenti sulle eventuali aperture e chiusure
Per tenere il sistema il più semplice possibile, l'idea è anche quella di partire dallo stesso progetto realizzato per la costruzione di una stazione meteo casalinga, ma con qualche piccola aggiunta interessante e necessaria.


2.1. l'hardware


Quali componenti utilizzare?

Nota: quella che è descritta in questa guida è l'ossatura del progetto, quindi sarà poi indispensabile pensare (in separata sede) come proteggere i vari sensori, come installarli fisicamente in loco, come posizionare gli alimentatori, e così via... Argomenti decisamente importanti e da tenere in considerazione ma che vanno un po' oltre gli scopi di questo tutorial e che soprattutto vanno studiati caso per caso.

Ad ogni modo, un Raspberry Pi farà da base per tutto e ad esso saranno collegati uno o più sensori Hall (analizzati in seguito) in base al numero di porte e/o finestre da monitorare. Chiaramente, a meno di non posizionare chilometri di filo in giro per casa, potrebbero essere necessari uno o più Raspberry Pi (o micro controller di varia natura) per gestire tutti i sensori. Sensori che richiedono l'installazione su ogni porta e/o finestra di piccoli magneti (calamite) indispensabili per le rilevazioni.



Come funziona un Hall Sensor? Un sensore di questo tipo sfrutta l'Hall Effect ma, senza addentrarci troppo, quello che esso fa è fondamentalmente rilevare la presenza (o assenza) di un campo magnetico. Esistono tanti tipi di sensori Hall (analogici o digitali). Per gli scopi di questo tutorial useremo sensori Hall lineari digitali capaci di rilevare la presenza (o assenza) di un magnete restituendo in output rispettivamente i valori binari 1 e 0.

L'idea è quella di posizionare una piccola calamita sull'infisso della nostra porta o finestra di interesse ed il sensore sull'anta che si muove. Quando la finestra o porta è chiusa, il sensore rileva il magnete e restituisce valore 1; quando la porta o finestra è aperta, il sensore non rileva più nulla e restituisce valore 0. Semplice ed efficace.

In generale un linear Hall sensor ha 4 PIN: il primo per inviare i dati rilevati in analogico (e non lo useremo), il secondo per il ground, il terzo per la corrente che deve essere a 5V, ed il quarto per l'invio dei dati rilevati in digitale (ed è quello che utilizzeremo). Questo quarto PIN può essere collegato ad un PIN qualsiasi del Pi (ad esempio il BCM 17). Inoltre, su questi sensori sono solitamente presenti due piccoli LED che indicano il primo se il sensore è attivo o no ed il secondo se viene rilevato un magnete o meno.

Nota: calamita ed Hall sensor devono toccarsi (o essere molto vicini) affinché il sensore stesso sia in grado di rilevare il magnete. Attenzione perciò a come si monta il tutto su porte e finestre.


2.2. il software


Che cosa deve fare il software di controllo?

L'idea è quella di analizzare costantemente lo stato dei vari sensori in uso, quindi immagazzinare le letture (se differiscono da quelle precedenti: tutti gli stati identici consecutivi vanno scartati), ed infine avvisare via notifiche se c'è stato un cambiamento di stato.

Ci sono 4 attori da impiegare:
  1. il software in python che legge lo stato del sensore
  2. un database per memorizzare tutte le aperture e chiusure del caso
  3. un server centralizzato in grado di gestire gli inserimenti su database ed il recupero di queste informazioni per inviarle a chi le richiede
  4. una componente finale che è il client che mostra lo storico per ogni serramento monitorato ed i cambiamenti in tempo reale

Per tirar su l'ambiente occorre installare: nodejs per il server; mongodb per il database; pip per recuperare le librerie usate dal codice python che controlla gli Hall sensor; git per scaricare il mio progetto caricato GitHub che contiene una possibile implementazione per server, client e codice di controllo per i sensori  (di più tra poco); ed npm per l'avvio del server e per il recupero di tutte le librerie mancanti ed indispensabili per il funzionamento.

Per installare il suddetto software basta il semplice comando sudo apt-get install nodejs npm mongodb python-pip git ed il sistema operativo si occuperà di configurare il tutto. Una volta installati i tool, con un git clone https://github.com/geekonerd/doorguard.git si può clonare sul Pi il codice del progetto.
Il progetto contiene il file check.py che è quello che controlla l'Hall sensor, il file main.js che è il server nodejs per la gestione di tutto il sistema, e dentro la cartella public i file index.html e script.js che danno vita al client web di controllo dello stato di porte e finestre monitorate.
Infine, prima di avviare il tutto, occorre installare la libreria socketIO_Client sfruttata lato python per dialogare con nodejs per inserire su mongodb lo stato delle rilevazioni. L'installazione tramite pip è banale: sudo pip install socketIO_client ed è anche l'unica libreria aggiuntiva da prelevare.


Tralasciando il database, analizziamo ora i 3 attori che sono appunto compresi nel progetto.

  1. i sensori Hall di monitoraggio

    # esempio di controllo del sensore Hall
    import time
    import RPi.GPIO as GPIO
    from socketIO_client import SocketIO

    socketIO = SocketIO('https://localhost:8080', verify=False)

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    door_name = "porta ingresso" // da cambiare per sensori differenti

    try:
        old_value = 0
        while True:
            v = GPIO.input(17)
        if (v and old_value == 0) or (not v and old_value == 1) :
            t = int(time.time())
            print '{0} - value: {1}'.format(t, v)
            socketIO.emit('insert', {'time': t, 'door': door_name, 'value': v})
            old_value = v
        time.sleep(1)

    except KeyboardInterrupt:
        GPIO.cleanup()



    Nel file check.py, a parte le librerie di sistema e l'inclusione della libreria socketIO_Client, la prima istruzione è quella di specificare dove si trovi il server nodejs.

    Nota: se l'Hall sensor è collegato direttamente al Pi che contiene anche il server allora l'indirizzo https://localhost:8080 è corretto. Qualora fossero presenti più sensori installati su Raspberry Pi differenti, l'indirizzo dovrebbe essere modificato con quello del Pi principale che contiene il server nodejs (sempre in HTTPS e sempre con la porta 8080).

    Viene quindi indicato il PIN della testata GPIO utilizzato (ad esempio il BCM 17), quindi avviene la vera e propria rilevazione in un ciclo infinito dello stato del sensore: se la lettura attuale differirà dalla precedente allora verrà inviato al server nodejs l'informazione formata da ora corrente + id della porta monitorata + valore rilevato (0 o 1).


  2. il server nodejs centralizzato

    Per quanto riguarda il server è necessario che esso comunichi tramite il protocollo HTTPS altrimenti non potremo utilizzare le notifiche push (di più tra poco). Per far sì che nodejs sia in grado di avviare su un server HTTPS, occorre generare una coppia di chiavi pubblica e privata.

    Nota: per gli scopi di questo tutorial si possono utilizzare senza problemi chiavi auto generate che però comporteranno alcune problematiche che analizzeremo in seguito. In linea di massima se si vuole avere un sistema funzionante in ogni scenario possibile occorrerebbe generare chiavi pubbliche e private certificate da una certification authority (CA), operazione a pagamento oppure con vincoli di verifica (vedi https://letsencrypt.org/). Oppure caricare il proprio progetto su di un cloud nodejs con connessioni HTTPS (probabilmente anche in questo caso a pagamento). Comunque, ancora una volta, per gli scopi di questo progetto vanno benissimo le chiavi auto generate.

    Per generare le chiavi pubblica e privata è sufficiente lanciare i seguenti comandi all'interno della cartella in cui avete scaricato il mio progetto GitHub:

    openssl req -newkey rsa:2048 -new -nodes -keyout key.pem -out csr.pem
    openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out server.crt


    Questi due comandi creano 3 file: csr.pem, key.pem e server.crt che verranno utilizzati automaticamente all'interno del file main.js e cioè dal server.
    Il codice JavaScript che tira su il server centralizzato di controllo contiene le istruzioni per gestire i processi memorizzazione degli stati dei sensori e la lettura di tali stati, il tutto gestito ad eventi tramite SocketIO
    . I dati vengono memorizzati su un database mongodb (il quale se non esiste viene creato automaticamente).

    Gli eventi principali sono quello di insert che viene richiamato dal codice python e non fa altro che salvare su DB le rilevazioni del sensore, e l'evento find che invece recupera lo storico delle ultime rilevazioni (ad esempio le ultime 10 in base a quanto richiesto dal client) più l'ultimo stato rilevato per ogni finestra o porta monitorata.

  3. il client web che mostrerà all'utente lo stato dei serramenti e lo storico generico

    Il codice si trova nella cartella public, ed il file index.html contiene lo scheletro dell'interfaccia, mentre il file script.js ne contiene la logica. Quello che viene fatto è specificare l'intervallo di interesse per lo storico delle rilevazioni (ad esempio le ultime 10 rilevazioni) nonché la definizione dei comportamenti per i vari pulsanti della UI. A seguire ci sono gli eventi scatenati dal server a cui il client deve reagire in tempo reale, ed abbiamo l'inizializzazione (started), la risposta real-time a nuove rilevazioni (inserted), e la visualizzazione dei risultati delle ricerche (found).
    Nello stesso file c'è anche la logica per la gestione delle notifiche push: se il browser web che si utilizza per visualizzare il client le supporta e l'utente accetta di ricevere notifiche dalla app, ad ogni aggiornamento dello stato di porte o finestre verrà mostrata una notifica relativa.

    Nota: ad occuparsi delle notifiche è un ServiceWorker. Come anticipato, per gli scopi di questo tutorial abbiamo auto generato le chiavi pubbliche e private per il nostro server HTTPS. Che cosa comporta ciò? Prima di tutto non essendo chiavi certificate da enti preposti, i browser web non le considereranno sicure e quindi accedendo -almeno la prima volta- al client web all'indirizzo IP del Raspberry Pi porta 8080 in https, saremo avvisati della non validità dei certificati (e occorrerà accettare di proseguire). Ma il problema più grande riguarda il ServiceWorker in sé che gestisce le notifiche: Chrome non ne permette il funzionamento se i certificati non sono validi o auto generati, mentre Firefox sì (almeno fino ad oggi) quindi, sempre per gli scopi di questo tutorial e per testare le notifiche in tempo reale, sarà necessario utilizzare questo browser (anche su mobile).
    La UI del client web in ogni caso si auto aggiorna in tempo reale sullo stato di porte e finestre, anche se il browser fa i capricci con i certificati, quindi con una rapida occhiata si riesce comunque sempre a capire quale è lo stato generale. Ma è ovvio che avere notifiche real time sulle manipolazioni di porte e finestre che si monitorano è sicuramente un plus molto interessante e comodo da avere.

    Nota: così per come è sviluppato il codice, le notifiche vengono generate solo se il browser è aperto sul dispositivo utilizzato per controllare i sensori (non necessariamente con il client web in primo piano ma deve essere stato quantomeno avviato), altrimenti non ci sarà alcuna notifica. Per superare tali limiti il passo successivo è quello di sfruttare sistemi come il Google Cloud Messaging per fare in modo che le notifiche arrivino anche a browser chiuso. Argomenti che vanno però oltre gli scopi di questa guida.


3. conclusioni ed ultime note


Sul client web è possibile vedere lo stato di porte e finestre monitorate e spostando il sensore dal magnete o avvicinandolo ad esso (quindi aprendo o chiudendo porte o finestre monitorate), in tempo reale sulla UI ed anche nelle notifiche del sistema operativo verranno mostrati i cambi di stato e lo storico sarà aggiornato con le nuove rilevazioni.
L'interfaccia permette anche di navigare tra tutte le rilevazioni effettuate nel tempo. Attivando la funzione real-time con l'apposito check, le notifiche e gli aggiornamenti avvengono in tempo reale, disattivando tale opzione invece non ci sarà alcun aggiornamento istantaneo ma si dovrà forzarlo manualmente o con il tasto reset oppure con un refresh della pagina.

I passi descritti nella guida consentono di tirar su l'ambiente ed utilizzarlo in una rete privata, esporlo su Internet richiede qualche step aggiuntivo:
  1. impostare un IP statico al Raspberry Pi che fa da server centralizzato (via configurazione sul router oppure sul sistema operativo, come visto in tanti altri precedenti tutorial)
  2. configurare il proprio router di casa (port mapping o port forward) affinché redirezioni le chiamate in entrata sulla porta 8080 verso l'indirizzo IP statico assegnato al Pi al punto 1
  3. utilizzare l'indirizzo IP pubblico assegnato al proprio router per accedere in HTTPS sulla porta 8080 alla dashboard di controllo
  4. opzionalmente, si può configurare un servizio DDNS per mappare l'indirizzo IP pubblico del router con un nome più semplice da ricordare cosicché si possa accedere alla dashboard di controllo tramite quello e non tramite IP (ed occorre tenere allineati IP pubblico del router con il DNS)

Nota: inutile dire che è consigliato aggiungere una autenticazione alla dashboard per evitare di mostrare al pubblico lo stato delle nostre porte e finestre di casa... :-)


Bene: come indicato ad inizio guida, alcuni aspetti sono stati lasciati in secondo piano, ma se siete interessati ad approfondirli non esitate a contattarmi nei commenti di questo tutorial o del video ad esso correlato, oppure sui canali social!

Spero che la guida vi sia stata utile. Al prossimo tutorial!

Nessun commento:

Posta un commento