Cron Heating Rules


(Kim Skatun) #3

Hi

I have a similar heating rule that works nice:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.util.*

rule "Heat on weekdays"
	when
		Time cron "0 45 5 ? * MON-FRI"
	then
		sendCommand(Heating_All,ON)
end

rule "Heat off weekdays"
	when
		Time cron "0 15 0 ? * MON-FRI"
	then
		sendCommand(Heating_All,OFF)
end

rule "Heat on weekends"
	when
		Time cron "0 45 7 ? * SAT,SUN"
	then
		sendCommand(Heating_All,OFF)
end

rule "Heat off weekends"
	when
		Time cron "0 15 1 ? * SAT,SUN"
	then
		sendCommand(Heating_All,OFF)
end

However I would also like to switch the heat off between 8 -16 on weekdays, but only if i am not at home: Do i need to add it another cron rule or can i somehow do it with a: if time>8 and <16 rule in my presence rule?

rule "Someone is at home"
   when
      Item MOB188 changed to ON or
      Item MOB137 changed to ON
   then
      postUpdate(PRAESENZ, ON)
      sendCommand(Light_All,ON)
      if time>8 and <24 then 
	  sendCommand(Heating_All,ON)
     end if
end
 
rule "No one is at home"
   when
      Item MOB188 changed to OFF or
      Item MOB137 changed to OFF
   then
      if(MOB188.state == OFF && MOB137.state == OFF) {
      postUpdate(PRAESENZ, OFF)
      sendCommand(Light_All,OFF)
      if time>8 and <16  then
	  sendCommand(Heating_All,OFF)
      end if
      }
end

Or how does people normally heat their homes? Ideally i think it should look like this:

If you are there then heating is on:
If it is at night lower temperature to 16
If you are home then temperature is 19 in living rooms,hallways,bedrooms,21 in bathroom and offices
If google now tells openhab its on its way home(lets say 30min) then boost heat
Keeps all rooms above 4 degree when you are away

Any input feedback on this?
And I hope Joe can use my simple cron heating rule…


(Rich Koshak) #4

Here is how I would approach the problem.

Create a set of Switch Items that get switched on or off to indicate time of day using your cron triggered rules.

Then check the state of those Switches as well as your presence Switch in the rules that turn on the heat on or off.

See this posting for an example of marking off time of day periods using a Switch.


(Kim Skatun) #5

Hi
I updated the heating rules as you suggested by adding two items:

So what i want to achieve is that i turn off lights as soon as both phone leaves the flat.

For the heating I want it to turn off during the day if no one is home, or turn it off you leave between 8 and 16. I started looking into getting arduino temperature sensor to as an add on to the heating rules. I also found a location add on, which can I think can be used to turn heat on when I am leaving work:) Then i dont arrive home in 15 minutes then switch heat off, and if i am closer than 500m from home i can switch heat on as well(No friends living closer then 1km… I guess it is possible to detect if you are closer than 1km and moving turn heat on… )

below are my code:

items:
Switch Present
Switch MOBKIM "Cell Kim"
Switch MOBLIVUNNI "Cell Liv Unni"

Switch timeState
Switch timeState2

phone rule:

rule "Someone is at home"
   when
		(Item MOBKIM changed to ON or
		Item MOBLIVUNNI changed to ON) 
   then
		sendCommand(Present, ON)
		// we dont want to accidently turn on lights and heat during the night if phone reconnects to network...
		if(testState2.state==OFF) {			
			sendCommand(Light_All,ON)
			sendCommand(Heating_LivingRoom, ON)		
		}
end
 
rule "No one is at home"
   when
   Item MOBKIM changed to OFF or
  Item MOBLIVUNNI changed to OFF
   then
   if(MOBKIM.state == OFF && MOBLIVUNNI.state == OFF ) {
			sendCommand(Present, OFF)
			//Only switch heat of during the day
			if (testState.state==OFF){
				sendCommand(Heating_LivingRoom,OFF)
			}
				
			//turn lights off
			sendCommand(Light_All,OFF)		
		}
 }
end

heat rule:
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.util.*

rule "Heat on weekdays"
	when
		Time cron "0 45 5 ? * MON-FRI"
	then
		sendCommand(Heating_LivingRoom, OFF)
		sendCommand(Heating_Kitchen, OFF)
		sendCommand(Heating_Bathroom, OFF)
		sendCommand(Heating_MasterBedroom, OFF)
		sendCommand(Heating_Bedroom, OFF)
		sendCommand(Heating_Hallway,OFF)
end

