Guide

PiGarden — Parte 4: Software (piGarden, piGardenWeb e mqttconnector)

Questa è la quarta parte della serie PiGarden. Nella parte 3 abbiamo montato l’hardware; adesso gli diamo un cervello. Installiamo lo script che comanda i relè, il pannello web per usarlo dal browser e il «traduttore» che lo fa parlare con Home Assistant. Non serve essere programmatori: si copiano dei comandi e ti spiego cosa fanno. L’indice della serie è in fondo.

Tre programmi, tre compiti

Il cuore di tutto è piGarden, un progetto open source di lejubila.net: uno script che apre e chiude le elettrovalvole pilotando i GPIO del Raspberry, controlla il sensore pioggia e tiene le schedulazioni. Da solo basterebbe per irrigare. Intorno a lui ne uso altri due, e per ricordarli mi aiuta un paragone con un cantiere:

  • piGarden è il capo cantiere: è l’unico che sa davvero come si apre una valvola.
  • piGardenWeb è il telecomando con lo schermo: un pannello web (un’applicazione Laravel) per comandare le zone dal browser.
  • mqttconnector è l’interprete: traduce i messaggi MQTT che arrivano da Home Assistant in ordini che il capo cantiere capisce.

Il mio Raspberry è un Pi 3 Model B+ con Raspberry Pi OS 10 (Buster), PHP 7.3 e nginx. La versione dello script è la 0.6, quella di piGardenWeb la 0.6.2.

Schema dei programmi sul Raspberry: cron e la porta TCP interna comandano piGarden; piGardenWeb e mqttconnector si collegano alla porta; mqttconnector parla con il broker MQTT e Home Assistant; piGarden comanda relè e valvole
Chi parla con chi. Tutto ciò che sta nel riquadro tratteggiato gira sul Raspberry.

Guarda il disegno. Al centro c’è piGarden, che ascolta su una porta TCP interna (la 8084): è come un citofono, ma installato dentro casa, che solo il Raspberry stesso può raggiungere. Chi vuole dare un ordine ci «bussa»: lo fa il pannello web, lo fa mqttconnector. Il cron, la sveglia di Linux, si occupa invece dei compiti ricorrenti.

Le parole difficili, tradotte

ParolaCosa vuol dire
Script Bashun file di testo con dei comandi che il computer esegue uno dopo l’altro, come una ricetta
cronla sveglia di Linux: esegue un comando a orari o intervalli fissi
Porta TCPun «citofono» numerato su un computer: un programma ci ascolta, un altro ci bussa per parlargli
MQTTun sistema di messaggi nato per la domotica: chi vuole dire qualcosa appende un biglietto su una bacheca, chi è interessato lo legge
Brokerla bacheca di MQTT: riceve i biglietti e li consegna a chi si è iscritto
Topicl’etichetta di un biglietto, per esempio pigarden/command: serve a decidere chi legge cosa
systemdil gestore dei servizi di Linux: avvia un programma all’accensione e lo rilancia se si ferma

Ti preoccupi troppo di ciò che era e di ciò che sarà. C’è un detto: ieri è storia, domani è un mistero, ma oggi è un dono… per questo si chiama presente.

Maestro Oogway

Preparare le dipendenze

piGarden usa alcuni strumenti di base, jq per leggere i dati in formato JSON e WiringPi, la libreria che permette di comandare i GPIO con il comando gpio:

bash
sudo apt-get update
sudo apt-get install -y git curl gzip grep sed ucspi-tcp jq

WiringPi si compila dai sorgenti:

bash
git clone https://github.com/WiringPi/WiringPi.git
cd WiringPi
./build
gpio -v

L’ultimo comando deve stampare la versione di WiringPi: se lo fa, il Raspberry sa parlare con i suoi pin. Il programma finisce in /usr/local/bin/gpio, percorso che ritroveremo nella configurazione.

Installare piGarden

bash
cd
git clone https://github.com/lejubila/piGarden.git
sudo cp ~/piGarden/conf/piGarden.conf.example /etc/piGarden.conf
sudo nano /etc/piGarden.conf

Tutta la configurazione sta in /etc/piGarden.conf. È un file lungo, ma le voci che contano sono poche: le vediamo una alla volta.

Tipo di valvola e logica del relè

codice
GPIO="/usr/local/bin/gpio"
EV_MONOSTABLE=1
RELE_GPIO_CLOSE=0
RELE_GPIO_OPEN=1

EV_MONOSTABLE=1 dice a piGarden che le valvole sono monostabili: restano aperte finché il relè le alimenta e si chiudono da sole quando smette. È il caso delle Hunter PGV che ho scelto. RELE_GPIO_OPEN e RELE_GPIO_CLOSE indicano quale livello del GPIO fa scattare il relè: dipende dalla scheda che usi, e nella parte 3 c’è il mio caso.

Nota

Con valvole monostabili l’alimentazione deve essere in 24 V corrente alternata. Un alimentatore in corrente continua mi ha bruciato i solenoidi: ne parlo nella parte 3.

Le zone e i pin

