Creare un temporizzatore per sistemi clima su Home Assistant

SCOPI DEL PROGETTO:
  • Creare un temporizzatore per pianificare l’attivazione di un termostato integrato con Home Assistant
  • Livello di difficoltàmedio/basso
  • Costo: nullo
CONCETTI AFFRONTATI:
  • Configurazione software
COMPONENTI SOFTWARE UTILIZZATE:
PREREQUISITI:
DISPOSITIVI FISICI UTILIZZATI:
GUIDA maggiormente indicatA per:

Tutti gli ambienti

Note e disclaimer
  • qualsiasi modifica all'impianto elettrico dev'essere effettuata da personale qualificato
  • qualsiasi modifica attuata in proprio è a propria responsabilità personale nonché a proprio rischio e pericolo (la presente guida ha puro scopo didattico)
  • qualsiasi modifica attuata in proprio a un dispositivo ne fa decadere la garanzia.

Abstract

Uno dei più grossi ed evidenti limiti del componente “Climate” – a quale fanno capo tutte le piattaforme dedicate all’integrazione di termostati e più genericamente di sistemi regolazione clima disponibili su Home Assistant – è l’assenza di uno scheduler, ovvero di un temporizzatore che permetta alle entità di questo tipo (sia dedicate alla gestione del riscaldamento che del raffrescamento) di accendersi/spegnersi non solo in relazione alla temperatura, ma anche a specifiche fasce orarie giornaliere/settimanali.

Termostato frontale
un termostato-temporizzatore.

In attesa che Home Assistant si evolva in tal senso provvederemo allo scopo, tramite questo progetto, implementando il componete “Python Scripts“, il quale genera una o più entità di tipo servizio a partire da script scritti in linguaggio Python. Tali script possono personalizzare il comportamento di Home Assistant: in questo caso li sfrutteremo, appunto, per creare un temporizzatore.

Per attivare l’entità “Climate” lo script proposto nel progetto utilizza una logica semplice, ovvero quella di variare la temperatura “target” del termostato in base al giorno e l’ora. Il comportamento del termostato, al variare della temperatura target, sarà ovviamente quello ordinario (attiva l’impianto in base al confronto con la temperatura dell’ambiente).

Creeremo quindi anche due entità “Input Number” atte alla “raccolta” di due temperature “target”:

  • per impianti di riscaldamento, quella alta (target di riscaldamento ordinario) e quella di soglia bassa (temperatura minima da garantire sempre, a prescindere – a volte nota come “temperatura ECO”);
  • per impianti di raffrescamento (condizionatori), quella di soglia alta (temperatura massima da garantire sempre, a prescindere) e quella bassa (target di raffreddamento ordinario).

Python Scripts

Come anticipato, il componente “Python Scripts” serve per definire delle entità che, se evocate (come servizio), eseguano degli script scritti in Python.

Per attivare questo componente è necessario creare una cartella chiamata:

python_scripts/

all’interno della cartella principale di Home Assistant (su Raspbian, “/home/homeassistant/.homeassistant“); in seguito, modificare la configurazione inserendo:

python_scripts:

e infine riavviare Home Assistant. Il riavvio dev’essere effettuato anche ad ogni eventuale aggiunta di script (sotto forma di file di testo con estensione “.py”) all’interno della cartella di cui sopra; al riavvio, una nuova entità chiamata “python_scripts.nomedelfile” apparirà nell’elenco dei servizi presenti su Home Assistant.

Assunti

Daremo per scontata l’esistenza di un’entità di tipo “Climate” chiamata “climate.termostato“, nonché della presenza di una lettura di temperatura ambientale, a scelta tra:

  • l’attributo “temperature” dell’entità “climate.termostato“;
  • un sensore “sensor.temperature“.

Alcune piattaforme di integrazione figlie del componente “Climate”, infatti, generano entità prive dell’attributo “temperature“, il che obbliga a censire il dato direttamente da un’altra entità.

Temperature target

Definiamo in configurazione due “Input Number” allo scopo di raccogliere da frontend le due temperature target:

input_number:
  temp_high:
    name: Target alto
    min: 0
    max: 30
    step: 1
  temp_low:
    name: Target basso
    min: 0
    max: 30
    step: 1

Le due entità (“input_number.temp_high” e “input_number.temp_low“) verranno utilizzate dallo script Python per valutare come regolare dinamicamente l’entità “climate.termostato“.

Script

Dopo aver attivato il componente “Python Script“, creiamo presso la cartella dedicata agli script un nuovo file chiamato “scheduler.py” contenente il seguente codice:

TEMP_HIGH = hass.states.get('input_number.temp_high')
TEMP_LOW = hass.states.get('input_number.temp_low')
climate_entity = 'climate.termostato' # definisce l'entità "Climate" da controllare
current_temp = hass.states.get(climate_entity).attributes['temperature']
# current_temp =  float(hass.states.get('sensor.temperature'))

WEEK_SCHEDULE = [
    [datetime.time( 0, 0), datetime.time( 1, 0)],     # dalle 00:00 alle 01:00
    [datetime.time( 7, 0), datetime.time( 9, 0)],     # dalle 07:00 alle 09:00
    [datetime.time(18, 0), datetime.time(23, 59, 59)] # dalle 18:00 alle 23:59
]
WEEKEND_SCHEDULE = [
    [datetime.time( 0, 0), datetime.time( 2, 0)],     # dalle 00:00 alle 01:00
    [datetime.time(10, 0), datetime.time(13, 0)],     # dalle 10:00 alle 13:00
    [datetime.time(18, 0), datetime.time(23, 59, 59)] # dalle 18:00 alle 23:59
]

now = datetime.datetime.now().time()
if datetime.datetime.now().date().weekday() < 5:
    current_schedule = WEEK_SCHEDULE
else:
    current_schedule = WEEKEND_SCHEDULE

in_high_time = False
for high_time in current_schedule:
    start = high_time[0]
    end = high_time[1]
    
    if start <= now <= end:        
        in_high_time = True
        break

new_temp = TEMP_HIGH if in_high_time else TEMP_LOW 
if new_temp != current_temp:
    # imposta la nuova temperatura sul termostato
    hass.services.call('climate', 'set_temperature', {'entity_id': climate_entity, 'temperature': new_temp})

    # invio inoltre una notifica di sistema
    hass.services.call('script', 'notifications_send', {'title' : 'HA: Variazione al termostato', 
        'message': 'Temperatura impostata a {} (era {})'.format(new_temp, current_temp)})

Ricordarsi dunque di riavviare Home Assistant per generare l’entità “python_script.scheduler“.
Riavviare Home Assitant.

Analisi

Blocco iniziale
TEMP_HIGH = hass.states.get('input_number.temp_high')
TEMP_LOW = hass.states.get('input_number.temp_low')
climate_entity = 'climate.termostato' # definisce l'entità "Climate" da controllare
current_temp = hass.states.get(climate_entity).attributes['temperature']
# current_temp = float(hass.states.get('sensor.temperature'))

WEEK_SCHEDULE = [
    [datetime.time( 0, 0), datetime.time( 1, 0)],     # dalle 00:00 alle 01:00
    [datetime.time( 7, 0), datetime.time( 9, 0)],     # dalle 07:00 alle 09:00
    [datetime.time(18, 0), datetime.time(23, 59, 59)] # dalle 18:00 alle 23:59
]
WEEKEND_SCHEDULE = [
    [datetime.time( 0, 0), datetime.time( 2, 0)],     # dalle 00:00 alle 01:00
    [datetime.time(10, 0), datetime.time(13, 0)],     # dalle 10:00 alle 13:00
    [datetime.time(18, 0), datetime.time(23, 59, 59)] # dalle 18:00 alle 23:59
]

In questa prima parte si nota la raccolta dei valori dei due “Input Number” (“input_number.temp_high” e “input_number.temp_low“)  presso due variabili ad hoc (“TEMP_HIGH” e “TEMP_LOW“) e altre due variabili, una contenente l’entity_id da controllare (“climate_entity“, in questo caso impostata a “climate.termostato“) e la temperatura ambientale attuale (“current_temp“) raccolta dallo stato del sensore “sensor.temperature“.

La riga commentata:

