Suggestion: only change the temp on the TRVs if the central boiler is running to save battery power. If the boiler goes from off to on then update the TRVs with the appropriate value.
You can use winter mode for that purpose. Just map it to an entity with a binary value e.g. a switch or an input boolean. If it’s on, the automation is active and temperatures will be set. When it is off, the TRVs are also turned off.
Does this blueprint work with Tado heating systems? Is anyone using it with a Tado heating system?
This blueprint works with every climate entity in home assistant. If your valve doesn’t support the mode off the lowest temperature will be set. Calibration only works if the tado integration provides something like an offset entity. But it also works without calibration. Most of the features are optional.
Good to hear thanks. I’ll give it a go and report back
Hello panhans,
Thanks for your great blueprint. It seems this is what iam looking for. But i dont know what iam doing wrong. Every time if i start the automation my Aquara e1 is set to off. Schedule has been created and also the target temperatur is set. Any help would be appriciated.
Thanks Bernd
Hi There, I implemented and tested this blueprint version 2.9 over the weekend and had the same problem. I think there is a bug in the blueprint. The window state is checked and if open (false) the heating mode is set to OFF. The window_state variable that is being checked is never assigned a value in the blueprint and this results in the Heating mode to always be off. In my case I don’t require the window open functionality so I just removed it from the expression. So I changed the following to make it work. Hope this helps.
In the heating control .yaml file on line 266
{% if ((winter_state == true or party_state == true) and window_state == false) or maintenance == true %}
changed to:
{% if winter_state == true or party_state == true or maintenance == true %}
This was just a quick and nasty modification for testing purposes. You should actually add code above this that reads the Window limit and maps it to this variable if you want to use this functionality. @Panhans could you also please check the code and confirm whether this is a bug or whether I am misunderstanding something?
Thanks for your feedback. I will check it soon. Would be nice if you share your configuration and json trace.
Hi panhans,
Here is the yaml with my Automation config using your blueprint without the modification. I also added a Window sensor input entity:
alias: Heating Test
description: ""
use_blueprint:
path: panhans/heating_control.yaml
input:
heating:
- climate.bedroom_1_trv_thermostat
persons:
- person.johan_fourie
scheduler: schedule.heating_schedule
window: binary_sensor.windowopen
guest_mode: input_boolean.heating_guest_mode
party_mode: input_boolean.heating_party_mode
set_temp: input_number.heating_temp_sp
winter_mode: input_boolean.heating_enable
maintenance: input_boolean.heating_maintenance
The trace exports is as follows:
{
"trace": {
"last_step": "action/0/else/0/then/2/then/0",
"run_id": "7dd90415101cce19505f0aa5633c5261",
"state": "stopped",
"script_execution": "finished",
"timestamp": {
"start": "2023-10-02T12:00:22.007141+00:00",
"finish": "2023-10-02T12:00:26.763874+00:00"
},
"domain": "automation",
"item_id": "1696247938675",
"trigger": "state of input_number.heating_temp_sp",
"trace": {
"trigger/2": [
{
"path": "trigger/2",
"timestamp": "2023-10-02T12:00:22.010794+00:00",
"changed_variables": {
"this": {
"entity_id": "automation.heating_test",
"state": "on",
"attributes": {
"id": "1696247938675",
"last_triggered": "2023-10-02T12:00:02.827435+00:00",
"mode": "parallel",
"current": 0,
"max": 10,
"friendly_name": "Heating Test"
},
"last_changed": "2023-10-02T11:59:06.916528+00:00",
"last_updated": "2023-10-02T12:00:07.230554+00:00",
"context": {
"id": "01HBR44Y83487FBTG86TZR05KE",
"parent_id": "01HBR44MFFSW46K8T8P0AECQW9",
"user_id": null
}
},
"trigger": {
"id": "2",
"idx": "2",
"alias": null,
"platform": "state",
"entity_id": "input_number.heating_temp_sp",
"from_state": {
"entity_id": "input_number.heating_temp_sp",
"state": "22.5",
"attributes": {
"initial": null,
"editable": true,
"min": 0,
"max": 25,
"step": 0.5,
"mode": "slider",
"unit_of_measurement": "Deg C",
"icon": "mdi:temperature-celsius",
"friendly_name": "Heating_Temp_SP"
},
"last_changed": "2023-10-01T14:48:14.899305+00:00",
"last_updated": "2023-10-01T14:48:14.899305+00:00",
"context": {
"id": "01HBNVC6SJSX8Y7ABGX03AQXZX",
"parent_id": null,
"user_id": "7b1cd5e048fb423c89eb3b376d0391fb"
}
},
"to_state": {
"entity_id": "input_number.heating_temp_sp",
"state": "24.0",
"attributes": {
"initial": null,
"editable": true,
"min": 0,
"max": 25,
"step": 0.5,
"mode": "slider",
"unit_of_measurement": "Deg C",
"icon": "mdi:temperature-celsius",
"friendly_name": "Heating_Temp_SP"
},
"last_changed": "2023-10-02T12:00:19.993916+00:00",
"last_updated": "2023-10-02T12:00:19.993916+00:00",
"context": {
"id": "01HBR45F0MKHFQBXFX0X9MBVP1",
"parent_id": null,
"user_id": "7b1cd5e048fb423c89eb3b376d0391fb"
}
},
"for": {
"__type": "<class 'datetime.timedelta'>",
"total_seconds": 2
},
"attribute": null,
"description": "state of input_number.heating_temp_sp"
},
"winter_mode_t": "input_boolean.heating_enable",
"party_mode_t": "input_boolean.heating_party_mode",
"guest_mode_t": "input_boolean.heating_guest_mode",
"holiday_mode_t": null,
"window_t": "binary_sensor.windowopen",
"regular_scheduler_t": "schedule.heating_schedule",
"holiday_scheduler_t": null,
"persons_t": [
"person.johan_fourie"
],
"presence_sensor_t": null,
"maintenance_mode_t": "input_boolean.heating_maintenance",
"trvs": [
"climate.bedroom_1_trv_thermostat"
],
"valves": [
"climate.bedroom_1_trv_thermostat"
],
"valves_off_mode": [
"climate.bedroom_1_trv_thermostat"
],
"valves_without_off_mode": [],
"force_minimum_temperature": false,
"set_temp": "input_number.heating_temp_sp",
"min_temp": 19,
"scheduler_regular": "schedule.heating_schedule",
"scheduler_holiday": null,
"holiday_mode": null,
"window": "binary_sensor.windowopen",
"winter_mode": "input_boolean.heating_enable",
"party_mode": "input_boolean.heating_party_mode",
"guest_mode": "input_boolean.heating_guest_mode",
"persons": [
"person.johan_fourie"
],
"maintenance_mode": "input_boolean.heating_maintenance",
"party_state": false,
"guest_state": false,
"winter_state": true,
"maintenance": false,
"mode": "off",
"persons_home_count": 1,
"holiday_mode_state": false,
"active_scheduler": "schedule.heating_schedule",
"presence_sensor": null,
"presence_reaction_time": 5,
"presence_detected": true,
"presence_time_window": 1,
"is_presence_time_window": false,
"temperatur": 24,
"actual_local_temperature": null
}
}
],
"condition/0": [
{
"path": "condition/0",
"timestamp": "2023-10-02T12:00:22.010888+00:00",
"result": {
"result": true
}
}
],
"condition/0/conditions/0": [
{
"path": "condition/0/conditions/0",
"timestamp": "2023-10-02T12:00:22.010954+00:00",
"result": {
"result": false,
"entities": []
}
}
],
"condition/0/conditions/1": [
{
"path": "condition/0/conditions/1",
"timestamp": "2023-10-02T12:00:22.011152+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0": [
{
"path": "action/0",
"timestamp": "2023-10-02T12:00:22.015247+00:00",
"changed_variables": {
"context": {
"id": "01HBR45GZQJQRYM1SK8ETE1M4G",
"parent_id": "01HBR45F0MKHFQBXFX0X9MBVP1",
"user_id": null
}
},
"result": {
"choice": "else"
}
}
],
"action/0/if": [
{
"path": "action/0/if",
"timestamp": "2023-10-02T12:00:22.015394+00:00",
"result": {
"result": false
}
}
],
"action/0/if/condition/0": [
{
"path": "action/0/if/condition/0",
"timestamp": "2023-10-02T12:00:22.015459+00:00",
"result": {
"result": false,
"entities": []
}
}
],
"action/0/else/0": [
{
"path": "action/0/else/0",
"timestamp": "2023-10-02T12:00:22.016978+00:00",
"result": {
"choice": "then"
}
}
],
"action/0/else/0/if": [
{
"path": "action/0/else/0/if",
"timestamp": "2023-10-02T12:00:22.017082+00:00",
"result": {
"result": true
}
}
],
"action/0/else/0/if/condition/0": [
{
"path": "action/0/else/0/if/condition/0",
"timestamp": "2023-10-02T12:00:22.017134+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/0": [
{
"path": "action/0/else/0/then/0",
"timestamp": "2023-10-02T12:00:22.018295+00:00"
}
],
"action/0/else/0/then/1": [
{
"path": "action/0/else/0/then/1",
"timestamp": "2023-10-02T12:00:22.018608+00:00",
"changed_variables": {
"low_temp_valves": []
}
}
],
"action/0/else/0/then/2": [
{
"path": "action/0/else/0/then/2",
"timestamp": "2023-10-02T12:00:22.018830+00:00",
"result": {
"choice": "then"
}
}
],
"action/0/else/0/then/2/if": [
{
"path": "action/0/else/0/then/2/if",
"timestamp": "2023-10-02T12:00:22.018910+00:00",
"result": {
"result": true
}
}
],
"action/0/else/0/then/2/if/condition/0": [
{
"path": "action/0/else/0/then/2/if/condition/0",
"timestamp": "2023-10-02T12:00:22.018963+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/2/if/condition/1": [
{
"path": "action/0/else/0/then/2/if/condition/1",
"timestamp": "2023-10-02T12:00:22.019138+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/2/then/0": [
{
"path": "action/0/else/0/then/2/then/0",
"timestamp": "2023-10-02T12:00:22.021874+00:00",
"result": {
"params": {
"domain": "climate",
"service": "set_hvac_mode",
"service_data": {
"hvac_mode": "off",
"entity_id": [
"climate.bedroom_1_trv_thermostat"
]
},
"target": {
"entity_id": [
"climate.bedroom_1_trv_thermostat"
]
}
},
"running_script": false
}
}
]
},
"config": {
"variables": {
"trvs": [
"climate.bedroom_1_trv_thermostat"
],
"valves": "{{ expand(trvs) | map(attribute='entity_id') | list }}",
"valves_off_mode": "{% set climates_off = namespace(name=[]) %} {% for climate in valves %}\n {% if state_attr(climate,'hvac_modes') | regex_search('off', ignorecase=True) %}\n {% set climates_off.name = climates_off.name + [climate] %}\n {% endif %}\n{% endfor %} {{ climates_off.name }}\n",
"valves_without_off_mode": "{% set climates_not_off = namespace(name=[]) %} {% for climate in valves %}\n {% if climate not in valves_off_mode %}\n {% set climates_not_off.name = climates_not_off.name + [climate] %}\n {% endif %}\n{% endfor %} {{ climates_not_off.name }}\n",
"force_minimum_temperature": false,
"set_temp": "input_number.heating_temp_sp",
"min_temp": 19,
"scheduler_regular": "schedule.heating_schedule",
"scheduler_holiday": null,
"holiday_mode": null,
"window": "binary_sensor.windowopen",
"winter_mode": "input_boolean.heating_enable",
"party_mode": "input_boolean.heating_party_mode",
"guest_mode": "input_boolean.heating_guest_mode",
"persons": [
"person.johan_fourie"
],
"maintenance_mode": "input_boolean.heating_maintenance",
"party_state": "{{ party_mode != none and is_state(party_mode, 'on') }}",
"guest_state": "{{ guest_mode != none and is_state(guest_mode, 'on') }}",
"winter_state": "{{ winter_mode == none or (winter_mode != none and is_state(winter_mode, 'on')) }}",
"maintenance": "{{ maintenance_mode != none and is_state(maintenance_mode, 'on') }}",
"mode": "{% if ((winter_state == true or party_state == true) and window_state == false) or maintenance == true %}\n heat\n{% else %}\n off\n{% endif %}\n",
"persons_home_count": "{{ expand(persons) | selectattr('state', 'eq', 'home') | list | count }}",
"holiday_mode_state": "{{ scheduler_holiday != none and holiday_mode != none and is_state(holiday_mode, 'on') }}",
"active_scheduler": "{{ iif(holiday_mode_state,scheduler_holiday,scheduler_regular) }}",
"presence_sensor": null,
"presence_reaction_time": 5,
"presence_detected": "{{ presence_sensor == none or (presence_sensor != none and is_state(presence_sensor,'on') and (as_timestamp(now()) - as_timestamp(states[presence_sensor].last_changed, default=as_timestamp(now()))) / 60 >= presence_reaction_time) }}",
"presence_time_window": 1,
"is_presence_time_window": "{{ (as_timestamp(state_attr(active_scheduler,'next_event'),as_timestamp(now())) - as_timestamp(now())) / (60 * 60) <= presence_time_window }}",
"temperatur": "{% if ( states(active_scheduler) == 'on' and ( persons_home_count | int > 0 or guest_state == true)) %}\n\n {% if ( presence_detected == false and is_presence_time_window == true ) %}\n {{ min_temp }}\n {% else %}\n {{ states(set_temp) }}\n {% endif %}\n\n{% else %}\n\n {% if party_state == true %}\n {{ states(set_temp) }}\n {% else %}\n {{ min_temp }}\n {% endif %}\n\n{% endif %}\n",
"actual_local_temperature": null
},
"trigger_variables": {
"winter_mode_t": "input_boolean.heating_enable",
"party_mode_t": "input_boolean.heating_party_mode",
"guest_mode_t": "input_boolean.heating_guest_mode",
"holiday_mode_t": null,
"window_t": "binary_sensor.windowopen",
"regular_scheduler_t": "schedule.heating_schedule",
"holiday_scheduler_t": null,
"persons_t": [
"person.johan_fourie"
],
"presence_sensor_t": null,
"maintenance_mode_t": "input_boolean.heating_maintenance"
},
"trigger": [
{
"platform": "homeassistant",
"event": "start"
},
{
"platform": "event",
"event_type": "automation_reloaded"
},
{
"platform": "state",
"entity_id": "input_number.heating_temp_sp",
"for": {
"seconds": 2
}
},
{
"platform": "template",
"value_template": "{% set active_scheduler_t = iif(holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t,'on'), holiday_scheduler_t, regular_scheduler_t) %} {{ is_state(active_scheduler_t, 'on') }}\n"
},
{
"platform": "template",
"value_template": "{% set active_scheduler_t = iif(holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t,'on'), holiday_scheduler_t, regular_scheduler_t) %} {{ is_state(active_scheduler_t, 'off') }}\n"
},
{
"platform": "template",
"value_template": "{{ expand(persons_t) | selectattr('state', 'eq', 'home') | list | count > 0 }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ expand(persons_t) | selectattr('state', 'eq', 'home') | list | count == 0 }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ window_t != none and is_state(window_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ window_t != none and is_state(window_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ winter_mode_t != none and is_state(winter_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ winter_mode_t != none and is_state(winter_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ maintenance_mode_t != none and is_state(maintenance_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ maintenance_mode_t != none and is_state(maintenance_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ party_mode_t != none and is_state(party_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ party_mode_t != none and is_state(party_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ guest_mode_t != none and is_state(guest_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ guest_mode_t != none and is_state(guest_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ presence_sensor_t != none and is_state(presence_sensor_t, 'on') }}",
"for": {
"seconds": 5
}
},
{
"platform": "template",
"value_template": "{{ presence_sensor_t != none and is_state(presence_sensor_t, 'off') }}",
"for": {
"seconds": 5
}
},
{
"platform": "time_pattern",
"minutes": "/10",
"seconds": "30"
}
],
"condition": [
{
"condition": "or",
"conditions": [
{
"condition": "template",
"value_template": "{{ trigger.platform == 'time_pattern' and actual_local_temperature != none and mode == 'heat' }}"
},
{
"condition": "template",
"value_template": "{{ trigger.platform != 'time_pattern' }}"
}
]
}
],
"action": [
{
"if": [
{
"condition": "template",
"value_template": "{{ trigger.platform == 'time_pattern' }}"
}
],
"then": [
{
"repeat": {
"count": "{{ valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ valves[repeat.index-1] }}",
"calibration_entity": "{% set entities = device_entities(device_id(current_valve)) %} {% set calibration_entity_id = namespace(id=[]) %} {% for s in entities %}\n {% if (('calibration' in s) or ('offset' in s)) %}\n {% set calibration_entity_id.id = s %}\n {% endif %}\n{% endfor %} {{ iif (calibration_entity_id.id[0] is defined, calibration_entity_id.id, NULL) }}\n"
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ calibration_entity is defined }}"
}
],
"then": [
{
"variables": {
"offset_old": "{{ states(calibration_entity) }}",
"offset_new": "{% set current_calibration_value = states(calibration_entity) %} {% set step = state_attr(calibration_entity,'step') %}\n{% set local_temperature = state_attr(current_valve,'current_temperature') %} {% set actual_trv_temperature = (local_temperature | float(0) - current_calibration_value | float(0)) | round(1) %} {% set actual_sensor_temperature = states(actual_local_temperature) | float(0) | round(1) %} {% set new_calibration_value = actual_sensor_temperature - actual_trv_temperature %}\n{% set min_calibration_value = state_attr(calibration_entity,'min') %} {% set max_calibration_value = state_attr(calibration_entity,'max') %} {% if(new_calibration_value > max_calibration_value) %}\n {% set new_calibration_value = max_calibration_value %}\n{% elif (new_calibration_value < min_calibration_value) %}\n {% set new_calibration_value = min_calibration_value %}\n{% endif %}\n{{ (new_calibration_value | float(0) / step) | round(0) * step }}\n"
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ float(offset_old) != float(offset_new) }}"
}
],
"then": [
{
"service": "number.set_value",
"data": {
"value": "{{ float(offset_new) }}"
},
"target": {
"entity_id": "{{ calibration_entity }}"
}
}
]
}
]
}
]
}
}
],
"else": [
{
"if": [
{
"condition": "template",
"value_template": "{{ mode == 'off' }}"
}
],
"then": [
{
"variables": {
"low_temp_valves": "{{ iif(force_minimum_temperature == true, valves, valves_without_off_mode) }} "
}
},
{
"repeat": {
"count": "{{ low_temp_valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ low_temp_valves[repeat.index-1] }}",
"off_temperature": "{{ state_attr(current_valve,'min_temp') }}"
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": "{{ current_valve }}",
"temperature": "{{ off_temperature | float }}"
}
}
]
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ valves_off_mode | count > 0 }}"
},
{
"condition": "template",
"value_template": "{{ force_minimum_temperature == false }}"
}
],
"then": [
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": "{{ valves_off_mode }}"
},
"data": {
"hvac_mode": "off"
}
}
]
}
],
"else": [
{
"if": [
{
"condition": "template",
"value_template": "{{ maintenance }}"
}
],
"then": [
{
"repeat": {
"count": "{{ valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ valves[repeat.index-1] }}",
"max_temperature": "{{ state_attr(current_valve,'max_temp') }}"
}
},
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": "{{ current_valve }}"
},
"data": {
"hvac_mode": "heat"
}
},
{
"delay": {
"seconds": 2
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": "{{ current_valve }}",
"temperature": "{{ max_temperature | float }}"
}
}
]
}
}
],
"else": [
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": [
"climate.bedroom_1_trv_thermostat"
]
},
"data": {
"hvac_mode": "heat"
}
},
{
"delay": {
"seconds": 2
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": [
"climate.bedroom_1_trv_thermostat"
],
"temperature": "{{ temperatur | float }}"
}
}
]
}
]
}
]
}
],
"mode": "parallel",
"id": "1696247938675",
"alias": "Heating Test",
"description": ""
},
"blueprint_inputs": {
"id": "1696247938675",
"alias": "Heating Test",
"description": "",
"use_blueprint": {
"path": "panhans/heating_control.yaml",
"input": {
"heating": [
"climate.bedroom_1_trv_thermostat"
],
"persons": [
"person.johan_fourie"
],
"scheduler": "schedule.heating_schedule",
"window": "binary_sensor.windowopen",
"guest_mode": "input_boolean.heating_guest_mode",
"party_mode": "input_boolean.heating_party_mode",
"set_temp": "input_number.heating_temp_sp",
"winter_mode": "input_boolean.heating_enable",
"maintenance": "input_boolean.heating_maintenance"
}
}
},
"context": {
"id": "01HBR45GZQJQRYM1SK8ETE1M4G",
"parent_id": "01HBR45F0MKHFQBXFX0X9MBVP1",
"user_id": null
}
},
"logbookEntries": [
{
"name": "Heating Test",
"message": "triggered by state of input_number.heating_temp_sp",
"source": "state of input_number.heating_temp_sp",
"entity_id": "automation.heating_test",
"context_id": "01HBR45GZQJQRYM1SK8ETE1M4G",
"when": 1696248022.011404,
"domain": "automation"
}
]
}
Hi panhans,
here is my configuration;
id: '1696192408705'
alias: Bernd Heizung NEU
description: ''
use_blueprint:
path: panhans/heating_control.yaml
input:
heating:
- climate.heizung_bernd
persons:
- person.bernd_bleck
scheduler: schedule.heizung_bernd
min_temp: 18
set_temp: input_number.bernd_komforttemperatur
force_minimum_temperature: false
and trace:
{
"trace": {
"last_step": "action/0/else/0/then/2/then/0",
"run_id": "045acccf1d2bb6da8546a8ae45f6547a",
"state": "stopped",
"script_execution": "finished",
"timestamp": {
"start": "2023-10-01T21:03:50.291272+00:00",
"finish": "2023-10-01T21:03:50.304269+00:00"
},
"domain": "automation",
"item_id": "1696192408705",
"trigger": null,
"trace": {
"trigger": [
{
"path": "trigger",
"timestamp": "2023-10-01T21:03:50.293774+00:00",
"changed_variables": {
"this": {
"entity_id": "automation.bernd_heizung",
"state": "on",
"attributes": {
"id": "1696192408705",
"last_triggered": "2023-10-01T21:03:41.952610+00:00",
"mode": "parallel",
"current": 0,
"max": 10,
"friendly_name": "Bernd Heizung"
},
"last_changed": "2023-10-01T21:03:41.945781+00:00",
"last_updated": "2023-10-01T21:03:41.956497+00:00",
"context": {
"id": "01HBPGVNVZBZCSX79R3J8YRV6N",
"parent_id": "01HBPGVNSMNMAH6CV40A8B0Y1V",
"user_id": null
}
},
"trigger": {
"platform": null
},
"winter_mode_t": null,
"party_mode_t": null,
"guest_mode_t": null,
"holiday_mode_t": null,
"window_t": null,
"regular_scheduler_t": "schedule.heizung_bernd",
"holiday_scheduler_t": null,
"persons_t": [
"person.bernd_bleck"
],
"presence_sensor_t": null,
"maintenance_mode_t": null,
"trvs": [
"climate.heizung_bernd"
],
"valves": [
"climate.heizung_bernd"
],
"valves_off_mode": [
"climate.heizung_bernd"
],
"valves_without_off_mode": [],
"force_minimum_temperature": false,
"set_temp": "input_number.bernd_komforttemperatur",
"min_temp": 18,
"scheduler_regular": "schedule.heizung_bernd",
"scheduler_holiday": null,
"holiday_mode": null,
"window": null,
"winter_mode": null,
"party_mode": null,
"guest_mode": null,
"persons": [
"person.bernd_bleck"
],
"maintenance_mode": null,
"party_state": false,
"guest_state": false,
"winter_state": true,
"maintenance": false,
"mode": "off",
"persons_home_count": 1,
"holiday_mode_state": false,
"active_scheduler": "schedule.heizung_bernd",
"presence_sensor": null,
"presence_reaction_time": 5,
"presence_detected": true,
"presence_time_window": 1,
"is_presence_time_window": false,
"temperatur": 18,
"actual_local_temperature": null
}
}
],
"action/0": [
{
"path": "action/0",
"timestamp": "2023-10-01T21:03:50.296025+00:00",
"changed_variables": {
"context": {
"id": "01HBPGVY0KDPWXJWWJK8K1RZ8Y",
"parent_id": "01HBPGVY0JHYS6KTGN8J1M2MBM",
"user_id": null
}
},
"result": {
"choice": "else"
}
}
],
"action/0/if": [
{
"path": "action/0/if",
"timestamp": "2023-10-01T21:03:50.296163+00:00",
"result": {
"result": false
}
}
],
"action/0/if/condition/0": [
{
"path": "action/0/if/condition/0",
"timestamp": "2023-10-01T21:03:50.296229+00:00",
"result": {
"result": false,
"entities": []
}
}
],
"action/0/else/0": [
{
"path": "action/0/else/0",
"timestamp": "2023-10-01T21:03:50.296943+00:00",
"result": {
"choice": "then"
}
}
],
"action/0/else/0/if": [
{
"path": "action/0/else/0/if",
"timestamp": "2023-10-01T21:03:50.297049+00:00",
"result": {
"result": true
}
}
],
"action/0/else/0/if/condition/0": [
{
"path": "action/0/else/0/if/condition/0",
"timestamp": "2023-10-01T21:03:50.297105+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/0": [
{
"path": "action/0/else/0/then/0",
"timestamp": "2023-10-01T21:03:50.297697+00:00"
}
],
"action/0/else/0/then/1": [
{
"path": "action/0/else/0/then/1",
"timestamp": "2023-10-01T21:03:50.298017+00:00",
"changed_variables": {
"low_temp_valves": []
}
}
],
"action/0/else/0/then/2": [
{
"path": "action/0/else/0/then/2",
"timestamp": "2023-10-01T21:03:50.298269+00:00",
"result": {
"choice": "then"
}
}
],
"action/0/else/0/then/2/if": [
{
"path": "action/0/else/0/then/2/if",
"timestamp": "2023-10-01T21:03:50.298357+00:00",
"result": {
"result": true
}
}
],
"action/0/else/0/then/2/if/condition/0": [
{
"path": "action/0/else/0/then/2/if/condition/0",
"timestamp": "2023-10-01T21:03:50.298411+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/2/if/condition/1": [
{
"path": "action/0/else/0/then/2/if/condition/1",
"timestamp": "2023-10-01T21:03:50.298609+00:00",
"result": {
"result": true,
"entities": []
}
}
],
"action/0/else/0/then/2/then/0": [
{
"path": "action/0/else/0/then/2/then/0",
"timestamp": "2023-10-01T21:03:50.299183+00:00",
"result": {
"params": {
"domain": "climate",
"service": "set_hvac_mode",
"service_data": {
"hvac_mode": "off",
"entity_id": [
"climate.heizung_bernd"
]
},
"target": {
"entity_id": [
"climate.heizung_bernd"
]
}
},
"running_script": false
}
}
]
},
"config": {
"variables": {
"trvs": [
"climate.heizung_bernd"
],
"valves": "{{ expand(trvs) | map(attribute='entity_id') | list }}",
"valves_off_mode": "{% set climates_off = namespace(name=[]) %} {% for climate in valves %}\n {% if state_attr(climate,'hvac_modes') | regex_search('off', ignorecase=True) %}\n {% set climates_off.name = climates_off.name + [climate] %}\n {% endif %}\n{% endfor %} {{ climates_off.name }}\n",
"valves_without_off_mode": "{% set climates_not_off = namespace(name=[]) %} {% for climate in valves %}\n {% if climate not in valves_off_mode %}\n {% set climates_not_off.name = climates_not_off.name + [climate] %}\n {% endif %}\n{% endfor %} {{ climates_not_off.name }}\n",
"force_minimum_temperature": false,
"set_temp": "input_number.bernd_komforttemperatur",
"min_temp": 18,
"scheduler_regular": "schedule.heizung_bernd",
"scheduler_holiday": null,
"holiday_mode": null,
"window": null,
"winter_mode": null,
"party_mode": null,
"guest_mode": null,
"persons": [
"person.bernd_bleck"
],
"maintenance_mode": null,
"party_state": "{{ party_mode != none and is_state(party_mode, 'on') }}",
"guest_state": "{{ guest_mode != none and is_state(guest_mode, 'on') }}",
"winter_state": "{{ winter_mode == none or (winter_mode != none and is_state(winter_mode, 'on')) }}",
"maintenance": "{{ maintenance_mode != none and is_state(maintenance_mode, 'on') }}",
"mode": "{% if ((winter_state == true or party_state == true) and window_state == false) or maintenance == true %}\n heat\n{% else %}\n off\n{% endif %}\n",
"persons_home_count": "{{ expand(persons) | selectattr('state', 'eq', 'home') | list | count }}",
"holiday_mode_state": "{{ scheduler_holiday != none and holiday_mode != none and is_state(holiday_mode, 'on') }}",
"active_scheduler": "{{ iif(holiday_mode_state,scheduler_holiday,scheduler_regular) }}",
"presence_sensor": null,
"presence_reaction_time": 5,
"presence_detected": "{{ presence_sensor == none or (presence_sensor != none and is_state(presence_sensor,'on') and (as_timestamp(now()) - as_timestamp(states[presence_sensor].last_changed, default=as_timestamp(now()))) / 60 >= presence_reaction_time) }}",
"presence_time_window": 1,
"is_presence_time_window": "{{ (as_timestamp(state_attr(active_scheduler,'next_event'),as_timestamp(now())) - as_timestamp(now())) / (60 * 60) <= presence_time_window }}",
"temperatur": "{% if ( states(active_scheduler) == 'on' and ( persons_home_count | int > 0 or guest_state == true)) %}\n\n {% if ( presence_detected == false and is_presence_time_window == true ) %}\n {{ min_temp }}\n {% else %}\n {{ states(set_temp) }}\n {% endif %}\n\n{% else %}\n\n {% if party_state == true %}\n {{ states(set_temp) }}\n {% else %}\n {{ min_temp }}\n {% endif %}\n\n{% endif %}\n",
"actual_local_temperature": null
},
"trigger_variables": {
"winter_mode_t": null,
"party_mode_t": null,
"guest_mode_t": null,
"holiday_mode_t": null,
"window_t": null,
"regular_scheduler_t": "schedule.heizung_bernd",
"holiday_scheduler_t": null,
"persons_t": [
"person.bernd_bleck"
],
"presence_sensor_t": null,
"maintenance_mode_t": null
},
"trigger": [
{
"platform": "homeassistant",
"event": "start"
},
{
"platform": "event",
"event_type": "automation_reloaded"
},
{
"platform": "state",
"entity_id": "input_number.bernd_komforttemperatur",
"for": {
"seconds": 2
}
},
{
"platform": "template",
"value_template": "{% set active_scheduler_t = iif(holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t,'on'), holiday_scheduler_t, regular_scheduler_t) %} {{ is_state(active_scheduler_t, 'on') }}\n"
},
{
"platform": "template",
"value_template": "{% set active_scheduler_t = iif(holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t,'on'), holiday_scheduler_t, regular_scheduler_t) %} {{ is_state(active_scheduler_t, 'off') }}\n"
},
{
"platform": "template",
"value_template": "{{ expand(persons_t) | selectattr('state', 'eq', 'home') | list | count > 0 }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ expand(persons_t) | selectattr('state', 'eq', 'home') | list | count == 0 }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ window_t != none and is_state(window_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ window_t != none and is_state(window_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ holiday_scheduler_t != none and holiday_mode_t != none and is_state(holiday_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ winter_mode_t != none and is_state(winter_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ winter_mode_t != none and is_state(winter_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ maintenance_mode_t != none and is_state(maintenance_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ maintenance_mode_t != none and is_state(maintenance_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ party_mode_t != none and is_state(party_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ party_mode_t != none and is_state(party_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ guest_mode_t != none and is_state(guest_mode_t, 'on') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ guest_mode_t != none and is_state(guest_mode_t, 'off') }}",
"for": {
"seconds": 10
}
},
{
"platform": "template",
"value_template": "{{ presence_sensor_t != none and is_state(presence_sensor_t, 'on') }}",
"for": {
"seconds": 5
}
},
{
"platform": "template",
"value_template": "{{ presence_sensor_t != none and is_state(presence_sensor_t, 'off') }}",
"for": {
"seconds": 5
}
},
{
"platform": "time_pattern",
"minutes": "/10",
"seconds": "30"
}
],
"condition": [
{
"condition": "or",
"conditions": [
{
"condition": "template",
"value_template": "{{ trigger.platform == 'time_pattern' and actual_local_temperature != none and mode == 'heat' }}"
},
{
"condition": "template",
"value_template": "{{ trigger.platform != 'time_pattern' }}"
}
]
}
],
"action": [
{
"if": [
{
"condition": "template",
"value_template": "{{ trigger.platform == 'time_pattern' }}"
}
],
"then": [
{
"repeat": {
"count": "{{ valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ valves[repeat.index-1] }}",
"calibration_entity": "{% set entities = device_entities(device_id(current_valve)) %} {% set calibration_entity_id = namespace(id=[]) %} {% for s in entities %}\n {% if (('calibration' in s) or ('offset' in s)) %}\n {% set calibration_entity_id.id = s %}\n {% endif %}\n{% endfor %} {{ iif (calibration_entity_id.id[0] is defined, calibration_entity_id.id, NULL) }}\n"
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ calibration_entity is defined }}"
}
],
"then": [
{
"variables": {
"offset_old": "{{ states(calibration_entity) }}",
"offset_new": "{% set current_calibration_value = states(calibration_entity) %} {% set step = state_attr(calibration_entity,'step') %}\n{% set local_temperature = state_attr(current_valve,'current_temperature') %} {% set actual_trv_temperature = (local_temperature | float(0) - current_calibration_value | float(0)) | round(1) %} {% set actual_sensor_temperature = states(actual_local_temperature) | float(0) | round(1) %} {% set new_calibration_value = actual_sensor_temperature - actual_trv_temperature %}\n{% set min_calibration_value = state_attr(calibration_entity,'min') %} {% set max_calibration_value = state_attr(calibration_entity,'max') %} {% if(new_calibration_value > max_calibration_value) %}\n {% set new_calibration_value = max_calibration_value %}\n{% elif (new_calibration_value < min_calibration_value) %}\n {% set new_calibration_value = min_calibration_value %}\n{% endif %}\n{{ (new_calibration_value | float(0) / step) | round(0) * step }}\n"
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ float(offset_old) != float(offset_new) }}"
}
],
"then": [
{
"service": "number.set_value",
"data": {
"value": "{{ float(offset_new) }}"
},
"target": {
"entity_id": "{{ calibration_entity }}"
}
}
]
}
]
}
]
}
}
],
"else": [
{
"if": [
{
"condition": "template",
"value_template": "{{ mode == 'off' }}"
}
],
"then": [
{
"variables": {
"low_temp_valves": "{{ iif(force_minimum_temperature == true, valves, valves_without_off_mode) }} "
}
},
{
"repeat": {
"count": "{{ low_temp_valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ low_temp_valves[repeat.index-1] }}",
"off_temperature": "{{ state_attr(current_valve,'min_temp') }}"
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": "{{ current_valve }}",
"temperature": "{{ off_temperature | float }}"
}
}
]
}
},
{
"if": [
{
"condition": "template",
"value_template": "{{ valves_off_mode | count > 0 }}"
},
{
"condition": "template",
"value_template": "{{ force_minimum_temperature == false }}"
}
],
"then": [
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": "{{ valves_off_mode }}"
},
"data": {
"hvac_mode": "off"
}
}
]
}
],
"else": [
{
"if": [
{
"condition": "template",
"value_template": "{{ maintenance }}"
}
],
"then": [
{
"repeat": {
"count": "{{ valves | count | int }}",
"sequence": [
{
"variables": {
"current_valve": "{{ valves[repeat.index-1] }}",
"max_temperature": "{{ state_attr(current_valve,'max_temp') }}"
}
},
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": "{{ current_valve }}"
},
"data": {
"hvac_mode": "heat"
}
},
{
"delay": {
"seconds": 2
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": "{{ current_valve }}",
"temperature": "{{ max_temperature | float }}"
}
}
]
}
}
],
"else": [
{
"service": "climate.set_hvac_mode",
"target": {
"entity_id": [
"climate.heizung_bernd"
]
},
"data": {
"hvac_mode": "heat"
}
},
{
"delay": {
"seconds": 2
}
},
{
"service": "climate.set_temperature",
"data": {
"entity_id": [
"climate.heizung_bernd"
],
"temperature": "{{ temperatur | float }}"
}
}
]
}
]
}
]
}
],
"mode": "parallel",
"id": "1696192408705",
"alias": "Bernd Heizung",
"description": ""
},
"blueprint_inputs": {
"id": "1696192408705",
"alias": "Bernd Heizung",
"description": "",
"use_blueprint": {
"path": "panhans/heating_control.yaml",
"input": {
"heating": [
"climate.heizung_bernd"
],
"persons": [
"person.bernd_bleck"
],
"scheduler": "schedule.heizung_bernd",
"min_temp": 18,
"set_temp": "input_number.bernd_komforttemperatur"
}
}
},
"context": {
"id": "01HBPGVY0KDPWXJWWJK8K1RZ8Y",
"parent_id": "01HBPGVY0JHYS6KTGN8J1M2MBM",
"user_id": null
}
},
"logbookEntries": [
{
"name": "Bernd Heizung",
"message": "triggered",
"source": null,
"entity_id": "automation.bernd_heizung",
"context_id": "01HBPGVY0KDPWXJWWJK8K1RZ8Y",
"when": 1696194230.293901,
"domain": "automation"
}
]
}
Thanks for your support
I have been testing a bit. the following line will fix it and make it work as an optional Window sensor as well. Add the line below to the heating_control.yaml just before the if statement I mentioned before at line 266. Leave the original if statement as per the original yaml file.
window_state: "{{ window != none and is_state(window, 'on') }}"
Great job. Works for me.
Thanks for debugging. Indeed the variable is missing for some reason. I put the line in the recent version of the blueprint. Hopefully everything works again for you!
Pleasure. Gave me a chance to understand your code better. I have learnt a lot from this Blueprint!
Hi @panhans, sorry for the late reply. I just tried it out. It works for my cheap Tuya valves that have a temperature offset value, but not for the one Tado valve I have.
For the Tado I could find this blueprint, which works well.
I could implement that for tado trvs with your help. Could you go to the developer options and paste this line into the template editor? Then just post back the returned value shown on the right. Don’t forget to fill in the entity id of your tado trv.
{{ device_attr('climate.YOUR_TADO_TRV_ENTITY_ID', 'manufacturer') }}
@P6Dave @coldspark29 Here is a test version with implemented calibration for tado. So you just need to define a external temperature sensor. Then have a look on the offset attribute or the trace of the automation. Every 10 minutes the calibration gets called.
Waiting for your feedback.
Hi,
First of all thanks for a great blueprint. It has all the features that I need for controlling the heating in my home. I use Tado TRV’s and last night I installed the test version you provided two days ago. I have a kitchen/dinner room with 3 TRV’s and an external temperature/humidity sensor in the room, making it a great candidate for testing. I have created a graph plotting the “offset_celsius” for the 3 TRV’s over the last 12 hours, and all offsets remain constant. I am not sure if this intended or the blueprint doesn’t update my manually configured offsets. How can I verify that the blueprint actually tries to correct the offset?
You could check the trace or post the json trace here. Be sure the trigger was the time trigger (every 10 minute). I will add some logging to the test version. Thanks for your help.