Add heater to Z-Wave TRV

Is it possible to control a boiler switch using a TRV in Home Assistant? I’ve tried adding one through customisations but the boiler switch is never turned on/off. I have 5 Danfoss TRVs on radiators in my house that control the radiators, butthey don’t turn the boiler on, so I only get heat into rooms when they are too cold and my hallway is too cold (the hallway is controlled by a Horstmann HRT4-ZW, which is linked to the ASR-ZW on the boiler).

I’d like any room to be able to call for heat but so far the only thing I can come up with involves adding generic thermostats to shadow the TRVs and then add automations to sync target temperatures, which is super messy and unmaintainable.

Did you find any elegant solutions to this?

I have an Aeotec Z Wave TRV and a separate Z Wave boiler switch.

I currently have 2 potential plans:

  1. Create an additional generic thermostat entity with the boiler switch as the heater for each TRV and feed it with template sensors with the values taken from the thermostat entity created by the TRV.
    I would then have the TRV’s thermostat shown on a dashboard to control the generic ones in the background.

  2. Have an automation that monitors the mode of each TRV that turns on the boiler when necessary and some other logic to take care of the min_cycle_duration of the boiler.

I’m using zwave2mqtt and I’ve tried adding the heater to the mqtt component that it sends to home assistant, but it results in an error in the log.

I did not I’m afraid, I ended up just setting temperatures in each room through the TRV and setting the main boiler thermostat to a temperature that would fire off enough to get the rooms up to heat, at which point they all close and the remaining heat in the system goes through the heater near the boiler thermostat which switches it off.

I tried your first plan and I couldn’t get it to work, it seemed that if any of the TRVs wanted the boiler off then it would turn off, even if another wanted it on. It may be possible to have separate switches that are grouped together, and then set the boiler switch on and off depending on the status of the group (any switches turned on in the group will set the group to on).

I may revisit the first plan to see if I could get it working. The neatest solution would be if Home Assistant would let you add the boiler switch to the TRV, but I’ve found no way of doing that currently (I tried customising the entities with the right values, but it didn’t work). It would probably require a change to the climate code in Home Assistant, which i haven’t had the bravery to try yet.

Ah, I didn’t think of the TRV turning the boiler off if another still needed it.

How about replacing the heater switch with a template switch that triggers an automation on both on and off.

  • Off: check if any TRVs are still in Heat mode, if so, then leave the boiler on
  • On: use the status of the boiler switch itself

Do you think I’m overlooking anything here?

I’m not sure if you’re overlooking something to be honest. The whole thing ends up getting pretty complex, I’m sure there’s an easier way to do it. I might try to create a TRV switch group and see if I can trigger an automation based on that group to shadow the boiler. It sounds like it might be neater than my last attempt at this. The other problem I have is that the thermostat that controls the boiler is directly linked, so when it doesn’t want heat it will turn it off, and I don’t want to unlink them because then Home Assistant going down for whatever reason will stop my house heating at all, and it’s winter now :snowflake: :snowflake: :snowflake:

Appreciate this is an old thread. I was looking for something similar, couldn’t find anything that met my needs so created a script for this. Wanted to share in case it was still useful for anyone.


HELPERS

group.all_radiators
group of all TRV sensors (used when sleep mode is off)

group.upstairs_radiators
group of upstairs radiators (used when sleep mode is on)

input_boolean.auto_heating
enables the below automation

input_boolean.holiday_mode
used to set a frost mode (currently hard coded to 15 in script)

input_booemphasized textlean.sleep_mode
used to switch what radiators call for heating


AUTOMATION

This looks for changes in the TRV / radiators and calls the script.
Only works if input_boolean.auto_heating is “on”.

alias: "[Climate] Auto Switch Boiler Heating"
trigger:
  - platform: state
    entity_id:
      - climate.lounge_trv
      - climate.kitchen_trv
      - climate.utility_trv
      - climate.bedroom_trv
      - climate.bed2_trv
      - climate.ensuite_trv
      - climate.nursery_trv
condition:
  - condition: state
    entity_id: input_boolean.auto_heating
    state: "on"
action:
  - service: script.boiler_heating
    data: {}
mode: parallel

SCRIPT

This essentially loops through the radiators, and decides if any of them require heating.
If so the boiler is turned on, else it is turned off.

If the battery is too low for a radiator it skips it, as mine get stuck in a state when battery dies.
This stops heating being constantly on.

The battery levels on my TRVs are not an attribute but another sensor. So it is worth pointing out that my naming convention allows this to work as well.

For example if I have climate.lounge_trv, then the battery for this is named sensor.lounge_trv_battery_level.

There are also a few hard coded values / logic that I have not yet exposed to helpers:

  • frost mode set to 15 (this is used as the cuttOff when holiday_mode is “on”)
  • offset is set to 1 (this is how much lower a rad can go to before it requires heat)
  • offset is set to 2 when sleep_mode is “on”
entity_id: switch.boiler_heating
service: >
  {% set ns = namespace(value=0) %}

  {% set currentlyHeating = states('switch.boiler_heating') %}#
  {% set holiday_mode = states('input_boolean.holiday_mode') %}
  {% set sleep_mode = states('input_boolean.sleep_mode') %}

  {% if sleep_mode == 'on' %}
    {% set rads = states.group.upstairs_radiators.attributes.entity_id %}
  {% else %}
    {% set rads = states.group.all_radiators.attributes.entity_id %}
  {% endif %}

  {% for rad in rads %}
    {% set setPoint = state_attr(rad, 'temperature') %}
    {% set name = rad.split(".")[1] %}
    
    {# set temp to a float - defaults to 0 #}
    {% set currentTemp = state_attr(rad, 'current_temperature') | float(0) %} 
    {# set battery to a float - defaults to 0 #}
    {% set battery = states('sensor.' + name +'_battery_level') | float(0) %}

    {# if battery is too low skip this rad #}
    {% if battery <= 10 | float %}
      {% continue %}
    {% endif %}

    {# if currentTemp is the default 0 then skip this rad #}
    {# this also caters for an 'unknown' rad #}
    {% if currentTemp == 0 | float %}
      {% continue %}
    {% endif %}

    {# default offset and cuttoff #}
    {% set offset = 1 %}
    {% set cuttOff = setPoint - offset %}
    
    {# mode overrides #}
    {% if holiday_mode == 'on' %}
      {# when away use a frost mode #}
      {% set cuttOff = 15 %}
    {% elif sleep_mode == 'on' %}
      {# when asleep use a larger offset #}
      {% set offset = 2 %}
      {% set cuttOff = setPoint - offset %}
    {% endif %}
   
    {% if currentTemp < cuttOff | float %}
      {% set ns.value = ns.value + 1 %}
    {% endif %}
  {% endfor %}

  {% if ns.value | int > 0 %}
    switch.turn_on
  {% else %}
    switch.turn_off
  {% endif %}

Anyway, apologies for reviving an old thread but hopefully useful for someone.
I’m away a lot with work but hopefully I can answer any questions :slight_smile: