Al momento stai visualizzando Script con parametri opzionali in Home Assistant

Script con parametri opzionali in Home Assistant

In questo articolo impareremo come creare ed utilizzare uno script con parametri opzionali in Home Assistant. Per farlo prenderemo in esame come traccia lo script multinotify che ho realizzato.

Lo scopo non è quello di fare copia/incolla acriticamente ma di seguire insieme un percorso intorno a questo codice per acquisire diverse nozioni e diventare autonomi nel creare strutture di questo tipo. Tali nozioni possono infatti risultare utili in tanti contesti applicativi anche molto diversi.

Il risultato sarà un servizio richiamabile con parametri che possono essere specificati in modo esplicito oppure omessi, proprio alla pari dei servizi core come light.turn_on, a cui possiamo passare la luminosità desiderata, la velocità di accensione, ecc… oppure no.

Non è quindi importante che tu utilizzi gli stessi servizi di notifica che utilizzo io, basterà seguire il filo logico e comprendere come funziona per creare infine del codice come questo ma calato nella tua specifica realtà.

Servizi utilizzati

Come detto non è importante avere gli stessi servizi ma è importante capire quali siano utilizzati così da comprendere i principi alla base del funzionamento dello script. Ecco quindi i servizi usati:

Home Assistant Companion App
Per le notifiche tramite app mi affido totalmente all’app ufficiale di Home Assistant, nel mio caso per Android. Tali notifiche sono molto potenti e versatili, più di qualunque altra piattaforma. Prima o poi farò un articolo con questo argomento…

Diversi assistenti vocali Alexa Echo Dot disseminati per casa
Come assistenti vocali utilizzo Alexa di Amazon che si presta notevolmente bene alle notifiche da Home Assistant.
Per pronunciare le notifiche (e molto altro!) utilizzo componente custom Alexa Media Player, installabile da HACS.

A cosa serve e quali vantaggi offre uno script generico con parametri opzionali in Home Assistant

Avendo molte automazioni che notificano delle situazioni di attenzione o di allarme, durante la loro scrittura mi sono trovato spesso a scrivere e riscrivere lo stesso codice per inviare le notifiche che mi servivano.

Il buon programmatore sa che quando questo accade è arrivato il momento di creare una “funzione” richiamabile e centralizzata dove implementare una volta sola e in modo ottimale il codice ripetuto precedentemente.
Qui stiamo parlando di codice yaml, che è un linguaggio di markup, certo, ma i principi non sono così diversi dalla stesura di un programma, seppur con tutte le limitazioni del caso.

Ho quindi creato lo script multinotify con l’intento di avere una unica interfaccia da utilizzare per inviare notifiche singole o multiple ad uno o più smartphone e/o ad una o più Alexa di casa, con diverse possibilità interessanti.
Ma quali sono i concreti vantaggi di avere uno script che raggruppa delle funzionalità utilizzate spesso? Eccoli:

  • Si semplifica il codice ripetuto, richiamando solo lo script e specificando i soli parametri necessari allo scopo specifico, permettendo di omettere i parametri non necessari.
  • Si implementa una volta per tutte la funzionalità in un unico punto, permettendo un più agevole debug in caso di problemi. Nell’eventualità si presentasse un difetto, infatti, ci sarà un unico punto da verificare e correggere.
  • In caso si voglia aumentare le funzioni o migliorare le funzionalità basterà modificare lo script e le migliorie saranno automaticamente utilizzate da tutti i punti dove lo script è richiamato

Sintassi di utilizzo dello script multinotify

Con logica top down partiamo da come si utilizza tale script di home assistant con parametri opzionali con qualche esempio pratico che rende chiaro il concetto più di mille parole.

Esempi di utilizzo

- service: script.multinotify
  data:
    message: "Questa è una notifica pronunciata da Alexa"
    alexa_target: media_player.ovunque

Il servizio pronuncerà il messaggio su tutte le assistenti Alexa di casa solo se l’orario è compreso tra le 9:00 e le 23:00 (per evitare messaggi notturni poco gradevoli).

- service: script.multinotify
  data:
    message: "Questa è una notifica alle app"
    notify_app: notify.ALL_DEVICES

In questo modo arriverà invece una notifica a tutte le app con il testo specificato.

Ciò che semplifica maggiormente l’uso di tale script è la possibilità di unire le due potenzialità:

- service: script.multinotify
  data:
    message: "Questa è una notifica di prova"
    alexa_target: media_player.ovunque
    notify_app: notify.ALL_DEVICES

Il servizio, oltre a pronunciare il messaggio su tutte le assistenti Alexa di casa tra le 9:00 e le 23:00, invierà una notifica a tutti gli smartphone con il medesimo messaggio, nel canale e gruppo info con icona info.png.

Ma possiamo specificare ulteriori parametri opzionali:

- service: script.multinotify
  data:
    title: "Prova notifica"
    message: "Questa è una notifica un po' più complessa"
    notify_app: notify.ALL_DEVICES
    channel: warning
    critical: true
    alexa_target: media_player.ovunque
    alexa_volume_target: media_player.pian_terreno

In questo modo, oltre a quanto già detto nell’esempio precedente, la notifica alle app avverà nel canale e gruppo “warning” e con priorità immediata. Inoltre l’Echo Dot con nome pian_terreno modificherà il suo volume a 60% per poi ritornare al volume precedente dopo l’annuncio.

Un ultimo esempio di utilizzo con tutti i possibili parametri e modalità di utilizzo più specifiche:

- service: script.multinotify
  data:
    title: "Notifica dalla cucina"
    message: "E' pronto da mangiare!"
    alexa_message: '<say-as interpret-as="interjection">hey</say-as>, è pronto da mangiare!'
    notify_app: notify.mobile_app_tel_henrik
    channel: meal
    group: meal-cucina
    icon: meal
    tag: pronto_da_mangiare
    critical: false
    alexa_target:
      - media_player.mansarda
      - media_player.primo_piano
    alexa_volume_target: media_player.mansarda
    alexa_volume: 0.8
    alexa_volume_restore: false
    alexa_force: true

In questo esempio di utilizzo le cose si fanno un po’ diverse: saranno emesse le notifiche di Alexa solo dai dispositivi chiamati primo_piano e mansarda, con un volume dell’80%, il volume precedente non verrà ripristinato al termine e sarà riprodotto il messaggio anche tra le 23:00 e le 9:00. Verrà inviata un notifica solo all’app “tel_henrik” con canale “meal”, gruppo “meal-cucina”, icona “notify_meal.png”, tag “pronto_da_mangiare” ma non in modo critico (al primo risveglio dell’app o del telefono).
Inoltre i messaggi per l’app e per Alexa saranno differenti (usando le interiezioni la notifica nell’app non sarebbe molto leggibile…)

Parametri dello script di Home Assistant e loro significato

Vediamo insieme tutti i parametri dello script Home Assistant con parametri opzionali e a cosa servono per capire meglio il codice che seguirà.

  • message: è il testo della notifica inviata alle app e pronunciata da Alexa, a seconda dei parametri specificati in seguito.
    [obbligatorio]
  • alexa_message: è il testo che dovrà pronunciare Alexa al posto di usare il contenuto di message. Utile per diversificare i messaggi, ad esempio usando le interiezioni.
    [opzionale. Se non specificato sarà pronunciato il contenuto del parametro message]
  • title: è il titolo della notifica inviata alle app.
    [opzionale. Se non specificato il titolo sarà “Notifica da casa”]
  • alexa_target: è il dispositivo media_player Alexa che dovrà pronunciare il messaggio, il media_player ovunque oppure un elenco di specifici media_player (vedi ultimo esempio sopra).
    [opzionale. Se non specificato non verrà pronunciato il messaggio da Alexa]
  • alexa_volume_target: permette di specificare un singolo dispositivo Alexa a cui alzare il volume durante la notifica per poi tornare al volume precedente.
    [opzionale. Se non specificato non verrà modificato il volume ad alcuna Alexa]
  • alexa_volume: permette di specificare il volume da impostare durante l’annuncio al dispositivo Alexa specificato in alexa_volume_target.
    [opzionale. Se non specificato il volume dell’annuncio sarà al 60%]
  • alexa_volume_restore: se alexa_volume_target è impostato specifica se al termine dell’annuncio dovrà essere ripristinato il volume precedentemente trovato.
    [opzionale. Se non specificato il volume viene ripristinato]
  • alexa_force: specifica se forzare la pronuncia della notifica tramite Alexa anche se l’orario è notturno tra le 23:00 e le 9:00.
    [opzionale. Se non specificato non verrà riprodotta la notifica in orario notturno].
  • notify_app: il nome del servizio notify dell’app o del gruppo notify a cui inviare la notifica.
    [opzionale. Se non specificato non verrà inviata alcuna notifica alle app]
  • group: nome del gruppo della notifica alle app. Le notifiche verranno raggruppate in base a questo valore, così da non essere in ordine sparso.
    [opzionale. Se non specificato ma specificato il parametro channel verrà usato quest’ultimo anche come gruppo, altrimenti verrà usato “info”]
  • channel: nome del canale della notifica alle app. Ogni notifica con diverso channel, su Android, è configurabile con una suoneria, colore led, vibrazione e priorità differente. Così si può gestire le notifiche informative in modo diverso dagli allarmi critici, per esempio.
    [opzionale. Se non specificato ma specificato il parametro group verrà usato quest’ultimo anche come canale, altrimenti verrà usato “info”]
  • icon: nome dell’icona da utilizzare nella notifica. Il file dovrà trovarsi in /config/www e dovrà essere nominato notify_NOME.png, dove NOME è il solo valore da passare in questo parametro.
    [opzionale. Se non specificato ma specificato group o channel verrà usato il valore di questi ultimi, altrimenti “info”]
  • tag: se si specifica questo valore e viene inviata una ulteriore notifica all’app con tag uguale, la notifica precedente verrà sostituita con quest’ultima, andandola a sostituire.
    [opzionale. Se non si specifica la notifica sarà inviata senza sostituire altre notifiche]
  • critical: specifica se la notifica all’app deve avere priorità immediata. Specificando true la notifica verrà immediatamente inviata e mostrata nel centro notifiche. Specificando false la notifica verrà inviata allo sblocco del telefono o quando l’app effettua un ciclo in background, utile per risparmiare batterie.
    [opzionale. Se non viene specificato varrà false]

