Skip to content

Instantly share code, notes, and snippets.

@hansharhoff
Last active January 20, 2026 21:41
Show Gist options
  • Select an option

  • Save hansharhoff/0c8f5e6b94b7e26d27f8d1675fd38b23 to your computer and use it in GitHub Desktop.

Select an option

Save hansharhoff/0c8f5e6b94b7e26d27f8d1675fd38b23 to your computer and use it in GitHub Desktop.
boost heat for X hours on Danfoss ally
blueprint:
name: Danfoss Ally 2 - Heat boost (no-default choose)
description: >
Press an input_button to boost selected Danfoss Ally thermostats for X hours.
If pressed again while the timer is active/paused, adds +extend hours.
When timer ends/cancels, restores previous preset + temperature (and hvac_mode).
domain: automation
input:
activation_button:
name: Activation input_button
selector:
entity:
domain: input_button
thermostats:
name: Danfoss Ally thermostats (climate entities)
selector:
entity:
domain: climate
multiple: true
boost_timer:
name: Timer helper
selector:
entity:
domain: timer
snapshot_store:
name: Snapshot store (input_text helper)
description: Stores thermostat states (JSON) so they can be restored after boost.
selector:
entity:
domain: input_text
boost_hours:
name: Boost duration (hours)
default: 2
selector:
number:
min: 0.25
max: 24
step: 0.25
unit_of_measurement: h
mode: box
extend_hours:
name: Extend by (hours) when pressed again
default: 1
selector:
number:
min: 0.25
max: 12
step: 0.25
unit_of_measurement: h
mode: box
boost_preset:
name: Boost preset
default: "Manual"
selector:
select:
options:
- "home"
- "away"
- "Pause"
- "Manual"
- "Holiday (Home)"
- "Holiday (Away)"
boost_temperature:
name: Boost target temperature (°C) - optional
description: >
If > 0 and boost_preset is Manual, sets this target temperature during boost. If 0, does not change temperature.
default: 0
selector:
number:
min: 0
max: 30
step: 0.5
unit_of_measurement: "°C"
mode: box
mode: queued
max: 10
trigger:
- platform: event
event_type: input_button.press
event_data:
entity_id: !input activation_button
id: activate
- platform: event
event_type: timer.finished
event_data:
entity_id: !input boost_timer
id: restore
- platform: event
event_type: timer.cancelled
event_data:
entity_id: !input boost_timer
id: restore
- platform: state
entity_id: !input boost_timer
from: "active"
to: "idle"
id: restore
- platform: state
entity_id: !input boost_timer
from: "paused"
to: "idle"
id: restore
- platform: homeassistant
event: start
id: restore
variables:
timer_entity: !input boost_timer
thermostats: !input thermostats
store_entity: !input snapshot_store
boost_hours: !input boost_hours
extend_hours: !input extend_hours
boost_preset: !input boost_preset
boost_temperature: !input boost_temperature
action:
- choose:
# =========================================================
# ACTIVATE: timer already running -> EXTEND
# =========================================================
- conditions: >
{{ trigger.id == 'activate'
and (is_state(timer_entity, 'active') or is_state(timer_entity, 'paused')) }}
sequence:
- service: timer.start
target:
entity_id: !input boost_timer
data:
duration: >
{% set finish = state_attr(timer_entity, 'finishes_at') %}
{% if finish %}
{% set remaining = as_timestamp(finish) - as_timestamp(now()) %}
{% else %}
{% set rem_str = state_attr(timer_entity, 'remaining') %}
{% set remaining = (as_timedelta(rem_str).total_seconds() if rem_str else 0) %}
{% endif %}
{% if remaining < 0 %}{% set remaining = 0 %}{% endif %}
{% set sec = (remaining + (extend_hours | float * 3600)) | int %}
{{ '%02d:%02d:%02d'|format(sec//3600, (sec%3600)//60, sec%60) }}
- service: climate.set_hvac_mode
target:
entity_id: !input thermostats
data:
hvac_mode: "heat"
- service: climate.set_preset_mode
target:
entity_id: !input thermostats
data:
preset_mode: !input boost_preset
- choose:
- conditions: "{{ (boost_temperature | float > 0) and (boost_preset == 'Manual') }}"
sequence:
- service: climate.set_temperature
target:
entity_id: !input thermostats
data:
temperature: !input boost_temperature
# =========================================================
# ACTIVATE: timer idle -> SNAPSHOT + START
# =========================================================
- conditions: >
{{ trigger.id == 'activate' and is_state(timer_entity, 'idle') }}
sequence:
- service: input_text.set_value
target:
entity_id: !input snapshot_store
data:
value: >
{% set ns = namespace(items=[]) %}
{% for eid in thermostats %}
{% set ns.items = ns.items + [{
"entity_id": eid,
"hvac_mode": states(eid),
"preset_mode": state_attr(eid, "preset_mode"),
"temperature": state_attr(eid, "temperature")
}] %}
{% endfor %}
{{ ns.items | to_json }}
- service: climate.set_hvac_mode
target:
entity_id: !input thermostats
data:
hvac_mode: "heat"
- service: climate.set_preset_mode
target:
entity_id: !input thermostats
data:
preset_mode: !input boost_preset
- choose:
- conditions: "{{ (boost_temperature | float > 0) and (boost_preset == 'Manual') }}"
sequence:
- service: climate.set_temperature
target:
entity_id: !input thermostats
data:
temperature: !input boost_temperature
- service: timer.start
target:
entity_id: !input boost_timer
data:
duration: >
{% set sec = (boost_hours | float * 3600) | int %}
{{ '%02d:%02d:%02d'|format(sec//3600, (sec%3600)//60, sec%60) }}
# =========================================================
# RESTORE: timer ended/cancelled -> RESTORE snapshot
# =========================================================
- conditions: "{{ trigger.id == 'restore' }}"
sequence:
- variables:
saved: >
{% set raw = states(store_entity) %}
{% if raw in ['unknown', 'unavailable', ''] %}
[]
{% else %}
{{ raw | from_json }}
{% endif %}
- condition: template
value_template: "{{ (saved | length) > 0 and is_state(timer_entity, 'idle') }}"
- repeat:
for_each: "{{ saved }}"
sequence:
- variables:
eid: "{{ repeat.item.entity_id }}"
hvac: "{{ repeat.item.hvac_mode }}"
preset: "{{ repeat.item.preset_mode }}"
temp: "{{ repeat.item.temperature }}"
- choose:
- conditions: "{{ hvac is not none and hvac not in ['unknown','unavailable',''] }}"
sequence:
- service: climate.set_hvac_mode
target:
entity_id: "{{ eid }}"
data:
hvac_mode: "{{ hvac }}"
- choose:
- conditions: "{{ preset is not none and preset not in ['unknown','unavailable',''] }}"
sequence:
- service: climate.set_preset_mode
target:
entity_id: "{{ eid }}"
data:
preset_mode: "{{ preset }}"
# Restore temperature only if it was Manual before (avoid overriding schedule-like presets)
- choose:
- conditions: >
{{ (preset == 'Manual')
and temp is not none
and temp not in ['unknown','unavailable',''] }}
sequence:
- service: climate.set_temperature
target:
entity_id: "{{ eid }}"
data:
temperature: "{{ temp }}"
- service: input_text.set_value
target:
entity_id: !input snapshot_store
data:
value: ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment