[SOLVED] Heater thermostat control

Tags: #<Tag:0x00007f6173de0b80> #<Tag:0x00007f6173de0a90> #<Tag:0x00007f6173de09c8>

Hi,

I have small electric heater which I would like to control with temperature setpoint.

My item to control heater looks like this:

Switch Heating_GF_Bath 	"Bathroom"	<heating>	(GF_Bath, Heating)   {mqtt=">[broker:/sonoff/switch8/switch8/cmd:command:ON:on],>[broker:/sonoff/switch8/switch8/cmd:command:OFF:off],<[broker:/sonoff/switch8/switch8/state:state:ON:on],<[broker:/sonoff/switch8/switch8/state:state:OFF:off]"}

And item providing temperature

Number Temperature_GF_Bath "Bathroom Temp [%.1f °C]"   <temperature>   (Temperature, GF_Bath) [ "CurrentTemperature" ] { mqtt="<[broker:/sonoff/switch8/temperature:state:default]"}	

I have created new setpoint item:

Number Temperature_Setpoint		"Temperature [%.1f °C]" <temperature>  { mqtt=">[broker:cmnd/sonoff/switch8/set_point:command:*:default]" }

And updated Sitemap accordingly

Setpoint item=Temperature_Setpoint minValue=16 maxValue=28 step=0.5

And finally rule which should fire heater when reading temperature is below the requested temp.

//Heater Control
    if (Temperature_GF_Bath.state <= Temperature_Setpoint.state) {
        Heating_GF_Bath.sendCommand(ON)
    } else { 
        Heating_GF_Bath.sendCommand(OFF)
    }    

However it doesn’t work at the moment.
Cant find anything in logs related to this setpoint.
What`s wrong here ?

1 Like

Are you sure the rule gets triggered? You could add some logging to see what is (not) happening.

Does this help you at all?

If that’s not the whole rule, may we see it all?

If it is the whole thing, you are missing rule name, when trigger then section, and an end.
You would most likely trigger the rule to run whenever the temperature changes.

Yeap, my rules was posted incomplete.
I have redone it slightly but still is not working as expected.

rule "Heater Control"
when
    (Temperature_GF_Bath.state <= Temperature_Setpoint.state) 
then {
    Heating_GF_Bath.sendCommand(ON)
} else {
    Heating_GF_Bath.sendCommand(OFF) 
	}
end
rule "Heater Control"
when
  Item Temperature_GF_Bath changed
then
  if (Temperature_GF_Bath.state <= Temperature_Setpoint.state)
  {
    Heating_GF_Bath.sendCommand(ON)
  }
  else
  {
    Heating_GF_Bath.sendCommand(OFF)
  }
end

Try this way…

and even set up some logging to the ruel, e.g. when the rule is triggered (above the if-clause) and in the if and else part…

If it is turning on and off correctly you should set up a hysteresis for the setpoint value.
If the temperature is at the setpoint, the heater will turn on and off very quickly. You should allow a difference of 1 or 0.5 K for this…

@imhofa

Modified rule accordingly as per your suggestion above and seems to be working now :grinning:
I can start and stop heater by increasing or decreasing temperature setpoint.
I will need to test it well over the next few days to see if this setup is reliable.

Looking in the log I can see the following warning stating NULL value…

2019-01-31 22:17:27.445 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:18:27.520 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:19:27.420 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:20:27.439 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:21:27.534 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:22:27.504 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:23:27.538 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:24:27.533 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'
2019-01-31 22:25:27.619 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'Temperature_Setpoint'

This Item is not updated in the rule that you have shown us, so the source of the warning is elsewhere.
Perhaps another rule, perhaps your UI, perhaps a binding.
How are you expecting that Item to get updated?

@rossko57 You are right - I had another “Temperature_Setpoint” in my demo code which was causing this error - removed now.

I need to improve my rule slightly to prevent some failure scenarios.

  1. I noticed that when my temperature sensor gets disconnected from the system (for any reason) it showing reading -5C. If that ever happens my heater will be continuously working. So would like to add condition to my rule to only execute when temperature reading is above 0C. Temperature in the bath never drops below 13C when heating is off.
    Would this work ?
rule "Heater Control"
when
  Item Temperature_GF_Bath changed
  (Temperature_GF_Bath >0)
then
  if (Temperature_GF_Bath.state <= Temperature_Setpoint.state)
  {
    Heating_GF_Bath.sendCommand(ON)
  }
  else
  {
    Heating_GF_Bath.sendCommand(OFF)
  }
end
  1. Additionally I would like to add switch to sitemap in order to enable/disable (ON?OFF) temperature setpoint control. At the moment my system doesnt know if Im at home (presence is not implemented yet - on the list to do). So when I`m not at home this rule should be disabled.
Switch item=Temperature_Setpoint_Mode       mappings=[0="OFF", 1="ON"]  

Is that the best way of doing it ?

Just a warning! If for some reason your sensor will fail or doesn’t give the correct you value (like always give the same value back) you might still have the heater continuously working. So be careful what you implement and add some extra safeguards. For example don’t run the heater for longer than x or don’t run the heater when the temperature doesn’t change even while the heater is on. But these are far more complex rules than a simple on/off.

Thanks, yes my scenario number 1 should cover the event of failure the temperature sensor at any time.
I like the idea of limiting heater run to x minutes or if the heater is running for x minutes and temperature hasn`t changed. How would you implement these conditions into working rule please?

when
  Item Temperature_GF_Bath changed
  (Temperature_GF_Bath >0)
then

Best will be to read the documentation for triggers:

The trigger is for events to start the rule. The other things (to check for values) has to be done within the “then” part of the rule…

Thanks @imhofa

With regards to number 2 from my list I added switch to sitemap & items to enable heater setpoint control is needed.

Sitemap

Switch item=Temperature_Setpoint_Mode  label="Control ON" mappings=[1="OFF", 2="ON", 3="SHOWER"]

Items

Number Temperature_Setpoint_Mode  

Also modified the rule above to include this switch which woulld be used to enable/disable heater control. Third mode “Shower” will be used when there is request to warm up bathroom to certain fixed temperature - lets say 24C for younger generation.
But some reason when flicking switch from OFF to ON position heater is not starting anymore.
Any ideas where is the mistake ?

rule "Bathroom Heater Control"
when
    Item Temperature_Setpoint_Mode changed from OFF to ON
   (Temperature_GF_Bath >0)
then
    if (Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state)
   {
    Heating_GF_Bath.sendCommand(ON)
   }
else
   {
    Heating_GF_Bath.sendCommand(OFF)
   }
end

Tried the following rule but there seems to be a problem switching on heater after adding these news conditions (Temperature_GF_Bath>0 & Temperature_Setpoint_Mode)

rule "Bathroom Heater Control ON"
when
    Item Temperature_GF_Bath changed
   (Temperature_GF_Bath >0)
   (Temperature_Setpoint_Mode changed to ON)
then
    if (Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state)
	{
    Heating_GF_Bath.sendCommand(ON)
	}
else
   {
    Heating_GF_Bath.sendCommand(OFF)
   }
end

Any idea how to cure it ?

You should be seeing error report for your rules file in openhab.log

You can’t have conditions in rule triggers. They’re not suggested in the documentation already pointed to. Rule triggers are just events.
If you want to evaluate conditions, you do it inside the rule body.

rule "Bathroom Heater Control ON"
when
    Item Temperature_GF_Bath changed or 
    Item Temperature_Setpoint_Mode changed to ON
then
   if ( (Temperature_GF_Bath.state as Number) > 0) {
       if (Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state)	{
           Heating_GF_Bath.sendCommand(ON)
       } else {
           Heating_GF_Bath.sendCommand(OFF)
       }
    }
end

I’m not sure if you wanted Temperature_Setpoint_Mode as a trigger, a condition, or both.

Thanks @rossko57 I prefer to set Temperature_Setpoint_Mode as trigger (when set to 1=Heat).
Temperature_Setpoint_Mode generally will be switched ON during day when someone is at home to maintain requested temperature in the bathroom.

I have removed the temperature change condition from rule leaving only setpoint_mode as trigger.
But it works to the degree. When Temperature_Setpoint_Mode is set to 1, heater is turning ON but not stopping after reaching requested temperature - it`s constantly running till heater is switched off manually.

rule "Bathroom Heater Control ON"
when
    Item Temperature_Setpoint_Mode changed to 1
then
   if ( (Temperature_GF_Bath.state as Number) > 0) {
       if (Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state)	{
           Heating_GF_Bath.sendCommand(ON)
	} else {
           Heating_GF_Bath.sendCommand(OFF)
        }
    }