Il package multinotify

Effettuiamo ora l’analisi del codice dello script multinotify per imparare come creare script con parametri opzionali in Home Assistant. Cominciamo con l’intero codice, da inserire in un package (se non sai cosa sono i package ti rimando alla guida ufficiale o all’articolo di Indomus)

input_number:
  # Input number di servizio usato per memorizzare il volume precedente quando viene modificato per una notifica, così da ripristinarlo al termine della notifica
  alexa_prev_volume:
    name: Volume precedente di Alexa
    min: 0
    max: 1
    initial: 0.6
    mode: slider
    step: 0.1
    
notify:
  # Gruppo notify.ALL_DEVICES da utilizzare in multinotify per inviare una notifica a tutte le app
  - name: ALL_DEVICES
    platform: group
    services:
      - service: mobile_app_tel_henrik
      - service: mobile_app_smartphone_antonella

script:
  # Script di notifica centralizzato intelligente
  multinotify:
    alias: 'Notifica intelligente'
    description: 'Invia una notifica parametrica alle app/Alexa, potendo selezionare il volume e vari parametri opzionali'
    fields:
      title:
        description: 'Titolo della notifica'
        example: 'Avviso importante'
      message:
        description: 'Testo da notificare che verrà letto ed inviato come corpo della notifica'
        example: 'Un dispositivo non sta funzionando'
      alexa_message:
        description: 'Testo che Alexa dovrà pronunciare, se differente da message. Se non specificato verrà usato message.'
        example: '<say-as interpret-as="interjection">yippii</say-as>. Questo verrebbe male nelle notifiche dell''app!'
      alexa_target:
        description: 'Dispositivo o dispositivi Alexa a cui inviare la notifica'
        example: 'media_player.ovunque'
      alexa_volume_target:
        description: 'Singolo dispositivo Alexa a cui modificare il volume per la notifica'
        example: 'media_player.mansarda'
      alexa_volume:
        description: "Volume che si desidera impostare per l'annuncio su alexa_volume_target"
        example: "0.6"
      alexa_volume_restore:
        description: 'Se alexa_volume_target è impostato, se true o non specificato ripristina il volume precedente. Se false non ripristina il volume precedente'
        example: 'false'
      alexa_force:
        description: "True per forzare la notifica Alexa al di fuori dell'orario, False o non definita per riprodurre la notifica Alexa solo in orario consono"
        example: 'false'
      notify_app:
        description: "Il nome del servizio di notifica app o non compilare per non inviare notifiche all'app"
        example: 'notify.ALL_DEVICES'
      group:
        description: 'Stringa identificativa del gruppo di notifiche. Sul telefono le notifiche saranno raggruppate in base a questo valore. Se non specificato sarà usato channel o "info"'
        example: 'alarm'
      channel:
        description: 'Stringa identificativa del canale, ovvero il gruppo di notifiche con impostazioni a se stanti sul telefono. Se non specificato sarà usato group o "info"'
        example: 'Generic'
      icon:
        description: 'nome del file (senza percorso, senza notify_ e senza estensione) che deve essere usato da mostrare nella notifica. nell''esempio "warning" diventerà "/local/notify_warning.png". Se non specificato userà channel, group o "info"'
        example: 'warning'
      tag:
        description: "Campo tag della notifica ad app. Se impostato sul telefono l'eventuale notifica sarà sostituita alla seguente con tag uguale"
        example: 'fulmini'
      critical:
        description: 'impostare a "true" per inviare una notifica immediata. Se "false" o non specificata la notifica sarà riprodotta quando verrà sbloccato il telefono'
        example: 'true'
    sequence:
      # Sezione messaggio all'app
      - choose:
        - conditions:
            - condition: template
              value_template: "{{ notify_app is defined }}"
            - condition: template
              value_template: "{{critical}}"
          sequence:
            - service: '{{notify_app}}'
              data:
                title: "{{title | default('Notifica da casa')}}"
                message: "{{message}}"
                data:
                  group: "{{group | default(channel) | default('info')}}"
                  channel: "{{channel | default(group) | default('info')}}"
                  tag: "{{tag}}"
                  icon_url: "/local/notify_{{icon | default(channel) | default(group) | default('info')}}.png"
                  ttl: 0
                  priority: high
        - conditions:
          - condition: template
            value_template: "{{ notify_app is defined }}"
          sequence:
            - service: '{{notify_app}}'
              data:
                title: "{{title | default('Notifica da casa')}}"
                message: "{{message}}"
                data:
                  group: "{{group | default(channel) | default('info')}}"
                  channel: "{{channel | default(group) | default('info')}}"
                  tag: "{{tag}}"
                  icon_url: "/local/notify_{{icon | default(channel) | default(group) | default('info')}}.png"
          
      # Sezione messaggio Alexa      
      - choose:
          - conditions:
              - condition: or
                conditions:
                  - condition: template
                    value_template: "{{ alexa_force | default(false) }}"
                  - condition: time
                    after: '09:00:00'
                    before: '23:00:00'
            sequence:
              - choose:
                - conditions:
                    - condition: template
                      value_template: "{{ alexa_volume_target is defined}}"
                  sequence:
                    - service: input_number.set_value
                      data:
                        entity_id: input_number.alexa_prev_volume
                        value: "{{state_attr(alexa_volume_target, 'volume_level')}}"
                    - service: media_player.volume_set
                      data:
                        entity_id: "{{alexa_volume_target}}"
                        volume_level: "{{alexa_volume | default('0.6') | round(2)}}"
              - choose:
                  - conditions:
                      - condition: template
                        value_template: "{{ alexa_target is defined }}"
                    sequence:
                      - service: notify.alexa_media
                        data:  
                          message: "{{alexa_message | default(message)}}"
                          data:
                            method: all
                            type: announce
                          target: "{{alexa_target}}"
              - choose:
                - conditions:
                    - condition: template
                      value_template: "{{ alexa_volume_target is defined and (alexa_volume_restore is not defined or alexa_volume_restore == true)}}"
                  sequence:
                    - service: media_player.volume_set
                      data:
                        entity_id: "{{alexa_volume_target}}"
                        volume_level: "{{states('input_number.alexa_prev_volume') | round(2)}}"

