Heating Boilerplate - A Universal Temperature Control Solution with Modes

I guess you are using HmIP thermostats as well? If yes, you can set your devices to do so on your own. Use the “Direktverknüpfung” of your ccu2.

I suggest to put the basic function in the devices and just put a comfort layer with openHAB on top.

@reissp, @job,
Gentlemen, it seems that we are going off subject here.
I have some examples of window sensor driven heating control
In a new thread?

@job , @vzorglub
I was sceptical concerning mixing rules within the ccu2 and OH - what happens, when ccu2 sets the temperature to 15 °C because the window is open and OH to 24 °C, because it’s 6 am and I want to have a warm bathroom? I thought having all roules in one place, would be more logical. But in fact using the ccu2 programs is quite easy.
@vzorglub: Yes, if the topic driftes towards using the ccu2, we should start a new thread, but it also could be intersting to discus adding sensors to boilerplate. It would be nice if you could inform us about your windows driven heating controls in a new thread.

Hi Thom (@ThomDietrich)

first of all, thank you very much for the great tutorial. It is working very nice and I am currently trying to build my own sitemap with the summaries. Very helpful was the link to your config, thank you therefore!

I have a question regarding my current situation. In one room I do have two thermostats and a DHT22. What would you recommend to

  1. combine these two thermostats that I can control them together (use group items? - both are showing different values e.g for act. temp and valve etc.)
  2. how can I include my DHT22 which is showing as well different current values? Any hints?

Kindly,
Woogi

Hi @ThomDietrich, @vzorglub, hi everyone else :slight_smile:

based on this tutorial I was able to combine the two values with a group item. I am struggling with the “Schnellauswahl”. I have the following rule in place:

rule "WZ Schnellauswahl (Sitemap)"
when
    Item WZ_Temp_Preset received command
then {
    logInfo(filename, "Auswertung Schnellauswahl WZ (Sitemap)")
    switch (receivedCommand){
        case 0: {
            HM1_Manu_Mode.sendCommand(tempLower)
            HM2_Manu_Mode.sendCommand(tempLower)
        }
        case 1: {
            HM1_Manu_Mode.sendCommand(tempComfort)
            HM2_Manu_Mode.sendCommand(tempComfort)
        }
        case 2: {
            HM1_Manu_Mode.sendCommand(tempHigh)
            HM2_Manu_Mode.sendCommand(tempHigh)
        }
    }
    WZ_Temp_Preset.postUpdate(-1)
}
end

Corresponding items:

Number WZ_Temp_Preset               "Schnellauswahl Soll WZ"                      <heating>         (G_Heating)
Number HM1_Manu_Mode                "Manu-Mode [%.1f °C]"                       <heating-40>      (G_Heating_WZ)                        {channel="homematic:HM-CC-RT-DN:ccu:NUMBEROFHEATERDEVICE:4#MANU_MODE"}
Number HM2_Manu_Mode                "Manu-Mode [%.1f °C]"                       <heating-40>      (G_Heating_WZ)                        {channel="homematic:HM-CC-RT-DN:ccu:NUMBEROFHEATERDEVICE:4#MANU_MODE"}

So far so good, but the problem is, after the first time I used this rule, I can’t use it again and the whole heating is not controllable any longer. Not even the heating mode and the cronjob time rules are working any longer.

The log is not showing the logInfo, but the temp is set. why? I have the impression, that the rule is not triggered and have no idea why. My log file:

019-02-08 09:44:36.295 [ome.event.ItemCommandEvent] - Item 'WZ_Temp_Preset' received command 2
2019-02-08 09:44:36.305 [vent.ItemStateChangedEvent] - WZ_Temp_Preset changed from NULL to 2
2019-02-08 09:44:36.339 [ome.event.ItemCommandEvent] - Item 'HM1_Set_Temp' received command 23.0
2019-02-08 09:44:36.345 [nt.ItemStatePredictedEvent] - HM1_Set_Temp predicted to become 23.0
2019-02-08 09:44:36.353 [vent.ItemStateChangedEvent] - HM1_Set_Temp changed from 15.00 to 23.0
2019-02-08 09:44:36.358 [GroupItemStateChangedEvent] - G_Heating_TargetTemps changed from 15.50 to 17.50 through HM1_Set_Temp
2019-02-08 09:44:36.367 [ome.event.ItemCommandEvent] - Item 'HM2_Set_Temp' received command 23.0
2019-02-08 09:44:36.375 [nt.ItemStatePredictedEvent] - HM2_Set_Temp predicted to become 23.0
2019-02-08 09:44:36.400 [GroupItemStateChangedEvent] - G_Heating_TargetTemps changed from 17.50 to 19.50 through HM2_Set_Temp
2019-02-08 09:44:36.405 [vent.ItemStateChangedEvent] - HM2_Set_Temp changed from 15.00 to 23.0
2019-02-08 09:44:36.410 [vent.ItemStateChangedEvent] - WZ_Temp_Preset changed from 2 to -1
2019-02-08 09:44:36.465 [vent.ItemStateChangedEvent] - WZ_Heizung_Summary changed from ( • 15.0 °C ) 19.6 °C to ( • 23.0 °C ) 19.5 °C

the second time I am using the button, the log shows the following:

2019-02-08 18:15:21.989 [ome.event.ItemCommandEvent] - Item 'WZ_Temp_Preset' received command 2

Thats it, nothing else… I don’t get it :slight_smile: Hope someone has an Idea.

Thank you in advance. Kindly,

Woogi

True today, but hopefully in the future we will all have this luxury / essential energy saving option.

Hi Thanks for the tutorial and the time taken, I am a bit confused and very new to Openhab.
you state to create the following:
heating_mode.items
heating_mode.rules
mapdb.persist and myhome.sitemap

I know where and how to create then, however I have no idea whatbits of code to insert into what file cheers in advance

If the text description mentions “Items” and the code looks like what is documented here it goes in a .items file.

If the text description mentions “Rules” and the code looks like what is documented here it goes in a .rules file.

If the text talks about persistence or restoring Items and the code looks like what is documented here it goes in the .persist file.

It it talks about sitemaps and the code looks like what is documented here it goes in the .sitemap file.

Don’t forget to click the little black triangles to unhide parts of the posting.

image

image

Cool cheers, just off to work will try and digest that tonight. thanks

Hi @ThomDietrich,

First of all,
Thanks for this super tutorial. I’ve recently made my thermostat “smart” (OTGW + ESP) and now able to control my heating.
I will probably start with your suggestions and see if they fit my house during the implementation.
However, I have two additional floor heating pumps. Which are “dump” and just pump water around all day.
Now, I don’t think these pumps have to pump 24/7, since when there is no heating going on, they are not contributing anymore. But, right after the room has reached its desired temperature I’m sure the water of the floor heating is still contributing…
My question is now, since I’m not a heating expert at all, when shall the pumps of (wet) floor heating be ON and when shall they be OFF? Is there any (smart) rule (not an OpenHab rule :wink: ) for this?
Maybe it’s not right to ask the question here, but we seem to have a lot of people with far more knowledge of heating then myself :slight_smile:

Thank you in advance!
/Jasper

If there are people interested in “savings”, I had a conversation with a friend who works at a heating /cooling installation company. When I discussed the Openhab, Opentherm gateway and schedule as above as solution, he also mentioned…since I use floor heating, to lower the “MAX CH water setpoint”…default setting is 75 degrees.
But I’m using floor heating in the living room and he explained that the thermostat of the floorheating is “cooling” the water down to around 50 degrees…so that’s a “waste” of 25 degrees simply said. He said, lower it to 70 (cannot be lower then 60 degrees due to bacteria). That “saves” 5 degrees of unneeded heating.
I could probably lower it more, but…I need to do this step by step since also the rooms upstairs use the same boiler. So if that is too cold, it could give problems with heating the other rooms…

Anyway, just as a side note to the heating schedule…which works as a charm!

/Jasper

1 Like

Hello

I am surprised to see a 70deg for floor heating .
My floor heating works with temperature between 30 and 45 deg depending of outside temperature ( 45 when outside is - 20, 30 when outside is 10 or higher, interpolation in between)

Controlling the water flow of floor heating make sense only if inertia is not too big… depending of thickness of concrete ground under floor tiles .

