Abbiamo visto nel post dedicato quali sono i passi per installare Home Assistant Core su un Raspberry PI, che è solo una delle diverse combinazioni di ambiente e piattaforma con cui possiamo mettere in piedi il nostro hub di domotica personale. Ma quali sono i passi successivi?

Certamente, quello che succederà dopo è che andremo ad integrare i dispositivi intelligenti con i quali automatizzare la nostra casa, come interruttori, prese, lampadine ed ogni altra sorta di attuatore smart: ciascuno dei dispositivi integrato darà vita ad una o più entità. Da questi dispositivi, raccoglieremo tutte le informazioni, circa lo stato operativo, in altrettanti sensori. E ancora, costruiremo le automazioni con cui tali dispositivi soddisferanno le nostre esigenze, ma anche le scene, ovvero le combinazioni di stati ed azioni rispondenti alla situazioni di vita più disparate.

Quello che dunque accadrà è che, al crescere del numero di integrazioni, il nostro hub diventerà più corposo ed il numero di file con cui è implementata la configurazione crescerà enormemente. Inoltre anche la parte di frontend crescerà: per ciascun aspetto che vogliamo gestire, ci saranno uno o più dashboard ci monitoraggio e controllo.

Cosa vogliamo fare

Risulta quindi chiaro quale sia l’unico approccio da perseguire per avere tutto sotto controllo ed evitare proliferare confuso e dispersivo di file. “Divide et impera”.

L’obiettivo di questo post è, dunque, raccontare un modo per organizzare i file di configurazione in modo ordinato, a partire dalla linea guida ufficiale.

Nella cartella di configurazione andremo a creare tante cartelle per contenere le varie tessere del nostro grande puzzle:

  • automations per le automazioni raggruppate per ambito
  • blueprints per i modelli (come da documentazione)
  • configurations per tutti i file di integrazioni da includere
  • lovelace-views con i le implementazioni delle viste in dashboard
  • packages per i file package
  • sensors con tutti i sensori raggruppati per ambito

Inclusione di file e cartelle

Per perseguire il nostro obiettivo useremo i comandi di inclusione:

  • !include lavora su un singolo file yaml. Non funziona ricorsivamente.
  • !include_dir_list come i seguenti, lavora su una cartella di file yaml, dove ogni file è una voce di elenco (ad esempio una automation). Le voci saranno ordinate secondo l’ordine alfanumerico dei nomi dei rispettivi file
  • !include_dir_merge_list crea una unica grande lista con le singole liste di ciascun file nella cartella
  • !include_dir_named legge da una cartella file contenenti singole voci di un unico dizionario
  • !include_dir_merge_named legge da ua cartella file contenenti elenchi di dizionari e li unisce

Ecco alcuni esempi che vedremo più avanti:

homeassistant:
  ...
  packages: !include_dir_named packages
  customize: !include configurations/customize.yaml
  ...
automation: !include_dir_merge_list automations
...

Il file configuration.yaml

Immaginiamo di avere una piccola dispensa nella quale conserviamo ogni bene indispensabile per la nostra alimentazione. Supponiamo di accumulare il contenuto di questa dispensa senza alcuna razionalità: apro, ripongo nel primo spazio disponibile, chiudo la dispensa. Dopo un po' non avremo più la minima idea di cosa abbiamo conservato e trovarlo sarà impossibile, compreremo cose che già abbiamo e ne trascureremo altre che pemsavamo di avere.

La dispensa di Home Assistant è il file configuration.yaml. Questo contiene appunto tutte le configurazioni necessarie per il corretto funzionamento dei componenti e delle integrazioni. Qualsivoglia funzionalità è attivata e configurata dentro questo file. Ammucchiare in questo file ogni singola riga di codice utile ai nostri scopi sarebbe una un grosso errore: il risultato sarebbe un enorme file ingestibile. Viceversa, la chiave per una efficace gestione della configurazione è l’organizzazione capillare di questo file.

Il file secret.yaml

