đŸ”„ Advanced Heating Control

@KF2806

Could you paste this into the template editor, edit your thermostat in the first row and post the result here? :pray:

{% set valves_calibration_common = ['climate.YOUR_THERMOSTAT'] %}
{% set input_calibration_key_word = 'external' %}

{% set value_temperature_sensor = 19 %}
{% set is_native_calibration_trigger = true %}
{% set is_calibration_enabled = true %}
{% set input_calibration_delta = 0.1 %}
{% set is_calibration_trigger = true %}
{% set keep_alive_manufactures = [] %}
{% set is_aggressive_mode_calibration = false %}

{% set n = namespace(dict=[]) %}

    {% if is_native_calibration_trigger and is_calibration_enabled %}
      {% for valve in valves_calibration_common %}

        {% set calibration_entity = device_entities(device_id(valve)) |
                                    expand | selectattr('domain','in','number') |
                                    selectattr('entity_id', 'search', input_calibration_key_word) |
                                    map(attribute='entity_id') | list | first | default(none) %}

        {% if calibration_entity is not none %}

          {% set calibration_entity_min = state_attr(calibration_entity,'min') | float %}
          {% set calibration_entity_max = state_attr(calibration_entity,'max') | float %}
          {% set calibration_entity_value_old = states(calibration_entity) | float %}
          {% set local_temperature = value_temperature_sensor | float %}
          {% set calibration_entity_value_new = local_temperature %}
          {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %}
          {% set calibration_select = none %}

          {% if is_offset_entity %}
            {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %}
            {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %}
          {% else %}
            {% set calibration_select = device_entities(device_id(valve))
                        | expand
                        | selectattr('domain','in','select')
                        | selectattr('attributes.options', 'contains', 'external')
                        | map(attribute='entity_id') | list | first | default(none) %}
          {% endif %}

          {% set calibration_entities = device_entities(device_id(valve)) |
                                    expand | selectattr('domain','in','number') |
                                    selectattr('entity_id', 'search', input_calibration_key_word) |
                                    map(attribute='entity_id') | list %}

          {% set step = state_attr(calibration_entity, 'step') | float(1) %}
          {% if rounding_mode == 'manual' %}
              {% set step = input_calibration_step_size | float(1) %}
          {% endif %}

          {% if is_aggressive_mode_calibration %}
            {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %}

            {% if temp_diff * factor < input_aggressive_mode_range * -1 %}
              {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %}
            {% elif temp_diff * factor > input_aggressive_mode_range %}
              {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %}
            {% endif %}
          {% endif %}

          {% if step <= 1 and calibration_entity_max | float < 1000 %}
            {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %}
            {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %}
          {% else %}
            {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %}
          {% endif %}

          {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %}
          {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %}

          {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %}

          {% set keep_alive = false %}

          {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %}
            {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %}
            {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %}
          {% endif %}

Entity: {{ calibration_entity }}
State: {{ states(calibration_entity) }}
New State: {{ calibration_entity_value_new }}
Old State: {{ calibration_entity_value_old }}
Min: {{ calibration_entity_min }}
Max: {{ calibration_entity_max }}
Is Offset Entity: {{ is_offset_entity }}
Select: {{ calibration_select }}
{% if calibration_select is not none %}Select Value: {{ states(calibration_select) }}{% endif %}

          {% if is_min_difference or keep_alive %}
            {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity,
                                                  'value': calibration_entity_value_new,
                                                  'select':calibration_select,
                                                  'value_old':calibration_entity_value_old }])] %}
          {% endif %}
        {% endif %}

      {% endfor %}
    {% endif %}

    {{ dict.from_keys(n.dict) }}

@kartname

Could you use share the trace log for example here? Just share the link here.

Today the external temp got not updated (and the TRV stayed at 100% all the time) for 5h. 5h ago was probably the time i installed the HA beta.
After going back to 2025.12 it working again.

Yes, there must be some errors in your home assistant log:

ValueError: Template error: float got invalid input 'unknown' when rendering template '{% set n = namespace(dict=[]) %}\n{% if is_native_calibration_trigger and is_calibration_enabled %}\n  {% for valve in valves_calibration_common %}\n\n    {% set calibration_entity = device_entities(device_id(valve)) |\n                                expand | selectattr('domain','in','number') |\n                                selectattr('entity_id', 'search', input_calibration_key_word) |\n                                map(attribute='entity_id') | list | first | default(none) %}\n\n    {% if calibration_entity is not none %}\n\n      {% set calibration_entity_min = state_attr(calibration_entity,'min') | float %}\n      {% set calibration_entity_max = state_attr(calibration_entity,'max') | float %}\n      {% set calibration_entity_value_old = states(calibration_entity) | float %}\n      {% set local_temperature = value_temperature_sensor | float %}\n      {% set calibration_entity_value_new = local_temperature %}\n      {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %}\n      {% set calibration_select = none %}\n\n      {% if is_offset_entity %}\n        {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %}\n        {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %}\n      {% else %}\n        {% set calibration_select = device_entities(device_id(valve))\n                    | expand\n                    | selectattr('domain','in','select')\n                    | selectattr('attributes.options', 'contains', 'external')\n                    | map(attribute='entity_id') | list | first | default(none) %}\n      {% endif %}\n\n      {% set calibration_entities = device_entities(device_id(valve)) |\n                                expand | selectattr('domain','in','number') |\n                                selectattr('entity_id', 'search', input_calibration_key_word) |\n                                map(attribute='entity_id') | list %}\n\n      {% set step = state_attr(calibration_entity, 'step') | float(1) %}\n      {% if rounding_mode == 'manual' %}\n          {% set step = input_calibration_step_size | float(1) %}\n      {% endif %}\n\n      {% if is_aggressive_mode_calibration %}\n        {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %}\n\n        {% if temp_diff * factor < input_aggressive_mode_range * -1 %}\n          {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %}\n        {% elif temp_diff * factor > input_aggressive_mode_range %}\n          {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %}\n        {% endif %}\n      {% endif %}\n\n      {% if step <= 1 and calibration_entity_max | float < 1000 %}\n        {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %}\n        {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %}\n      {% else %}\n        {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %}\n      {% endif %}\n\n      {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %}\n      {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %}\n\n      {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %}\n\n      {% set keep_alive = false %}\n\n      {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %}\n        {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %}\n        {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %}\n      {% endif %}\n\n      {% if is_min_difference or keep_alive %}\n        {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity,\n                                              'value': calibration_entity_value_new,\n                                              'select':calibration_select,\n  

I dont’ know exactly whicht entity is in unknown state but this fires an error. Because all values here are necessary for calibration it doesn’t happen in your case.

https://pastecode.io/s/xrkw3fwe

Here is the result:



{% set valves_calibration_common = ['climate.heizung_bad'] %}
{% set input_calibration_key_word = 'external' %}

{% set value_temperature_sensor = 19 %}
{% set is_native_calibration_trigger = true %}
{% set is_calibration_enabled = true %}
{% set input_calibration_delta = 0.1 %}
{% set is_calibration_trigger = true %}
{% set keep_alive_manufactures = [] %}
{% set is_aggressive_mode_calibration = false %}

{% set n = namespace(dict=[]) %}

    {% if is_native_calibration_trigger and is_calibration_enabled %}
      {% for valve in valves_calibration_common %}

        {% set calibration_entity = device_entities(device_id(valve)) |
                                    expand | selectattr('domain','in','number') |
                                    selectattr('entity_id', 'search', input_calibration_key_word) |
                                    map(attribute='entity_id') | list | first | default(none) %}

        {% if calibration_entity is not none %}

          {% set calibration_entity_min = state_attr(calibration_entity,'min') | float %}
          {% set calibration_entity_max = state_attr(calibration_entity,'max') | float %}
          {% set calibration_entity_value_old = states(calibration_entity) | float %}
          {% set local_temperature = value_temperature_sensor | float %}
          {% set calibration_entity_value_new = local_temperature %}
          {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %}
          {% set calibration_select = none %}

          {% if is_offset_entity %}
            {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %}
            {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %}
          {% else %}
            {% set calibration_select = device_entities(device_id(valve))
                        | expand
                        | selectattr('domain','in','select')
                        | selectattr('attributes.options', 'contains', 'external')
                        | map(attribute='entity_id') | list | first | default(none) %}
          {% endif %}

          {% set calibration_entities = device_entities(device_id(valve)) |
                                    expand | selectattr('domain','in','number') |
                                    selectattr('entity_id', 'search', input_calibration_key_word) |
                                    map(attribute='entity_id') | list %}

          {% set step = state_attr(calibration_entity, 'step') | float(1) %}
          {% if rounding_mode == 'manual' %}
              {% set step = input_calibration_step_size | float(1) %}
          {% endif %}

          {% if is_aggressive_mode_calibration %}
            {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %}

            {% if temp_diff * factor < input_aggressive_mode_range * -1 %}
              {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %}
            {% elif temp_diff * factor > input_aggressive_mode_range %}
              {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %}
            {% endif %}
          {% endif %}

          {% if step <= 1 and calibration_entity_max | float < 1000 %}
            {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %}
            {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %}
          {% else %}
            {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %}
          {% endif %}

          {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %}
          {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %}

          {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %}

          {% set keep_alive = false %}

          {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %}
            {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %}
            {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %}
          {% endif %}

Entity: {{ calibration_entity }}
State: {{ states(calibration_entity) }}
New State: {{ calibration_entity_value_new }}
Old State: {{ calibration_entity_value_old }}
Min: {{ calibration_entity_min }}
Max: {{ calibration_entity_max }}
Is Offset Entity: {{ is_offset_entity }}
Select: {{ calibration_select }}
{% if calibration_select is not none %}Select Value: {{ states(calibration_select) }}{% endif %}

          {% if is_min_difference or keep_alive %}
            {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity,
                                                  'value': calibration_entity_value_new,
                                                  'select':calibration_select,
                                                  'value_old':calibration_entity_value_old }])] %}
          {% endif %}
        {% endif %}

      {% endfor %}
    {% endif %}

    {{ dict.from_keys(n.dict) }}
ValueError: Template error: float got invalid input 'unknown' when rendering template '{% set valves_calibration_common = ['climate.heizung_bad'] %} {% set input_calibration_key_word = 'external' %} {% set value_temperature_sensor = 19 %} {% set is_native_calibration_trigger = true %} {% set is_calibration_enabled = true %} {% set input_calibration_delta = 0.1 %} {% set is_calibration_trigger = true %} {% set keep_alive_manufactures = [] %} {% set is_aggressive_mode_calibration = false %} {% set n = namespace(dict=[]) %} {% if is_native_calibration_trigger and is_calibration_enabled %} {% for valve in valves_calibration_common %} {% set calibration_entity = device_entities(device_id(valve)) | expand | selectattr('domain','in','number') | selectattr('entity_id', 'search', input_calibration_key_word) | map(attribute='entity_id') | list | first | default(none) %} {% if calibration_entity is not none %} {% set calibration_entity_min = state_attr(calibration_entity,'min') | float %} {% set calibration_entity_max = state_attr(calibration_entity,'max') | float %} {% set calibration_entity_value_old = states(calibration_entity) | float %} {% set local_temperature = value_temperature_sensor | float %} {% set calibration_entity_value_new = local_temperature %} {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %} {% set calibration_select = none %} {% if is_offset_entity %} {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %} {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %} {% else %} {% set calibration_select = device_entities(device_id(valve)) | expand | selectattr('domain','in','select') | selectattr('attributes.options', 'contains', 'external') | map(attribute='entity_id') | list | first | default(none) %} {% endif %} {% set calibration_entities = device_entities(device_id(valve)) | expand | selectattr('domain','in','number') | selectattr('entity_id', 'search', input_calibration_key_word) | map(attribute='entity_id') | list %} {% set step = state_attr(calibration_entity, 'step') | float(1) %} {% if rounding_mode == 'manual' %} {% set step = input_calibration_step_size | float(1) %} {% endif %} {% if is_aggressive_mode_calibration %} {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %} {% if temp_diff * factor < input_aggressive_mode_range * -1 %} {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %} {% elif temp_diff * factor > input_aggressive_mode_range %} {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %} {% endif %} {% endif %} {% if step <= 1 and calibration_entity_max | float < 1000 %} {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %} {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %} {% else %} {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %} {% endif %} {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %} {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %} {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %} {% set keep_alive = false %} {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %} {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %} {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %} {% endif %} Entity: {{ calibration_entity }} State: {{ states(calibration_entity) }} New State: {{ calibration_entity_value_new }} Old State: {{ calibration_entity_value_old }} Min: {{ calibration_entity_min }} Max: {{ calibration_entity_max }} Is Offset Entity: {{ is_offset_entity }} Select: {{ calibration_select }} {% if calibration_select is not none %}Select Value: {{ states(calibration_select) }}{% endif %} {% if is_min_difference or keep_alive %} {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity, 'value': calibration_entity_value_new, 'select':calibration_select, 'value_old':calibration_entity_value_old }])] %} {% endif %} {% endif %} {% endfor %} {% endif %} {{ dict.from_keys(n.dict) }}' but no default was specified
1 Like

Could you test again with this snippet?

{% set valves_calibration_common = ['climate.heizung_bad'] %}
{% set input_calibration_key_word = 'external' %}

{% set value_temperature_sensor = 19 %}
{% set is_native_calibration_trigger = true %}
{% set is_calibration_enabled = true %}
{% set input_calibration_delta = 0.1 %}
{% set is_calibration_trigger = true %}
{% set keep_alive_manufactures = [] %}
{% set is_aggressive_mode_calibration = false %}

{% set n = namespace(dict=[]) %}

{% if is_native_calibration_trigger and is_calibration_enabled %}
  {% for valve in valves_calibration_common %}

    {% set calibration_entity = device_entities(device_id(valve)) |
                                expand | selectattr('domain','in','number') |
                                selectattr('entity_id', 'search', input_calibration_key_word) |
                                map(attribute='entity_id') | list | first | default(none) %}

    {% if calibration_entity is not none %}
    
      {% set fallback_min = iif('external' in calibration_entity, 0, -12)%}
      {% set fallback_max = iif('external' in calibration_entity, 50, 12)%}

      {% set calibration_entity_min = state_attr(calibration_entity,'min') | float(fallback_min) %}
      {% set calibration_entity_max = state_attr(calibration_entity,'max') | float(fallback_max) %}
      {% set calibration_entity_value_old = states(calibration_entity) | float(0) %}
      {% set local_temperature = value_temperature_sensor | float %}
      {% set calibration_entity_value_new = local_temperature %}
      {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %}
      {% set calibration_select = none %}

      {% if is_offset_entity %}
        {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %}
        {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %}
      {% else %}
        {% set calibration_select = device_entities(device_id(valve))
                    | expand
                    | selectattr('domain','in','select')
                    | selectattr('attributes.options', 'contains', 'external')
                    | map(attribute='entity_id') | list | first | default(none) %}
      {% endif %}

      {% set step = state_attr(calibration_entity, 'step') | float(1) %}
      {% if rounding_mode == 'manual' %}
          {% set step = input_calibration_step_size | float(1) %}
      {% endif %}

      {% if is_aggressive_mode_calibration %}
        {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %}

        {% if temp_diff * factor < input_aggressive_mode_range * -1 %}
          {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %}
        {% elif temp_diff * factor > input_aggressive_mode_range %}
          {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %}
        {% endif %}
      {% endif %}

      {% if step <= 1 and calibration_entity_max | float < 1000 %}
        {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %}
        {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %}
      {% else %}
        {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %}
      {% endif %}

      {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %}
      {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %}

      {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %}

      {% set keep_alive = false %}

      {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %}
        {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %}
        {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %}
      {% endif %}

Entity: {{ calibration_entity }}
State: {{ states(calibration_entity) }}
New State: {{ calibration_entity_value_new }}
Old State: {{ calibration_entity_value_old }}
Min: {{ calibration_entity_min }}
Max: {{ calibration_entity_max }}
Is Offset Entity: {{ is_offset_entity }}
Select: {{ calibration_select }}
{% if calibration_select is not none %}Select Value: {{ states(calibration_select) }}{% endif %}

          {% if is_min_difference or keep_alive %}
            {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity,
                                                  'value': calibration_entity_value_new,
                                                  'select':calibration_select,
                                                  'value_old':calibration_entity_value_old }])] %}
          {% endif %}
        {% endif %}

      {% endfor %}
    {% endif %}

    {{ dict.from_keys(n.dict) }}

If this won’t result in an error again, you could update to the latest version of the blueprint.

Just set this to 0:

Hello panhans, seems fine now.



{% set valves_calibration_common = ['climate.heizung_bad'] %}
{% set input_calibration_key_word = 'external' %}

{% set value_temperature_sensor = 19 %}
{% set is_native_calibration_trigger = true %}
{% set is_calibration_enabled = true %}
{% set input_calibration_delta = 0.1 %}
{% set is_calibration_trigger = true %}
{% set keep_alive_manufactures = [] %}
{% set is_aggressive_mode_calibration = false %}

