This Jinja template generates automations, groups and schedules for my heating system at home. I use Bosch Radiator Thermostat II valves and Zigbee temperature sensors.
The end result is generated automatically using the ha-jinja2config addon.
This Jinja template generates automations, groups and schedules for my heating system at home. I use Bosch Radiator Thermostat II valves and Zigbee temperature sensors.
The end result is generated automatically using the ha-jinja2config addon.
{% set rooms = [ | |
{ | |
'name': 'Living Room', | |
'external_source': 'living_room_climate_temperature', | |
'radiators': [ 'living_room_radiator' ], | |
'temperature': { | |
'off': 14, | |
'on': 17 | |
}, | |
'schedule': { | |
'weekdays': [ | |
{ 'from': '07:15', 'to': '22:00' } | |
], | |
'weekend': [ | |
{ 'from': '09:00', 'to': '23:00' } | |
] | |
} | |
}, | |
{ | |
'name': 'Bedroom', | |
'external_source': 'bedroom_climate_temperature', | |
'radiators': [ 'bedroom_radiator' ], | |
'temperature': { | |
'off': 14, | |
'on': 17 | |
}, | |
'schedule': { | |
'weekdays': [ | |
{ 'from': '07:00', 'to': '08:00' }, | |
{ 'from': '22:00', 'to': '23:00' } | |
], | |
'friday': [ | |
{ 'from': '07:00', 'to': '08:00' }, | |
{ 'from': '22:30', 'to': '23:30' } | |
], | |
'weekend': [ | |
{ 'from': '09:00', 'to': '10:00' }, | |
{ 'from': '22:30', 'to': '23:30' } | |
], | |
'sunday': [ | |
{ 'from': '09:00', 'to': '10:00' }, | |
{ 'from': '22:00', 'to': '23:30' } | |
] | |
} | |
} | |
] %} | |
{%- set ns = namespace(radiators=[]) -%} | |
{%- for room in rooms -%} | |
{%- set ns.radiators = ns.radiators + room.radiators -%} | |
{%- endfor -%} | |
automation heating: | |
- alias: "Heating - Control" | |
id: "heating_control" | |
description: > | |
Control the thermostats based on the schedule and home state. | |
mode: restart | |
triggers: | |
- trigger: state | |
entity_id: | |
- binary_sensor.home_state_nearby_anyone | |
{%- for room in rooms %} | |
- schedule.{{ room.name|lower|replace(' ', '_') }}_heating{% endfor %} | |
actions: | |
{% for room in rooms %} | |
- if: | |
- condition: and | |
conditions: | |
- condition: state | |
entity_id: binary_sensor.home_state_nearby_anyone | |
state: "on" | |
- condition: state | |
entity_id: schedule.{{ room.name|lower|replace(' ', '_') }}_heating | |
state: "on" | |
then: | |
- action: climate.set_temperature | |
data: | |
temperature: "{{ "{{" }} state_attr('schedule.{{ room.name|lower|replace(' ', '_') }}_heating', 'temperature') {{ "}}" }}" | |
hvac_mode: heat | |
target: | |
entity_id: group.{{ room.name|lower|replace(' ', '_') }}_thermostat | |
else: | |
- action: climate.set_temperature | |
data: | |
temperature: {{ room.temperature.off }} | |
hvac_mode: heat | |
target: | |
entity_id: group.{{ room.name|lower|replace(' ', '_') }}_thermostat | |
{% endfor %} | |
- alias: "Heating - External Temperature" | |
id: "heating_set_external_temperature" | |
description: > | |
This will sync the temperature on the radiator valves to the external sensors. | |
mode: restart | |
triggers: | |
{% for room in rooms %} | |
- trigger: state | |
entity_id: | |
- "sensor.{{ room.external_source }}" | |
variables: | |
room: "{{ room.name|lower|replace(' ', '_') }}" | |
radiators: {{ room.radiators }} | |
external_source: "{{ room.external_source }}" | |
external_sensor: "{{ "sensor." + room.external_source }}" | |
schedule: "{{ room.name|lower|replace(' ', '_') }}_heating" | |
- trigger: time | |
at: input_datetime.{{ room.name|lower|replace(' ', '_') }}_heating_next_update | |
variables: | |
room: "{{ room.name|lower|replace(' ', '_') }}" | |
radiators: {{ room.radiators }} | |
external_source: "{{ room.external_source }}" | |
external_sensor: "{{ "sensor." + room.external_source }}" | |
schedule: "schedule.{{ room.name|lower|replace(' ', '_') }}_heating" | |
{% endfor %} | |
conditions: | |
- condition: template | |
value_template: > | |
{{ "{{" }} (as_timestamp(now()) - as_timestamp(states.sensor[external_source].last_changed)) < 5400 {{ "}}" }} | |
actions: | |
- action: input_datetime.set_datetime | |
target: | |
entity_id: "{{ "{{" }} 'input_datetime.' + room + '_heating_next_update' {{ "}}" }}" | |
data: | |
timestamp: "{{ "{{" }} as_timestamp(now() + timedelta(minutes=29)) {{ "}}" }}" | |
- action: number.set_value | |
data: | |
value: "{{ "{{" }} states(external_sensor) {{ "}}" }}" | |
target: | |
entity_id: "{{ "{{" }} radiators|map('regex_replace', '^', 'number.')|map('regex_replace', '$', '_remote_temperature')|list {{ "}}" }}" | |
- alias: "Heating - Calibration" | |
id: "heating_calibration" | |
description: > | |
When a radiator valve has reconnected and is waiting for a calbration, | |
start the calibration process automatically. | |
initial_state: true | |
mode: restart | |
triggers: | |
{% for radiator in ns.radiators %} | |
- trigger: state | |
entity_id: sensor.{{ radiator }}_valve_adapt_status | |
to: ready_to_calibrate | |
{%- endfor %} | |
actions: | |
- action: switch.turn_on | |
target: | |
entity_id: "{{ "{{" }} trigger.entity_id|regex_replace('^sensor.', 'switch.')|regex_replace('_status$', '_process') {{ "}}" }}" | |
- alias: "Heating - Error state" | |
id: "heating_error" | |
description: > | |
Notify people whenever a radiator valve is in error state | |
mode: restart | |
triggers: | |
{% for radiator in ns.radiators %} | |
- trigger: state | |
entity_id: sensor.{{ radiator }}_valve_adapt_status | |
to: error | |
{%- endfor %} | |
actions: | |
- action: notify.notify | |
data: | |
title: "Radiator valve error: {{ "{{" }} trigger.entity_id|regex_replace('^sensor.', '')|regex_replace('_status$', '') {{ "}}" }}" | |
message: Please check the valve | |
data: | |
push: | |
sound: | |
critical: 1 | |
group: | |
{% for room in rooms %} | |
{{ room.name|lower|replace(' ', '_') }}_thermostat: | |
name: "{{ room.name }} Thermostat" | |
entities: | |
{% for radiator in room.radiators %} | |
- climate.{{ radiator }}{% endfor %} | |
{% endfor %} | |
schedule: | |
{% for room in rooms %} | |
{{ room.name|lower|replace(' ', '_') }}_heating: | |
name: "{{ room.name }}: Heating Schedule" | |
{%- for day in ["monday", "tuesday", "wednesday", "thursday", "friday"] %} | |
{{ day }}: | |
{% for _block in room.schedule[day]|default(room.schedule.weekdays) %} | |
- from: "{{ _block.from }}" | |
to: "{{ _block.to }}" | |
data: | |
temperature: {{ _block.temperature|default(room.temperature.on) }}{% endfor %} | |
{%- endfor %} | |
{%- for day in ["saturday", "sunday"] %} | |
{{ day }}: | |
{% for _block in room.schedule[day]|default(room.schedule.weekend) %} | |
- from: "{{ _block.from }}" | |
to: "{{ _block.to }}" | |
data: | |
temperature: {{ _block.temperature|default(room.temperature.on) }}{% endfor %} | |
{%- endfor %} | |
{% endfor %} | |
input_datetime: | |
{% for room in rooms %} | |
{{ room.name|lower|replace(' ', '_') }}_heating_next_update: | |
name: "{{ room.name }}: Heating - Next forced update" | |
has_date: true | |
has_time: true | |
{% endfor %} |
automation heating: | |
- alias: "Heating - Control" | |
id: "heating_control" | |
description: > | |
Control the thermostats based on the schedule and home state. | |
mode: restart | |
triggers: | |
- trigger: state | |
entity_id: | |
- binary_sensor.home_state_nearby_anyone | |
- schedule.living_room_heating | |
- schedule.bedroom_heating | |
actions: | |
- if: | |
- condition: and | |
conditions: | |
- condition: state | |
entity_id: binary_sensor.home_state_nearby_anyone | |
state: "on" | |
- condition: state | |
entity_id: schedule.living_room_heating | |
state: "on" | |
then: | |
- action: climate.set_temperature | |
data: | |
temperature: "{{ state_attr('schedule.living_room_heating', 'temperature') }}" | |
hvac_mode: heat | |
target: | |
entity_id: group.living_room_thermostat | |
else: | |
- action: climate.set_temperature | |
data: | |
temperature: 14 | |
hvac_mode: heat | |
target: | |
entity_id: group.living_room_thermostat | |
- if: | |
- condition: and | |
conditions: | |
- condition: state | |
entity_id: binary_sensor.home_state_nearby_anyone | |
state: "on" | |
- condition: state | |
entity_id: schedule.bedroom_heating | |
state: "on" | |
then: | |
- action: climate.set_temperature | |
data: | |
temperature: "{{ state_attr('schedule.bedroom_heating', 'temperature') }}" | |
hvac_mode: heat | |
target: | |
entity_id: group.bedroom_thermostat | |
else: | |
- action: climate.set_temperature | |
data: | |
temperature: 14 | |
hvac_mode: heat | |
target: | |
entity_id: group.bedroom_thermostat | |
- alias: "Heating - External Temperature" | |
id: "heating_set_external_temperature" | |
description: > | |
This will sync the temperature on the radiator valves to the external sensors. | |
mode: restart | |
triggers: | |
- trigger: state | |
entity_id: | |
- "sensor.living_room_climate_temperature" | |
variables: | |
room: "living_room" | |
radiators: ["living_room_radiator"] | |
external_source: "living_room_climate_temperature" | |
external_sensor: "sensor.living_room_climate_temperature" | |
schedule: "living_room_heating" | |
- trigger: time | |
at: input_datetime.living_room_heating_next_update | |
variables: | |
room: "living_room" | |
radiators: ["living_room_radiator"] | |
external_source: "living_room_climate_temperature" | |
external_sensor: "sensor.living_room_climate_temperature" | |
schedule: "schedule.living_room_heating" | |
- trigger: state | |
entity_id: | |
- "sensor.bedroom_climate_temperature" | |
variables: | |
room: "bedroom" | |
radiators: ["bedroom_radiator"] | |
external_source: "bedroom_climate_temperature" | |
external_sensor: "sensor.bedroom_climate_temperature" | |
schedule: "bedroom_heating" | |
- trigger: time | |
at: input_datetime.bedroom_heating_next_update | |
variables: | |
room: "bedroom" | |
radiators: ["bedroom_radiator"] | |
external_source: "bedroom_climate_temperature" | |
external_sensor: "sensor.bedroom_climate_temperature" | |
schedule: "schedule.bedroom_heating" | |
conditions: | |
- condition: template | |
value_template: > | |
{{ (as_timestamp(now()) - as_timestamp(states.sensor[external_source].last_changed)) < 5400 }} | |
actions: | |
- action: input_datetime.set_datetime | |
target: | |
entity_id: "{{ 'input_datetime.' + room + '_heating_next_update' }}" | |
data: | |
timestamp: "{{ as_timestamp(now() + timedelta(minutes=29)) }}" | |
- action: number.set_value | |
data: | |
value: "{{ states(external_sensor) }}" | |
target: | |
entity_id: "{{ radiators|map('regex_replace', '^', 'number.')|map('regex_replace', '$', '_remote_temperature')|list }}" | |
- alias: "Heating - Calibration" | |
id: "heating_calibration" | |
description: > | |
When a radiator valve has reconnected and is waiting for a calbration, | |
start the calibration process automatically. | |
initial_state: true | |
mode: restart | |
triggers: | |
- trigger: state | |
entity_id: sensor.living_room_radiator_valve_adapt_status | |
to: ready_to_calibrate | |
- trigger: state | |
entity_id: sensor.bedroom_radiator_valve_adapt_status | |
to: ready_to_calibrate | |
actions: | |
- action: switch.turn_on | |
target: | |
entity_id: "{{ trigger.entity_id|regex_replace('^sensor.', 'switch.')|regex_replace('_status$', '_process') }}" | |
- alias: "Heating - Error state" | |
id: "heating_error" | |
description: > | |
Notify people whenever a radiator valve is in error state | |
mode: restart | |
triggers: | |
- trigger: state | |
entity_id: sensor.living_room_radiator_valve_adapt_status | |
to: error | |
- trigger: state | |
entity_id: sensor.bedroom_radiator_valve_adapt_status | |
to: error | |
actions: | |
- action: notify.notify | |
data: | |
title: "Radiator valve error: {{ trigger.entity_id|regex_replace('^sensor.', '')|regex_replace('_status$', '') }}" | |
message: Please check the valve | |
data: | |
push: | |
sound: | |
critical: 1 | |
group: | |
living_room_thermostat: | |
name: "Living Room Thermostat" | |
entities: | |
- climate.living_room_radiator | |
bedroom_thermostat: | |
name: "Bedroom Thermostat" | |
entities: | |
- climate.bedroom_radiator | |
schedule: | |
living_room_heating: | |
name: "Living Room: Heating Schedule" | |
monday: | |
- from: "07:15" | |
to: "22:00" | |
data: | |
temperature: 17 | |
tuesday: | |
- from: "07:15" | |
to: "22:00" | |
data: | |
temperature: 17 | |
wednesday: | |
- from: "07:15" | |
to: "22:00" | |
data: | |
temperature: 17 | |
thursday: | |
- from: "07:15" | |
to: "22:00" | |
data: | |
temperature: 17 | |
friday: | |
- from: "07:15" | |
to: "22:00" | |
data: | |
temperature: 17 | |
saturday: | |
- from: "09:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
sunday: | |
- from: "09:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
bedroom_heating: | |
name: "Bedroom: Heating Schedule" | |
monday: | |
- from: "07:00" | |
to: "08:00" | |
data: | |
temperature: 17 | |
- from: "22:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
tuesday: | |
- from: "07:00" | |
to: "08:00" | |
data: | |
temperature: 17 | |
- from: "22:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
wednesday: | |
- from: "07:00" | |
to: "08:00" | |
data: | |
temperature: 17 | |
- from: "22:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
thursday: | |
- from: "07:00" | |
to: "08:00" | |
data: | |
temperature: 17 | |
- from: "22:00" | |
to: "23:00" | |
data: | |
temperature: 17 | |
friday: | |
- from: "07:00" | |
to: "08:00" | |
data: | |
temperature: 17 | |
- from: "22:30" | |
to: "23:30" | |
data: | |
temperature: 17 | |
saturday: | |
- from: "09:00" | |
to: "10:00" | |
data: | |
temperature: 17 | |
- from: "22:30" | |
to: "23:30" | |
data: | |
temperature: 17 | |
sunday: | |
- from: "09:00" | |
to: "10:00" | |
data: | |
temperature: 17 | |
- from: "22:00" | |
to: "23:30" | |
data: | |
temperature: 17 | |
input_datetime: | |
living_room_heating_next_update: | |
name: "Living Room: Heating - Next forced update" | |
has_date: true | |
has_time: true | |
bedroom_heating_next_update: | |
name: "Bedroom: Heating - Next forced update" | |
has_date: true | |
has_time: true |