Ora andiamo ad analizzare pezzo per pezzo lo script così da capire come funzionano le varie sue parti.

Input_number per il volume precedente

input_number:
  # Input number di servizio usato per memorizzare il volume precedente quando viene modificato per una notifica, così da ripristinarlo al termine della notifica
  alexa_prev_volume:
    name: Volume precedente di Alexa
    min: 0
    max: 1
    initial: 0.6
    mode: slider
    step: 0.1

Questo campo numerico, dichiarato all’inizio del package, non è da usare nell’interfaccia grafica ma viene usato internamente dallo script per “salvare” il valore del volume corrente di Alexa per poi modificarlo e infine ripristinarlo al precedente valore, presente appunto in questo campo.

Gruppo di notifica

notify:
  # Gruppo notify.ALL_DEVICES da utilizzare in multinotify per inviare una notifica a tutte le app
  - name: ALL_DEVICES
    platform: group
    services:
      - service: mobile_app_tel_henrik
      - service: mobile_app_smartphone_antonella

Questo codice definisce il gruppo di notifica notify.ALL_DEVICES utile per inviare le notifiche a tutte le app presenti nel gruppo.

Dichiarazione dello script con parametri opzionali di Home Assistant: multinotify

script:
  # Script di notifica centralizzato intelligente
  multinotify:
    alias: 'Notifica intelligente'
    description: 'Invia una notifica parametrica alle app/Alexa, potendo selezionare il volume e vari parametri opzionali'

Subito dopo il dominio script: viene specificato l’entity_id dello script, ovvero multinotify.
In seguito viene specificato l’alias, che viene mostrato come nome dello script nella sezione Impostazioni -> Script e il valore description, che descrive cosa fa lo script in strumenti per sviluppatori -> servizi quando usato in modalità interfaccia utente.

La dichiarazione dello script è preceduta da un commento che descrive cosa fa il blocco dichiarato in seguito, nello specifico lo script, come buona regola per la chiarezza del codice. Con qualunque editor che evidenzi la sintassi come VSCode, infatti, i commenti vengono mostrati in verde e “spezzano” visivamente il flusso di caratteri, permettendo una più rapida individuazione dell’inizio di ogni dichiarazione.
Ti consiglio vivamente di non tralasciare questi particolari “descrittivi” in quanto è vero che, se non dichiarati, non inficiano il corretto funzionamento dello script, ma ne aumentano notevolmente la leggibilità e la tua stessa comprensione quando tra tanto tempo tornerai a dover modificare questa sezione di file e non avrai più i particolari freschi in memoria.

Definizione dei parametri

    fields:
      title:
        description: 'Titolo della notifica'
        example: 'Avviso importante'
      message:
        description: 'Testo da notificare che verrà letto ed inviato come corpo della notifica'
        example: 'Un dispositivo non sta funzionando'
      ...........................
      critical:
        description: 'impostare a "true" per inviare una notifica immediata. Se "false" o non specificata la notifica sarà riprodotta quando verrà sbloccato il telefono'
        example: 'true'

Nella sezione fields: dichiariamo i campi da utilizzare. Basterebbe dichiararne i nomi come title: e message: per il corretto funzionamento ma, come consigliato nel paragrafo precedente, specifichiamo anche il valore description: ed example: che, in Strumenti per sviluppatori -> Servizi, ne definiscono rispettivamente la descrizione e un esempio concreto di utilizzo.
Questo ci aiuterà notevolmente sia durante le prove di utilizzo, sia dopo diverso tempo dalla stesura del codice, per ricordarci a cosa servono e come usare ogni parametro.

Parametri in Servizi - Strumenti per sviluppatori di Home Assistant
Interfaccia in Strumenti per sviluppatori -> Servizi, che ci aiuta a capire come funzionano i vari parametri

Nell’esecuzione dello script poi, per utilizzare i parametri dichiarati, basterà utilizzare il loro nome nei template.
Nella dissezione della sequenza di comandi vedremo inoltre come capire se il parametro è stato specificato o no e come utilizzare un valore di default in quest’ultimo caso.

Sequenza di comandi

Uno script non è nient’altro che una sequenza di comandi ordinata. Home Assistant parte dal primo e al termine dell’esecuzione di tale comando passa al secondo e così via fino al termine della sequenza.

Alcuni elementi specificabili nella sequenza permettono di avere sottoelementi ed effettuare quindi delle scelte, vedile come dei percorsi differenti, a seconda di una o più condizioni. Il principale elemento delle sequenze che permette questa ramificazione è choose: e lo vedremo in azione tra poco.
Per iniziare la sequenza di comandi da eseguire dello script si utilizza il seguente elemento:

sequence:
Notifiche alle app Home Assistant Companion
- choose:
  - conditions:
      - condition: template
        value_template: "{{ notify_app is defined }}"
      - condition: template
        value_template: "{{critical}}"
    sequence:
      - service: '{{notify_app}}'
        data:
          title: "{{title | default('Notifica da casa')}}"
          message: "{{message}}"
          data:
            group: "{{group | default(channel) | default('info')}}"
            channel: "{{channel | default(group) | default('info')}}"
            tag: "{{tag}}"
            icon_url: "/local/notify_{{icon | default(channel) | default(group) | default('info')}}.png"
            ttl: 0
            priority: high
  - conditions:
    - condition: template
      value_template: "{{ notify_app is defined }}"
    sequence:
      - service: '{{notify_app}}'
        data:
          title: "{{title | default('Notifica da casa')}}"
          message: "{{message}}"
          data:
            group: "{{group | default(channel) | default('info')}}"
            channel: "{{channel | default(group) | default('info')}}"
            tag: "{{tag}}"
            icon_url: "/local/notify_{{icon | default(channel) | default(group) | default('info')}}.png"
Il comando choose

Il primo comando della sequenza è un choose che divide l’esecuzione in due possibili vie a seconda che sia stato specificato critical: true (primo blocco) oppure critical: false o non specificato (secondo blocco). Questo è un workaround che non mi piace ma si rende necessario per richiamare il servizio di notifica all’app con i parametri ttl: 0 e priority: high oppure no in quanto nella documentazione ufficiale delle notifiche critical non è specificato il valore che debbano assumere tali parametri per le notifiche non critiche.

Il percorso di esecuzione varia in funzione delle condizioni espresse in conditions: se tutte le condizioni di tale sezione risultano vere viene allora eseguita la sequenza di comandi contenuta nella sezione sequence: relativa e, al termine, il percorso di esecuzione torna al comando successivo al choose (vedi documentazione)

Come testare se un parametro è stato specificato dal chiamante e valore di default

Nel caso specifico entrambi i blocchi di condizioni riportano come primo test una condizione uguale, ovvero value_template: "{{ notify_app is defined }}" che è il modo per testare se un parametro dello script (in questo caso notify_app) sia stato specificato oppure no. In un linguaggio di programmazione avrei inserito tutto in un IF esterno con questa condizione ma il comando choose richiede una forte indentazione che trovo crei molta confusione, soprattutto per comandi choose uno dentro l’altro che cerco quindi di evitare laddove possibile.

Le condizioni presenti nei due blocchi determinano quindi questa scelta:

  • La prima sequenza viene eseguita se il parametro notify_app è stato specificato dal chiamante e il parametro critical è true (va da sé che se il parametro critical non viene passato dal chiamante non assumerà il valore true e possiamo quindi capire che non passando tale parametro sarà equivalente e passarlo con valore false)
  • La seconda sequenza viene eseguita se il parametro notify_app è stato specificato dal chiamante senza ulteriori condizioni. In sostanza funziona da ELSE per la precedente esecuzione ovvero viene eseguito se il parametro critical non è stato passato o è stato passato false.
Service template

Nei due blocchi viene poi chiamato il servizio di notifica all’app o al gruppo di app sfruttando un template per specificare a quale app inviare la notifica, visto che ogni app espone un servizio distinto contenente il nome dell’app da richiamare. Questa tecnica si chiama service template, più informazioni nella documentazione.

Utilizzo dei parametri, di valori di fallback e di default

La differenza tra i due blocchi è soltanto la presenza o l’assenza dei parametri ttl: 0 e priority: high, analizziamo quindi il più breve tra i due per capirne il funzionamento specificamente nell’utilizzo dei parametri:

- service: '{{notify_app}}'
  data:
    title: "{{title | default('Notifica da casa')}}"
    message: "{{message}}"
    data:
      group: "{{group | default(channel) | default('info')}}"
      channel: "{{channel | default(group) | default('info')}}"
      tag: "{{tag}}"
      icon_url: "/local/notify_{{icon | default(channel) | default(group) | default('info')}}.png"

Il titolo, specificato in questo modo title: "{{title | default('Notifica da casa')}}" verrà valorizzato con il valore del parametro dello script title passato dal chiamante oppure, tramite il filtro default (vedi documentazione) che si concatena tramite il carattere pipe “|” (vedi documentazione), il valore di default “Notifica da casa” che sarà quindi usato quando non viene passato alcun valore al parametro title.

Al parametro message sarà semplicemente assegnato il contenuto del parametro dello script message in quanto sappiamo che questo è l’unico parametro obbligatorio (non avrebbe senso chiamare una notifica senza messaggio…)

Nei parametri group, channel e icon_url sono usati più filtri default concatenati tra loro. Analizziamo per tutti il significato del parametro group:

group: "{{group | default(channel) | default('info')}}"

Il valore che assumerà questo parametro sarà quindi corrispondente al parametro dello script group.
Oppure, qualora group non sia stato specificato, al parametro dello script channel.
O infine, qualora non sia stato specificato il valore né di group né di channel, assumerà un valore di default fissoinfo“.

Con questa tecnica, quando richiamiamo lo script, possiamo specificare solo uno di questi parametri per impostarli tutti e tre al medesimo valore oppure specificarli tutti per specificare valori diversi. In questo modo avremo la possibilità di scrivere meno codice quando dovremo richiamare notifiche semplici nelle nostre automazioni.

Notifiche tramite Alexa

A questo punto verranno processate le notifiche agli assistenti vocali Alexa, se specificati.

Condizione oraria o parametro di forzatura

Questa sezione è tutta contenuta in uno choose:

- choose:
    - conditions:
        - condition: or
          conditions:
            - condition: template
              value_template: "{{ alexa_force | default(false)}}"
            - condition: time
              after: '09:00:00'
              before: '23:00:00'
      sequence:
        ......

In sostanza vengono poste due condizioni in OR: se è stato specificato il parametro alexa_force = true oppure se l’orare è dopo le 9:00 e prima delle 23:00.

Lo stesso scopo avrei potuto raggiungerlo con un semplice comando condition contenente le medesime valutazioni ma la differenza sostanziale è che con choose se le condizioni non sono rispettate l’esecuzione di eventuali ulteriori comandi che seguono il blocco choose continueranno normalmente. Usando condition, invece, se la condizione non è rispettata l’esecuzione di tutto lo script/automazione termina completamente.

Ma in seguito non ci sono ulteriori istruzioni, mi si potrebbe obiettare. Vero, ma preferisco prevedere che in futuro potrei voler aggiungere delle ulteriori operazioni in coda e se avessi usato condition, prima delle 9:00 o dopo le 23:00, non verrebbero eseguite nemmeno loro e magari passerei del tempo a cercare di capire come mai.

Gestione del volume con ripristino del volume precedente

Superata la condizione oraria vista precedentemente abbiamo di nuovo un comando choose:

- choose:
  - conditions:
      - condition: template
        value_template: "{{ alexa_volume_target is defined}}"
    sequence:
      - service: input_number.set_value
        data:
          entity_id: input_number.alexa_prev_volume
          value: "{{state_attr(alexa_volume_target, 'volume_level')}}"
      - service: media_player.volume_set
        data:
          entity_id: "{{alexa_volume_target}}"
          volume_level: "{{alexa_volume | default('0.6') | round(2)}}"

La condizione dice “se il parametro alexa_volume_target è stato specificato dal chiamante” allora esegui quelle due operazioni:

  • Scrive, tramite il servizio input_number.set_value, il valore del volume corrente del dispositivo Alexa specificato in alexa_volume_target nell’input_number alexa_prev_volume, dichiarato all’inizio del package. Questo ci servirà dopo l’annuncio per ripristinare il volume precedente.
  • Allo stesso dispositivo specificato tramite il parametro alexa_volume_target, Imposta il volume passato dal chiamante tramite il parametro alexa_volume oppure, se non specificato, il valore di default 0.6 (ricordate l’utilizzo del filtro default, visto in precedenza?)
    Inoltre il valore così generato viene ulteriormente elaborato tramite il filtro round(2) che arrotonda il valore a massimo due decimali, per evitare di passare ad Alexa un volume come 0,6666666666666666.
Ad oggi, purtroppo, capita che l’integrazione alexa_media_player smetta di ricevere gli aggiornamenti dal sistema Alexa. Quando ciò accade non viene aggiornato il volume, pertanto il ripristino del volume precedente non funzionerà. In tale situazione un riavvio di Home Assistant generalmente risolve la situazione.
Riproduzione del messaggio tramite Alexa

A questo punto, impostato l’eventuale volume, siamo pronti per riprodurre il tanto agognato messaggio tramite il seguente codice:

- choose:
    - conditions:
        - condition: template
          value_template: "{{ alexa_target is defined }}"
      sequence:
        - service: notify.alexa_media
          data:  
            message: "{{alexa_message | default(message)}}"
            data:
              method: all
              type: announce
            target: "{{alexa_target}}"

Ancora una volta il blocco è incluso in un comando choose che esegue la sequenza solo se il parametro alexa_target è definito, ovvero se è stato specificato almeno un dispositivo Alexa a cui inviare la notifica.

La sequenza è composta semplicemente dal servizio notify.alexa_media che riproduce il caratteristico suono seguito dalla lettura vocale del messaggio specificato in alexa_message: o, se non passato, in message: nei dispositivi specificati da target: (che accetta un singolo dispositivo oppure un elenco, come specificato sopra)

Ripristino del volume precedente

Non resta ora che ripristinare il volume precedente del dispositivo Alexa specificato:

- choose:
  - conditions:
      - condition: template
        value_template: "{{ alexa_volume_target is defined and (alexa_volume_restore is not defined or alexa_volume_restore == true)}}"
    sequence:
      - service: media_player.volume_set
        data:
          entity_id: "{{alexa_volume_target}}"
          volume_level: "{{states('input_number.alexa_prev_volume') | round(2)}}"

La condizione è un po’ più complessa e sostanzialmente viene tradotta così: procedi solo se alexa_volume_target è stato passato dal chiamante e (alexa_volume_restore non è stato specificato oppure è stato specificato con valore true).

In questo modo diamo ad alexa_volume_restore il valore di default true in quanto, se il parametro non verrà specificato dal chiamante, avverrà la stessa condizione di quando verrà specificato true.
La stessa condizione poteva essere espressa anche come {{ alexa_volume_target is defined and alexa_volume_restore | default(true) }} è anche utile mostrare modi diversi di fare le stesse cose.

Se la condizione è rispettata verrà semplicemente richiamato il servizio media_player.volume_set passandogli l’entity_id definito nel parametro alexa_volume_target e il volume precedentemente salvato nell’input_number di appoggio chiamato alexa_prev_volume, per sicurezza sempre arrotondando a due decimali tramite il filtro round(2).

Conclusione

Abbiamo visto come creare uno script con parametri opzionali in Home Assistant, che accetti parametri che possono essere specificati oppure no e in tal caso come gestire i loro valori di default. Abbiamo anche imparato come usare il potente comando choose per determinare percorsi di codice differenti in base a delle condizioni.

Ora non resta che adattare il contenuto dello script alle tue esigenze o utilizzarlo così com’è (cambiando però i nomi dei dispositivi del gruppo ALL_DEVICES) se usi Alexa e app companion come me.

Spero che questo articolo abbia potuto far comprendere alcune tecniche utili in script e automazioni anche di tipo differente, sebbene non sia entrata nel dettaglio dei singoli comandi che invece consiglio sempre di consultare sulla guida ufficiale di Home Assistant.

Approfondimenti e link

Se vuoi ulteriore materiale che può esserti molto utile nel contesto di questo articolo ti consiglio le seguenti letture:

Ti va di darmi una mano?

Il contenuto di questo sito è completamente gratuito senza pubblicità invasive e il fine non è certo guadagnare …ma mantenere un sito ha un costo. Se ti va di darmi una mano per sostenere le spese o ti va di sostenere questo progetto hai le seguenti modalità:


  • Donazione con Paypal:

  • Regalami un caffè su Buymeacoffee:


  • Effettua i tuoi acquisti Amazon a partire da QUESTO LINK (o tramite i prodotti sotto)

  • Effettuare i tuoi acquisti AliExpress usando QUESTO LINK

Henrik Sozzi

Sono un analista programmatore per lavoro e per passione. Amo la domotica, la stampa 3D e la tecnologia in generale. Mastodon: @pixel

Questo articolo ha 15 commenti

  1. Alessandro Terrusso

    Ciao Henrik, arrivo un filo in ritardo ma preferivo guardarmelo bene. Preziosissimo lo script, ma ancora più prezioso ritengo il modo in cui l’hai spiegato e il ventaglio di possibilità di riutilizzo. Il passaggio variabili rende gli script uno strumento potentissimo e ad essere onesto me ne sono reso conto SOLO grazie a questo articolo. In quest’ottica anche i filtri default e defined iniziano a trovare la loro utilità 😀 Complimenti davvero e GRAZIE!!!!!

  2. Giuseppe

    Complimenti per il lavoro svolto ho un problema con la riproduzione con alexa tramite app funziona correttamente

    1. Henrik Sozzi

      Grazie! Ti consiglio di esporre il problema in modo dettagliato sul gruppo Facebook Home Assistant Italia (dove ci sono anch’io), troverai tante persone competenti e tra tutti è più probabile avere l’illuminazione giusta

  3. Andrea Santinelli

    Ciao Henrik! Ti porgo una domanda anche qui! E’ possibile eseguire uno script ciclicamente senza condizionamento? Spiego meglio. Devo generare un segnale di heartbeat per il PLC a cui è connesso HA. In pratica scrivo 1 su uno switch, aspetto 2 secondi poi scrivo 0 ed aspetto altri 2 secondi. Finita la sequenza deve ripartire in autonomia, senza che io chieda un riavvio così da generare un clock con periodo 4 secondi. E’ possibile?? Grazie.

    1. Henrik Sozzi

      Ciao Andrea, ti stai leggendo tutti i miei articoli? 🙂 Ne sono contento! Si, è possibile, guarda qui!
      Se ‘ un heartbeat puoi usare come trigger l’avvio di Home Assistant, nessuna condizione e un loop infinito.
      Diciamo che certamente funzionerebbe ma come approccio personalmente mi piace poco. Preferirei usare un timer, farlo partire all’avvio di Home Assistant e allo scadere dello stesso negare l’out dell’heartbeat e riarmare il timer. In tal modo non hai uno script perennemente in esecuzione. Ma sono dettagli.

  4. Massimo

    Ciao Henrik è possibile creare una notifica “rumorosa” tipo allarme che possa svegliarmi eventualmente di notte
    perché la semplice notifica è troppo silenziosa. Grazie di tutto.

    1. Henrik Sozzi

      Con Alexa? Puoi solo riprodurre una serie di suoni predefiniti, puoi vedere se tra quelli al massimo volume ti svegli 😉 Se poi hai il sonno super duro ti toccherà ricorrere ad una sirena ZigBee da interno… 😜

  5. daniele

    Buongiorno Henrik, guida bellissima per chi incomincia a masticare qualcosina in più di HA. Dopo due anni anch’io sento la necessità di non lasciare codice ripetuto e riscritto in ogni dove. Volevo chiederti se non c’è la possibilità di usare la variabile ‘!include’ usata nel file configuration anche in altre parti di HA, per richiamare un file/ o pezzo di codice. Ad esempio ho scritto questo template per controllare le finestre aperte quando esco:

    ——————-(pezzo di azione di una automazione)
    – service: script.my_notify
    data:
    title: ‘*| controllo finestre *’
    message: >-
    stai per uscire? ti ricordo che hai lasciato
    {{ ‘la finestra sala aperta’ if states(‘binary_sensor………..’) == ‘on’ else ” }}
    {{ ‘la finestra studio aperta’ if states(‘binary_sensor………….’) == ‘on’ else ” }}
    {{ ‘la finestra lavanderia aperta’ if states(‘binary_sensor…………….’) == ‘on’ else ” }}
    {{ ‘la finestra bagno aperta’ if states(‘binary_sensor………….’) == ‘on’ else ” }}
    {{ ‘la finestra cucina aperta’ if states(‘binary_sensor……………….’) == ‘on’ else ” }}
    {{ ‘la finestra camera aperta’ if states(‘binary_sensor………………..’) == ‘on’ else” }}
    alexa: true
    ————————————-

    Vorrei sapere se questo pezzettino di template può essere scritto in un ‘file’ e richiamato in “message:>-” con una ‘variante’ tipo !include. (perdona la mia approssimazione tecnico-linguistica ma sono solo un gran maneggione, sorry).

    1. Henrik Sozzi

      Ciao, scusa per il ritardo nella risposta, sono stato all’estero e impegnatissimo al lavoro 🙁
      Sono contento che hai apprezzato e capisco bene la necessità, da programmatore è un must… 😉
      Anch’io ho cercato di inserire in file i messaggi per le notifiche ma, ti deluderò, non ci sono riuscito come avrei voluto io (con !include). C’è chi ha usato !secret ma non mi piace l’approccio.
      So che c’è chi ha usato !include per fare sta cosa quindi sicuramente è possibile ma personalmente non ci ho provato più di tanto e ho perso l’interesse.
      Un appunto: …e se lasci aperte due finestre quando esci? Non sarebbe meglio usare un template che compone tutte le finestre aperte tipo il seguente (avendo definito un gruppo con entity_id “finestre”)?
      {{ expand(states.binary_sensor.finestre) | selectattr('state', 'eq', 'on') | list | map(attribute='name') | list | join(', ') }}
      Altra cosa, per le notifiche hai provato a vedere il multinotify che ho su github? 🙂

Rispondi

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