rule "Heat off weekdays"
	when
		Time cron "0 15 0 ? * MON-FRI"
	then
		sendCommand(Heating_LivingRoom, ON)
		sendCommand(Heating_Kitchen, ON)
		sendCommand(Heating_Bathroom, ON)
		sendCommand(Heating_MasterBedroom, ON)
		sendCommand(Heating_Bedroom, ON)
		sendCommand(Heating_Hallway,ON)
end

rule "Heat off weekends"
	when
		Time cron "0 45 5 ? * SAT,SUN"
	then
		sendCommand(Heating_LivingRoom, OFF)
		sendCommand(Heating_Kitchen, OFF)
		sendCommand(Heating_Bathroom, OFF)
		sendCommand(Heating_MasterBedroom, OFF)
		sendCommand(Heating_Bedroom, OFF)
		sendCommand(Heating_Hallway,OFF)
end

rule "Heat on weekdays"
	when
		Time cron "0 15 0 ? * SAT,SUN"
	then
		sendCommand(Heating_LivingRoom, ON)
		sendCommand(Heating_Kitchen, ON)
		sendCommand(Heating_Bathroom, ON)
		sendCommand(Heating_MasterBedroom, ON)
		sendCommand(Heating_Bedroom, ON)
		sendCommand(Heating_Hallway,ON)
end

rule "heat off when away"
	when
		Time cron "0 15 8 ? * MON-SUN"
	then
		sendCommand(timeState,OFF)
end

rule "heat ON when back"
	when
		Time cron "0 15 16 ? * MON-SUN"
	then
		sendCommand(timeState,ON)
end

rule "heat off when night"
	when
		Time cron "0 15 8 ? * MON-SUN"
	then
		sendCommand(timeState2,OFF)
end

rule "heat ON when its is day"
	when
		Time cron "0 15 0 ? * MON-SUN"
	then
		sendCommand(timeState2,ON)
end

Is it possible that we can add heating rules to the demo on either the wiki or make a seperate demo download, because it seems like a lot of people uses heating rules or want to implement it:)

I came over a swedish article the other day, and that family also lower the temperature by 5 degreece if a window opens.


(Rich Koshak) #6

The wiki is the most appropriate place in my opinion. It’s a wiki so go for it.


(Kim Skatun) #7

Hi, For xmas I got Netatmo temperature sensor and now I would like to use this to control the heat in my flat. So I was wondering if anyone out there could give me some tips on how to do this:)

My idea is as follow:

I have 4 different set temperature:
dayTime nightTime away windowsOpen

So basically we want to have 20C in day time, 18C at night in bedrooms, 10 in living room and hallway and 15 at bathroom or?

when i am not there I dont see why I cant set the temperature to 10 degree, and if I open the windows i would like to set the temperature for 18C

So how do I best define this temperatures? In var daytime = 20 in rules file, or do we make an item that we could adjust This would then get reset to default by reboot, or somehow saved?

Secondly how do i best make the thermostat?

Do i write a cron rule that runs every 5 minutes?(more often?) and then take ::

if time>timeOn then sendCommand(heater,Off) else (dayTime-actualTemperature )*kp = timeOn time = new Timer(timeOn) sendCommand(heater,On)

Where kp is the gain that needs somehow to be set appropiate.

How has other people done this kind of heating?


(Rich Koshak) #8

As with most things related to openHAB, there are tons of ways to go about this. I personally would set it up as follows:

Assumptions:

  • Persistence is installed and configured to reload values at start (addresses your question about reboot)
  • “away” takes precedence over windowsOpen
  • I hate polling and avoid it where ever I can
  • Uses the Astro binding to start dayTime at dawn and nightTime at Sunset
  • I have no idea what “kp” is supposed to be representing or controlling, hopefully you can figure out how to incorporate it

Create switches for all four of your temperature flags and rules to turn these switches on and off. It is a little more complicated state machine than most because your windows and your away status could be ON at any time. Then I would store the temperatures you want for each of these zones also in Items and name these Items so we can easily “look them up” based on which switch is ON. Put these Nunmber Items on your sitemap with a setpoint so you can adjust it (at least to set their initial value. Put the switches into one Group which we use to trigger the temperature change rule. Put the temperature Items into another Group so we can look them up. Then in the rule that triggers on the switches just look to see which ones are on, look up the right temp and set the goal temp.

Then you need an Item to represent the current temp and the goal temp and a rule that triggers when current temp changes and determines when to turn the heater on or off based on the goal temp.

Items: NOTE: I’m adding the Heater and WindowsOpen Items for reference. Obviously in your version they will be bound to something.

Group gTempSwitches
Group gTemps

Switch s_DayTimeTemp (gTempSwitches)
Switch s_NightTimeTemp (gTempSwitches)
Switch s_AwayTemp (gTempSwitches)
Switch s_WindowsOpenTemp (gTempSwitches)

Number DayTimeTemp (gTemps)
Number NightTimeTemp (gTemps)
Number AwayTemp (gTemps)
Number WindowsOpenTemp (gTemps)

Switch Sunrise { astro="planet=sun, type=rise, property=start" }
Switch Sunset { astro="planet=sun, type=set, property=start" }

Number TargetTemp
...

Contact WindowsOpen
Switch Heater
Number CurrentTemp
Switch Away

Rules:

// Rules that determine heater switch states
rule "Set s_DayTimeTemp"
when
    Item Sunrise received command ON
then
    s_NightTimeTemp.sendCommand(OFF)
    s_DayTimeTemp.sendCommand(ON)
end

rule "Set s_NightTimeTemp"
when
    Item Sunset received command ON
then
    s_DayTimeTemp.sendCommand(OFF)
    s_NightTimeTemp.sendCommand(ON)
end

rule "Set s_AwayTemp"
when
    Item Away received command
then
    s_AwayTemp.sendCommand(Away.state)
end

rule "Set s_WindowsOpenTemp"
when
    Item WindowsOpen received command
then
    s_WindowsOpenTemp.sendCommand(WindowsOpen.state)
end

// Rule to change the target temp
rule "Update target temp"
when
    Item gTempSwitches received update // triggers when on of the s_*Temp switches changes
then

    // If s_AwayTemp is ON, set the TargetTemp to AwayTemp
    if(gTempSwitches.members.filter(sw|sw.name == "s_AwayTemp").head.state == ON) {
        TargetTemp.postUpdate(AwayTemp.state)
    }

    // If s_AwayTemp is OFF but s_WindowsOpenTemp is ON set TargetTemp to WindowsOpenTemp
    else if(gTempSwitches.members.filter(sw|sw.name == "s_WindowsOpenTemp").head.state == ON){
        TargetTemp.postUpdate(WindowsOpenTemp.state)
    }

    // Both s_AwayTemp and s_WindowsOpenTemp are OFF, set TargetTemp to whatever remaining switch is ON
    // Assumes only one switch will be ON. If more than one then the first one found will apply
    else {
        val SwitchItem onSwitch = gTempSwitches.members.filter(sw|sw.state == ON).head
        val String tempName = onSwitch.name.split("_").get(1)
        TargetTemp.postUpdate(gTemps.members.filter(num|num.name == tempName).head.state)
    }
end

// Rule to drive the Heater
rule "Heater"
when
    Item CurrentTemp received update or
    Item TargetTemp received update
then
    // Turn on the heater if the temp gets more than 2 degrees below the TargetTemp to prevent rapid cycling
    if((CurrentTemp.state as DecimalType)-2 < (TargetTemp.state as DecimalType)) {
        Heater.sendCommand(ON)
    }
    else {
        Heater.sendCommand(OFF)
    }
end

(Kim Skatun) #9

Thanks for the reply, I am on to it. Will be away the rest of this week so will try to implement it next week.

This is where i was thinking of implementing a proportional regulator, hence the kp gain. WIKI

Would be slightly better than the simple on/off if error >2 degree because that might overshoot and you have an error of 2 degreece. So ideally we would like to have 0.5 degree error as maximum, but also avoid turning heat on and off more than necessary. No idea how to achieve this though, so for now i would stick with your solution:)


(Rich Koshak) #10

From what I can gather on that wiki page, proportional control would only work if you can control the amount of heating power the heater generates at a given time. For example, do something like have five burners on when the temp is a certain amount below the threshold and gradually turning off burners until you reach the target temp.

In my admittedly limited experience (forced air natural gas heaters in the US) the burners are either on or they are off. And rapidly turning the heater on an off, at least for the units I have experience with, is a sure way to kill your unit. Also, most heaters run much more efficiently after they have been on for awhile so it is actually more energy efficient and puts less stress on the heater to run it for longer periods of time fewer times a day. So I would not recommend proportional control for any heater I’ve seen.

That being said, there is no reason why you can’t have the buffer be .5 as opposed to 2. I just threw that number in there as it seemed a reasonable compromise between having the heat come on a dozen times a day for five to ten minutes to keep temp verses it coming on fewer times a day but for longer periods, remembering though that the fewer/longer periods of time that the heater is on, the longer your heater will last and the less energy it will burn. But that is based on how my heater works in my house so YMMV and depends on a lot of things like how powerful your heater is, how it works forced air verses ambient), and how well insulated your house is.