Prima di continuare, facciamo un breve cenno ad un aspetto inizialmente trascurato da tutti: le informazioni sensibili. La configurazione dei componenti e delle integrazioni richiede, quasi sempre, di specificare parametri sensibili, come ad esempio le coordinate della propria casa, username e password delle integrazioni, token di accesso, indirizzi internet o di macchina. Home Assistant ci mette a disposizione un semplice meccanismo per separare queste informazioni in un file esterno secrets.yaml e richiamarle all’occorrenza, come spiegato nella (documentazione ufficiale)[https://www.home-assistant.io/docs/configuration/secrets/].

Ad esempio, per l’integrazione Tado abbiamo nel configuration.yaml:

tado:
  username: !secret tado_key
  password: !secret tado_pwd

E nel file secrets.yaml indichiamo:

tado_key: my.user@email.com
tado_pwd: my.pswd.123

In questo modo, escludendo il file secrets.yaml, potremo anche condividere la nostra configurazione senza temere la diffusione di dati sensibili.

Configurazione base

Partiamo con la compilazione del file configuration.yaml, che troviamo nella cartella ~/.homeassistant della nostra installazione Core oppure nella cartella /config di Home Assistant, come da documentazione ufficiale.

In testa al file di norma si aggiungono le informazioni di base, opportunamente nascoste:

  • name: il nome dell’istanza
  • latitude, longitude, elevation: coordinate del punto geografico in cui si trova la casa
  • unit_system: sistema di unità di misura, nel nostro caso sistema metrico
  • time_zone: indicazione del fuso orario, per noi Roma
  • internal_url, external_url: URL interno e/o esterno dell’istanza
  • packages: per attivare la preziosa funzionalità spiegata qui
  • customize: per le customizzazioni delle entità
  • allowlist_external_dirs: le cartelle esterne a cui HA può accedere
# Setup basic information
homeassistant:
  name: SmartHome
  latitude: !secret latitude
  longitude: !secret longitude
  elevation: !secret elevation
  unit_system: metric
  time_zone: Europe/Rome
  packages: !include_dir_named packages
  customize: !include configurations/customize.yaml
  allowlist_external_dirs:
    - /home/homeassistant/.homeassistant/snapshot
    - /home/homeassistant/.homeassistant/www/snapshot

Procediamo poi con alcune integrazioni che offrono funzionalità basilari per l’utilizzo efficace del nostro hub.

Integrazione logger

Il logger: consente di definire il livello di log-severity (la verbosità) per ciascun componente. La regolazione di questo livello ci consente di entrare in profindità in caso di problemi ed avere un dettaglio maggiore per la nostra analisi causa-effetto. I livelli di log possibili sono:

  • critical, fatal, error sono meno parlanti, con messaggi log solo in casi di problemi seri
  • warning, warn includono messaggi di avvertimento, anche se il funzionamento non è pregiudicato
  • info, debug (default) sono più parlanti

Nel mio caso, ho innalzato il livello default dei log, essendo in una situazione ormai stabile, mentre per alcuni componenti critici ho impostato un valore basso per avere più informazioni:

logger:
  default: error
  logs:
    recorder: warning
    custom_components.sonoff: debug
    custom_components.switch.sonoff: debug

Queste impostazioni possono essere cambiate a runtime mediante i servizi logger.set_default_level e logger.set_level.

Storicizzazione dei dati: recorder e history

Tutti i dati raccolti ed elaborati da Home Assistant possono, in alcuni casi devono, essere storicizzati su un database per poter essere, ad esempio, trendizzati efficacemente in interfaccia. Il database nativo è un SQLite, ma sono tante le soluzioni possibili, come spiegato nella guida ufficiale.

Quello che ci interessa come configurazione base, quindi usando il database standard, è come settare i parametri che influiscono sulla disponibilità dei dati raccolti, sia in termini di tempo (retention), sia in termini di informazioni storicizzate. In particolare:

  • purge_keep_days (default: 10) è il tempo in giorni di conservanzione dei dati raccolti (retention). Oltre questo numero di giorni, le informazioni più vecchie vengono cancellate (purge) e per fare spazio alle nuove più recenti
  • commit_interval (default: 1) è il periodo in secondi tra le operazioni effettive di salvataggio sul database (commit). Alzare questo valore consente di avere un numero minore di scritture e di proteggere il supporto (ad esempio scheda micro SD del Raspi), ma introduce ovviamente dei ritardi nell’elaborazione dei dati e nei conseguenti eventi.

Ben più critica è la scelta di cosa storicizzare, avendo un impatto diretto sulle dimensioni, dunque la sostenibilità, del database, in particolare nel caso del SQLite, il cui database è un unico file (home-assistant_v2.db nella cartella di configurazione).

Per gestire questa selezione, è comodo utilizzare un file esterno nel quale configurare i filtri. Questa soluzione consente di riutilizzare i medesimi filtri anche per l’integrazione history. Quest’ultimo ha il compito di tracciare tutto quello che accade in Home Assistant e di fornire all’utente la possibilità di navigare i dati raccolti. Risulta evidente come non si possano navigare dati che non sono stati inclusi nel recorder.

Dunque avremo nel configuration.yaml:

#Storicizzazione in database 
recorder:
  purge_keep_days: 8
  commit_interval: 2
  include: !include configurations/recorder_include.yaml
history:
  include: !include configurations/recorder_include.yaml

E nel file che chiamiamo recorder-include.yaml ad esempio:

  domains:
    - climate
  entities:
    # tracker
    - device_tracker.giuseppe
    ...
    # consumi condizionatori
    - sensor.clima_cucina_kwh
    ...
    # climates sensors
    - sensor.cucina_temperature
    - sensor.cucina_heating
    ...

Il registro eventi invece, consente di visualizzare tutti gli eventi che occorrono, per le entità incluse nell’apposito filtro, in rodine cronologico inverso. Questo è utile per realizzare card di riepilogo, ad esempio, delle automazioni o dei cambi stato delle entità critiche.

logbook:
  include:
    domains:
      - automation
      - climate

Altre integrazioni

Le integrazioni più numerose sono quelle anche più comuni. Sicuramente se abbiamo una casa intelligente avremo un numero non trascurabile di entità relative all’illuminazione, agli accessi, alla video-sorveglianza. E ancora, avremo sicuramente numerosi sensori, script ed automazioni con cui la nostra casa risponde alle nostre richieste e si adegua autonomamente alle varie situazioni.

Per evitare di ammucchiare tutto in un unico grande file, dedichiamo semplicemente a ciascuno di questi domini (ovvero domain come sono chiamati nel gergo di HA) un appostio file o una apposta cartella con tanti file. Il tutto mediante le semplici direttive di inclusione viste prima:

# Automazioni
automation: !include_dir_merge_list automations
# Telecamere 
camera: !include configurations/camera.yaml
# Tapparelle
cover: !include configurations/cover.yaml
# Selettori e filtri
input_select: !include configurations/input_select.yaml 
# Luci
light: !include configurations/light.yaml
# Dispositivi multimediali
media_player: !include configurations/media_player.yaml
# Notifiche
notify: !include configurations/notification.yaml
# Script
script: !include configurations/script.yaml
# Sensori
sensor: !include_dir_merge_list sensors

E poi, ad esempio, nel file cover.yaml l’elenco delle entità di quel dominio:

  - platform: mqtt
    device_class: shutter
    name: "Finestra cucina"
    command_topic: "shellies/shellyswitch25-123456/roller/0/command"
    position_topic: "shellies/shellyswitch25-123456/roller/0/pos"
    set_position_topic: "shellies/shellyswitch25-123456/roller/0/command/pos" 
    payload_open: "open"
    payload_close: "close"
    payload_stop: "stop"
    value_template: '{{ value }}' 

  - platform: mqtt
    device_class: shutter
    name: "Balcone cucina"
    ...

I package

Un ulteriore modo molto efficace per snellire e strutturare la configurazione è senza dubbio l’utilizzo dei packages. Pur utilizzando l’approccio descritto nei paragrafi precedenti, infatti, se il numero di integrazioni e, soprattutto, di entità per tipologia di integrazione è importante, avere la configurazione divisa su più file può risultare dispersivo. Ci viene quindi in aiuto questa importante funzione.

Un package è un file yaml che contiene interamente la configurazione di una porzione di Home Assistant, ovvero una singola funzionalità nella sua interezza, come potrebbe essere ad esempio il controllo dei consumi o la gestione degli stream musicali. In questo modo, in un unico file, si gestiscono tutte le integrazioni inerenti un certo ambito, con grande guadagno in termini di leggibilità e manutenibilità del codice.

Questa funzionalità va configurata, come già visto in precedenza, indicando la cartella in cui Home Assistant dovrà cercare i package implementati. Il tutto mediante la seguente direttiva:

homeassistant:
  ...
  packages: !include_dir_named packages # Abilita i packages

Mentre la struttura di un package somiglierà ad un piccolo configuration.yaml con tutte le sue sezioni:

homeassistant:
  customize:
    sensor.studio_desk_w:
      friendly_name: Studio Desk   
      icon: mdi:desk    

sensor:
  - platform: mqtt
    name: studio_desk_w
    state_topic: "shellies/shellyplug-s-123456/relay/0/power"
    unit_of_measurement: 'W'
    force_update: true
  - platform: integration
    source: sensor.studio_desk_w
    name: studio_desk_kWh
    unit_prefix: k
    unit_time: h
    method: left   
    
utility_meter:   
  studio_desk_energy_day:
    source: sensor.studio_desk_kWh
    cycle: daily 

script:
  ...
  
automation:
  ...

I file di lovelace

Particolare menzione va fatta anche alla gestione delle dashboard di interfaccia che possiamo potenzialmente definire.

Nota Come avrete capito, scrivere il codice yaml ci piace. La gestione delle dahboard Lovelace è qualcosa che, potenzialmente, può essere fatto interamente tramite UI. Tuttavia, se si vuole sfruttare pienamente la potenza delle varie card ed al contempo tenere tutto sotto controllo ed anche fare dei backup, la modalità manuale è consigliata.

Come da documentazione ufficiale dichiariamo nel nostro configuration.yaml che vogliamo utilizzare la modalità YAML per la nostra interfaccia. Per questo, nella cartella di configurazione creiamo il file ui-lovelace.yaml ed configuriamo la sezione:

  lovelace:
    mode: yaml
    resources: !include configurations/ui-lovelace-resource.yaml

Nella riga resources indichiamo tutte le risorse da caricare per usare Lovelace, ovveo tutte i moduli .js oppure i fogli di stile .css che intendiamo utilizzare nelle varie dashboard. Sempre seguendo l’approccio presentato in questo post, considerando la lunga lista di risorse da dichiarare in questa sezione, utilizziamo un file esterno incluso mediante apposita direttiva.

Possiamo definire anche dashboard multiple: per farlo, creiamo nella cartella di configurazione tanti file che richiamiamo nella definizione delle rispettive dashboard:

  # Nel nodo lovelace:
    dashboards:
      lovelace-advanced: # Needs to contain a hyphen (-)
        mode: yaml
        filename: ui-lovelace-advanced.yaml
        title: Avanzato
        icon: mdi:alert
      lovelace-mobile: # Needs to contain a hyphen (-)
        mode: yaml
        filename: ui-lovelace-mobile.yaml
        ...

Ciascun file ui-lovelace-* conterrà la definizione della dashboard, ovvero le pagine (views nel gergo di HA) che la compongono.

views:
  - !include lovelace-views/view_home.yaml
  - !include lovelace-views/view_covers.yaml
  - !include lovelace-views/view_lights.yaml
  ...

Ancora una volta, usiamo le direttive !include per distribure opportunamente il codice in tanti file di più facile lettura e gestione. Ogni file implementa una pagina, con tutte le card che la compongono, definendo, di fatto, le modalità di interazione tra l’utente e Home Assistant.

  title: Automations panel
  path: automations  
  icon: 'mdi:cogs'
  panel: true  
  badges: []
  cards:
    ...

Risultato finale

In definitiva, organizzare nella modalità presentata la configurazione di Home Assistant è un lavoro certosino e ricco di insidie. Personalmente, prima di arrivare a questo livello di organizzazione, sono passato per numerose revisioni del mio codice e della mia distribuzione in file e cartelle.

Avere già in mente un criterio ed impostarlo dall’inizio può essere invece un grande vantaggio. Anche se si hanno poche integrazioni, cominciare a organizzare le cose in modo razionale ci farà avere automaticamente in ordine la configurazione quando questa inevitabilmente crescerà.

Un ultimo consiglio: nella scelta dei nomi delle cartelle, dei file e perfino delle entità, usare un criterio preciso, una naming convention rigida e parlante, aumenterà enormemente il livello della gestibilità della soluzione implementata.

└── .homeassistant
    ├── automations
    │   ├── auto_climate.yaml
    │   ├── auto_cover.yaml
    │   ├── auto_light.yaml    
    │   └── auto_music.yaml
    ├── configurations
    │   ├── cover.yaml
    │   ├── light.yaml
    │   ├── recorder-include.yaml
    │   ├── script.yaml
    │   └── ui-lovelace-resource.yaml
    ├── lovelace-views
    │   ├── mobile
    │   │   ├── view_home.yaml
    │   │   └── view_light.yaml
    │   ├── view_cover.yaml
    │   ├── view_home.yaml
    │   └── view_light.yaml
    ├── packages
    │   ├── pkg_climate.yaml
    │   ├── pkg_energy_monitor.yaml
    │   └── pkg_music_player.yaml
    ├── sensors
    │   ├── sensor_climate.yaml
    │   ├── sensor_cover.yaml
    │   └── sensor_light.yaml
    ├── configuration.yaml
    ├── ui-lovelace.yaml
    └── ui-lovelace-mobile.yaml

Enjoy!