community italiana di domotica personale
 
Esercizi di domotica su Home Assistant: “4 – Script, come realizzarli ed eseguirli”

Esercizi di domotica su Home Assistant: “4 – Script, come realizzarli ed eseguirli”

Questo è un contenuto esplicitamente concepito per i principianti della domotica personale. Serve per impratichirsi e prendere confidenza con l'HUB per domotica personale Home Assistant. Se non conoscete quest'ultimo, una rapida scheda per farvi un quadro è disponibile qui; i concetti principali sono invece elencati qui.

Cosa serve per questi esercizi

Ovviamente, avere a disposizione Home Assistant installato e funzionante, qualunque sia la modalità di implementazione scelta, che sia Home Assistant OS (HASSIO, HassOS) o Home Assistant Core. Se non si ha ancora a disposizione questo potente HUB open source per domotica personale, è possibile installarlo e configurarlo gratuitamente nelle più disparate modalità. Serve, inoltre, un computer d'appoggio qualsiasi tramite il quale collegarsi alla propria istanza di Home Assistant, utilizzando tipicamente il proprio browser preferito.
 

Home Assistant - Esercizi - 4 crop

Altre esercitazioni:

Gli esercizi di questa puntata

In questa esercitazione vi insegneremo a prendere dimestichezza con l’HUB per quanto riguarda uno strumento particolarmente utile: gli script.

Prenderemo dimestichezza sulle modalità con le quali si può far eseguire all’HUB degli script predeterminati; gli esempi sono esplicativi: sta all’utente identificare, sulla base di quanto a propria disposizione, gli elementi da utilizzare per testare le tecniche qui spigate.

Si consiglia di non saltare alcuna parte del corso espresso in questa puntata.

Gli script

Prima di affrontare lo studio specifico in merito al loro uso, spendiamo due parole di ripasso (per chi non avesse ancora dimestichezza) sugli script, uno degli adegli strumenti più utili e versatili della domotica basata su Home Assistant.

In buona sostanza, gli script non sono altro che una sequenza di azioni, la quale può venire innescata in diversi modi sfruttando, volendo, anche delle variabili esterne. Questo modello operativo è particolarmente utile quando, per esempio, si desidera “astrarre” un insieme di azioni in un’unica azione logica.

Si immagini per esempio di aver integrato un attuatore a infrarossi (vedi approfondimento) tramite il quale controllare un vecchio TV: tramite gli script è particolarmente semplice ed efficace definire una sequenza la quale provveda a inviare il codice infrarosso per l’accensione della TV, poi quello relativo a un dato canale e infine quello per impostare un certo volume. Evocando tale script (in diversi modi, che vedremo) è possibile far sì che la TV si accenda, si posizioni sul canale predefinito a un volume altrettanto predefinito. E così via per altre centinaia di esempi.

Gli script ricordano molto da vicino il blocco action delle automazioni, oggetto dell’esercitazione precedente. A differenza loro, però, gli script sono un blocco di azioni eseguibili a prescindere, mentre l’esecuzione del blocco action è sempre vincolato all’esecuzione completa di una data automazonue.

Gli scipt non vanno confusi con le scene: come abbiamo spiegato in dettaglio qui, quest’ultime sono infatti uno strumento utile a imporre a delle entità, tutte contemporaneamente, un determinato stato e non eseguono alcuna azione strutturata. In pratica, se per esempio volessimo definire una scena (o scenario) in cui tutte le luci vengano spente, sarebbe possibile farlo tramite una scena “buonanotte” nella quale indicare tutte le entità coinvolte associate allo stato “off“. 

N.b. Agli script, a cosa servano e come funzionino, abbiamo dedicato una scheda approfondita ad hoc. Se non si sa proprio di che si parla, prima si consiglia di leggerla.

Preparazione

Prima di iniziare gli esercizi, prepariamoci verificando di essere in grado di effettuarli.

Aggiungere al file di configurazione di Home Assistant (oppure all’eventuale file sidecar dedicato alle automazioni), presso la chiave “script:” (se non esiste andrà creata – e ce ne deve essere una e una sola, così come per qualsiasi altro componente) il seguente codice:

script:
  esercizio: 
    alias: "Esercizio"
    sequence:
      - delay:
          seconds: 1

Uscire e salvare.  Questo punto verificare che la propria configurazione sia corretta: recarsi alla voce di menu “Strumenti per sviluppatori” > “YAML“, cliccare su “Verifica configurazione“: se tutto ok, cliccare sotto “Ricarica configurazione YAML” la voce “SCRIPT“, altrimenti correggere l’errore eventualmente indicato e riprovare.

N.b. Attenzione: è fondamentale che, oltre alla semantica, sia corretta anche l’indentazione del proprio codice YAML. Per verificarla, copia-incollare sempre (almeno finché non si diventa abili) la propria configurazione presso YAMLLint per verificare che sia corretta.

Dopo aver ricaricato manualmente le automazioni su YAML, sarà “nata” una nuova entità chiamata, in questo caso, “script.esercizio“. L’elenco completo di tutte le entità presenti in dato momento sull’HUB è disponibile, presso la sua interfaccia è disponibile alla voce “Strumenti per gli sviluppatori” > “Stati“.

Se è tutto ok, bene: de facto un primo esercizio è stato effettuato, ovvero quello di creare uno script  che contenga un’unica azione nel blocco sequence:, ovvero una semplice attesa di un secondo.

Ora modifichiamo lo script di cui sopra come segue:

script:
  esercizio: 
    alias: "Esercizio"
    sequence:
      - service: persistent_notification.create
        data:
          message: "Script eseguito."
          title: "Esercizio"

A questo punto verificare nuovamente la configurazione (sia come semantica che come indentazione) e, se ok, ricaricare nuovamente gli script. Una volta fatto, lo script sarà aggiornato: essa presenterà una singola azione “concreta”, (non più una semplice attesa di un secondo) ovvero la creazione di una notifica persistente.

Vediamo quindi di innescarla manualmente: recarsi alla voce di menu “Configurazione” > “Script” e, individuata la nostra automazione (“Esempio“), cliccare su “ESEGUI“.

Se tutto andrà bene, in basso a sinistra sullo schermo (voce “Notifiche“) apparirà un “1” a indicare la presenza di una nuova notifica persistente generata dall’esecuzione dell’automazione di cui sopra:

Home Assistant - Esempio notifica persistente

Complimenti, avete appena eseguito (sebbene in modo manuale) l’azione prevista dallo script. Questa appena realizzata sarà la scheletratura dello script che utilizzeremo per i nostri esercizi.

Cosa, come, quando

Illustrare per intero cosa si possa utilizzare in uno script è un’impresa titanica, data la vastità delle possibilità e degli scenari nonché dall’evoluzione continua dell’HUB. Cercheremo quidi di offrire un’istantanea di “grana grossa” che faccia capire all’utente cosa sia possibile fare e dove, eventualmente e successivamente, approfondire ulteriormente le proprie competenze.

In primis, ciò che maggiormente si usa nelle azioni di un’automazione sono i servizi.

Ogni componente core dell’HUB (come per esempio “Light“, “Switch“, “Climate” e così via) prevede un certo set di servizi. Prendiamo l’esempio del componente “Light”, il quale viene solitamente utilizzato dalle piattaforme di integrazione per integrare i punti luce: nella pagina ufficiale del componente vengono elencati tutti i servizi ad esso afferenti e la relativa spiegazione di come usarli (per esempio light.turn_on, light.turn_off e light.toggle).

Va da sé che un’entità di tipo “Light” possa essere tipicamente usata con i servizi del componente dal quale essa derivi.

Se si volesse per esempio pilotare un termostato afferente quindi al componente “Climate”, si dovrà far riferimento ai servizi di tale componente per capire come gestirlo in modo automatico nelle azioni delle mie automazioni. E così via. Va da sé che evocando un servizio in associazione a un’entità inappropriata (eg. usare light.turn_on con l’ipotetica entità climate.termostato_sala) non possa che portare a un errore.


Altro che si possa fare nel blocco sequence: di uno script è relativo, per esempio, a:

  • gestire delle variabili;
  • verificare delle condizioni;
  • attendere il trascorrere di un dato lasso di tempo;
  • attendere il verificarsi di un template, di una condizione e altro;
  • innescare un evento sullo state bus (spiegato nell’esercitazione relativa ai trigger);
  • effettuare dei clicli;
  • gestire delle condizioni if-then;
  • gestire variabili;
  • parallelizzare le esecuzioni

e altro ancora.

Effettueremo una serie di esercizi in tal senso; comunque, l’elenco completo di ciò che si può eseguire (e come) nel blocco sequence: di uno script (o nel blocco action: delle automazioni di Home Assistant) è spiegato in dettaglio qui.

Esercizi

Eseguire gli script

In tutti gli esempi di questa esercitazione tutti gli script che realizzeremo verranno innescati a mano come fatto sopra (voce di menu “Configurazione” > “Automazione e scene” e, individundo lo script in questione (“Esempio“), cliccando su “ESEGUI“).

Un’altra modalità – importante – da conoscere per innescare gli script è quella programmatica, ovvero utilizzata, per esempio, nel blocco action: delle automazioni:

automation:
  alias: "Automazioni di esempio"
  trigger: [] #quel che è
  condition: [] #quel che è
  action:
    - service: script.turn_on
      entity_id: script.nome_dello_script

così facendo, l’esecuzione dell’automazione innesca l’esecuzione dello script indicato nel blocco action:.

Esercizio 4.1

Iniziamo dalla più semplice delle azioni: evocare un servizio, o meglio, più di uno in sequenza.

Ipotizziamo di avere all’interno del nostro HUB due entità di tipo “Light” (l’astrazione di punti luce integrati, in qualche modo, su Home Assistant) chiamate light.punto_luce_1 e light.punto_luce_2.

Ipotizziamo di voler scrivere uno script che accenda le due luci quando innescato:

script:
  esercizio: 
    alias: "Accensione luci"
    sequence:
      - service: light.turn_on
        entity_id: light.punto_luce_1
      - service: light.turn_on
        entity_id: light.punto_luce_2

Una volta salvata la configurazione e ricaricati gli script come spiegato sopra e infine eseguito lo script, le due luci dovrebbero, salvo problemi di diversa natura, accendersi.

Le action delle automazioni vengono sempre eseguite in sequenza così nell’ordine in cui sono scritte quindi, anche se impercettibilmente, l’entità light.punto_luce_1 si accenderà prima di light.punto_luce_2.

In realtà lo script di cui sopra può essere scritta in modo più efficiente, come segue:

script:
  esercizio: 
    alias: "Accesione luci"
    sequence:
      - service: light.turn_on
        entity_id:
          - light.punto_luce_1
          - light.punto_luce_2 

Per lo più, infatti, i servizi consentono di ingaggiare anche più entità contemporaneamente. Nel caso di cui sopra, passiamo da due action a una sola (rispetto alla prima definizione).

ESERCIZIO DA EFFETTUARE IN PROPRIO
Trovare nel proprio elenco una o più entità e pilotarla con un servizio a scelta previsto dal componente dal quale deriva (ricordare quanto spiegato sopra in termini di coerenza servizio/entità). Come forzare l’esecuzione dello script l‘abbiamo spiegato sopra.
Vetrina - Offerte del giorno

Esercizio 4.2

Mantenendo valido l’esempio dell’esercizio 4.1, ipotizziamo di voler accedere la seconda luce con un ritardo di un minuto e mezzo. Modifichiamo quindi la definizione dello script come segue:

script:
  esercizio: 
    mode: single
    alias: "Accensione luci"
    sequence:
      - service: light.turn_on
        entity_id: light.punto_luce_1
      - delay:
          minutes: 1
          seconds: 30
      - service: light.turn_on
        entity_id: light.punto_luce_2 

L’introduzione del delay: fa sì che, dopo l’esecuzione della prima action, Home Assistant attenda un minuto e mezzo prima di eseguire tutto ciò che segue dopo il delay stesso, in questo caso l’accensione della seconda luce.

Ma cosa succede se, durante l’attesa del minuto previsto, l’automazione viene eseguita nuovamente? Per com’è scritto l’esempio sopra, non succede nulla, questo perché abbiamo indicato mode: single. Se avessimo indicato per esempio mode: queue, una nuova esecuzione dello script sarebbe stata accodata in attesa del termine della prima esecuzione, per essere poi eseguita nuovamente. Le varia modalità di esecuzione sono illustrate qui.

Tutti i dettagli relativi al delay sono, invece, disponibili qui.

ESERCIZIO DA EFFETTUARE IN PROPRIO
Effettuare la stessa esercitazione dell’esercizio precedente ma, in questo caso, introdurre un’attesa personalizzata tra un servizio e l’altro.

Esercizio 4.3

Mantenendo sempre valido l’esempio dell’esercizio 4.1, ipotizziamo ora di voler eseguire l’accesione della seconda luce solo e unicamente a patto che la seconda sia effettivamente già spenta.

script:
  esercizio: 
    alias: "Accensione luci"
    sequence:
      - service: light.turn_on
        entity_id: light.punto_luce_1
      - condition: state
        entity_id: light.punto_luce_2
        state: 'off'
      - service: light.turn_on
        entity_id: light.punto_luce_2 

Dato che le azioni vengono eseguite in sequenza (salvo diverse configurazioni, che vedremo), la prima accensione viene eseguita a prescindere, mentre a seguire viene verificata la condizione relativa allo stato dell’entità light.punto_luce_2 la quale, se è effettivamente spenta, fa sì che l’automazione prosegua e, quindi, la accenda tramite il servizio light.turn_on.

Se invece light.punto_luce_2 è accesa, allora l’automazione verrà interrotta, indipendentemente che a seguire possano esserci anche altre decine di altre action: l’esecuzione termina. Questo potrebbe essere un problema in certe situazioni, e a seguire vedremo come eventualmente risolvere la questione.

In alternativa, avremmo potuto utilizzare un blocco if…then:

script:
  esercizio: 
    alias: "Accensione luci"
    sequence:
      - service: light.turn_on
        entity_id: light.punto_luce_1
      - if:
        - condition: state
          entity_id: light.punto_luce_2
          state: 'off'
        then:
        - service: light.turn_on
          entity_id: light.punto_luce_2  

Tale blocco è maggiormente efficace, in quanto non interrompe l’esecuzione sequenzale delle azioni:  in caso ci fossero altre azioni successive, infatti, il blocco condition: state della prima soluzione sopra, quando non verificato (luce spenta), blocca completamente l’esecuzione dello script mentre if: invece no, in quanto esso si limita a non eseguire quando indicato sotto then ma poi prosegue. Su questo tema torneremo nell’esercizio 4.8.

ESERCIZIO DA EFFETTUARE IN PROPRIO
Effettuare la stessa esercitazione dell’esercizio precedente ma, in questo caso, introdurre una condizione personalizzata tra un’action e l’altra ed effettuare vari test in base ai risultati attesi.

Esercizio 4.4

Ipotizziamo ora di ripetere l’esercizio 4.3 ma, stavolta, risolvendo il problema di cui sopra. Nello specifico, faremo in modo che lo script:

  • accenda subito la luce 1;
  • subordini l’accensione immediata della luce 2 in base al fatto che essa sia spenta;
  • regoli il climatizzatore (entità ipotetica climate.mitsubishi) dopo 10 minuti dall’avvio dell’automazione.

Il nostro script corretta in base ai requisiti diventa:

script:
  esercizio: 
    alias: "Accensione luci e clima"
    sequence:
      - parallel:
          - service: light.turn_on #primo blocco
            entity_id: light.punto_luce_1
          - sequence: #secondo blocco
              - condition: state
                entity_id: light.punto_luce_2
                state: 'off'
              - service: light.turn_on
                entity_id: light.punto_luce_2
          - sequence: #terzo blocco
              - delay:
                  minutes: 10
              - service: climate.set_temperature
                data:
                  entity_id: climate.mitsubishi
                  temperature: 20
                  hvac_mode: cool

Utilizzare la parallelizzazione introdotta con parallel: permette di definire tre blocchi indipendenti e paralleli (all’interno dei quali l’esecuzione torna ad essere sequenziale). Il primo, relativo all’accensione immediata della luce 1; il secondo, che verifica lo stato della luce 2 e semmai la accende; il terzo ed ultimo che attende dieci minuti prima di avanzare e quindi di regolare il climatizzatore.

ESERCIZIO DA EFFETTUARE IN PROPRIO
Effettuare la stessa esercitazione degli esercizi precedenti, questa volta parallelizzando le azioni e introducendo delle condizioni come spiegato al fine di appurare il corretto funzionamento della parallelizzaizone dell’esecuzione.

Esercizio 4.5

In questo esercizio effettuiamo il toggle (ovvero l’inversione di stato, quale esso sia) di una luce, effettuandolo diverse volte, a distanza di due secondi uno dall’altro.

script:
  esercizio: 
    alias: "Toggle luce"
    sequence:
      - service: light.turn_on
        entity_id: light.punto_luce_1
      - repeat:
          count: 5
          sequence:
            - delay: 2
            - service: light.toggle
              target:
                entity_id: light.punto_luce_1

Utilizzando il repeat:, infatti, è possibile… ripetere il contenuto della sequence: sottostante. Dato che tale sequenza contiene un delay di 2 secondi e il toggle della luce, questo ciclo causa la ripetuta accensione/spegnimento (per un totale di cinque volte, indicate in configurazione).

ESERCIZIO DA EFFETTUARE IN PROPRIO
Individuare un’entità appropriata e tentare di agire sui servizi che le riguardano utilizzando in cliclo come sopra spiegato.

Esercizio 4.6

Riprendiamo ora il secondo esercizio, quello in cui introducevamo il delay. Immaginiamo ora di poter introdurre un’attesa subordinata, ovvero: attendi al massimo un tot di tempo, ma se si verifica una data condizione, interrompi l’attesa e vai avanti (oppure no).

Ecco come funziona:

script:
  esercizio: 
    alias: "Esercizio"
    sequence:
      - wait_template: "{{ is_state('light.punto_luce_1', 'on') }}"
        timeout: '00:01:30'
        continue_on_timeout: 'false'
      - service: light.turn_on
        entity_id: light.punto_luce_2

L’adozione di wait_template: ci consente di scrivere questo script che, avviato, attende:

  • o che passi un minuto e mezzo;
  • o che la luce light.punto_luce_1 si accenda/si accesa.

Dopodichè:

  • se è passato il minuto e mezzo di attesa, lo script si ferma (a causa del continue_on_timeout: ‘false’);
  • se light.punto_luce_1 si sarà accesa, allora lo script proseguirà con l’accensione di light.punto_luce_2.

Chiaramente, impostando continue_on_timeout: a ‘true’, lo script proseguirebbe a prescindere anche dopo il minuto e mezzo d’attesa.

ESERCIZIO DA EFFETTUARE IN PROPRIO
Individuare delle entità appropriate ed effettuare dei test sfruttando wait_template: nelle due modalità, ovvero usando continue_on_timeout: configurato ‘true’ e ‘false’.

Esercizio 4.7

Ora proviamo a scrivere uno script che, in base a una variabile in ingresso, provveda a regolare automaticamente il volume di media player integrato a Home Assistant, per esempio un Amazon Echo Alexa.

Valutiamo questo script:

script:
  esercizio:
    alias: "Regolazione dinamica volume"
    sequence:
      - service: media_player.volume_set
        entity_id: media_player.alexa
        data:
          volume_level: '{{ volumelevel|float }}' 

Questo script attende una variabile volumelevel di tipo float la quale contenga un valore da 0.1 a 1.0 (con passi da 0.1) utile a regolare dinamicamente il volume dell’entità media_player.alexa.

N.b. Naturalmente le variaibli possono essere le più disparate e dalle più disparate nature e usi.

Per evocare lo script passandogli la variabile corretta, per esempio dentro il blocco action: di un’automazione, la sintassi è  questa:

    - service: script.turn_on
      entity_id: script.esercizio
      data:
        variables:
          volumelevel: 0.5 

Questa chiamata esemplificativa regola il volume al 50%.

ESERCIZIO DA EFFETTUARE IN PROPRIO
Definire un proprio script che preveda delle variabili in ingresso e appurarne il funzionamento evocandolo tramite un’automazione. 

Esercizio 4.8

Ora proviamo a scrivere uno script che, in base allo stato di light.punto_luce_1, provveda a invertirne lo stato senza usare il servizio light.toggle (cosa che sarebbe più pratica, ma ovviamente siamo nell’ambito di esercizi per far pratica):

script:
  esercizio: 
    alias: "Gestione luce"
    sequence:
      - if:
          - condition: state
            entity_id: light.punto_luce_1
            state: 'off'
        then:
          - light.turn_on
            entity_id: light.punto_luce_1
        else:
          - light.turn_off
            entity_id: light.punto_luce_1      

abbiamo quindi usato if/then/else, il più classico dei costrutti per verificare un condizione (ed eventualmente effettuare delle azioni conseguenziali).

ESERCIZIO DA EFFETTUARE IN PROPRIO
Individuare un’entità appropriata e tentare di agire sui servizi che le riguardano utilizzando la gestione delle condizioni tramite if/then/else.

Conclusioni

Non è affatto facile spiegare tutte le possibili azioni in una sola scheda d’esercitazione. O meglio: spiegarli non è difficile, quel che è arduo è individuare tutte le casistiche possibili, che sono davvero le più disparate.

Per tutte le possibilità legate si faccia dunque riferimento alla documentazione ufficiale.


Altre esercitazioni:

⚠️ Se di Home Assistant ne sai poco ma sei interessato a capirne di più, ti suggeriamo di partire da qui.

Questa pagina è redatta, manutenuta e aggiornata dallo staff di inDomus, un gruppo di persone molto diverse tra loro che trovi, per domande e supporto, sul forum e sulla chat del sito. Alcuni link sono taggati in qualità di affiliati Amazon e riceviamo un compenso dagli acquisti idonei, utile al sostenimento del sito, ma le nostre recensioni sono tutte indipendenti e non sponsorizzate. Se ti sei perso, a tua disposizione c'è la mappa.