I have a schlutter bekotec fast floor heating with an average thickness of 5 cm tile included and have about one hour inertia.

My best advice is to control the room based on room temperature forecast as I explained in detail in another post on Smart virtual thermostat topic.

Pierre

Hi @cl-oh, @rlkoshak

I am a future newbie of openhab but had previous experience with open home heating control.
I also have a long experience in oven heating in industry.

oH is a fantastic tool but Software will never be able to solve problems in control due to bad hardware configuration without a quite complex and difficult to tune and maintain bunch of code.

As you said, the sensor position is the most critical. Even with AI, the PID controller inside the valve head cannot know the room temperature

Also, the building thermal properties like inertia and insulation, air tightness are influencing confort feeling by people

So when radiator is hidden by a desk, move the desk or radiator or at least add a connected sensor somewhere else.

So let us see OH like a nice tool to combine multiple technology and make them communicating together.

Let us use OH to record sensor and heating action compared to target and evaluate in our home how it works and then try to improve step by step.

Pierre

Thanks for this clear presentation of your architecture

I would also prefer to use Jython more than DSL because I know already python.

I would prefer coding simple function in python as a library that I can use in Jython code

I haves running home heating freely programmable system running for 14 years in my home . I want to migrate to oH now because this previous system is not supported anymore.
I did the configuration by self and have the internal logic of all functions blocks used. I want to keep it running in the same way with same logic and same parameter at the beginning .

The biggest problem is that most of this code was running on a cyclic base like a PLC, not like an event triggered code.

So I am wondering now how to manage the cyclic code for some specific task like measurement filtering or forecast or long cycle PWM management for heating actuators without disturbing the whole OH system.

Perhaps I need to manage these cyclic Functions in a separate controller running node red communicating with OH.

Thanks for your feedback.

Pierre

Hi guys,

I have followed this tutorial and it works great, my only issue is when the system restarts its not updating my thermostat setpoints?

Here’s my heating_mode.rules

val String filename = "heating_mode.rules"

rule "Initialize uninitialized virtual Items"
when
    System started
then
    createTimer(now.plusSeconds(180)) [ |
        logInfo(filename, "Executing 'System started' rule for Heating")
        if (Heating_Mode.state == NULL) Heating_Mode.postUpdate("NORMAL")
        Heating_PresetNormal_Group.members.filter[item | item.state == NULL].forEach[item | item.postUpdate(21.0)]
    ]
end

// ========================

rule "React on heating mode switch, send target temperatures"
when
    Item Heating_Mode received update or
    Item Heating_UpdateHeater received command ON
then
    Heating_UpdateHeater.postUpdate(OFF)
    logInfo(filename, "Heating Mode: " + Heating_Mode.state)
    switch Heating_Mode.state {
        case "NORMAL": {
			CB_Heating_TargetTemp.sendCommand(CB_Heating_PresetTempNormal.state as Number)
			MB_Heating_TargetTemp.sendCommand(CB_Heating_PresetTempNormal.state as Number)
            LB_Heating_TargetTemp.sendCommand(LB_Heating_PresetTempNormal.state as Number)
			Office_Heating_TargetTemp.sendCommand(Office_Heating_PresetTempNormal.state as Number)
			Ensuite_Heating_TargetTemp.sendCommand(Ensuite_Heating_PresetTempNormal.state as Number)
			Landing_Heating_TargetTemp.sendCommand(Landing_Heating_PresetTempNormal.state as Number)
			Bathroom_Heating_TargetTemp.sendCommand(Bathroom_Heating_PresetTempNormal.state as Number)
			Lounge_Heating_TargetTemp.sendCommand(Lounge_Heating_PresetTempNormal.state as Number)
        }
        case "HOME": {
            CB_Heating_TargetTemp.sendCommand(21.0)
			MB_Heating_TargetTemp.sendCommand(21.0)
            LB_Heating_TargetTemp.sendCommand(21.0)
			Office_Heating_TargetTemp.sendCommand(20.0)
			Ensuite_Heating_TargetTemp.sendCommand(20.0)
			Landing_Heating_TargetTemp.sendCommand(20.0)
			Bathroom_Heating_TargetTemp.sendCommand(20.0)
			Lounge_Heating_TargetTemp.sendCommand(21.0)
        }
        case "WEEKEND_TRIP": {
			CB_Heating_TargetTemp.sendCommand(15.0)
			MB_Heating_TargetTemp.sendCommand(15.0)
            LB_Heating_TargetTemp.sendCommand(15.0)
			Office_Heating_TargetTemp.sendCommand(15.0)
			Ensuite_Heating_TargetTemp.sendCommand(15.0)
			Landing_Heating_TargetTemp.sendCommand(15.0)
			Bathroom_Heating_TargetTemp.sendCommand(15.0)
			Lounge_Heating_TargetTemp.sendCommand(15.0)
        }
        case "AWAY": {
            CB_Heating_TargetTemp.sendCommand(13.0)
            LB_Heating_TargetTemp.sendCommand(13.0)
			MB_Heating_TargetTemp.sendCommand(13.0)
			Office_Heating_TargetTemp.sendCommand(13.0)
			Ensuite_Heating_TargetTemp.sendCommand(13.0)
			Landing_Heating_TargetTemp.sendCommand(13.0)
			Bathroom_Heating_TargetTemp.sendCommand(13.0)
			Lounge_Heating_TargetTemp.sendCommand(13.0)
        }
        case "OFF_SUMMER": {
			CB_Heating_TargetTemp.sendCommand(0.0)
            LB_Heating_TargetTemp.sendCommand(0.0)
			Office_Heating_TargetTemp.sendCommand(0.0)
			MB_Heating_TargetTemp.sendCommand(0.0)
			Ensuite_Heating_TargetTemp.sendCommand(0.0)
			Landing_Heating_TargetTemp.sendCommand(0.0)
			Bathroom_Heating_TargetTemp.sendCommand(0.0)
			Lounge_Heating_TargetTemp.sendCommand(0.0)
        }
        default : { logError(heating_mode.rules, "Heating Mode unknown: " + Heating_Mode.state) }
    }
end

And items

Group gHeating
Group gTemperature {alexa="TemperatureSensor.temperature"}
Group gChart

Number CB_Heating_TargetTemp 	"CharlieBed Heating Target 	[%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}
Number MB_Heating_TargetTemp 	"MasterBed Heating Target 	[%.1f °C]"  <heating>	{alexa="ThermostatController.targetSetpoint"}
Number LB_Heating_TargetTemp 	"LillyBed Heating Target 	[%.1f °C]"  <heating>	{alexa="ThermostatController.targetSetpoint"}
Number Office_Heating_TargetTemp "Office Heating Target 	[%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}
Number Ensuite_Heating_TargetTemp "Ensuite Heating Target 	[%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}
Number Landing_Heating_TargetTemp "Landing Heating Target 	[%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}
Number Bathroom_Heating_TargetTemp "Bathroom Heating Target [%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}
Number Lounge_Heating_TargetTemp "Lounge Heating Target 	[%.1f °C]" 	<heating>	{alexa="ThermostatController.targetSetpoint"}

String Heating_Mode "Global Heating Mode [%s]" <heating>
Switch Heating_UpdateHeater "Send Target Temperatures to Heaters"

Group:Number:AVG LB_avgTemp 
Group:Number:AVG CB_avgTemp
Group:Number:AVG MB_avgTemp

Number Lilys_Bedroom          "Lilys Bedroom Temperature 	[%.1f °C]"		<temperature> (gTemperature, gChart) {alexa="TemperatureSensor.temperature"}
Number LB_Temperature         "LB Temperature 				[%.1f °C]"		<temperature> (LB_avgTemp) 			 { channel="mqtt:topic:mosquitto:lillythermostat:temperature" }
Number LB1_Temperature        "LB1 Temperature 			[%.1f °C]"			<temperature> (LB_avgTemp) 			 { channel="mqtt:topic:mosquitto:lilylamp:temperature" }

Number Charlies_Bedroom       "Charlie's Bedroom Temperature 	[%.1f °C]"	<temperature> (gTemperature, gChart) {alexa="TemperatureSensor.temperature"}
Number CB_Temperature         "Charlie's Bedroom Temperature	[%.1f °C]"	<temperature> (CB_avgTemp) 			 { channel="mqtt:topic:mosquitto:charliethermostat:temperature" }
Number CB1_Temperature        "Charlie's Bedroom1 Temperature	[%.1f °C]"	<temperature> (CB_avgTemp) 			 { channel="mqtt:topic:mosquitto:charlielamp:temperature" }

Number Master_Bedroom         "Master Bedroom Temperature 	[%.1f °C]"		<temperature> (gTemperature, gChart) {alexa="TemperatureSensor.temperature"}
Number MB_Temperature         "MB Temperature	[%.1f °C]"					<temperature> (MB_avgTemp)			 { channel="mqtt:topic:mosquitto:masterbedtemp:temperature" }
Number MB1_Temperature        "MB1 Temperature	[%.1f °C]"					<temperature> (MB_avgTemp)			 { channel="mqtt:topic:mosquitto:masterbedthermostat:temperature" }

Number Ensuite_Temperature     "Ensuite Temperature			[%.1f °C]"	<temperature> 	  (gTemperature, gChart)	 { alexa="TemperatureSensor.temperature", channel="mqtt:topic:mosquitto:ensuitethermostat:temperature" }
Number Office_Temperature     "Office Temperature			[%.1f °C]"	<temperature> 	  (gTemperature, gChart)	 { alexa="TemperatureSensor.temperature", channel="mqtt:topic:mosquitto:officethermostat:temperature" }
Number Landing_Temperature     "Landing Temperature			[%.1f °C]"	<temperature> 	  (gTemperature, gChart)	 { alexa="TemperatureSensor.temperature", channel="mqtt:topic:mosquitto:landingthermostat:temperature" }
Number Bathroom_Temperature     "Bathroom Temperature		[%.1f °C]"	<temperature> 	  (gTemperature, gChart)     { alexa="TemperatureSensor.temperature", channel="mqtt:topic:mosquitto:bathroomthermostat:temperature" }
Number Lounge_Temperature     "Lounge Temperature			[%.1f °C]"	<temperature> 	  (gTemperature, gChart)	 { alexa="TemperatureSensor.temperature", channel="mqtt:topic:mosquitto:loungethermostat:temperature" }

Switch LB_Heating_Actuator "LillBed Heating	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:lillythermostat:power" }
Switch CB_Heating_Actuator "CharlieBed Heating	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:charliethermostat:power" }
Switch MB_Heating_Actuator "MasterBed Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:masterbedthermostat:power" }
Switch Office_Heating_Actuator "Office Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:officethermostat:power" }
Switch Ensuite_Heating_Actuator "Ensuite Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:ensuitethermostat:power" }
Switch Landing_Heating_Actuator "Landing Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:landingthermostat:power" }
Switch Bathroom_Heating_Actuator "Bathroom Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:bathroomthermostat:power" }
Switch Lounge_Heating_Actuator "Lounge Heating 	[%s]" <fire> (gTemperature, gHeatingActuators) { channel="mqtt:topic:mosquitto:loungethermostat:power" }

Group Heating_PresetNormal_Group
Number LB_Heating_PresetTempNormal "LilyBed Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number CB_Heating_PresetTempNormal "CharlieBed Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number MB_Heating_PresetTempNormal "MasterBed Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number Office_Heating_PresetTempNormal "Office Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number Ensuite_Heating_PresetTempNormal "Ensuite Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number Landing_Heating_PresetTempNormal "Landing Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number Bathroom_Heating_PresetTempNormal "Bathroom Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}
Number Lounge_Heating_PresetTempNormal "Lounge Heating Preset 	[%.1f °C]" (Heating_PresetNormal_Group)	{alexa="Thermostat"}

I’m not sure what I’m missing?

Although I’m getting this log?

2020-04-13 22:31:03.846 [INFO ] [home.model.script.heating_mode.rules] - Executing 'System started' rule for Heating

Might be a bit late but I’ve only just found this thread…

If you are getting that log file entry then OH has reached the


if (Heating_Mode.state == NULL) Heating_Mode.postUpdate("NORMAL")

And is stopping because the IF isn’t true.

If that IF isn’t true then the second rule with all the case statements, ie the rule that does your donkey work will never run.

You need to find out what the Heating_Mode state is in start up and then change the IF to match.

1 Like

Wondering if someone could help me with a rule related to this. Currently have a system that is working very well. I have recently implemented a rule so that once the temperature outside is above 10 degrees set heating mode to OFF. I have then implemented a second rule to turn the Heating Mode to Night if the temperature goes below 10 degrees. The issue im having is ideally if for instance at 1pm the temperature outside goes below 10 degrees the heating mode wants setting to DAY not Night. So im looking for a rule that is something along the lines of if the temperature outside goes below 10 degrees, if the current time is between 6.30am and 9am set to MORNING, If current time is between 9am and 6pm set to Day and so forth?

Current Configs

//Heating Items
Switch Boiler_Status "Boiler Status"  {channel="mqtt:topic:Boiler_Control:relay2"}
String Heating_Mode "Heating Mode"    
Switch Heating_Switch "Heating Switch"   {channel="mqtt:topic:Boiler_Control:relay1"}
Switch Heating_UpdateHeaters "Send Target Temperatures to Heaters"

// Kids Bedroom
Switch Kids_Bedroom_Radiator_Valve "Radiator" <heating>  (gALLRADIATORS) { channel="mqtt:topic:Kids_Bedroom_Radiator_Valve:Power" }
Number Kids_Bedroom_Temp_Setpoint  "Set Point [%.1f]" 


// Living Room
Switch Living_Room_Radiator_Valve "Radiator" <heating>  (gALLRADIATORS)
Number Living_Room_Temp_Setpoint  "Set Point [%.1f]" 

rule "Kids Bedroom heating"
when
    Item Kids_Bedroom_Temp_Setpoint changed or
    Item Kids_Bedroom_Temperature changed
then
    var Number cur_temp = Kids_Bedroom_Temperature.state as Number
    var Number setpoint = Kids_Bedroom_Temp_Setpoint.state as Number
    val  Number hysteresis = 0.2

    if (cur_temp < (setpoint - hysteresis) ){
        if (Kids_Bedroom_Radiator_Valve.state != ON) {Kids_Bedroom_Radiator_Valve.sendCommand(ON)}
    }
    else if(cur_temp > setpoint + hysteresis) {
        if (Kids_Bedroom_Radiator_Valve.state != OFF) {Kids_Bedroom_Radiator_Valve.sendCommand(OFF)}
    }
end

rule "Living Room heating"
when
    Item Living_Room_Temp_Setpoint changed or
    Item Living_Room_Temperature changed
then
    var Number cur_temp = Living_Room_Temperature.state as Number
    var Number setpoint = Living_Room_Temp_Setpoint.state as Number
    val  Number hysteresis = 0.2

    if (cur_temp < (setpoint - hysteresis) ){
        if (Living_Room_Radiator_Valve.state != ON) {Living_Room_Radiator_Valve.sendCommand(ON)}
    }
    else if(cur_temp > setpoint + hysteresis) {
        if (Living_Room_Radiator_Valve.state != OFF) {Living_Room_Radiator_Valve.sendCommand(OFF)}
    }
end


rule "React on heating mode switch, send target temperatures"
when
    Item Heating_Mode received update 
then
    Heating_UpdateHeaters.postUpdate(OFF)
    logInfo("heating_mode.rules", "Heating Mode: " + Heating_Mode.state)
    switch Heating_Mode.state {
        case "ON": {
            Living_Room_Temp_Setpoint.sendCommand(21.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(21.0)
        }
        case "MORNING": {
            Living_Room_Temp_Setpoint.sendCommand(21.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(21.0)
        }
        case "DAY": {
            Living_Room_Temp_Setpoint.sendCommand(21.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(18.0)
        }
        case "EVENING": {
            Living_Room_Temp_Setpoint.sendCommand(21.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(21.0)
        }
        case "NIGHT": {
            Living_Room_Temp_Setpoint.sendCommand(19.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(19.0)
        }
        case "OFF": {
            Living_Room_Temp_Setpoint.sendCommand(15.0)
            Kids_Bedroom_Temp_Setpoint.sendCommand(15.0)
        }
        
       default : { logError("heating_mode.rules", "Heating Mode unknown: " + Heating_Mode.state) }
    }

All the rest of my rules have been created on the ui in openhab3