end

Not sure why is not stopping after hitting requested temperature ?

All I really want is to turn on this setpoint_mode in the morning and let it run to maintain temperature as per setpoint.

Why would it? It’s doing just what you told it to. Triggers are events. The rule in its last iteration runs once only, when you change Temperature_Setpoint_Mode to 1. The rule then exits, and that’s the end of that.
It’s like a script. “When I say Go, read the script”. You’d only read it once and then put it back on the table.

I think what you want to do is trigger the rule whenever the temperature changes, so that you can do the comparison/thermostat action.

If you only want it to do that when the mode is 1, then you need to do the mode comparison within the rule. The rule will still run at every temperature change, but you set it up so that it does nothing useful if the mode is wrong.

If you do only that much, then changing the mode won’t have any immediate effect. It’ll get taken into account the next time the temperature changes and causes the rule to run.

If you want something to happen immediately you change mode, then you will need to trigger on a mode change as well.

You probably want to think about what you want to happen if you set the mode “off” while heater is on. That could determine where you do comparisons and what you have in ‘else’ parts.

Fair point my friend, its probably better to trigger on temperature change if I can add Temperature_Setpoint_Mode to then section.Modified the following rule so now have three if conditions before heater can be started:

  1. Temperature_GF_Bath greater than 0 C.

  2. Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state

  3. Temperature_Setpoint_Mode changed to 1 (Heat)

rule "Bathroom Heater Control ON"
when
    Item Temperature_GF_Bath changed
then
       if ( (Temperature_GF_Bath.state as Number) > 0) {
       if (Temperature_GF_Bath.state <= Temperature_Setpoint_Bath.state)	{
	   } if (Temperature_Setpoint_Mode changed to 1) {
           Heating_GF_Bath.sendCommand(ON)
	}
} else {
           Heating_GF_Bath.sendCommand(OFF)
        }
end

As a result of the above modification heater is starting as expected but again is just carry on running exceeding setup temperature till heater is manually switched off. What am I doing wrong again?

You still should be seeing errors in your openhab.log for this rules file.

That’s a nonsense condition, looking for an event to happen just as you test it in the middle of a rule.

Because this rule is broken as it stands, I suspect you’ve got something else hanging around that also switches the heater on.

I do not like “writing code for people” because you don’t learn from it, but offer up a solution in the hope you can figure out why it is this way. It’s not the only way, or the most elegant way.

rule "Bathroom Heater Control"
when
   Item Temperature_GF_Bath changed or
      // triggers whenever temp changes
   Item Temperature_Setpoint_Mode changed
      // also triggers when mode changes for immediate action
      // else nothing would happen until temp changed, if it ever did
then
      // first we check if the temp reading is valid
   if ( Temperature_GF_Bath.state != NULL &&
        Temperature_GF_Bath.state != UNDEF &&
        Temperature_GF_Bath.state > 0) {
             // that != means "not equal" in an if(condition)
             // while the && means "and"

        // temp sensor is valid, so
        // let's set up a target temperature
      var Number tempMax = 0
      if (Temperature_Setpoint_Mode.state == 2) {
           // shower mode
         tempMax = 24
      } else if (Temperature_Setpoint_Mode.state == 1) {
            // normal mode
         tempMax = Temperature_Setpoint_Bath.state
      }
         // if the mode is anything else, the target stays 0 i.e. off

         // now let's check against upper limit
      if (Temperature_GF_Bath.state < (tempMax - 1)) {
            // we allow 1 degree hysteresis
            // It's colder than target
            // so turn heater on if it isn't already
         if (Heating_GF_Bath.state != ON) {
            Heating_GF_Bath.sendCommand(ON)
         }

         // else lets check if we're at the target
      } else if (Temperature_GF_Bath.state > tempMax) {
            // reached target temp
            // (our target could be 0 if mode is off)
            // so turn heater off if it isn't already
         if (Heating_GF_Bath.state != OFF) {
            Heating_GF_Bath.sendCommand(OFF)
         }
      }  // else we do nothing here
         // temp could be within 1 degree of target
         // and the heater will continue doing what it is doing
         // That's the hysteresis

   } else {   // this else belongs to the valid temp reading check
      Heating_GF_Bath.sendCommand(OFF)
          // temp sensor broken, turn off heater for safety
   }
end
2 Likes