# current_temp = float(hass.states.get(‘sensor.temperature’))

è utile per quelle entità “Climate” che non espongano un dato reale della temperatura ambientale, ad esempio quelle prodotte tramite l’integrazione della testa termostatica “Eqiva eQ-3”. In questi casi – dato che il valore di lettura della temperatura è essenziale per il funzionamento del temporizzatore – basterà eliminare il # di commento (e commentare quella precedente) per far sì che la variabile (“current_temp“) venga valorizzata tramite il valore dello stato di un sensore di temperatura presente in configurazione (qui assunto come “sensor.temperature“).

Infine, il blocco di codice definisce gli orari settimanali di accensione (“WEEK_SCHEDULE“) e nel fine settimana (“WEEKEND_SCHEDULE“).


Ovviamente questo blocco è ampiamente personalizzabile sulla base delle proprie esigenze (specialmente il campo “climate_entity“).

BLOCCO OPERATIVO

È nella seconda parte che avviene tutta la magia:

now = datetime.datetime.now().time()
if datetime.datetime.now().date().weekday() < 5:
    current_schedule = WEEK_SCHEDULE
else:
    current_schedule = WEEKEND_SCHEDULE

in_high_time = False
for high_time in current_schedule:
    start = high_time[0]
    end = high_time[1]
    
    if start <= now <= end:        
        in_high_time = True
        break

new_temp = TEMP_HIGH if in_high_time else TEMP_LOW 
if new_temp != current_temp:
    # imposta la nuova temperatura sul termostato
    hass.services.call('climate', 'set_temperature', {'entity_id': climate_entity, 'temperature': new_temp})

    # invio inoltre una notifica di sistema
    hass.services.call('script', 'notifications_send', {'title' : 'HA: Variazione al termostato', 
        'message': 'Temperatura impostata a {} (era {})'.format(new_temp, current_temp)})

Lo script innanzitutto determina se sia un giorno settimanale o del weekend; poi verifica che ci si trovi in una delle fasce orarie impostate dall’utente: in caso ci si trovi in una fascia di accensione, imposta il valore della temperatura target dell’entità “Climate” (“climate.termostato“) alla temperatura “TEMP_HIGH“, altrimenti imposta “TEMP_LOW“.

Ovviamente questo è valido per un sistema di riscaldamento. In presenza di impianti di raffrescamento, modificare la riga:

new_temp = TEMP_HIGH if in_high_time else TEMP_LOW

in:

new_temp = TEMP_LOW if in_high_time else TEMP_HIGH

Automazione

A questo punto bisogna far sì che lo script venga eseguito ciclicamente.
Definiamo pertanto un’automazione di questo tipo:

automation:
  - alias: 'Temporizzatore'
    initial_state: True
    trigger:
      - platform: time      
        minutes: '/1' # ogni minuto
        seconds: 00
      - platform: homeassistant
        event: start
    condition: []
    action:
      service: python_script.scheduler

Così facendo, l’automazione evocherà lo script una volta al minuto (anche questo è personalizzabile), così da agire sul termostato in base alle regole impostate.

Il campo “condition” è stato lasciato volutamente vuoto; una personalizzazione aggiuntiva potrebbe essere quella di verificare (sfruttando il componente “Device Tracker“) l’effettiva presenza degli inquilini in casa, così da non agire sul sistema clima in assenza di quest’ultimi.

Considerazioni finali

Questo tipo di implementazione si sposa particolarmente bene con progetti e guide precedentemente pubblicate, tra i quali:


Questo progetto è ispirato al lavoro di Abílio Costa al quale va il ringraziamento della nostra community.

Domotizzare il riscaldamento autonomo tramite contatto pulito e Home Assistant (senza termostato fisico)


Home Assistant iconATTENZIONE: ricorda che sul nostro community FORUM c'è una sezione ad hoc dedica a Home Assistant, per qualsiasi dubbio, domanda, informazione nel merito specifico di queste componenti.

Dubbi? Perplessità? Fai un salto sul FORUM o sulla CHAT @DISCORD!
Questa pagina è coperta dalla licenza Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Licenseil che significa che puoi liberamente condividerlo, senza modificarlo, citando il link della fonte.