piGarden: le a.p.i.

In questo articolo vorrei approfondire e fare più chiarezza sulle api (Application Program Interface) che piGarden mette a disposizione e con le quali può interfacciarsi con altri software esterni.

Le api vengono esposte tramite socket server già da tempo e più recentemente invece possono essere utilizzate anche tramite protocollo mqtt.

Tramite l’utilizzo delle api è possibile conoscere lo stato di piGardem, aprire o chiudere le elettrovalvole, creare schedulazioni e molto altro.

Socket Server

Come detto precedentemente, le api vengono esposte al mondo esterno tramite socket server. Questo vuole dire che per poterle utilizzare è necessario instaurare una connessione tcp verso l’host che ospita piGarden sulla porta indicata nel file di configurazione. Questo è anche il sistema che viene utilizzato da piGardenWeb per interfacciarsi con piGarden.

Per maggiori informazioni sulla configurazione del socket server di piGarden vi rimando all’articolo nel quale veniva annunciato, piGarden 2.0 Ester Egg, e più in particolare a quello relativo all’installazione e configurazione di piGarden.

Come dicevo prima, per utilizzare le api, dobbiamo instaurare una connessione tcp con il server socket di piGarden. Instaurata la connessione sarà possibile inviare il comando api più appropriato in base a quello che vogliamo ottenere. L’invio del comando avviene scrivendo una semplice stringa (contenente il comando stesso) seguita dal carattere carriage return e line feed (cr+lf).

Se piGarden è stato configurato in modo che il socket server sia sottoposto ad autenticazione, prima del comando api, sarà necessario inviare le credenziali corrette, indicando prima lo username e poi sulla password.

Una volta ricevuto il comando, piGarden lo eseguirà e successivamente restituirà in output un json contenente lo stato attuale dell’applicazione. Nel caso che il comando o le credenziali di autenticazioni siano errate verrà restituito sempre un json ma questa volta contenente un codice di errore.

Per renderci meglio conto su come funziona, possiamo utilizzare la shell del nostro Raspberry e usare il comando telnet per instaurare una connessione verso il socket server ed inviare un comando a piGarden.

Tenendo conto che il socket server sia in ascolto sulla porta 8084 del Raspberry su cui stiamo operando, possiamo instaurare la connessione localmente con il seguente comando:

telnet 127.0.0.1 8084

se tutto va per il verso giusto, verranno emesso in output le seguenti stringhe che indicheranno che è avvenuta la connessione:

Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

Arrivati a questo punto possiamo impartire il comando api che vogliamo, preceduto da utente e password se il socket server è soggetto ad autenticazione. Scrivete quanto segue per impartire il comando status. Questo farà si che venga restituito un json contenente lo stato di piGarden.

username_socket_server
password_socket_server
status

o molto più semplicemente come segue se il socket server non ha autenticazione

status

in output verrà emesso un json tipo il seguente:

{"version":{"ver":0,"sub":5,"rel":12},"timestamp": 1546366100,"event": {"event": "", "alias": ""},"zones":{"Giardino_Posteriore_DX":{"name":"Giardino_Posteriore_DX","state":0},"Giardino_Posteriore_CN":{"name":"Giardino_Posteriore_CN","state":0},"Giardino_Posteriore_SX":{"name":"Giardino_Posteriore_SX","state":0}},"last_weather_online":{
  "display_location": {
    "city": "Pieve a Nievole"
  },
  "observation_epoch": "1546363200",
  "local_epoch": "1546363200",
  "local_tz_long": "Europe/Rome",
  "weather": "Clear",
  "temp_c": "6.78",
  "relative_humidity": "80%",
  "wind_dir": "ENE",
  "wind_degrees": "60",
  "wind_kph": "1.5",
  "wind_gust_kph": "--",
  "pressure_mb": "1024",
  "dewpoint_c": "--",
  "feelslike_c": "--",
  "icon_url": "http://icons.wxug.com/i/c/k/nt_clear.gif"
},"error":{"code":0,"description":""},"info":"","warning":"","success":"","last_rain_online":"1545907800","last_rain_sensor":"1546366082","cron":{},"cron_open_in":{}}

Il comando state è utile per capire lo stato di piGarden, ma se invece vogliamo avviare l’irrigazione aprendo un’elettrovalvola ci basterà utilizzare il comando open seguito dall’alias dell’elettrovalvola:

telnet 127.0.0.1 8084
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
open Giardino_Posteriore_DX
{"version":{"ver":0,"sub":5,"rel":12},"timestamp": 1546381436,"event": {"event": "ev_open_after", "alias": "Giardino_Posteriore_DX"},"zones":{"Giardino_Posteriore_DX":{"name":"Giardino_Posteriore_DX","state":1},"Giardino_Posteriore_CN":{"name":"Giardino_Posteriore_CN","state":0},"Giardino_Posteriore_SX":{"name":"Giardino_Posteriore_SX","state":0}},"last_weather_online":{
  "display_location": {
    "city": "Pieve a Nievole"
  },
  "observation_epoch": "1546379400",
  "local_epoch": "1546379400",
  "local_tz_long": "Europe/Rome",
  "weather": "Scattered Clouds",
  "temp_c": "5",
  "relative_humidity": "80%",
  "wind_dir": "",
  "wind_degrees": "null",
  "wind_kph": "0.5",
  "wind_gust_kph": "--",
  "pressure_mb": "1021",
  "dewpoint_c": "--",
  "feelslike_c": "--",
  "icon_url": "http://icons.wxug.com/i/c/k/nt_cloudy.gif"
},"error":{"code":0,"description":""},"info":"","warning":"","success":"Solenoid open","last_rain_online":"1545907800","last_rain_sensor":"","cron":{},"cron_open_in":{"open_in": {"Giardino_Posteriore_DX": ""},"open_in_stop": {"Giardino_Posteriore_DX": ""}}}
Connection closed by foreign host.

Volendo interagire con le api da shell senza l’utilizzo di telnet potete usare uno script tipo il seguente:

#!/bin/bash
cmd="$1"
remote_ip="$2"
remote_port="$3"
exec 5<>/dev/tcp/$remote_ip/$remote_port
echo -e "$cmd" >&5
cat <&5

Potrete utilizzarlo fornendo come primo argomento una stringa delimitata da doppi apici contenente le eventuali credenziali seguite dal comando api da impartire. Come secondo e terzo parametro invece dovranno essere indicati hostname/ip e porta del socket server.

Per esempio, se avete chiamato lo script sopra indicato con il nome di pigarden_api.sh, potrete eseguire l’apertura della zona nel seguente modo:

./pigarden_api.sh "username\npassword\nopen Giardino_Posteriore_DX" garden 8084

MQTT

Più recentemente è stato introdotto la possibilità di utilizzare le api di piGarden tramite protocollo mqtt. Questo è possibile utilizzando mqttconnector, uno script python che funziona da proxy tra mqtt e il socket server. Per maggiori dettagli sull’installazione e configurazione di mqtt connector potete consultare l’articolo dedicato “mqttconnector, utilizza le api piGarden e piGuardian tramite mqtt“.

Una volta che mqttconnector sarà avviato, potrete comandare piGarden tramite protocollo mqtt, inviando un messaggio verso il topic pigarden/command. Il payload del messaggio dovrà contenere il comando api che volete utilizzare.

Volendo fare una prova, potete utilizzare l’utility di mosquitto_pub presente nel pacchetto mosquitto-clients

mosquitto_pub -h host_broker -p porta_broker -u user_broker -P password_broker -t "pigarden/command" -m "open Giardino_Posteriore_DX"

Con il comando sopra indicato verrà inviato il comando di apertura della zona Giardino_Posteriore_DX.

Una volta eseguito il comando piGarden, se opportunatamente configurato, pubblicherà lo stato in formato json inviando un messaggio mqtt sul topic pigarden/result.

Elenco delle api utilizzabili

Di seguito riporto l’elenco delle api di piGarden con la rispettiva descrizione.

ComandoDescrizione
status [get_cron[:nome_zona]] [get_cron_open_in[:nome_zona]]Restituisce lo stato di piGarden in formato json.
Se specificato il parametro get_cron viene restituito anche le eventuali schedulazioni di apertura/chisura di tutte le zone.
Se il parametro get_cron è seguito da :nome_zona verranno restituite solo le schedulazioni della zona indicata in nome_zona.
Similmente a quanto sopra accade anche per il parametro get_cron_open_in restituendo le eventuali schedulazioni utilizzate per la funzione di apertura ritardata.
open alias_zona [force]Esegue l'avvio dell'irrigazione per la zona indicata da alias_zona.
Se il indicato il parametro force verrà forzata l'irrigazione anche in caso di pioggia.
A seguito del comando viene restituito il json contenente lo stato di piGarden contenente anche le eventuali schedulazioni utilizzati dalla funzione di apertura ritardata della zona in oggetto.
open_in minute_start minute_stop alias_zona [force]Esegue la funzione di avvio ritardato della zona indicata nel parametro alias_zona.
minute_start indica dopo quanti minuti deve partire l'irrigazione (se indicato il valore zero l'irrigazione partirà subito).
minute_stop indica dopo quanti minuti l'irrigazione si dovrà interrompere.
Il parametro force se indicato forzerà l'irrigazione anche in caso di pioggia.
A seguito del comando viene restituito il json contenente lo stato di piGarden contenente anche le eventuali schedulazioni utilizzate dalla funzione di apertura ritardata della zona in oggetto.
close alias_zonaEsegue la chiusura dell'irrigazione della zona indicata in alias_zona.
A seguito del comando viene restituito il json contenente lo stato di piGarden contenente anche le eventuali schedulazioni utilizzati dalla funzione di apertura ritardata della zona in oggetto.
set_general_cron [set_cron_init] [set_cron_start_socket_server] [set_cron_check_rain_sensor] [set_cron_check_rain_online] [set_cron_close_all_for_rain]Imposta i cron per l'inizializzazione di piGarden, l'avvio del socket server, il controllo del sensore di rilevamento pioggia, l'interrogazione del servizio online del rilevamento pioggia, la chiusura delle elettrovalvole in caso di rilevamento pioggia.
In caso di errore viene restituito un json contenente la descrizione dell'errore. In caso contrario viene restituito il json contenente lo stato di piGarden.
del_cron_open alias_zoneElimina tutte le schedulazioni di apertura relative ad una zona.
In caso di errore viene restituito un json contenente la descrizione dell'errore. In caso contrario viene restituito il json contenente lo stato di piGarden.
del_cron_open_in alias_zoneElimina la schedulazione di apertura di una zona relativamente ad una programmazione di avvio ritardato.
A seguito del comando viene restituito il json contenente lo stato di piGarden contenente anche le eventuali schedulazioni utilizzate dalla funzione di apertura ritardata della zona in oggetto.
del_cron_close alias_zoneElimina tutte le schedulazioni di chiusura relative ad una zona.
In caso di errore viene restituito un json contenente la descrizione dell'errore. In caso contrario viene restituito il json contenente lo stato di piGarden.
add_cron_open alias_zone min hour dom month dow [disabled]Aggiunge una schedulazione di apertura dell'elettrovalvola alias_zone.
Gli altri parametri ricalcano il formato cron di linux:
min: minuto
houar: ora
dom: giorno del mese
month: mese
dow: giorno della setimana

Come ultimo parametro se indicato e inserita la strina "disabled" inserirà la schedulazione di apertura ma in modalità disabilitata.

In caso di errore viene restituito un json contenente la descrizione dell'errore. In caso contrario viene restituito il json contenente lo stato di piGarden.

add_cron_close alias_zone min hour dom month dow [disabled]Come add_cron_open ma relativamente alla schedulazione di chiusura di una zona.
rebootEsegue il riavvio del sistema dove è ospitato piGarden.
Restituisce un json contenente lo stato di piGarden.
poweroffEsegue lo spegnimento del sistema dove è ospitato piGarden.
Restituisce un json contenente lo stato di piGarden.

Il json contenente lo stato

Analizziamo ora un po’ più in dettaglio il json contenente lo stato di piGarden, che viene restituito dopo ogni chiamata oppure a seguito del comando state:

{
	"version": {
		"ver": 0,
		"sub": 5,
		"rel": 12
	},
	"timestamp": 1546381436,
	"event": {
		"event": "ev_open_after",
		"alias": "Giardino_Posteriore_DX"
	},
	"zones": {
		"Giardino_Posteriore_DX": {
			"name": "Giardino_Posteriore_DX",
			"state": 1
		},
		"Giardino_Posteriore_CN": {
			"name": "Giardino_Posteriore_CN",
			"state": 0
		},
		"Giardino_Posteriore_SX": {
			"name": "Giardino_Posteriore_SX",
			"state": 0
		}
	},
	"last_weather_online": {
		"display_location": {
			"city": "Pieve a Nievole"
		},
		"observation_epoch": "1546379400",
		"local_epoch": "1546379400",
		"local_tz_long": "Europe/Rome",
		"weather": "Scattered Clouds",
		"temp_c": "5",
		"relative_humidity": "80%",
		"wind_dir": "",
		"wind_degrees": "null",
		"wind_kph": "0.5",
		"wind_gust_kph": "--",
		"pressure_mb": "1021",
		"dewpoint_c": "--",
		"feelslike_c": "--",
		"icon_url": "http://icons.wxug.com/i/c/k/nt_cloudy.gif"
	},
	"error": {
		"code": 0,
		"description": ""
	},
	"info": "",
	"warning": "",
	"success": "Solenoid open",
	"last_rain_online": "1545907800",
	"last_rain_sensor": "",
	"cron": {},
	"cron_open_in": {
		"open_in": {
			"Giardino_Posteriore_DX": ""
		},
		"open_in_stop": {
			"Giardino_Posteriore_DX": ""
		}
	}
}