(Kim Skatun) #11

Thanks,
I have electric floor heating connected to a 32A relay. How often will your rule excute? Every 0.5s? I am just a bit worried that the relay will burn if it gets turn on and off a lot. Lets say that the rule gets exceuted every .5s, heat on and then it reach -1.9 offset in the next minute and then off. then in the next minute its -2.01 then it will turn on again. So my idea was rather that its kept on untill its +2.01 and then first turns on again when its -2.01.

if(abs(CurrentTemp.state as DecimalType- TargetTemp.state as DecimalType) >2)) might work or?


(Rich Koshak) #12

The rule executes every time there is a change in CurrentTemp or TargetTemp. So it largely depends on how often whatever is reporting the current temp sends a new value and how rapidly the temperature changes. However, it only changes the state of the relay when the temp gets 2 degrees below the target temp or reaches the target temp so it is not cycling the relay every time the temp changes.

The bigger the buffer the fewer times the relay will need to turn on and off in a given day and a given temp, but also the more temperature swings you will experience. So if you change the 2 to .5, it will come on more often because your buffer is only half a degree as opposed to two degrees.

That is exactly what the rule does, only I only put the “buffer” on the low side. Basically the heater will only turn on when the temp gets below 2 degrees of the TargetTemp and remain on until it reaches or exceeds TargetTemp. That is the whole point of the

if((CurrentTemp.state as DecimalType)-2 < (TargetTemp.state as DecimalType)) {

The only other thing you may want to do in the case that your relay does weird things if it receives an ON when it is already ON and is to only send the ON command if the Heater is OFF.

if((CurrentTemp.state as DecimalType)-2 < (TargetTemp.state as DecimalType)) {
    if(Heater.state != ON) Heater.sendCommand(ON)
}
else {
    if(Heater.state != OFF) Heater.sendCommand(OFF)
}

This is how commercial thermostats work.


(Kim Skatun) #13

Well i guess what you really want is to have the room at 65F±2F or 18C±1C, so i guess your rule works superb:) When i get it to work properly I will add it to the wiki.


(Porthos) #14

Thank you for the wonderful and a very elegant recipe for controlling one heat source (furnace). I used in my apartment and it works beautifully. I would like to extend the scope with additional thermo valves and I have a problem. I have a central heating (radiator in every room, gas furnace outside the apartment) and I would like to link in some way the opening / closing sensors of the window with thermo valve control (Danfoss z-wave) for each radiator individually, i.e. if I open the window in the kitchen to the its thermo valve will be sent a command with the temperature set for the open window (eg WindowsOpenTemp), but in other rooms the temperature sent to their thermo valves remains unchanged (eg DayTimeTemp), because the windows in them are closed. So each radiator is a separate source of heat for each room and is controlled separately. I would like to keep the convention and state machine introduced by Rikoshak. I will be grateful for any help.


(Rich Koshak) #15

Use Design Pattern: Associated Items to name your window sensor Items, thermostats Items, and target temp Items. Construct the names so you can easily parse and create the name of the associated Items based on the name of an Item you already have.

For example, The Window sensor changes triggering a rule. You parse out the common parts of the Window Sensor Item and construct the name of the associated thermostat and the target temp for when the window is open. Then you can pull the target temp Item from a Group by name and send that number as a command to the thermostat.


(Porthos) #16

Rich, you’re always reliable. Thank you for sharing your knowledge and advice - I have learned a lot reading your tutorials and I’m still learning. I will try to improve something in my script following your suggestion and let you know.


(Michael Ingraham) #17

I thought I’d tack on to this thread because my topic is related and there are a lot of great examples and suggestions to which this might be valuable to expand with.

I would like to extend the idea of specifying an HVAC schedule with the flexibility to have multiple daily windows and variance between workdays/weekdays and weekends/holidays.

I suppose that I could hard code lots of rules with specific cron triggers, etc. I was instead looking to implement more of a data driven approach.

I have a Nest thermostat. I’m on a journey to implement my own remote temperature sensors for my thermostat. The Nest implementation leaves a lot to be desired. In addition, they aren’t providing (and I am not hopeful that they will) access to the sensor data through the API.

Now my journey now would like to make use of the scheduling scheme Nest provides. Wouldn’t it be ideal if I could just read that schedule? But, alas, that’s another gap in the Nest API.

I wouldn’t necessarily need to specify a schedule for every day of the week. But, there is a need to specify a schedule for the days where a workday > day-off or day-off > workday transition occurs.

I think specifying multiple time windows for four schedules would suffice:

  • Workday
  • Day off
  • Workday heading into a day off
  • Day off heading into a workday

Also

  • A “regular” workweek is Monday-Friday but could be configured.
  • A workday would be modified by a list of regional holidays which should have a scheduled yearly download task.
  • Vacations are handled separately through Home/Away state set by location tracking or set manually (e.g., the Nest Structure state).

So, yes, my question is broad. I’m honestly not sure where to begin. But I’m hoping that there is someone with a similar kind of scheduling scenario already (not necessarily limited to HVAC). I didn’t find anything on the Community or in a broader, non-openHAB search. And, if not a scheduling setup someone has already cracked, then I wanted to mine the hive :wink:

Much appreciated.

Mike

P.S. I’m not looking to have the schedule “exposed” through a Sitemap. I can live with editing a file to make schedule changes. This ought to be pretty static.


(Rich Koshak) #18

?

What other sensors are you after? The proximity sensor? Not shown is also a Channel for “time to target temp”.

Even though the Time of Day design pattern uses an example based on the hour:minute of the day, the exact same approach can be used for setting the type of day. The challenge is how to calculate what type of day it is. If your work week is pretty regular though the Rule shouldn’t be too complicated.

There isn’t. It’s a known missing feature in OH. There is an attempt to address it in the work going into the next generation version of PaperUI under work now (see Next generation design: Paper UI design study). There are other improvements in work that will make something like this easier to implement as well like the ability to set and read metadata on Items from Rules or the REST API. So, for example, you can put the temps for a given type of day in an Item’s metadata instead of needing to create separate Items to store each heating and cooling temp for each time for each type of day.

In the mean time, my usual recommendation is to use the CalDav binding and use a calendar to create your schedule.

Hmmmm. This does simplify things significantly.

OK, so if we have a way to figure out what type of day it is it is possible to load and parse some file types inside a Rule. Though often what I’ll do is create a .map file and use the transform Action to convert some Item name or other similar value (in your case they type of day and time) to a value.

It would be a bit awkward though but it could work.


(Michael Ingraham) #19

Rich,

The Nest thermostat has its own sensors, yes. And the binding exposes those. Nest also has some “integrated” remote temperature sensors. Nest has not added them to their API and it’s been a year since they announced the sensors and 10 months since they hit the shelves. I’m sure that if/when the API would be available, Wouter would add the sensors to the binding. But until Nest gets off its keister, …

CalDav - The concept is more of a recurring weekly calendar rather that a complete day by day calendar.

Time of Day Design Pattern - something to explore. Thanks.

I think specifying what the work days are plus comparing against downloaded holidays (e.g., https://www.timeanddate.com/holidays/us/) should allow a relatively straightforward now == !(Weekend || Holiday) to know which “pattern” to compare against for selecting the HVAC target temperatures.

Mike


(Rich Koshak) #20

Every calendar I’m familiar with allows the creation of repeating events.

image

There is no interface in OH to manage something like this. There is an interface in a calendar to handle something like this. I still stand by my suggestion, until such time that the Scheduler gets implemented an released.

Just about any other approach is going to be orders of magnitude more work.


(Michael Ingraham) #21

So, CalDav… Right now I’m going to use my Google Calendar because I need to tackle CalDav before I tackle OwnCloud :wink:

So, I’d implement something like your “Calculate the type of day” Rule based on my workdays/holidays. Relatively straightforward. With Google, there are holidays calendars one can subscribe to. They are read only. Could CalDav play a part with the Holidays Calendar to trigger setting the type of day?

I can create a separate “openHAB” calendar in my Google Calendar. I can add my HVAC schedule there using weekly repeating entries for each time window.

I am having a hard time understanding how to make use use of the binding(s). I can’t conceptualize the difference between these:

CalDAV Command
- Used to execute commands through an event, triggered at the start or the end of an event.

CalDAV Personal
- Used to detect presence through calendar events.
- Used to show upcoming/active events in openhab.

Mike


(Rich Koshak) #22

Most likely. I don’t know the full capabilities of the CalDAV binding, but I do know that you can trigger a Rule based on calendar events. So if you trigger the Rule with an event around midnight and the name of the entry is “Holiday” or the like then that could be used to drive the Rule.

I don’t have a whole lot of experience with the binding so I can’t say exactly how to do the above. I only know it is possible and the docs seem to support that assessment.

To drive your type of day Rule you would probably want to use the Command. I think the Personal binding is used to read your future calendar events to do stuff like put them on your sitemap and such. You don’t get an event when the scheduled time occurs, you get a list of all the scheduled events (potentially filtered).