I hit a few instances where the ‘10 minutes of no response’ happened even when just using the integration, but not sure of what triggers it. I’ve factored that into my solution below.
After significant experimentation, I’ve built a ‘wrapper script’ for controlling the thermostat, included below. I’m pretty new to HA, so assume there are better ways to implement much of this. I’d love to get feedback! In particular, this seems way to complex. ?? I’m also wondering if much of this should actually be pushed down into the integration itself?
Notes:
- This works on thermostats set to both heat, and to heat/cool.
- I rely on a gmail notifier for when things fail. Substitute whatever you’d like.
- The variable ‘waits’ is an array of how long to wait for the action to happen before it’s considered failed… and then retried. I start out with a couple short retries (network error or other random failure), and then do a 10min (600 sec) delay due to the issue I noted above, followed by a couple additional short retries if needed. This can certainly be adjusted if your observations are different than mine,.
- I use a non-standard but I think more intuitive set of ‘modes’ (to reduce confusion, I call them ‘settings’). These are documented below, along with a description of each argument.
alias: "Thermostat: Control"
description: |-
Arguments:
- 'house' must be the name of the thermostat. ie entity climate.house
- 'setting' must be 'sched', 'temp', 'perm', or undefined.
'sched' means it's following the schedule.
'temp' means a temporary hold (until next scheduled change).
'perm' means a permanent hold (eg vacation mode)
Note that 'setting' can only be undefined if changing temperature
but not mode (increasing the temperature by 1 degree).
Note that changing the temperature when in 'sched' implies an
automatic change to 'temp'.
- 'low' is optional, and is the lowest temperature before heat turns on.
If not specified, the current low temperature state is used, with the
exception of if setting to 'perm', in which case 55 is used.
- 'high' is optional, and is the highest temperature before a/c turns on.
If not specified, the current high temperature state is used, with the
exception of if setting to 'perm', 84 is used.
sequence:
- variables:
house: "{{ house | default('undef') }}"
mode: |-
{% if setting == 'sched' %}
none
{% elif setting == 'temp' %}
none
{% elif setting == 'perm' %}
hold
{% else %}
undef
{% endif %}
set_mode: |-
{% if setting == 'sched' %}
True
{% elif setting == 'temp' %}
True
{% elif setting == 'perm' %}
True
{% else %}
False
{% endif %}
set_temp: |-
{% if setting == 'sched' %}
False
{% elif setting == 'temp' %}
True
{% elif setting == 'perm' %}
True
{% elif (low is defined) or (high is defined) %}
True
{% else %}
False
{% endif %}
start: "{{ now().timestamp() }}"
entity: climate.{{house}}
low: |-
{% if low is defined %}
{{ low|float }}
{% elif setting == 'perm' %}
55
{% elif states(entity) == 'heat_cool' %}
{{ state_attr(entity, 'target_temp_low') }}
{% else %}
{{ state_attr(entity, 'temperature') }}
{%endif%}
high: |-
{% if (high is defined) and (high != '') %}
{{ high|float }}
{% elif setting == 'perm' %}
84
{% elif states(entity) == 'heat_cool' %}
{{ state_attr(entity, 'target_temp_high') }}
{%endif%}
waits:
- 5
- 30
- 600
- 5
- 30
- if:
- condition: template
value_template: "{{ set_mode == True }}"
then:
- repeat:
sequence:
- action: climate.set_preset_mode
target:
entity_id: "{{ entity }}"
data:
preset_mode: "{{ mode }}"
- wait_template: "{{ is_state_attr(entity, 'preset_mode', mode) }}"
timeout: "{{ waits[repeat.index-1] }}"
until:
- condition: or
conditions:
- condition: template
value_template: "{{ state_attr(entity, 'preset_mode') == mode }}"
- condition: template
value_template: "{{ repeat.index == (waits|length) }}"
- if:
- condition: template
value_template: >-
{{ (set_mode == True) and (state_attr(entity, 'preset_mode') != mode)
}}
then:
- action: notify.gmail_{{house}}
metadata: {}
data:
target: [email protected]
title: Thermostat Control Error
message: >
Error setting thermostat for {{ house }}
Mode: requested {{ mode }}, but have {{ state_attr(entity,
'preset_mode') }}
Duration: "{{ now().timestamp() - start }}"
- if:
- condition: and
conditions:
- condition: template
value_template: "{{ set_temp == True }}"
- condition: template
value_template: >-
{{ (set_mode == False) or ((set_mode == True) and
(state_attr(entity, 'preset_mode') == mode)) }}
then:
- if:
- condition: template
value_template: "{{ states(entity) == 'heat_cool' }}"
then:
- repeat:
sequence:
- action: climate.set_temperature
target:
entity_id: "{{ entity }}"
data:
target_temp_low: "{{ low }}"
target_temp_high: "{{ high }}"
- wait_template: >-
{{ is_state_attr(entity, 'target_temp_low', low) and
is_state_attr(entity, 'target_temp_high', high) }}
timeout: "{{ waits[repeat.index-1] }}"
until:
- condition: or
conditions:
- condition: template
value_template: >-
{{ is_state_attr(entity, 'target_temp_low', low) and
is_state_attr(entity, 'target_temp_high', high) }}
- condition: template
value_template: "{{ repeat.index == (waits|length) }}"
- if:
- condition: template
value_template: >-
{{ (state_attr(entity, 'target_temp_low') != low) or
(state_attr(entity, 'target_temp_high') != high) }}
then:
- action: notify.gmail_{{house}}
metadata: {}
data:
target: [email protected]
title: Thermostat Control Error
message: >
Error setting thermostat for {{ house }}
Target: requested {{ low }}-{{ high }}, but have {{
state_attr(entity, 'target_temp_low')
}}-{{state_attr(entity, 'target_temp_high')}}
Duration: "{{ now().timestamp() - start }}"
else:
- repeat:
sequence:
- action: climate.set_temperature
target:
entity_id: "{{ entity }}"
data:
temperature: "{{ low }}"
- wait_template: "{{ is_state_attr(entity, 'temperature', low) }}"
timeout: "{{ waits[repeat.index-1] }}"
until:
- condition: or
conditions:
- condition: template
value_template: "{{ is_state_attr(entity, 'temperature', low) }}"
- condition: template
value_template: "{{ repeat.index == (waits|length) }}"
- if:
- condition: template
value_template: "{{ (state_attr(entity, 'temperature') != low) }}"
then:
- action: notify.gmail_{{house}}
metadata: {}
data:
target: [email protected]
title: Thermostat Control Error
message: >
Error setting thermostat for {{ house }}
Target: requested {{ low }}, but have {{ state_attr(entity,
'temperature') }}
Duration: "{{ now().timestamp() - start }}"
mode: restart
I also created a custom sensor (Helper → Template → Template a sensor) that’s not required but makes it easy to observe the current state of the thermostat during debugging. ie: just have the card for the sensor displayed, and you can see all the settings info. Just copy/paste and fill in the correct value for HOUSE.
{% set device = 'climate.HOUSE' %}
{% if is_state_attr(device, 'preset_mode', 'hold') %}
{% if is_state_attr(device, 'permanent_hold', true) %}
{% set setting= 'perm' %}
{% else %}
{% set setting= 'temp' %}
{% endif %}
{% else %}
{% set setting= 'sched' %}
{% endif %}
{% if is_state(device, 'heat_cool') %}
{% set temp = state_attr(device, 'target_temp_low') ~ '-' ~ state_attr(device, 'target_temp_high') %}
{% else %}
{% set temp = state_attr(device, 'temperature') %}
{% endif %}
{{setting}}-{{temp}}