Opentherm Multi Room brainstorming / ideas

I did take that into account: (scroll up to the code sections)

alias: CV Aan/Uit
description: ''
trigger:
  - platform: template
    value_template: >-
      {{ states('sensor.setpoint_cv_virtual') >
      states('sensor.temperature_cv_virtual') and states('climate.heating') ==
      "off" }}
    id: StartWarmteVraag
  - platform: template
    value_template: >-
      {{ states('sensor.setpoint_cv_virtual') <
      states('sensor.temperature_cv_virtual') and states('climate.heating') ==
      "heat"  }}
    id: EindeWarmteVraag
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: StartWarmteVraag
        sequence:
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.heating
            data:
              hvac_mode: heat
      - conditions:
          - condition: trigger
            id: EindeWarmteVraag
        sequence:
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.heating
            data:
              hvac_mode: 'off'
    default: []
mode: restart

the entity in question is defined as a mqtt climate:

climate:
  - name: "Heating"
    modes:
      - "off"
      - "heat"
    current_temperature_topic: "opentherm-thermostat/current-temperature/get"
    mode_command_topic: "opentherm-thermostat/mode/set"
    mode_state_topic: "opentherm-thermostat/mode/get"
    temperature_command_topic: "opentherm-thermostat/setpoint-temperature/set"
    temperature_state_topic: "opentherm-thermostat/setpoint-temperature/get"
    min_temp: 12
    max_temp: 28
    value_template: "{{ value }}"
    temp_step: 0.5

You might want to look at this thread i once made for a boost function. While its not exactly for what u want to do. It should be able todo the same thing.

I think in the value_template add another if statement to check the window sensor and just send a fixed value like 7 degrees to the virtual objects.

I am very interested in the DIYLess thermostat, my boiler sorts opentherm too. I have a question though, can opentherm support multi-zones? I have 2 thermostats currently controlling each zone independently. If so how would it operate?

1 Like

@Dujith i followed your ideas, and i’m implementing them too. My diyless thermostat works great, altough i sometimes suspect there is still room to improve the algorithm in it. i will have a look at the esphome opentherm sketch too. However optimal PID parameters seem to be less important if you switch regularily to other rooms, which whould require other PID’s paramaters i think

One question tough, do you take into account the time your motors take to open or close? I’m testing one (NC) motor, and it takes 5 minutes to fully open. I think a bit more to fully close. Or is this time negligible? I suppose it could be easily implemented by just delaying the sending of virtual setpoint and room temperature to the opentherm thermostat?

Thx for sharing your solution!

My motors are instant unlike wax motors so i dont have to take that time into account.
Closing isnt the issue as those minutes wont make the difference temperature wise.

Opening is a problem with wax motors but that has more to do with the Central Heating pump as pumping while everything is closed isnt that great for the pump. Either have a bypass, delay on heating command or what i usually do when i implement this in houses have 1-2 locations always open.

For example:
The radiator in the hallway has no thermostat but will instead heat whenever a room requires heat.
Thus always providing flow and the pump can freely run.

Hey @Dujith, I am also looking to create a multiroom setup with an OpenTherm supporting heater (Intergas CV) using the DIYless OpenTherm Thermostat.
I have been able to follow up on your instructions, up to the point of sending the setpoint_cv_virtual to the DIYless thermostat using Node-RED.
Could you please provide some instructions on how to set this up in Node-RED?

I have Node-RED running within HomeAssistant, but have no experience working with with it.

Thanks for the answer. I have a bypass.

What kind of motors are you using?
I just bought one wax motor to test out (cheap). Plan is buying a collector where i can mount the motors. I still have all the possibilities to change the plan :wink:

@Dujith , could you please share an export of the Node-RED flow (or sequence) through which you send the virtual sensor data to the diyless shield?

The node red is only for repeating the setpoint and actual temperature. When the DIYLESS does not receive them for a while it will fallback to its defaults. So you can also set that up with an automation.

Seemed simpler when i started with HA to do it this way. But if memory serves my correctly i had to find a custom component for node red (resend)


I have setup the state_change node like this:

But how do I setup the mqtt out node? I have Mosquitto Broker running on HA and selected that. But which topic should I use?
afbeelding

Sorry for my ignorance.

Whatever topic you specified in your mqtt:
So in my case that would be:
Setpoint: opentherm-thermostat/setpoint-temperature/set
Actual Temp: opentherm-thermostat/current-temperature/set

Yours might differ since the code changed a bit since i used it.

Thanks for the swift reply.
I used your code above for the mqtt. I presume I need to rewrite this using the mqtt topics described here: OpenTherm Thermostat Initial Configuration - DIYLESS Electronics

Looking at the github and blog its still those 2 topics unless you changed something yourself.

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.