Il primo elemento che troviamo è version che a sua volta contiene altri tre elementi che vanno ad indicare il numero di versione di piGarden.

A seguire troviamo il timestamp in chi è stato emesso lo stato.

L’elemento event con i suoi due sotto-elementi sta ad indicare l’evento che ha scaturito l’emissione dello stato. Oltre a questo viene anche indicato l’alias della zona sulla quale è intervenuto l’evento.

Se segue l’elemento zones, che va contenere tutte le zone definite in piGarden e per ognuna oltre al nome viene indicato anche lo stato. Lo stato può assumere i seguenti valori: 0=chiuso 1=aperto 2=aperto in modo forzato.

Segue poi last_weather_online che va a indicare le ultime condizioni meteo recuperate dal servizio online.

Continuiamo con error che va indicare eventuali errori riscontrati durante la chiamata alle api indicando un codice di errore e una descrizione.

Seguono i tre elementi info, warning e success che possono contenere dei messaggi testuali descrittivi che piGaden emette a seguito della chiamata alle api.

last_rain_online contiene il timestamp dell’ultima pioggia rilevata dal servizio online.

last_rain_sensor contiene l’ultima pioggia rilevata dal sensore hardware.

croncron_open_in vanno a contenere le schedulazioni delle apertura, chiusura e avvio ritardato delle zone.

Conclusioni

Questo articolo si conclude qui e spero possa essere di aiuto per chiunque voglia cercare di interfacciare piGarden con altri software esterni.

Un saluto a tutti e buoni divertimento.

5 pensieri su “piGarden: le a.p.i.

  1. Se mi connetto con telnet tutto funziona ma se provo via mqtt,qualsiasi comando invio mi ritorna

    192.168.0.100 1883 xxxxxx yyyyyy
    Connected to broker
    subscribe: pigarden/command
    subscribe: piguardian/command
    Topic : pigarden/command
    Message received: status
    pigarden command: status
    cat: -: Connection reset by peer
    Command : ‘xxxxx@yyyyyy.zzz
    xxxxxx
    status’
    Command output : {“error”:{“code”:0,”description”:”invalid command”}}

    Command exit status/return code : 1

    questo e il io mqttconnector.ini

    [mqtt]
    broker_address=192.168.0.100
    port=1883
    user=xxxxxxx
    password=yyyyy
    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
    user=yyyyyyyy
    pwd=xxxxx
    topic=pigarden

  2. @Stefano
    dall’output vedo che mqttconnector oltre che al comando invia al socket server anche l’utente e password.
    Su piGarden hai attivato l’autenticazione sul socket server? Se così non fosse disattiva l’autenticazione su mqttconnector lasciando nel file di configurazione vuoti i campi user e pwd.
    Fammi sapere.

  3. @lejubila Funziona perfettamente,non so perche immaginavo di dover inserire li le credenziali che uso su pigardenweb.
    Veramente un ottimo lavoro

  4. buonasera sto provando ad installare mqttconnector quando faccio prima cosa non si avvia e se faccio uno status mi da questo errore
    pi@masterhome:~ $ sudo systemctl status mqttconnector.service ● mqttconnector.service – mqttconnector
    Loaded: bad-setting (Reason: Unit mqttconnector.service has a bad unit file setting.)
    Active: inactive (dead)

    apr 12 20:44:15 masterhome systemd[1]: /etc/systemd/system/mqttconnector.service:6: Invalid user/group name or numeric ID:
    qualcuno mi potrebbe aiutare. grazie

  5. @luciano

    puoi risolvere questo problema andando a sostituire la squente riga in /etc/systemd/system/mqttconnector.service
    User=%i

    con

    User=pi

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.