Ogni zona è un’elettrovalvola con un nome (alias) e un pin GPIO. Sono quelli della tabella della parte 3:

codice
EV_TOTAL=5
EV1_ALIAS="1"
EV1_GPIO=17
EV2_ALIAS="2"
EV2_GPIO=27
EV3_ALIAS="3"
EV3_GPIO=12
EV4_ALIAS="4"
EV4_GPIO=18
EV5_ALIAS="5"
EV5_GPIO=23

Ho usato alias numerici, così i comandi restano brevi (open 3) e coincidono con le zone che vedrai in Home Assistant.

Sensore pioggia e porta interna

codice
RAIN_GPIO=25
RAIN_GPIO_STATE=1
NOT_IRRIGATE_IF_RAIN_SENSOR=86400
TCPSERVER_IP="127.0.0.1"
TCPSERVER_PORT="8084"

NOT_IRRIGATE_IF_RAIN_SENSOR=86400 impedisce di avviare le zone per 24 ore (86.400 secondi) dopo una pioggia rilevata. Il server TCP resta in ascolto solo su localhost: è la «porta del citofono» a cui si collegano piGardenWeb e mqttconnector, e non ha motivo di essere raggiungibile dalla rete.

Attenzione

Due trappole sul sensore pioggia. Se non hai il sensore, lascia RAIN_GPIO vuoto: un pin scollegato viene letto come pioggia permanente e tutte le zone si rifiutano di partire. E se sostituisci il sensore, controlla RAIN_GPIO_STATE: due sensori diversi possono avere polarità opposte, e con quella sbagliata ogni zona risponde «ha appena piovuto».

Le voci MQTT

Ultimo blocco: piGarden può pubblicare da solo lo stato dell’impianto su una bacheca MQTT. È così che Home Assistant scopre se una zona è aperta o chiusa.

codice
MQTT_ENABLE=1
MQTT_HOST="<IP-DEL-BROKER>"
MQTT_PORT=1883
MQTT_USER="<UTENTE-MQTT>"
MQTT_PWD="<PASSWORD-MQTT>"
MQTT_TOPIC="pigarden/result"
MQTT_CLIENT_ID=piGarden

Con queste voci piGarden scrive lo stato delle zone sul topic pigarden/result a ogni evento: un’apertura, una chiusura, un controllo della pioggia.

Attenzione

Se MQTT_HOST punta a un indirizzo sbagliato, piGarden non protesta: i messaggi finiscono nel vuoto. Nel mio caso puntava al Raspberry stesso, dove non gira nessun broker. Il sintomo era subdolo: Home Assistant vedeva lo stato solo dopo i comandi partiti da lui, e le chiusure decise dal Raspberry restavano invisibili. Se una zona resta «accesa» in dashboard dopo essersi chiusa, controlla questa riga per prima.

Avvio automatico con il cron

piGarden va inizializzato a ogni accensione e ha bisogno di qualche controllo periodico. Nel crontab dell’utente pi (si apre con crontab -e):

codice
@reboot /home/pi/piGarden/piGarden.sh init
@reboot /home/pi/piGarden/piGarden.sh start_socket_server force
* * * * * /home/pi/piGarden/piGarden.sh check_rain_sensor 2> /tmp/check_rain_sensor.err
*/3 * * * * /home/pi/piGarden/piGarden.sh check_rain_online 2> /tmp/check_rain_online.err
*/5 * * * * /home/pi/piGarden/piGarden.sh close_all_for_rain 2> /tmp/close_all_for_rain.err 1> /dev/null

Le prime due righe (@reboot) si eseguono a ogni riavvio: preparano i GPIO e accendono il «citofono» interno. Le altre tre sono i controlli periodici: leggono il sensore pioggia ogni minuto, interrogano il servizio meteo online ogni tre minuti e chiudono tutte le zone se sta piovendo.

Provare le zone da riga di comando

Prima di aggiungere altro, verifica che lo script comandi davvero i relè. Con l’acqua chiusa a monte, la prima volta:

bash
cd ~/piGarden
./piGarden.sh init
./piGarden.sh open 1
./piGarden.sh ev_status_all
./piGarden.sh close 1

Al comando open 1 devi sentire il «clic» del relè della zona 1; ev_status_all mostra lo stato di tutte le zone e close 1 le richiude. Lo stesso stato si legge in formato JSON con json_status.

Irrigare a tempo: open_in

Per irrigare un tempo preciso serve un comando diverso da open. Si chiama open_in:

codice
./piGarden.sh open_in 0 10 1

Si legge così: «tra 0 minuti apri la zona 1 e chiudila dopo 10». Il primo numero è l’attesa prima dell’apertura (0 vuol dire subito), il secondo è la durata, il terzo è la zona. In coda si può aggiungere force per ignorare il controllo pioggia.

Attenzione

Il comando open accetta solo il numero della zona e, volendo, la parola force: se ci scrivi dietro una durata, viene ignorata. La valvola si apre e resta aperta finché non arriva un close. È una trappola in cui sono caduto io: per irrigare a tempo usa sempre open_in.

Una cosa da sapere: la chiusura la fa una riga di cron che gira ogni minuto, quindi la zona resta aperta tra M e M+1 minuti. In una prova con un timer di 1 minuto la valvola è rimasta aperta 1 minuto e 23 secondi. Per irrigare va benissimo; conta solo se cronometri.

Il pannello web: piGardenWeb

piGardenWeb è il telecomando con lo schermo. È un’applicazione Laravel che si appoggia alla porta interna di piGarden: sul mio Raspberry vive in /home/pi/piGardenWeb, servita da nginx con PHP 7.3, e la dashboard si apre da http://<IP-DEL-RASPBERRY>/admin/dashboard. Da lì si aprono e chiudono le zone e si vedono stato e log.

Dashboard di piGardenWeb con le cinque zone e i pulsanti di avvio
La dashboard di piGardenWeb: una scheda per zona, con avvio manuale e timer.

L’installazione segue la solita strada delle applicazioni Laravel: si scarica il progetto, si installano le dipendenze con Composer e si punta nginx alla cartella pubblica. Il procedimento completo è descritto bene nella guida di lejubila.net e non lo ripeto.

Il pannello non è indispensabile. Nel mio impianto il comando quotidiano passa da Home Assistant, e il pannello resta per le prove e la diagnostica: è comodo per controllare una zona senza uscire dal browser.

mqttconnector: il ponte verso Home Assistant

mqttconnector è l’interprete. Si iscrive a un topic MQTT, gira i comandi alla porta interna di piGarden e pubblica la risposta. Home Assistant non deve sapere nulla di piGarden: appende un biglietto sulla bacheca, e il resto è compito del ponte.

La versione upstream è scritta per Python 2.7, ormai fuori supporto: sul mio Raspberry gira una versione riscritta in Python 3, con la libreria paho-mqtt 1.6.1 (l’ultima compatibile con il Python 3.7 di Buster). L’originale è rimasto come copia di riserva accanto al nuovo file.

La configurazione

Il file principale è /etc/mqttconnector.ini. Qui ci sono la sezione del broker e quella di piGarden (le credenziali vanno nelle voci user e password, che qui ometto):

codice
[mqtt]
broker_address=<IP-DEL-BROKER>
port=1883
client_id=mqttconnector
path_connector=/home/pi/mqttconnector/
subtopic_command=command
subtopic_result=result

[pigarden]
enabled=1
host=127.0.0.1
port=8084
exec_command=exec_cmd2sck.sh
topic=pigarden
result_enable=1
topic_result_qos=0
topic_result_retain=1

Il broker è il Mosquitto di Home Assistant, con un utente dedicato a piGarden. Con topic=pigarden i comandi arrivano su pigarden/command e le risposte escono su pigarden/result.

Il servizio systemd

Perché il ponte parta da solo e si rialzi se cade, lo affido a systemd:

codice
[Unit]
Description=mqttconnector
After=network-online.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=pi
ExecStart=/usr/bin/python3 /home/pi/mqttconnector/mqttconnector.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl enable --now mqttconnector

Restart=always con StartLimitIntervalSec=0 fa ripartire il servizio sempre, senza mai fermarsi dopo troppi tentativi. A questo aggiungo una cintura di sicurezza nel crontab, che ogni minuto controlla e riavvia se serve:

codice
* * * * * systemctl is-active --quiet mqttconnector || sudo systemctl restart mqttconnector

Per permettere all’utente pi quel sudo senza password, in /etc/sudoers.d/ ho autorizzato solo quel comando esatto:

codice
pi ALL=(ALL) NOPASSWD: /bin/systemctl restart mqttconnector

I comandi disponibili

Questi sono i «biglietti» che il ponte sa leggere:

MessaggioEffetto
open Napre la zona N
open N forceapre la zona N ignorando il controllo pioggia
open_in 0 M Napre la zona N subito e la chiude dopo M minuti
close Nchiude la zona N
close_allchiude tutte le zone
close_all disable_schedulingchiude tutto e disabilita le schedulazioni
rebootriavvia il Raspberry

Verificare la catena completa

Da un computer con i client Mosquitto, metti un ascolto sul topic dei risultati e manda un comando:

codice
mosquitto_sub -h <IP-DEL-BROKER> -u <UTENTE-MQTT> -P <PASSWORD-MQTT> -t 'pigarden/#' -v
mosquitto_pub -h <IP-DEL-BROKER> -u <UTENTE-MQTT> -P <PASSWORD-MQTT> -t pigarden/command -m 'open 1'
mosquitto_pub -h <IP-DEL-BROKER> -u <UTENTE-MQTT> -P <PASSWORD-MQTT> -t pigarden/command -m 'close 1'

Il primo comando resta in ascolto e stampa ogni biglietto che passa; gli altri due sono un «apri» e un «chiudi» sulla zona 1. Se il relè scatta e sul topic pigarden/result compare la risposta, la catena Home Assistant → MQTT → mqttconnector → piGarden → relè funziona.

Nel prossimo articolo costruiamo la parte di Home Assistant: switch, timer, script e schedulazioni.

Riferimenti: lejubila.net/pigarden per il software open source · github.com/lejubila/piGarden

Scroll to Top