Opentherm Multi Room brainstorming / ideas

I have somehere an error in this code

Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: unexpected 'end of print statement') for dictionary value @ data['sensors']['virtual_target']['value_template']. Got "{% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %} {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %} {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %} {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen')...
invalid template (TemplateSyntaxError: unexpected 'end of print statement') for dictionary value @ data['sensors']['virtual_temperature']['value_template']. Got "{% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %} {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %} {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %} {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen').... (See ?, line ?).
    sensors:
      virtual_temperature:
        friendly_name: "Virtual Temperature"
        unit_of_measurement: "°C"
        value_template: >
          {% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %}
          {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %}
          {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %}
          {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen') | float) %}
          {% set bathroom_td = (states('sensor.target_temperature_bathr') - states('sensor.ble_temperature_clim_bathroom') | float) %}
          {% set max_td = ([masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] | max) %}
          {% set list_room_td = [masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] %}
          {% set index_td = list_room_td.index(max_td) %}
          {% if index_td == 1 %}
            {{ (states('sensor.ble_temperature_clim_master_bedroom') | float) % }}
          {% elif index_td == 2 %}
            {{ (states('sensor.ble_temperature_clim_kids_bedroom') | float) % }}
          {% elif index_td == 3 %}
            {{ (states('sensor.ble_temperature_clim_kitchen') | float) % }}
          {% elif index_td == 4 %}
            {{ (states('sensor.ble_temperature_clim_bathroom') | float) % }}
          {% else %}
            {{ (states('sensor.ble_temperature_clim_living') | float) % }}
          {% endif %}
      virtual_target:
        friendly_name: "Virtual Target"
        unit_of_measurement: "°C"
        value_template: >
          {% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %}
          {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %}
          {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %}
          {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen') | float) %}
          {% set bathroom_td = (states('sensor.target_temperature_bathr') - states('sensor.ble_temperature_clim_bathroom') | float) %}
          {% set max_td = ([masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] | max) %}
          {% set list_room_td = [masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] %}
          {% set index_td = list_room_td.index(max_td) %}
          {% if index_td == 1 %}
            {{ (states('sensor.target_temperature_br') | float) % }}
          {% elif index_td == 2 %}
            {{ (states('sensor.target_temperature_kidsbr') | float) % }}
          {% elif index_td == 3 %}
            {{ (states('sensor.target_temperature_kit') | float) % }}
          {% elif index_td == 4 %}
            {{ (states('sensor.target_temperature_bathr') | float) % }}
          {% else %}
            {{ (states('sensor.target_temperature_lr') | float) % }}
          {% endif %}

You got an extra % at the end there.
Also, always define a default value if for some reason the sensor wont work.

{% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float(18)) %}

{{ (states('sensor.target_temperature_br') | float(18)) }}

Just a pointer which I’ve spent a while try to figure out!

I think the {% if index_td == 1 %} should start at 0 and then run through to 1 - the number of rooms you have.

I had issues where the list was picking out the second largest temperature difference!

Credit to Chat GPT AI who help me haha!

1 Like

You know, you are right. I never realized that it would count from zero.
My lack of programming skills shows :smiley: Seem thats always the case be it Jinja or Python.

Ow Frell me… I already took that into account. The living room (woonkamer is 0) so i just check for 1 and 2 and if its 0 then take the living room value.
I noticed when it stopped working correctly after changing it :frowning:

1 Like

Which sketch are you using? The DIYLESS Git Hub one or the modified version by Joparmen?

I think I have everything working other than, for some reason the set values don’t seem to trigger the boiler to start heating. I’ve checked in MQTT explorer and they are been sent over correctly, but the get topics never seem to update.

I am running the Joparmen version though.

Cheers, happy to help.

Maybe I’m impatient… It seems to have the values now…

still not working here. I receive state: unavailable

- platform: template
    sensors:
      virtual_temperature:
        friendly_name: "Virtual Temperature"
        unit_of_measurement: "°C"
        value_template: >
          {% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %}
          {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %}
          {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %}
          {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen') | float) %}
          {% set bathroom_td = (states('sensor.target_temperature_bathr') - states('sensor.ble_temperature_clim_bathroom') | float) %}
          {% set max_td = ([masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] | max) %}
          {% set list_room_td = [masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] %}
          {% set index_td = list_room_td.index(max_td) %}
          {% if index_td == 1 %}
            {{ (states('sensor.ble_temperature_clim_master_bedroom') | float(18)) }}
          {% elif index_td == 2 %}
            {{ (states('sensor.ble_temperature_clim_kids_bedroom') | float(18)) }}
          {% elif index_td == 3 %}
            {{ (states('sensor.ble_temperature_clim_kitchen') | float(18)) }}
          {% elif index_td == 4 %}
            {{ (states('sensor.ble_temperature_clim_bathroom') | float(18)) }}
          {% else %}
            {{ (states('sensor.ble_temperature_clim_living') | float(18)) }}
          {% endif %}
      virtual_target:
        friendly_name: "Virtual Target"
        unit_of_measurement: "°C"
        value_template: >
          {% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %}
          {% set kidsbedroom_td = (states('sensor.target_temperature_kidsbr') - states('sensor.ble_temperature_clim_kids_bedroom') | float) %}
          {% set livingroom_td = (states('sensor.target_temperature_lr') - states('sensor.ble_temperature_clim_living') | float) %}
          {% set kitchen_td = (states('sensor.target_temperature_kit') - states('sensor.ble_temperature_clim_kitchen') | float) %}
          {% set bathroom_td = (states('sensor.target_temperature_bathr') - states('sensor.ble_temperature_clim_bathroom') | float) %}
          {% set max_td = ([masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] | max) %}
          {% set list_room_td = [masterbedroom_td,kidsbedroom_td,kitchen_td,bathroom_td,livingroom_td] %}
          {% set index_td = list_room_td.index(max_td) %}
          {% if index_td == 1 %}
            {{ (states('sensor.target_temperature_br') | float(18)) }}
          {% elif index_td == 2 %}
            {{ (states('sensor.target_temperature_kidsbr') | float(18)) }}
          {% elif index_td == 3 %}
            {{ (states('sensor.target_temperature_kit') | float(18)) }}
          {% elif index_td == 4 %}
            {{ (states('sensor.target_temperature_bathr') | float(18)) }}
          {% else %}
            {{ (states('sensor.target_temperature_lr') | float(18)) }}
          {% endif %}

Lets take a step back and just insert this in the Developer ToolsTemplate

{% set masterbedroom_td = (states('sensor.target_temperature_br') - states('sensor.ble_temperature_clim_master_bedroom') | float) %}
{{ masterbedroom_td }}

And just this:

{{ states('sensor.target_temperature_br') }}
{{ states('sensor.ble_temperature_clim_master_bedroom') }}

Also you should always define a default value for if the sensor bugs out or any other startup problem when the sensor is unknow for some reason

So what do those 2 give?

The first one

TypeError: unsupported operand type(s) for -: ‘str’ and ‘float’

The second one
19.0
20.7

{% set masterbedroom_td = (states('sensor.target_temperature_br') | float(18) - states('sensor.ble_temperature_clim_master_bedroom') | float(18)) %}
{{ masterbedroom_td }}

I think you need to define both as floats (and give them a default value)
Right you you just specified the last one as a float and HA is seeing the first one as a string, and since you cannot subtract a float from a string, you get that error.

thank u this works. another problem, how can I exclude the rooms with a negative difference from the list? For example living room is 2 degrees to warm, the rest of the room is 0,5 degrees below set point. How do I ban the living room from determining the temperature?

You dont. 2 degrees to warm means its -2 difference. Thats smaller then 0,5 so it will pick the 0,5 difference

Hello,

I’m trying your code for the virtual temp and set temp.
I have more zones and tried to extend it.

It doesn’t seem to work, Can someone guide me what I’m doing wrong?

this is what I added in the “sensor.yaml”

Thanks in advance.

setpoint_cv_virtual:
  friendly_name: "CV Virtual Setpoint"
  unit_of_measurement: "°C"
  value_template: >
    {% set woonkamer_td = (state_attr('climate.woonkamer_bt','temperature') - states('sensor.living_room_temperature') | float) %}
    {% set berging_td = (state_attr('climate.berging_bt','temperature') - states('sensor.berging_mija_temp_temperature') | float) %}
    {% set slaapkamer_td = (state_attr('climate.slaapkamer','temperature') - states('sensor.mbr_temperature') | float) %}
    {% set badkamer_td = (state_attr('climate.badkamer_bt','temperature') - states('sensor.badkamer_mija_temp_temperature') | float) %}
    {% set inkomhall_td = (state_attr('climate.inkomhall','temperature') - states('sensor.inkomhal_radiator_local_temperature') | float) %}
    {% set fitness_td = (state_attr('climate.fitness','temperature') - states('sensor.fitness_temperature') | float) %}
    {% set max_td = ([woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] | max) %}
    {% set list_room_td = [woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] %}
    {% set index_td = list_room_td.index(max_td) %}
    {% if index_td == 1 %}
      {{ state_attr('climate.woonkamer_bt','temperature') }}
    {% elif index_td == 2 %}
      {{ state_attr('climate.berging_bt','temperature') }}
    {% elif index_td == 3 %}
      {{ state_attr('climate.slaapkamer','temperature') }} 
    {% elif index_td == 4 %}
      {{ state_attr('climate.badkamer_bt','temperature') }}  
    {% elif index_td == 5 %}
      {{ state_attr('climate.inkomhall','temperature') }}          
    {% else %}
      {{ state_attr('climate.fitness','temperature') }}          
    {% endif %}
temperature_cv_virtual:
  friendly_name: "CV Virtual Temperature"
  unit_of_measurement: "°C"
  value_template: >
    {% set woonkamer_td = (state_attr('climate.woonkamer_bt','temperature') - states('sensor.living_room_temperature') | float) %}
    {% set berging_td = (state_attr('climate.berging_bt','temperature') - states('sensor.berging_mija_temp_temperature') | float)%}
    {% set slaapkamer_td = (state_attr('climate.slaapkamer','temperature') - states('sensor.mbr_temperature') | float) %}
    {% set badkamer_td = (state_attr('climate.badkamer_bt','temperature') - states('sensor.badkamer_mija_temp_temperature') | float) %}
    {% set inkomhall_td = (state_attr('climate.inkomhall','temperature') - states('sensor.inkomhal_radiator_local_temperature') | float) %}
    {% set fitness_td = (state_attr('climate.fitness','temperature') - states('sensor.fitness_temperature') | float) %}
    {% set max_td = ([woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] | max) %}
    {% set list_room_td = [woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] %}
    {% set index_td = list_room_td.index(max_td) %}
    {% if index_td == 1 %}
      {{ states('sensor.living_room_temperature') | float }}
    {% elif index_td == 2 %}
      {{ states('sensor.berging_mija_temp_temperature') | float }}
    {% elif index_td == 3 %}
      {{ states('sensor.mbr_temperature') | float }}  
    {% elif index_td == 4 %}
      {{ states('sensor.badkamer_mija_temp_temperature') | float }} 
    {% elif index_td == 5 %}
      {{ states('sensor.inkomhal_radiator_local_temperature') | float }} 
    {% else %}
      {{ states('sensor.fitness_temperature') | float }}          
    {% endif %}

If you are posting code, use the code tags and not quotes. That way you can pick out errors with indentations more easily. Like the first part:

setpoint_cv_virtual:
  friendly_name: "CV Virtual Setpoint"
  unit_of_measurement: "°C"
  value_template: >
    {% set woonkamer_td = (state_attr('climate.woonkamer_bt','temperature') - states('sensor.living_room_temperature') | float) %}
    {% set berging_td = (state_attr('climate.berging_bt','temperature') - states('sensor.berging_mija_temp_temperature') | float) %}
    {% set slaapkamer_td = (state_attr('climate.slaapkamer','temperature') - states('sensor.mbr_temperature') | float) %}
    {% set badkamer_td = (state_attr('climate.badkamer_bt','temperature') - states('sensor.badkamer_mija_temp_temperature') | float) %}
    {% set inkomhall_td = (state_attr('climate.inkomhall','temperature') - states('sensor.inkomhal_radiator_local_temperature') | float) %}
    {% set fitness_td = (state_attr('climate.fitness','temperature') - states('sensor.fitness_temperature') | float) %}
    {% set max_td = ([woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] | max) %}
    {% set list_room_td = [woonkamer_td,berging_td,slaapkamer_td,badkamer_td,inkomhall_td,fitness_td] %}
    {% set index_td = list_room_td.index(max_td) %}
    {% if index_td == 1 %}
      {{ state_attr('climate.woonkamer_bt','temperature') }}
    {% elif index_td == 2 %}
      {{ state_attr('climate.berging_bt','temperature') }}
    {% elif index_td == 3 %}
      {{ state_attr('climate.slaapkamer','temperature') }} 
    {% elif index_td == 4 %}
      {{ state_attr('climate.badkamer_bt','temperature') }}  
    {% elif index_td == 5 %}
      {{ state_attr('climate.inkomhall','temperature') }}          
    {% else %}
      {{ state_attr('climate.fitness','temperature') }}          
    {% endif %}

Having said that, you never seemed to define this is a template sensor.

Keep in mind that my code is old and had a few revisions. Important thing is to add default values so these get used when sensors are offline.

- platform: template
  sensors:
      setpoint_cv_virtual:
      friendly_name: "CV Virtual Setpoint"
      unit_of_measurement: "°C"
      value_template: >
        {% set alex_td = state_attr('climate.alex','temperature') | float(18) - states('sensor.alex_sensor_temperature') | float(18) %}
        {% set esther_td = state_attr('climate.esther','temperature') | float(18) - states('sensor.esther_sensor_temperature') | float(18) %}
        {% set woonkamer_td = state_attr('climate.woonkamer','temperature') | float(18) - states('sensor.woonkamer_sensor_temperature') | float(18) %}
        {% set max_td = ([woonkamer_td,alex_td,esther_td] | max) %}
        {% set list_room_td = [woonkamer_td,alex_td,esther_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ state_attr('climate.alex','temperature') | float(18)}}
        {% elif index_td == 2 %}
          {{ state_attr('climate.esther','temperature') | float(18)}}
        {% else %}
          {{ state_attr('climate.woonkamer','temperature') | float(18)}}
        {% endif %}
    temperature_cv_virtual:
      friendly_name: "CV Virtual Temperature"
      unit_of_measurement: "°C"
      value_template: >
        {% set alex_td = state_attr('climate.alex','temperature') - states('sensor.alex_sensor_temperature') | float(23) %}
        {% set esther_td = state_attr('climate.esther','temperature') - states('sensor.esther_sensor_temperature') | float(23) %}
        {% set woonkamer_td = state_attr('climate.woonkamer','temperature') - states('sensor.woonkamer_sensor_temperature') | float(23) %}
        {% set max_td = ([woonkamer_td,alex_td,esther_td] | max) %}
        {% set list_room_td = [woonkamer_td,alex_td,esther_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ states('sensor.alex_sensor_temperature') | float(23)}}
        {% elif index_td == 2 %}
          {{ states('sensor.esther_sensor_temperature') | float(23)}}
        {% else %}
          {{ states('sensor.woonkamer_sensor_temperature') | float(23)}}
        {% endif %}

Note that this is the old style as there was an issue getting the friendly_name to behave correctly in the new style. There is a long debate around this: Add (bring back) friendly_name to template sensors
But since the old style does not show signs of being decraped, i will use it like this :smiley:

Edit: i’ll mark this for future reference.

For now (31-7-2023) This is the code i use. Adjusted to use default values and some cleanup.

- platform: template
  sensors:
      setpoint_cv_virtual:
      friendly_name: "CV Virtual Setpoint"
      unit_of_measurement: "°C"
      value_template: >
        {% set alex_td = state_attr('climate.alex','temperature') | float(18) - states('sensor.alex_sensor_temperature') | float(18) %}
        {% set esther_td = state_attr('climate.esther','temperature') | float(18) - states('sensor.esther_sensor_temperature') | float(18) %}
        {% set woonkamer_td = state_attr('climate.woonkamer','temperature') | float(18) - states('sensor.woonkamer_sensor_temperature') | float(18) %}
        {% set max_td = ([woonkamer_td,alex_td,esther_td] | max) %}
        {% set list_room_td = [woonkamer_td,alex_td,esther_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ state_attr('climate.alex','temperature') | float(18)}}
        {% elif index_td == 2 %}
          {{ state_attr('climate.esther','temperature') | float(18)}}
        {% else %}
          {{ state_attr('climate.woonkamer','temperature') | float(18)}}
        {% endif %}
    temperature_cv_virtual:
      friendly_name: "CV Virtual Temperature"
      unit_of_measurement: "°C"
      value_template: >
        {% set alex_td = state_attr('climate.alex','temperature') - states('sensor.alex_sensor_temperature') | float(23) %}
        {% set esther_td = state_attr('climate.esther','temperature') - states('sensor.esther_sensor_temperature') | float(23) %}
        {% set woonkamer_td = state_attr('climate.woonkamer','temperature') - states('sensor.woonkamer_sensor_temperature') | float(23) %}
        {% set max_td = ([woonkamer_td,alex_td,esther_td] | max) %}
        {% set list_room_td = [woonkamer_td,alex_td,esther_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ states('sensor.alex_sensor_temperature') | float(23)}}
        {% elif index_td == 2 %}
          {{ states('sensor.esther_sensor_temperature') | float(23)}}
        {% else %}
          {{ states('sensor.woonkamer_sensor_temperature') | float(23)}}
        {% endif %}

Hello Dujith,

Thanks for your reply.

I forgot to mention that the code I added was only the part for these 2 sensors, I already defined the template sensor.

download the sensor.yaml here

When using this I get the following error while doing “Quick reload”

Failed to reload configuration

Cannot quick reload all YAML configurations because the configuration is not valid: Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: unexpected ‘}’, expected ‘)’) for dictionary value @ data[‘sensors’][‘setpoint_cv_virtual’][‘value_template’]. Got "{% set woonkamer_td = (state_attr(‘climate.woonkamer_bt’,‘temperature’) | float(18) - states(‘sensor.living_room_temperature’) | float(18) %} {% set berging_td = (state_attr(‘climate.berging_bt’,‘temperature’) | float(18) - states(‘sensor.berging_mija_temp_temperature’) | float(18) %} {% set slaapkamer_td = (state_attr(‘climate.slaapkamer’,‘temperature’) | float(18) - states(‘sensor.mbr_temperature’) | float(18) %} {% set badkamer_td = (state_attr(‘climate.badkamer_bt’,‘temperature’) | float… (See ?, line ?).

Just need to add a ) or remove the one at the start: (state_attr
Check all the lines for the missing ) :smiley:

Thanks all for your help, that did it!

It has been interesting to read. I might end up pitching this to my moms association of owners.

The first alteration I would try is moving list_room_td up one line and try to use it for max_td to make things a bit more DRY.

HI I have read all your posts. My intended setup would be a little different. I have one main living room that shoul allways remain working. No matter the state of my HA instance. (i can be away for long times).
But: The bathroom, twoo studies, and maybe another room i want to control separate. I want to use Zigbee TRV’s in those rooms. If HA is not working everything should work the old fashioned way. Just based on the living room temeperature. So when the HA setup is working properly the boiler should turn on and supply heat to at least one room that is requesting heat. If the Living Room is not requesting heat, the floor heating system should be closed. In ALL other situations the floor heating valve must be open.
Is this setup possible?