Raspberry Pi, la domotica con Node-Red: comandi bash e log errori. #2


Informatica / martedì, Gennaio 5th, 2021

Bentornato nel secondo esperimento della rubrica “Raspberry Pi, la domotica con Node-Red” . Hai fatto i compiti per casa del precedente articolo?

Per partire tutti con lo stesso progetto, che ne dici di aprire il menu import-> selezionare new flow ed incollare questo.

[{"id":"b313a11e.083d4","type":"tab","label":"Gestione Rpi","disabled":false,"info":""},{"id":"3b9b99af.191326","type":"tab","label":"Giardino","disabled":false,"info":""},{"id":"410cbd5e.a67d54","type":"tab","label":"Camere","disabled":false,"info":""},{"id":"a56bea5e.7d34e8","type":"tab","label":"Cucina","disabled":false,"info":""},{"id":"3d5177aa.ced968","type":"tab","label":"Soggiorno","disabled":false,"info":""},{"id":"6958a417.a71d7c","type":"tab","label":"Garage","disabled":false,"info":""},{"id":"ec5c73e5.37c23","type":"tab","label":"Ingresso","disabled":false,"info":""},{"id":"9f6c0c56.d3882","type":"ui_base","theme":{"name":"theme-dark","lightTheme":{"default":"#0094CE","baseColor":"#0094CE","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#04c0e1","baseFont":"Gill Sans,Geneva,sans-serif","edited":true,"reset":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"},"themeState":{"base-color":{"default":"#097479","value":"#04c0e1","edited":true},"page-titlebar-backgroundColor":{"value":"#04c0e1","edited":false},"page-backgroundColor":{"value":"#111111","edited":false},"page-sidebar-backgroundColor":{"value":"#ffffff","edited":false},"group-textColor":{"value":"#36defb","edited":false},"group-borderColor":{"value":"#555555","edited":false},"group-backgroundColor":{"value":"#333333","edited":false},"widget-textColor":{"value":"#eeeeee","edited":false},"widget-backgroundColor":{"value":"#04c0e1","edited":false},"widget-borderColor":{"value":"#333333","edited":false},"base-font":{"value":"Gill Sans,Geneva,sans-serif"}},"angularTheme":{"primary":"indigo","accents":"blue","warn":"red","background":"grey"}},"site":{"name":"Casa in città","hideToolbar":"false","allowSwipe":"true","lockMenu":"true","allowTempTheme":"true","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"1d57abec.c27e64","type":"ui_tab","z":"","name":"Gestione Rpi","icon":"fa-gear","order":2,"disabled":false,"hidden":false},{"id":"f67d8e98.208ce","type":"ui_group","z":"","name":"Comandi","tab":"1d57abec.c27e64","order":2,"disp":true,"width":"6","collapse":false},{"id":"dd6e7407.c24778","type":"ui_tab","z":"","name":"Giardino","icon":"fa-tree","order":3,"disabled":false,"hidden":false},{"id":"83400738.e95138","type":"ui_group","z":"","name":"Grafici","tab":"dd6e7407.c24778","order":1,"disp":true,"width":"6","collapse":false},{"id":"70c6ceff.19408","type":"ui_group","z":"","name":"Comandi","tab":"dd6e7407.c24778","order":2,"disp":true,"width":"6","collapse":false},{"id":"103d5cef.f351e3","type":"ui_tab","z":"","name":"Camere","icon":"fa-bed","order":4,"disabled":false,"hidden":false},{"id":"9bdd5115.fdbfb","type":"ui_group","z":"","name":"Grafici","tab":"103d5cef.f351e3","order":1,"disp":true,"width":"6","collapse":false},{"id":"3be54e01.71e4f2","type":"ui_group","z":"","name":"Comandi","tab":"103d5cef.f351e3","order":2,"disp":true,"width":"6","collapse":false},{"id":"274e796c.c9bd96","type":"ui_group","z":"","name":"Grafici","tab":"1d57abec.c27e64","order":2,"disp":true,"width":"6","collapse":false},{"id":"c74430ac.40f9a","type":"ui_tab","z":"","name":"Cucina","icon":"fa-coffe","order":5,"disabled":false,"hidden":false},{"id":"6f473ac0.004394","type":"ui_group","z":"","name":"Grafici","tab":"c74430ac.40f9a","order":1,"disp":true,"width":"6","collapse":false},{"id":"f0b70fb4.d0fc9","type":"ui_group","z":"","name":"Comandi","tab":"c74430ac.40f9a","order":2,"disp":true,"width":"6","collapse":false},{"id":"7dff101e.6c44a","type":"ui_tab","z":"","name":"Soggiorno","icon":"fa-tv","order":6,"disabled":false,"hidden":false},{"id":"5fd73eb6.46957","type":"ui_group","z":"","name":"Grafici","tab":"7dff101e.6c44a","order":1,"disp":true,"width":"6","collapse":false},{"id":"f925a233.8d765","type":"ui_group","z":"","name":"Comandi","tab":"7dff101e.6c44a","order":2,"disp":true,"width":"6","collapse":false},{"id":"3c43d956.bf4706","type":"ui_tab","z":"","name":"Garage","icon":"fa-car","order":7,"disabled":false,"hidden":false},{"id":"5f9e413d.39565","type":"ui_group","z":"","name":"Grafici","tab":"3c43d956.bf4706","order":1,"disp":true,"width":"6","collapse":false},{"id":"f91f386f.884fb8","type":"ui_group","z":"","name":"Comandi","tab":"3c43d956.bf4706","order":2,"disp":true,"width":"6","collapse":false},{"id":"b458edff.701f3","type":"ui_tab","z":"","name":"Ingresso","icon":"fa-road","order":8,"disabled":false,"hidden":false},{"id":"c7e7a411.5ea8e8","type":"ui_group","z":"","name":"Grafici","tab":"b458edff.701f3","order":1,"disp":true,"width":"6","collapse":false},{"id":"6ca369fc.8383f8","type":"ui_group","z":"","name":"Comandi","tab":"b458edff.701f3","order":2,"disp":true,"width":"6","collapse":false},{"id":"dc5de6b6.b88888","type":"ui_link","z":"","name":"MoreWare","link":"https://www.moreware.org/wp/","icon":"open_in_browser","target":"iframe","order":1},{"id":"f389c16c.07142","type":"ui_button","z":"b313a11e.083d4","name":"Spegnimento","group":"f67d8e98.208ce","order":1,"width":0,"height":0,"passthru":false,"label":"spegni il Raspberry Pi","tooltip":"spegni il Raspberry Pi","color":"yellow","bgcolor":"red","icon":"fa-power-off","payload":"","payloadType":"str","topic":"","x":110,"y":60,"wires":[["3f531577.edd70a"]]},{"id":"3f531577.edd70a","type":"exec","z":"b313a11e.083d4","command":"sudo shutdown now","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"sudo shutdown now","x":300,"y":60,"wires":[[],[],[]]}]

Lo scopo della mia nuova rubrica sarà sperimentare insieme la gestione di una casa domotica.

Penseremo un po’ alla volta, zona per zona, cosa implementare e come, nel modo più semplice possibile ed evitando il più possibile di scrivere codice.

Il bello di Node-Red è eseguire una gran quantità di operazioni, senza scrivere codice, ma solo creando flussi.

Backup Node Red

Il file coi nostri flussi, usando l’installazione di default, li troveremo nella home dell’utente, in una cartella nascosta. Nel caso di Raspberry Pi /home/pi/.node-red/flows_<nome host>.json .

La configurazione sarà contenuta nel file settings.js .

Quindi ogni tanto ricordiamoci di fare un backup della cartella. Un semplice esempio di backup si può fare con rsync

rsync -av /home/pi/.node-red/ /home/pi/backup/

Eseguire comandi shell

Nella scorsa puntata, oltre ad un rapida introduzione a Node-Red, abbiamo visto come eseguire comandi da shell.

L’esecuzione di comandi da shell permette di ottenere e gestire informazioni di ogni genere con una sola riga di codice.

Il node Exec, ha la fantastica caratteristica di avere tre uscite, lo standard output, lo standard error, ed il return code.

In parole molto semplici, lo standard output, stdout, è il mesaggio che restituisce un programma eseguito da riga di comando, ad esempio per leggere la temperatura del nostro Raspberry Pi, useremo

vcgencmd measure_temp

Lo stardard output sarà

temp=43.5'C

Nel caso di errori, nel nodo exec, potremmo proseguire il flusso in una diramazione legata solo ai casi di errore.

La terza uscita del nodo, è il return code, che come standard è 0 se l’operazione è andata a buon fine, ed un numero a scelta dai programmatori in base al software richiamato.

Ad esempio questi sono gli exit code di rsync

 0      Success
       1      Syntax or usage error
       2      Protocol incompatibility
       3      Errors selecting input/output files, dirs
       4      Requested  action not supported: an attempt was made to manipulate 64-bit files on a platform 
              that cannot support them; or an option was specified that is supported by the client and not by the server.
       5      Error starting client-server protocol
       6      Daemon unable to append to log-file
       10     Error in socket I/O
       11     Error in file I/O
       12     Error in rsync protocol data stream
       13     Errors with program diagnostics
       14     Error in IPC code
       20     Received SIGUSR1 or SIGINT
       21     Some error returned by waitpid()
       22     Error allocating core memory buffers
       23     Partial transfer due to error
       24     Partial transfer due to vanished source files
       25     The --max-delete limit stopped deletions
       30     Timeout in data send/receive
       35     Timeout waiting for daemon connection

Posizioniamo i nodi

La mia idea è creare un Tab nella Dashboard di Node-Red in grado di gestire una serie di comandi shell assegnati a determinati pulsanti.

node red exec node shell

Partiamo con il primo Flow, chiamato “Gestione RPI”, aggiungiamo alcuni pulsanti, collegati al nodo exec.

La prima uscita stout porterà ad un nodo file, per creare un file di log dei comandi ricevuti.

node red exec stout

L’uscita standard error, creerà un file di log dedicato ai soli errori. Volendo anche un avviso a video dell’errore, colleghiamo il nodo notification dopo il log errori, come da immagine precedente.

node red standard error

Configurare i pulsanti

Passiamo alla configurazione dei singoli nodi.

Il pulsante “Test Log errori” è abbastanza esplicativo e dovrà eseguire un comando errato. Al contrario dell’articolo precedente, i comando sarà contenuto nel pulsante ed inviato come msg.payload nel flusso, arrivando al nodo exec per venire eseguito.

node red node button

  • Group: è il gruppo in cui la Dashboard posiziona gli elementi. Lo troverai nel menù dashboard in alto a destra.
  • Size: sarà la dimensione del pulsante nella griglia responsive.
  • Icon: l’icona a scelta tra le Material Design icon (e.g. ‘check’, ‘close’) o Font Awesome icon (e.g. ‘fa-fire’), o Weather icon.
  • Label: il testo all’interno del pulsante.
  • Tooltip: il testo che comparirà lasciando la freccia del mouse sopra al pulsante.
  • Colour: il colore del testo, accetta nomi semplici come red, grey, green…
  • Background: il colore dello sfondo.
  • Payload: è il messaggio che invierà nel flusso, nel nostro caso il comando che il nodo exec dovrà eseguire.
  • Topic: è una parte del sistema di messaggi, e si potrà sfruttare in altre occasioni.
  • If msg arrives on input, emulate a button click: si può simulare la pressione del pulsante, per evitare di creare un doppione della stessa sequenza di nodi.
  • Name: il nome che comparirà nel pannello di programmazione.

Alla pressione del pulsante, il flusso invierà il msg.payload, in questo caso il comando, al nodo successivo, exec.

node red button

Eseguiamo i comandi

Analizziamo il nodo exec, il quale eseguirà nella shell del nostro Raspberry Pi, i comandi che arriveranno nel msg.payload.

node red node exec

  • Command: il comando a cui verrà appeso il msg.payload. Non abbiamo necessità di aggiungere qualcosa prima del messaggio in arrivo.
  • Output: sceglieremo se aspettare o no, il completamento del comando.
  • TimeOut: il tempo di attesa.
  • Name: è sempre il nome nel pannello di programmazione.

Log in Node Red

Il messaggio prosegue il suo viaggio nel flusso, è stato attivato, eseguito ed ora è il momento di gestirne l’esito.

node red file

Raggiunto il nodo file, lo standard output, che in sostanza è il testo che uscirà nella shell a comando eseguito, verrà “appeso” al file da noi indicato in Filename.

Selezionando la prima casellina, verrà scritto un comando per riga, mentre la seconda provvederà a creare la cartella in caso mancasse.

Riassumendo abbiamo un pulsante, che esegue un comando bash e scrive l’output in un file, ma noi vogliamo un file di log errori separato.

Semplicemente eseguiamo la stessa procedura, collegandoci all’uscita sterr del nodo exec, niente di più semplice. Ovviamente nulla vieta di proseguire il flusso con una gestione completa degli errori, ma ciò non fa parte dell’idea di questa rubrica, magari la prossima…

Pensiamo di gestire tutta la nostra casa domotica da smartphone, semplicemente aprendo la pagina web http://<ip del raspberry>:1880/ui . In caso di erorre lo voglio sapere subito, ma come? La via più semplice è il nodo notification che farà apparire l’avviso.

node red error

Nulla vieta di usare il nodo Play audio, perchè non lo provi?

Layout: è la posizione del messaggio.

Timeout: per quanto tempo resterà visibile. Attenzione che se ne verrà attivato un altro, questo verrà nascosto.

Border: il colore del bordo.

Al posto di notification, si potrebbe inviare un email, o attivare un serie di azioni con IFTTT.
Il limite è sempre la tua fantasia.

Abbiamo visto come con pochi nodi, senza scrivere codice, otteniamo una dashboard web responsive, in grado di eseguire ogni nostro comando e gestendo eventuali errori e return code.

Quante righe di codice bisognerebbe scrivere per ottenere lo stesso risultato usando altri sistemi?

Per importare i nodi di questo articolo, dal menu import, incolla questo codice.

[{"id":"f389c16c.07142","type":"ui_button","z":"b313a11e.083d4","name":"Spegnimento","group":"f67d8e98.208ce","order":2,"width":0,"height":0,"passthru":false,"label":"spegni il Raspberry Pi","tooltip":"spegni il Raspberry Pi","color":"yellow","bgcolor":"red","icon":"fa-power-off","payload":"sudo shutdown now","payloadType":"str","topic":"","x":150,"y":80,"wires":[["3f531577.edd70a"]]},{"id":"3f531577.edd70a","type":"exec","z":"b313a11e.083d4","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Shell","x":350,"y":120,"wires":[["1fb675ee.829aba"],["9ebc05d7.6344b8"],[]]},{"id":"e98bc1fd.ae496","type":"ui_toast","z":"b313a11e.083d4","position":"top right","displayTime":"10","highlight":"red","sendall":true,"outputs":0,"ok":"OK","cancel":"","raw":false,"topic":"","name":"Errori","x":670,"y":120,"wires":[]},{"id":"9ebc05d7.6344b8","type":"file","z":"b313a11e.083d4","name":"Log Errori","filename":"/home/pi/domotica/gestione_rpi/domoticaErrori.log","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":520,"y":120,"wires":[["e98bc1fd.ae496"]]},{"id":"121483f3.88414c","type":"ui_button","z":"b313a11e.083d4","name":"Test Log Errori","group":"f67d8e98.208ce","order":1,"width":0,"height":0,"passthru":false,"label":"Test Log Errori","tooltip":"","color":"","bgcolor":"grey","icon":"","payload":"comandoSbagliato","payloadType":"str","topic":"","x":160,"y":120,"wires":[["3f531577.edd70a"]]},{"id":"1fb675ee.829aba","type":"file","z":"b313a11e.083d4","name":"Output Comandi","filename":"/home/pi/domotica/gestione_rpi/OutputComandi.log","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":540,"y":80,"wires":[[]]},{"id":"91ce293.b9640d8","type":"comment","z":"b313a11e.083d4","name":"Comandi","info":"","x":460,"y":40,"wires":[]},{"id":"f67d8e98.208ce","type":"ui_group","z":"","name":"Comandi","tab":"1d57abec.c27e64","order":2,"disp":true,"width":4,"collapse":false},{"id":"1d57abec.c27e64","type":"ui_tab","z":"","name":"Gestione Rpi","icon":"fa-gear","order":1,"disabled":false,"hidden":false}]

Ci vediamo alla prossima, per iniziare con i grafici di monitoraggio della temperatura del Raspberry Pi 4, e lo stato di altri dispositivi in rete tramite un ping.

node red grafici

Compiti per casa

  1. Fai leggere a voce i messaggi di errore.
  2. Crea un pulsante per salvare il tuo lavoro con node red.
  3. Analizza con un solo nodo debug le tre uscite del nodo exec.