Underfloor heating project for a HA Newbie

Hi Convicte

Opening remark and disclaimer:
I am not at all a pro with HA, Linux or YAML so I will not tell you what you should do but only what I
have done and what works for me. Then you can do your own assessment and find out if it works
for you as well.

I have all my thermostats defined in a file called climate.yaml. They all look like this:
-.platform: generic_thermostat
name: Koekken
heater: switch.heating_relay_kitchen
target_sensor: sensor.koekken_temperature
min_temp: 15
max_temp: 25
ac_mode: false
target_temp: 20
cold_tolerance: 0.1
hot_tolerance: 0
initial_hvac_mode: “off”
away_temp: 18
precision: 0.1

It would seem that you have a different component (not generic_thermostat) and a lot of other
parameters?
My setup is very much the default params…

BR David

1 Like

How I am using Home Assistant to control my underfloor heating

Disclaimer: Below description contains what methods and components I have used to make my heating system work with Home Assistant. I am in no way an expert in HA, Linux, YAML or any related topic and you should only read this as inspiration. If you see anything that could be done smarter, simpler or otherwise better I would like to hear your comment.

My heating control system consist of 3 things:

  1. A temperature monitoring system which covers the whole house.
  2. A Heating control box placed next to the Thermo-Electric Actuators
  3. A laptop PC with HA installed

Temperature monitoring

By reading other people’s recommendations I choose to try the Aqara temperature sensor. https://www.aqara.com/us/temperature_humidity_sensor.html . It is relatively small and discrete and fits the purpose. I got a few samples and tested different locations and was satisfied with the result. I did not want a sensor with a display since I find that I get better results placing the sensors e.g. under the dinner table (close to where I sit) rather than on a cold (external) wall, far from where you mostly are located in the room. The sensor uses Zigbee and I started with a USB-receiver (called a Zigbee coordinator i believe) from https://slae.sh/ which worked fine, and have since also used Ethernet based receiver (coordinator) from smlight.tech. Home | SLZB-06 Manual and this also worked fine. In HA I use Zigbee2MQTT and mosquitto. The information collected is presented in a floor plan which presents all temperature readings and looks like this:

Heating Control box

My underfloor heating is using Thermo-Electric Actuators for opening and closing the valves individually for each of my 12 heating zones.

I am using 2 esp controlled relays (one 8x relay and 1 4x relay) similar to this:

At the time when I did my shopping I couldn’t find a 12 or 16 relay board so I got the two, 4 and 8 relays. The initial programming of the relay boards was done with a USB to serial adaptor. The ESP side of the boards are powered with 5VDC from a small PSU. All parts within the Heating Control Box are screw mounted on a metal perforated plate, the ESP boards with 15mm spacers.

The ESP boards are easily accessible from the ESPHome module inside HA. I do not update them all the time (the frequency of updates to ESP seems quite often) but only once every other month I update the SW over the air. I have not yet experienced the relay boards go offline and become unresponsive, but I have mounted a connector for serial programming if this should ever happen. The ESPs along with some other stuff is separated on a wifi of its own and not accessible from my regular wifi.

The Heating Control Box is also equipped with a temperature sensor just to be able to read if something gets very hot in here.

Home Assistant PC

In the beginning of my HA test runs I didn’t know what kind of hardware platform I wanted so I started with a 10 year old PC and installed the native HA operating system. I am not sure if I am missing out on some cool features by running the other types of install (docker conatiner) but this works well for me. I am looking into upgrading this to another PC but my current solution works well and is not power hungry.

So far I have installed the generic thermostat card in my heating dashboard and this enables me to read current temperatures, set the target temperature and look into the history (checking when the heating was switched on [orange color below])

strong text

3 Likes

thanks for your detailed post @c957031

I have the same requirement as you @gemboly - I was looking at MH7H-WH/MH7H-EH-广州迈赫姆电子科技有限公司 for a Z-Wave option although currently unsure if I need the WH or EH version for Thermo-Electric Actuators.

Edit: this could also work I believe: MH3901-Z-广州迈赫姆电子科技有限公司

You would of course also need a Z-Wave controller

1 Like

Also became aware of this off the shelf solution that looks interesting for the use case if you prefer Z-Wave over the custom ESP board solution:

https://www.mcohome.com/Multi-relay-controller-PG7037109

Although currently do not see it for sale from any retailers online.

Thanks for sharing, I’m planning a quite similar solution and this was good inspiration. Have most components acquired but have not come to the installation yet (mostly working on bench for now). During development I have also found these ESP32 Development Board - AliExpress, I still use the same ESP12E version as you but the extra versatility and exposed GPIO’s with those board look interesting as a future upgrade.

In addition I plan to use wall thermostats as room sensors, giving the option to set and view temperatures in rooms without using HA, but not connect the output or relay on them. I shoose these ones but are many other similar, Smart Thermostat - Aliexpress (that now also work with ZHA using the custom quirk ts0601_thermostat_avatto.py).
My initial goal is to let the room thermostat (virtual) heating status to be mirrored to the relay board via a home-assistant template.
Further on it might have to be replaced by a HA thermostat like swingerman/ha-dual-smart-thermostat (github.com) if adding AC to the equation as the wall thermostats only support heating.

A second addition is that I plan for connecting Dallas one-wire thermometers to the incomming water and all returns, is at least one input GPIO left on the relay-board. From those calculate the delta-temperature and estimate some statistics or usage per room. If someone has done anything similar I’m happy to receive guidance. I just have to assume some static water-flow once the valve is open, adding flow-meters seem a bit overambitious.

Hello there !

I am currently in the process of choosing my underfloor heating control system and so far I have identified three options:

  • The installer option based on Nussbaum hardware and relying on Modbus protocol for communication with HA. Probably the most expensive solution (And not that easy to integrate to HA?).

  • The “Kit” option using hardware such as the Homematic IP relying on Homematic HA integration for communication with HA. It looks easy and affordable but I don’t know how trusty this brand is and/or reliable it is.

  • And the DIY option (Relay board,etc…). The cheapest but regulation is maybe less accurate or more complex to manage?

I have a heat pump (geothermal) as heat source and it has “free cooling” capacity during the summer.

I don’t know if the DIY option would be feasible with both heating and cooling mode?

From what I have read here, the DIY option only work with ON/OFF valve and not adjustable valves, is that right?

What would be your suggestions for my use case? Can you give feedback about your installations?

Thanks in advance.

What did you end up with in the end? I’m going through the exact same thing in the next couple of months, so I’m curious to learn from your experiences.

thanks @c957031 for the reply. Seems interesting, but I agree with @Jack-Harper that adjustable valves (not just on/off) might be better to created a balanced system in which the heat pump can run longer, but on a modulated setting (requiring lower supply temperature and hence higher COP). Anybody any advice here? Interested in co-developing/co-prototyping something.

Hello again Jack-Harper and antonclaeys
I have to say that I was also skeptical regarding the binary (on/off only) valves and if I should investigate adjustable valves. However, my setup was born with the binary valves so I decided to give it a go.
The result was convincing to me, and if you look at the temperature log (screen dump below) the temperature fluctuates around half a degree (celsius) above and below the target temperature. This is close enough for my usage so I am not investigating further.
In my development I started with a beta setup of 2 rooms in order to investigate if the functionality was adequate and this proved the point to me. I then continued with building the control box and adding the rest of the house.

Of course my results cannot necessarily be reproduced in your setup since a variety of factors apply.

Please post what you come up with in your setups

BR David

@c957031 I follow your reasoning that the room temperature deviations are quite ok. However, do you have an idea of the supply water temperature of your heating device? You mention you have district heating; do you also have a small heat pump in your home to increase the supply temperature, or are you just directly using what comes in? Because in the latter case, you’re probably not really interested in the efficiency.
In case of a heat pump, it is key to avoid cycling and to have it running in as low power as possible, so instead of turning the loop ON three times as in your screenshot, you would want to have it cycle less and keep it on longer, but on a lower supply temperature

Hi antonclaeys,
The way district heating works in my setup is that I have a heat exchanger that transfers the heat from the district heating circuit into my home circuit (the circuits don’t exchange the water, only the energy). I don’t have a heat pump in my setup. The temperature of the water is max 35°C in my underfloor circuits.
/David

Yes, that’s what i thought. in your case, you have no benefit/incentive of lowering the supply temperature. when you have a heat pump you do. I typically can heat my home with 28 to 30°C °C supply temperature, but lowering it even further would increase my heat pump’s efficiency and hence lower my electricity consumption.

Have any of you come across a way to adjust the shunt thermostat with HA? I have water floor heating myself and would like to adjust the temperature of the circulating water with HA.

Hi @c957031
Its really interesting system you’ve setup and I plan to do something similar. I even believe we might be from the same country :smiley:

My question is, in my setup I have a pump that circulates the water in the underfloor heating. This pump is controlled by the old controller which I would like to replace.

I was thinking if you have such a pump, and how you control it? Ideally I could control it using one relay on the relay board, and just have some simple HA automation that would make sure the pump would run in case is any of the thermostats are calling for heating.

Thanks in advance.
/Martin

Hi Martin
Truthfully I have the same challenge that you are describing, and I was going to post a question in here asking the HA-wizards how to best solve it. In summary, I have 10 relays connected to heating valves, and relay connected to the pump. So the question is: I want the pump to switch on if either of the 10 relays is on and off again when all 10 relays are off.
Howto do that?
New post on this topic
/D

Hi Martin
I asked some wizards in another thread and solved the problem:

Share how your setup is doing when you get there.

/D

1 Like

Hi David, For some reason I do not get notified when replies are in. My apology for not getting back sooner.
Thank you very much for your help on this. I have not received the hardware yet, but when I do, I will make sure to post how I resolve it here. Your post will come handy in my setup Im sure. Thanks.

Br Martin

Hi All
I am experimenting with a similar setup but using offsetable Tuya TRVs in connection with the better-thermostat script. In my case the fluctuation usually stays at around 0.5°C around the target temperature too. (There are occasional outliers up- or downwards, but they might actually be caused by faults in the rather cheap TRVs.)

The Tuya TRV theoretically could partly open the valves given they are using a small electric motor. Unfortunately the internal firmware does not seem to support this, can only fully open or fully close the valve. Hence effectively the same setup as c957031’s.

What I wonder though is energy efficiency. Note I can not change the supply temperature as it is set by the building’s central heating (not controllable by me). Still, I wonder whether a continuous but limited/adjusted water flow would be more energy efficient that my on-off controlled setup.

Does anyone have an idea about this?

Hi everyone,
First of all - thank you @c957031 for this thread. I’d never come up to do this myself. Now I’m assembling my own system. :slight_smile:

I hope I can add something to this topic.

As I’ve had my HA crash on me multiple times, I’m very cautious about relying on it for such a critical part of the house.
Because of that I came up with some fall-backs.

For example, you can run a script on the node which checks for connection to HA, and if there is none then closes all valves and shuts off the pump. This is what that looks like:

YAML
esphome:
  name: "heating-1"
  friendly_name: Heating 1
  on_boot:
    then:
    - script.execute: connection_watchdog

script:
  - id: connection_watchdog
    mode: queued
    then:
      - if:
          condition:
            not:
              api.connected:
          then:
          - switch.turn_off: pump
          - switch.turn_off: valve_hot
          - switch.turn_off: valve_loop_1
          - switch.turn_off: valve_loop_2
          - switch.turn_off: valve_loop_3

This will speed up the reaction - ESP Home nodes by default reboot after 15 min without active connection.

You can also have the script handling the pump running on the ESP itself. This might be interesting for @Atomizer too.

script:
  - id: recirculate
    mode: restart
    then:
      - switch.turn_on: pump
      - wait_until:
            lambda: |-
                if (!id(valve_loop_1).state 
                and !id(valve_loop_2).state 
                and !id(valve_loop_3).state) {
                return true;
                } else {
                return false;
                 }
      - delay: 500s
      - switch.turn_off: pump

The script should be called when a valve is opened:

switch:
  - platform: gpio
    name: valve_loop_1
    on_turn_on:
      then:
        - script.execute: recirculate

For my setup I opted to use Thermostat component for ESP Home to run directly on the node.
Together with LYWSD03 BLE sensors in every room, that makes it completely independent of the HA, as the sensors can communicate directly with ESP.
It can also handle both heating and cooling, which was an additional requirement for me.

I also added Dallas sensors to monitor the temperature in the manifold and all returns and shut everything off if it exceeds a threshold.
@dala318 can you share what you’ve done with your sensor readings?

1 Like

Hi. Part of my ESPHome config.
Still not fully in operation, but i guess you can take some inspiration from it, and feedback if you find any bugs in it :wink:

# External connectors
# 5V
# TXd - GPIO1 - use for Dallas in non-flashing mode
# RXd - GPIO3
# IO0 - GPIO0 - connect to GND and reboot (power cycle) if you need to set the ESP8266 in flash mode
# GND
# GND
# IO2 - GPIO2 - also used for the (blue) LED on the ESP8266
# ADC - A0 / GPIO17 - the analog input of the ESP8266

substitutions:
  # Deafult values, can be overriden before <<: !include .<this file>.yaml
  pin_status: GPIO23        # Internal
  pin_onboard_button: GPIO0 # Internal

  pin_relay1: GPIO32        # Internal
  pin_relay2: GPIO33        # Internal
  pin_relay3: GPIO25        # Internal
  pin_relay4: GPIO26        # Internal
  pin_relay5: GPIO27        # Internal
  pin_relay6: GPIO14        # Internal
  pin_relay7: GPIO12        # Internal
  pin_relay8: GPIO13        # Internal

  pin_dallas: GPIO22        # data + gnd + 3.3v
  pin_water_pulse: GPIO02   # data + gnd + 3.3v

  incomming_temp_adress: "0x0000000000000000"

  room1_name: "Room #1"
  room1_temp_adress: "0x0000000000000000"
  room1_thermostat: "climate.one"
  room2_name: "Room #2"
  room2_temp_adress: "0x0000000000000000"
  room2_thermostat: "climate.two"
  room3_name: "Room #3"
  room3_temp_adress: "0x0000000000000000"
  room3_thermostat: "climate.three"
  room4_name: "Room #4"
  room4_temp_adress: "0x0000000000000000"
  room4_thermostat: "climate.four"
  room5_name: "Room #5"
  room5_temp_adress: "0x0000000000000000"
  room5_thermostat: "climate.five"

logger:
  baud_rate: 0  # Make sure logging is not using the serial port and RX/TX pins

dallas:
  - pin: ${pin_dallas}
    # update_interval: 10s

status_led:
  pin:
    number: ${pin_status}
    # inverted: yes

time:
  - platform: sntp
    on_time:
      - seconds: 0
        minutes: /5  # Every 5 minutes
        then:
          - script.execute: set_circulation_state

script:
  - id: set_circulation_state
    then:
      - logger.log: "Checking if circulation shall change"
      - if:
          condition:
            or:
              - switch.is_on: valve_1
              - switch.is_on: valve_2
              - switch.is_on: valve_3
              - switch.is_on: valve_4
              - switch.is_on: valve_5
          then:
            - switch.turn_on: cirkulation_relay
          else:
            - switch.turn_off: cirkulation_relay

switch:
  - platform: gpio
    pin: ${pin_relay1}
    name: Underfloor ${room1_name}
    id: valve_1
    icon: mdi:valve
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_circulation_state
    on_turn_off:
      - script.execute: set_circulation_state

  - platform: gpio
    pin: ${pin_relay2}
    name: Underfloor ${room2_name}
    id: valve_2
    icon: mdi:valve
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_circulation_state
    on_turn_off:
      - script.execute: set_circulation_state

  - platform: gpio
    pin: ${pin_relay3}
    name: Underfloor ${room3_name}
    id: valve_3
    icon: mdi:valve
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_circulation_state
    on_turn_off:
      - script.execute: set_circulation_state

  - platform: gpio
    pin: ${pin_relay4}
    name: Underfloor ${room4_name}
    id: valve_4
    icon: mdi:valve
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_circulation_state
    on_turn_off:
      - script.execute: set_circulation_state

  - platform: gpio
    pin: ${pin_relay5}
    name: Underfloor ${room5_name}
    id: valve_5
    icon: mdi:valve
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_circulation_state
    on_turn_off:
      - script.execute: set_circulation_state

  - platform: gpio
    pin: ${pin_relay6}
    name: "Relay #6"
    id: relay_6
    restore_mode: ALWAYS_OFF
    internal: true

  - platform: gpio
    pin: ${pin_relay7}
    name: "Relay #7"
    id: relay_7
    restore_mode: ALWAYS_OFF
    internal: true

  - platform: gpio
    pin: ${pin_relay8}
    name: "Underfloor cirkulation"
    id: cirkulation_relay
    icon: mdi:pump
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - delay: 5s  # Check pump do not run without open valve
      - script.execute: set_circulation_state
    on_turn_off:
      - switch.turn_off: valve_1
      - delay: 100ms
      - switch.turn_off: valve_2
      - delay: 100ms
      - switch.turn_off: valve_3
      - delay: 100ms
      - switch.turn_off: valve_4
      - delay: 100ms
      - switch.turn_off: valve_5

number:
  - platform: template
    name: Flow setting ${room1_name}
    id: flow_set_1
    unit_of_measurement: L/min
    restore_value: true
    step: 0.5
    min_value: 0
    max_value: 5
    mode: slider
    optimistic: true
    entity_category: config

  - platform: template
    name: Flow setting ${room2_name}
    id: flow_set_2
    unit_of_measurement: L/min
    restore_value: true
    step: 0.5
    min_value: 0
    max_value: 5
    mode: slider
    optimistic: true
    entity_category: config

  - platform: template
    name: Flow setting ${room3_name}
    id: flow_set_3
    unit_of_measurement: L/min
    restore_value: true
    step: 0.5
    min_value: 0
    max_value: 5
    mode: slider
    optimistic: true
    entity_category: config

  - platform: template
    name: Flow setting ${room4_name}
    id: flow_set_4
    unit_of_measurement: L/min
    restore_value: true
    step: 0.5
    min_value: 0
    max_value: 5
    mode: slider
    optimistic: true
    entity_category: config

  - platform: template
    name: Flow setting ${room5_name}
    id: flow_set_5
    unit_of_measurement: L/min
    restore_value: true
    step: 0.5
    min_value: 0
    max_value: 5
    mode: slider
    optimistic: true
    entity_category: config

sensor:
#   - platform: adc
#     pin: ${pin_adc}
#     id: water_pressure_adc
#     name: Water pressure ADC
#     attenuation: auto
#     unit_of_measurement: "v"
#     update_interval: 1s
#     entity_category: "diagnostic"

#   - platform: template
#     lambda: return id(water_pressure_adc).state;
#     name: Water pressure
#     id: water_pressure
#     unit_of_measurement: "bar"
#     icon: "mdi:water-sync"
#     device_class: "pressure"
#     state_class: "measurement"
#     accuracy_decimals: 2
#     update_interval: 1s
#     filters:
#       - calibrate_linear:
#         - 0.27     -> 0
#         - 0.60     -> 0.9
#         #- 3.11651  -> 10
#       - quantile:
#           window_size: 60
#           send_every: 10
#           quantile: 0.9
          
#   - platform: pulse_counter
#     # name: "Underfloor flow"
#     pin: ${pin_water_pulse}
#     id: water_flow_pulse
#     unit_of_measurement: L/min
#     icon: mdi:pump
#     update_interval: 1s
#     filters:
#     - lambda: return (x / 27.0) * 60.0;
#     - quantile:
#           window_size: 60
#           send_every: 10
#           quantile: 0.9

  - platform: pulse_meter
    pin:
      number: ${pin_water_pulse}
      # inverted: true
      # mode:
      #   input: true
      #   pullup: true
    id: water_flow
    name: Underfloor flow
    device_class: water
    entity_category: diagnostic
    timeout: 10s
    unit_of_measurement: L/min
    filters:
      - throttle_average: 10s
      - filter_out: nan
      - multiply: 0.037  # (27 pulses per liter)
      - multiply: 60.0   # (s to min)
    ### For debugging RAW sensor
    # unit_of_measurement: 'pulses/second'
    # filters:
    #   # - filter_out: 0.0
    #   - throttle_average: 2s
    #   - filter_out: nan
    #   - multiply: 0.0166666667
    ###

  - platform: template
    id: flow_set_combined
    lambda: |-
      float total = 0;
      if (id(valve_1).state) {
        total += id(flow_set_1).state;
      }
      if (id(valve_2).state) {
        total += id(flow_set_2).state;
      }
      if (id(valve_3).state) {
        total += id(flow_set_3).state;
      }
      if (id(valve_4).state) {
        total += id(flow_set_4).state;
      }
      if (id(valve_5).state) {
        total += id(flow_set_5).state;
      }
      return total;
    entity_category: diagnostic

  - platform: dallas
    address: ${incomming_temp_adress}
    name: Incomming water temp
    id: incomming_temp
    entity_category: diagnostic

  - platform: dallas
    address: ${room1_temp_adress}
    name: Return temp ${room1_name}
    id: return_temp_1
    entity_category: diagnostic

  - platform: dallas
    address: ${room2_temp_adress}
    name: Return temp ${room2_name}
    id: return_temp_2
    entity_category: diagnostic

  - platform: dallas
    address: ${room3_temp_adress}
    name: Return temp ${room3_name}
    id: return_temp_3
    entity_category: diagnostic

  - platform: dallas
    address: ${room4_temp_adress}
    name: Return temp ${room4_name}
    id: return_temp_4
    entity_category: diagnostic

  - platform: dallas
    address: ${room5_temp_adress}
    name: Return temp ${room5_name}
    id: return_temp_5
    entity_category: diagnostic

  - platform: template
    name: Energy ${room1_name}
    id: energy_1
    unit_of_measurement: W
    device_class: POWER
    icon: mdi:radiator
    lambda: |-
      if (! id(valve_1).state || id(flow_set_combined).state == 0.0) {
        return 0.0;
      }
      float flow = id(flow_set_1).state / id(flow_set_combined).state * id(water_flow).state;
      float temp_diff = id(incomming_temp).state - id(return_temp_1).state;
      return flow * temp_diff * 1000.0 * 4.184 / 60.0;

  - platform: template
    name: Energy ${room2_name}
    id: energy_2
    unit_of_measurement: W
    device_class: POWER
    icon: mdi:radiator
    lambda: |-
      if (! id(valve_2).state || id(flow_set_combined).state == 0.0) {
        return 0.0;
      }
      float flow = id(flow_set_2).state / id(flow_set_combined).state * id(water_flow).state;
      float temp_diff = id(incomming_temp).state - id(return_temp_2).state;
      return flow * temp_diff * 1000.0 * 4.184 / 60.0;

  - platform: template
    name: Energy ${room3_name}
    id: energy_3
    unit_of_measurement: W
    device_class: POWER
    icon: mdi:radiator
    lambda: |-
      if (! id(valve_3).state || id(flow_set_combined).state == 0.0) {
        return 0.0;
      }
      float flow = id(flow_set_3).state / id(flow_set_combined).state * id(water_flow).state;
      float temp_diff = id(incomming_temp).state - id(return_temp_3).state;
      return flow * temp_diff * 1000.0 * 4.184 / 60.0;

  - platform: template
    name: Energy ${room4_name}
    id: energy_4
    unit_of_measurement: W
    device_class: POWER
    icon: mdi:radiator
    lambda: |-
      if (! id(valve_4).state || id(flow_set_combined).state == 0.0) {
        return 0.0;
      }
      float flow = id(flow_set_4).state / id(flow_set_combined).state * id(water_flow).state;
      float temp_diff = id(incomming_temp).state - id(return_temp_4).state;
      return flow * temp_diff * 1000.0 * 4.184 / 60.0;

  - platform: template
    name: Energy ${room5_name}
    id: energy_5
    unit_of_measurement: W
    device_class: POWER
    icon: mdi:radiator
    lambda: |-
      if (! id(valve_5).state || id(flow_set_combined).state == 0.0) {
        return 0.0;
      }
      float flow = id(flow_set_5).state / id(flow_set_combined).state * id(water_flow).state;
      float temp_diff = id(incomming_temp).state - id(return_temp_5).state;
      return flow * temp_diff * 1000.0 * 4.184 / 60.0;

text_sensor:
  - platform: homeassistant
    name: Heating status text ${room1_name}
    id: heat_status_text_1
    entity_id: ${room1_thermostat}
    attribute: hvac_action
    filters:
      - lambda: |-
          if (x == "heating") {
            id(valve_1).turn_on();
          } else {
            id(valve_1).turn_off();
          }
          return x;
    internal: true

  - platform: homeassistant
    name: Heating status text ${room2_name}
    id: heat_status_text_2
    entity_id: ${room2_thermostat}
    attribute: hvac_action
    filters:
      - lambda: |-
          if (x == "heating") {
            id(valve_2).turn_on();
          } else {
            id(valve_2).turn_off();
          }
          return x;
    internal: true

  - platform: homeassistant
    name: Heating status text ${room3_name}
    id: heat_status_text_3
    entity_id: ${room3_thermostat}
    attribute: hvac_action
    filters:
      - lambda: |-
          if (x == "heating") {
            id(valve_3).turn_on();
          } else {
            id(valve_3).turn_off();
          }
          return x;
    internal: true

  - platform: homeassistant
    name: Heating status text ${room4_name}
    id: heat_status_text_4
    entity_id: ${room4_thermostat}
    attribute: hvac_action
    filters:
      - lambda: |-
          if (x == "heating") {
            id(valve_4).turn_on();
          } else {
            id(valve_4).turn_off();
          }
          return x;
    internal: true

  - platform: homeassistant
    name: Heating status text ${room5_name}
    id: heat_status_text_5
    entity_id: ${room5_thermostat}
    attribute: hvac_action
    filters:
      - lambda: |-
          if (x == "heating") {
            id(valve_5).turn_on();
          } else {
            id(valve_5).turn_off();
          }
          return x;
    internal: true