Opentherm Multi Room brainstorming / ideas

I succeeded in in sending current and setpoint temperature to the diyless thermostat.
I only need those 2 topics:

diyless_thermostat/cmnd/things/thermostat/properties/targetTemperature
diyless_thermostat/cmnd/things/thermostat/properties/temperature

no mqtt climate code needed in HA.
Thanks a lot.

My next challenge is to make my setup resistant to unavailable sensor data (I am using XIAOMI Mijia BLE sensors, one per room).
In my current code this makes both: virtual setpoint and virtual temperature unavailable as well.

I had the same issue and it locked up the DIYLESS module.
Fixed it with adding a default value when the sensor isnt doing anything:

{{ state_attr('climate.alex','temperature') | float(18)}}

instead of:

{{ state_attr('climate.alex','temperature') }}

Hey @Dujith, would you mind describing what motors you use?

Hi, thanks for all the good ideas. I’m trying to adapt it a bit to my own situation, so I added this to sensor.yaml:

#sensor virtual CV setpoint
- platform: template
  sensors:
    setpoint_cv_virtual:
      friendly_name: "CV Virtual Setpoint"
      unit_of_measurement: "°C"
      value_template: >
        {% set baby_td = (state_attr('climate.baby','temperature') - states('sensor.babykamer_temphum_temperature') | float) %}
        {% set work_td = (state_attr('climate.work','temperature') - states('sensor.werkkamer_temphum_temperature') | float)%}
        {% set living_td = (state_attr('climate.living','temperature') - states('sensor.temphum_sensor1_temperature') | float) %}
        {% set bath_td = (state_attr('climate.bath','temperature') - states('sensor.badkamer_sensor_temperature') | float) %}
        {% set max_td = ([living_td,baby_td,work_td,bath_td] | max) %}
        {% set list_room_td = [living_td,baby_td,work_td,bath_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ state_attr('climate.baby','temperature') }}
        {% elif index_td == 2 %}
          {{ state_attr('climate.work','temperature') }}
        {% elif %}
          {{ state_attr('climate.living','temperature') }}
        {% else %}
          {{ state_attr('climate.bath','temperature') }}
        {% endif %}
    temperature_cv_virtual:
      friendly_name: "CV Virtual Temperature"
      unit_of_measurement: "°C"
      value_template: >
        {% set baby_td = (state_attr('climate.baby','temperature') - states('sensor.babykamer_temphum_temperature') | float) %}
        {% set work_td = (state_attr('climate.work','temperature') - states('sensor.werkkamer_temphum_temperature') | float)%}
        {% set living_td = (state_attr('climate.living','temperature') - states('sensor.temphum_sensor1_temperature') | float) %}
        {% set bath_td = (state_attr('climate.bath','temperature') - states('sensor.badkamer_sensor_temperature') | float) %}
        {% set max_td = ([living_td,baby_td,work_td,bath_td] | max) %}
        {% set list_room_td = [living_td,baby_td,work_td,bath_td] %}
        {% set index_td = list_room_td.index(max_td) %}
        {% if index_td == 1 %}
          {{ states('sensor.babykamer_temphum_temperature') | float }}
        {% elif index_td == 2 %}
          {{ states('sensor.werkkamer_temphum_temperature') | float }}
        {% elif %}
          {{ states('sensor.temphum_sensor1_temperature') | float }}
        {% else %}
          {{ states('sensor.badkamer_sensor_temperature') | float }}
        {% endif %}
#end

Then I got this back. Any ideas?

Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: Expected an expression, got ‘end of statement block’) for dictionary value @ data[‘sensors’][‘setpoint_cv_virtual’][‘value_template’]. Got "{% set baby_td = (state_attr(‘climate.baby’,‘temperature’) - states(‘sensor.babykamer_temphum_temperature’) | float) %} {% set work_td = (state_attr(‘climate.work’,‘temperature’) - states(‘sensor.werkkamer_temphum_temperature’) | float)%} {% set living_td = (state_attr(‘climate.living’,‘temperature’) - states(‘sensor.temphum_sensor1_temperature’) | float) %} {% set bath_td = (state_attr(‘climate.bath’,‘temperature’) - states(‘sensor.badkamer_sensor_temperature’) | float) %} {% set max_td = (…
invalid template (TemplateSyntaxError: Expected an expression, got ‘end of statement block’) for dictionary value @ data[‘sensors’][‘temperature_cv_virtual’][‘value_template’]. Got "{% set baby_td = (state_attr(‘climate.baby’,‘temperature’) - states(‘sensor.babykamer_temphum_temperature’) | float) %} {% set work_td = (state_attr(‘climate.work’,‘temperature’) - states(‘sensor.werkkamer_temphum_temperature’) | float)%} {% set living_td = (state_attr(‘climate.living’,‘temperature’) - states(‘sensor.temphum_sensor1_temperature’) | float) %} {% set bath_td = (state_attr(‘climate.bath’,‘temperature’) - states(‘sensor.badkamer_sensor_temperature’) | float) %} {% set max_td = (… (See ?, line ?).

You did not specify an if statement here, should be : {% elif index_td == 3 %}
And you need to specify default values otherwise all kind of things can break, including locking up the DIYLESS module with invalid values (learned that the hard way)
So that code adjusted would be:

{% set baby_td = state_attr('climate.baby','temperature') | float(18) - states('sensor.babykamer_temphum_temperature') | float(18) %}
{% set work_td = state_attr('climate.work','temperature') | float(18) - states('sensor.werkkamer_temphum_temperature') | float(18) %}
{% set living_td = state_attr('climate.living','temperature') | float(18) - states('sensor.temphum_sensor1_temperature') | float(18) %}
{% set bath_td = state_attr('climate.bath','temperature') | float(18) - states('sensor.badkamer_sensor_temperature') | float(18) %}
{% set max_td = ([living_td,baby_td,work_td,bath_td] | max) %}
{% set list_room_td = [living_td,baby_td,work_td,bath_td] %}
{% set index_td = list_room_td.index(max_td) %}
{% if index_td == 1 %}
  {{ state_attr('climate.baby','temperature') | float(18) }}
{% elif index_td == 2 %}
  {{ state_attr('climate.work','temperature') | float(18) }}
{% elif index_td == 3 %}
  {{ state_attr('climate.living','temperature') | float(18)}}
{% else %}
  {{ state_attr('climate.bath','temperature') | float(18) }}
{% endif %}

the float(18) will specify a float value and the 18 is what it will report if one of your sensors is not working.

1 Like

I’m using Eurotronic motors. They have some quirks tho, but another user i was able to get them to behave:

They have been running for a year without needing a reset now.

You did not specify an if statement here, should be : {% elif index_td == 3 %}

Oh great, thanks a lot! on to the next challenge then.
I have one floor heating divider for the entire house (5 groups floor downstairs, floor bathroom, 2 wall groups). Running it with 8 24V dumb actuators and a 4 channel relay switch.

Now need to make sure the valves don’t close all at the same time when there is no heat request, otherwise the pump goes on error.
Probably something with an input boolean / virtual switch helper.

Any thoughts on failsafe’s for these kind of setups?
I am still in the testing fase and my first smart TRV has yet to arrive.

At the room level I have implemented a helper temperature sensor in between the BLE temperature sensor and the generic thermostat (climate.room). The helper goes to 21 degrees Celsius whenever the BLE sensor is unavailable. This should prevent heating a room with a faulty temperature sensor.

A the house level I am making sure that at least one TRV is always open. An TRV opens if a room starts to heat, but only closes if another room starts heating and the first room is already warm enough, This way hot water can always circulate.

But what if, while heating is turned on:

  • Wifi connection to the OpenTherm/ESP-board is lost, or
  • (PC running ) Home Assistant freezes up?

My temperature sensor data is send over mqtt to the OpenTherm-board and thus will not be updated anymore.
Will this cause the heating to be turned on without negative feedback?

I would love to have a failsafe in the DIYless OpenTherm/ESP-board GUI, that lets you set a period of time after which the heating is switched of in case the sensor is not updated.

My bad, I just noticed this option in the DIYless GUI:

afbeelding

@Dujith, am I correct in assuming that the Resend-node in Node-RED is needed to prevent this failsafe from triggering?

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?