[SOLVED] Control underfloor heating for multiple floors (OH as thermostat)

  • Platform information:
    • Hardware: AMD64/16GB
    • OS: Docker on Synology
    • Java Runtime Environment: zulu
    • openHAB version: 2.5.3 (will upgrade to 2.5.4)
  • Issue of the topic: need ideas for delayed switch control using proxy items (OH as a thermostat)


I was doing some searches but couldn’t find relevant discussions; if you know any, please point me towards them. I’m using OpenHAB to control lights & roller shutters for a few years now and they work fine, but now I would like to use OH to control heating (and get rid of my thermostat). Heating in general will be controlled by 3 switches:
1 switch to turn the heater on/off and this also heats the basement
1 switch to turn on the pump & electric valve for the ground floor
1 switch to turn on the pump & electric valve for the 1st floor

I have no issues with creating the switches and doing the wiring, however I’d like to ask for advice about how to set up the rules to control them. The long term plan is to leverage the temperature data collected from the rooms to automatically control the heating (I can also monitor the water return temperature in the heater), but for now I’m OK with controlling it via simple switches (like lights); the part that I’m having trouble with is how to keep track of the need to heat (for any of these 3 locations) and sync that with the switches (so e.g. 1st floor wants to heat, it turns on the pump & the heater, then ground floor wants to heat, turns on the pump but the heater is already on and when the ground floor finished, it only turns off the pump but not the heater. Also, if only the 1st floor wants heating, it turns both the pump & the heater on; when it finishes it turns both off. In theory, I need something like “need heating” and while that’s a yes, keep the heater on and only adjust the pumps; once it’s off, turn off the heater as well. I couldn’t find any relevant examples for that (everybody tries to control thermostats, not replicate the functionality).

On the long term I would like to automate this completely and calculate in the delays (I have underfloor heating and it takes some time to heat up & it keeps heating even after the heater is turned on) so try & act like an intelligent thermostat by taking into account the room temperature & external temperature / forecast as well. This would save me a few thousand euros so I’m happy to research and also share my results :slight_smile:

That seems like a smart idea.
I think I’d start with three virtual switches, one each for “Demand Basement”, “Demand ground floor”, etc.

That gives you a nice divide from rules that work pumps etc. according to demand, and rules that look at temperature to make the individual demands.


   Temp X changed
    if Temp X < threshold
           turn on Demand X
    else if Temp X > threshold + hysteresis
           turn off Demand X
          do nothing

    Demand X or Demand Y changed
    if Demand X or Demand Y are on
         turn on heating
    if Demand X is on
         turn on Pump X
1 Like

Thanks, this looks OK so I will set this up using the 3 virtual switches. I’m still missing a few thermometers (they are en route from China), but most likely there won’t be just a single temp, instead there will be multiple and I will average them on a periodic basis (to skip turning on the heater while the windows are open unless I get window open sensors for each room); any ideas for the periodic assessment?

EDIT: I already have InfluxDB & Grafana for storing the temperatures, guess I just need to average them there.

You can also use group items to average values from various items.

You could go as far as having sensors in multiple groups to allow for some overlap in your zones.

1 Like

If you are likely to be producing charts anyway to impress guests, you’d want to persist temperatures (store in a database).
Persistence service provides averaging over time features that you could exploit in rules. (and min and max too)


This is what I’ve done for my house. 16 individual zones, ability to add multiple temperatures per zone and use an average. If any individual zone wants heat, the boiler comes on.

It doesn’t have any learning, but it’s been pretty good for me, and my house is now always the temperature I want it in all rooms at all times.


Thank you all for the great suggestions. Let me review them and post here my rules / items once they are working.

OK, so I spent about an hour to figure out how the main rule works in @Confused 's config but I think I’m getting there :slight_smile:

I was able to come up with this for my own setup; I have 3 floors, but the basement pump turns on the heater so that has to be turned on when any of the 3 floors need heating; similarly when something no longer needs heating, the basement pump can only be turned off after nothing needs heating. Is there a better approach to design this in a rule (I was trying to follow @rlkoshak 1-2-3 rule design pattern)?

  Member of gHneed changed
  if(BF_Heat_need == ON) {
  } else if(GF_Heat_need == ON) {
  } else if (FF_Heat_need == ON) {
  } else if(GF_Heat_need == OFF) {
  } else if (FF_Heat_need == OFF) {
  } else if (BH_Heat_need == OFF && GF_Heat_need == OFF && FF_Heat_need == OFF) {

This is almost an application. But if you struictly follow the pattern, your sendCommands would only be at the end. Let’s see if we can do that…

  // 1. See if the rule needs to run
  // The rule needs to run any time any member of gHneed changes

  // 2. Calculate what needs to be done.
  // gf and ff always follow the corresponding need and bf needs to be ON if any need is ON
  val bf = if(BF_Heating_need.state == ON || GF_Heating_need.state == ON || FF_Heat_need.state == ON) ON else OFF
  val gf = GF_Heating_need.state // follows the need Item so just use that
  val ff = FF_Heating_need.state // follows the need Item so just use that

  // 3. Do it
  if(bf != BF_Heating_Pump.state) BF_Heating_Pump.sendCommand(bf)
  if(gf != GF_HEating_Pump.state) GF_Heating_Pump.sendCommand(gf)
  if(ff != FF_HEating_Pump.state) FF_Heating_Pump.sendCommand(ff)

We can further reduce it to

  val bf = if(BF_Heating_need.state == ON || GF_Heating_need.state == ON || FF_Heat_need.state == ON) ON else OFF

  if(bf != BF_Heating_Pump.state) BF_Heating_Pump.sendCommand(bf)
  if(GF_Heating_need.state != GF_Heating_Pump.state) GF_Heating_Pump.sendCommand(GF_Heating_need.state)
  if(FF_Heating_need.state != FF_Heating_Pump.state) FF_Heating_Pump.sendCommand(FF_Heating_need.state)

Or, if you don’t care if the Pump receives a command that is the same as it’s current state

    BF_Heating_Pump.sendCommand(BF_Heating_need.state == ON || GF_Heating_need.state == ON || FF_Heat_need.state == ON) ON else OFF)

Another way to do the comparison would be

    BF_Heating_Pump.sendCommand(if(gHneed.members.filter[ i | i.state == ON ].size > 0) ON else OFF)

Or if you define your Group as

Group:Switch:OR(ON,OFF) gHneed

The rule can become

1 Like

I have 16 UFH zones on both floors, I thought long and hard about replacing the old analogue thermostats in each room with temp sensors and a 8 chamnel relay to control each manifold, pump and boiler. But actually all I needed to do was update what I already have, I have replaced the old thermostats with a sonoff basic with a dht11 attached. Im using a simple rule to turn the thermostats on and off depending on the set point and now I use Alexa to turn them on and off or up and down with routines.

Its all very simple and works a perfectly.

Thanks Rich, fun fact is that gHneed was actually defined like that, so it’s really an elegant solution, I’m marking yours as the solution. I will need to iron out some quirks around some errors I got while the switches had null values but I saw an example in Confused’s config how to assign initial values during system startup, so I’ll try to do that in the evening.

Appreciate all the help & comments from the others as well, especially @Confused