{% set n = namespace(dict=[]) %}

{% if is_native_calibration_trigger and is_calibration_enabled %}
  {% for valve in valves_calibration_common %}

    {% set calibration_entity = device_entities(device_id(valve)) |
                                expand | selectattr('domain','in','number') |
                                selectattr('entity_id', 'search', input_calibration_key_word) |
                                map(attribute='entity_id') | list | first | default(none) %}

    {% if calibration_entity is not none %}
    
      {% set fallback_min = iif('external' in calibration_entity, 0, -12)%}
      {% set fallback_max = iif('external' in calibration_entity, 50, 12)%}

      {% set calibration_entity_min = state_attr(calibration_entity,'min') | float(fallback_min) %}
      {% set calibration_entity_max = state_attr(calibration_entity,'max') | float(fallback_max) %}
      {% set calibration_entity_value_old = states(calibration_entity) | float(0) %}
      {% set local_temperature = value_temperature_sensor | float %}
      {% set calibration_entity_value_new = local_temperature %}
      {% set is_offset_entity = (calibration_entity_min + calibration_entity_max) == 0 and calibration_entity_max < 30 %}
      {% set calibration_select = none %}

      {% if is_offset_entity %}
        {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %}
        {% set calibration_entity_value_new = (-(thermostat_temperature - local_temperature) + calibration_entity_value_old) %}
      {% else %}
        {% set calibration_select = device_entities(device_id(valve))
                    | expand
                    | selectattr('domain','in','select')
                    | selectattr('attributes.options', 'contains', 'external')
                    | map(attribute='entity_id') | list | first | default(none) %}
      {% endif %}

      {% set step = state_attr(calibration_entity, 'step') | float(1) %}
      {% if rounding_mode == 'manual' %}
          {% set step = input_calibration_step_size | float(1) %}
      {% endif %}

      {% if is_aggressive_mode_calibration %}
        {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - local_temperature %}

        {% if temp_diff * factor < input_aggressive_mode_range * -1 %}
          {% set calibration_entity_value_new = calibration_entity_value_new + input_aggressive_mode_offset * factor %}
        {% elif temp_diff * factor > input_aggressive_mode_range %}
          {% set calibration_entity_value_new = calibration_entity_value_new - input_aggressive_mode_offset * factor %}
        {% endif %}
      {% endif %}

      {% if step <= 1 and calibration_entity_max | float < 1000 %}
        {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %}
        {% set calibration_entity_value_new = ((calibration_entity_value_new | float(0) / step) | round(0) * step) | round(round_size) | float %}
      {% else %}
        {% set calibration_entity_value_new = calibration_entity_value_new * 100 | int %}
      {% endif %}

      {% set calibration_entity_value_new = iif(calibration_entity_value_new > calibration_entity_max, calibration_entity_max, calibration_entity_value_new) %}
      {% set calibration_entity_value_new = iif(calibration_entity_value_new < calibration_entity_min, calibration_entity_min, calibration_entity_value_new) %}

      {% set is_min_difference = (float(calibration_entity_value_old) - float(calibration_entity_value_new)) | abs >= float(input_calibration_delta) %}

      {% set keep_alive = false %}

      {% if is_calibration_trigger and not is_min_difference and device_attr(valve,'manufacturer') in keep_alive_manufactures %}
        {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %}
        {% set keep_alive = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %}
      {% endif %}

Entity: {{ calibration_entity }}
State: {{ states(calibration_entity) }}
New State: {{ calibration_entity_value_new }}
Old State: {{ calibration_entity_value_old }}
Min: {{ calibration_entity_min }}
Max: {{ calibration_entity_max }}
Is Offset Entity: {{ is_offset_entity }}
Select: {{ calibration_select }}
{% if calibration_select is not none %}Select Value: {{ states(calibration_select) }}{% endif %}

          {% if is_min_difference or keep_alive %}
            {% set n.dict = n.dict + [(valve, [{ 'calibration_entity': calibration_entity,
                                                  'value': calibration_entity_value_new,
                                                  'select':calibration_select,
                                                  'value_old':calibration_entity_value_old }])] %}
          {% endif %}
        {% endif %}

      {% endfor %}
    {% endif %}

    {{ dict.from_keys(n.dict) }}
Entity: number.heizung_bad_external_temperature_input
State: unknown
New State: 19.0
Old State: 0
Min: 0.0
Max: 55.0
Is Offset Entity: False
Select: select.heizung_bad_sensor
Select Value: external

          
            
          
        

      
    

    {'climate.heizung_bad': [{'calibration_entity': 'number.heizung_bad_external_temperature_input', 'value': 19.0, 'select': 'select.heizung_bad_sensor', 'value_old': 0}]}
Ergebnistyp: string

Dieses Template abonniert die folgenden Ereignisse zu ZustandsÀnderungen:

EntitÀt: binary_sensor.heizung_bad_calibrated
EntitÀt: binary_sensor.heizung_bad_setup
EntitÀt: binary_sensor.heizung_bad_valve_alarm
EntitÀt: binary_sensor.heizung_bad_window_open
EntitÀt: button.heizung_bad_calibrate
EntitÀt: climate.heizung_bad
EntitÀt: number.heizung_bad_away_preset_temperature
EntitÀt: number.heizung_bad_external_temperature_input
EntitÀt: select.heizung_bad_sensor
EntitÀt: sensor.heizung_bad_battery
EntitÀt: sensor.heizung_bad_device_temperature
EntitÀt: sensor.heizung_bad_last_seen
EntitÀt: sensor.heizung_bad_power_outage_count
EntitÀt: sensor.heizung_bad_voltage
EntitÀt: switch.heizung_bad_child_lock
EntitÀt: switch.heizung_bad_schedule
EntitÀt: switch.heizung_bad_valve_detection_2
EntitÀt: switch.heizung_bad_window_detection_2
EntitÀt: text.heizung_bad_schedule_settings
EntitÀt: update.heizung_bad
1 Like

This issue seems fixed now and i tried version 5.5.0_a4 since 3 hours,
But now heating will not turn off, if the windows is open.

Sry, another update should solve the problem. :grinning:

Great job. Thats how development works :grinning:.
Thanks for your great blueprint.

1 Like

I just realized that if multiple persons are added to the automation, the heating will only turn on if both are at home, so effectively this is an AND logic. I would appreciate it if this could be switched to a OR logic. At least optional. I want the heating to turn on if anybody is at home

@Tomibeck I don’t think that’s true. For me it is “if at least one is home”. Here’s a screenshot of my sensor with currently 1 person being at home:

Configuration:

1 Like

Hi, are you using the Bosch TRVs with Matter if yes how exactly does your configuration look like that calibration with an external sensor is working?

:fire: Advanced Heating Control 5.5.0 :fire:

  • input number for window open temperature
  • fallback option (off/heat) if weather entity or ouside temperature get unavailable or unknown
  • persons could be replaced by device trackers (recommended)
  • minimal configuration revised (window detection, liming protection)
  • event based restore after liming protection
  • static temperatures renamed to fallback temperatures
  • fallback temperature (static temperatures) could be replaced by input number entities
  • revised sections, selectors, and descriptions
  • idle temperature when automation is turned off (winter mode off)
  • dedicated hvac actions for eco mode and comfort mode
  • new logic for physical or ui / thermostat cards changes
  • summarized calibration logic:
    • calibration on/off toggle
    • automatic detection of offset or external temperature source for calibration
    • thermostats with external calibration get keep alives every 10 min automatically

:collision: BREAKING CHANGES

  • off instead of eco has been removed (set hvac mode off in eco mode options)
  • physical change is independent of UI changes now. check your settings if you like.
  • using calibration by offset be sure the calibration entity id contains the word ‘offset’
3 Likes

Nope, comfort kicks in if at least one person is at home. Eco when nobody is at home.

@panhans Do you have removed the dev Version? :see_no_evil:
Can you put it also in the dev Version? Than i can Test simultan. :see_no_evil:

Yes, since I worked on a dev branch this doesn’t fit to my workflow. But I’ve just restored it. :wink: Try again.

1 Like

That’s weird I swear when I removed my wife :sweat_smile:. Heating kicked in right away. I’ll check what was going on.

i think you should add in the breaking changes that we need manually delete “input_off_instead_of_eco: true” or override it with “input_hvac_mode_eco: “off”” if exist, to have a clean blueprint. (or i understand something wrong?)

PS: i know in the last releases we had often the problem when we have older variables in it.

PS2. What is happening when i have in the fallback Comfort Temp two inputs selected what selector is the primary when i change only in the gui input selector?

PS3: you need also update the ahc_template_sensor.yaml :slight_smile: