Time of Day Events - An easy approach

A very frequent problem when writing rules is how to determine if it is currently DAY Time of NIGHT Time in order your rules to take different paths .

Many solutions have already been provided in the community forum, some more easy than others.

A very simple approach would be just to follow the daily events using the Astro binding. This is based on the fact the Sun Rise will ALWAYS follow Sun Set and vice versa.
The same logic applies for any event during the day. eg Night time will always come after Afternoon time.
The two extremely simple rules can be used to change the state of an item accordingly, which in turn can be used in other rules depending if the state is ON or OFF.
/======================================================/
rule “Night time ON at sun set”
when
Channel “astro:sun:home:set#event” triggered START
then
Night_Time.sendCommand(ON)
end
/======================================================/
rule “Night time OFF at sun rise”
when
Channel “astro:sun:home:rise#event” triggered START
then
Night_Time.sendCommand(OFF)
end
/======================================================/

The above will work perfectly as long as there is no openHAB server down time for a significant amount of time. If the server is down long enough for one of the events to be passed during the down time period then the state of the Night_Time item will be wrong until the execution of the next event. (assuming suitable persistence is used at start up).

A better and yet very easy to determine the time of the day is to calculate it. This rule can be used at start up or at any other time. The rule below is based on the fact that " If the current time is after Sunset OR before Sunrise it will always be night time (respectively if the current time is before or after midnight)"

/======================================================/
rule “Calculate time of day state”
when
System started // run at system start in case the state changed when OH was offline
then
val Number epochNow = now.millis
val Number epochSunrise = (astro_sun_home_rise_start.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
val Number epochSunset = (astro_sun_home_set_start.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

if ((epochNow > epochSunset) || (epochNow < epochSunrise)) {
Night_Time.sendCommand(ON) // If the current time is after Sunset OR before Sunrise it will always be night time (before or after midnight)
}
else
Night_Time.sendCommand(OFF)
end
/======================================================/

Thanks for your contribution to the community. :+1:

It would help to read if you placed your rules inside code fences. :wink: It’s the paper icon to the left of gear icon when posting.

Example:

rule "Night time ON at sun set"
when
Channel 'astro:sun:home:set#event' triggered START
then
Night_Time.sendCommand(ON)
end
rule "Night time OFF at sun rise"
when
Channel 'astro:sun:home:rise#event' triggered START
then
Night_Time.sendCommand(OFF)
end
rule "Calculate time of day state"
when
System started // run at system start in case the state changed when OH was offline
then
val Number epochNow = now.millis
val Number epochSunrise = (astro_sun_home_rise_start.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
val Number epochSunset = (astro_sun_home_set_start.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

if ((epochNow > epochSunset) || (epochNow < epochSunrise)) {
Night_Time.sendCommand(ON) // If the current time is after Sunset OR before Sunrise it will always be night time (before or after midnight)
}
else
Night_Time.sendCommand(OFF)
end

@H102. Thank you for the advise. Didn’t know that. Will follow in the future.
Meantime thank you for making my example rules much more readable.

Not a problem.

I also just edited my post to remove all funny quotes in the event someone tries to copy and paste they won’t have a bunch of syntax errors. :wink:

How do you modify the script to turn light back ON if somebody turns the light OFF after the sunset trigger and before sunrise?

@ancheta61. Hi my rules are were mend to provide to the system a way to know if it is currently day time or night time. Then how this information is further used in other rules to turn lights ON and OFF or take other actions is up to the individual user.

Having said the above, there are several ways to tackle your question.
The simplest way would be to have a simple rule with a CRON trigger that runs at specified intervals (let’s say every minute, to turn the light ON, after checking if it is night time. For example,

 rule "check every minute"
 when
     Time cron    "0 0/1 * 1/1 * ? *"  // every 1 minute
 then
     if( Night_Time.state == ON ) {
         myLightItem.sendCommand (ON)       
     } else {
         myLightItem.sendCommand (OFF)
     }  
 end

Another way would be to set up a timer that when a light is turned OFF, would turn it back ON after a specified time interval, after checking if it is day time or night time. For example


var Timer myTimer = null
 rule "check with timer"
 when
     myLightItem changed to OFF
 then
     if (Night_Time.state == ON ) {
            myTimer?.cancel
            myTimer = createTimer(now.plusMinutes(30), [ |  // You can have any number of Seconds, Minutes or Hours
                myLightItem.sendCommand (ON)
            ])
        }
 end

Finally please don’t forget that you can use my third rule ‘Calculate time of day state’ at any moment, in order to find out if it is day time or night time. You can just Copy Paste the rule.

After re-checking my rules i found that I made a small mistake in my rule ‘check with timer’ above after the when line. Please find the corrected rule below.

var Timer myTimer = null  

 rule "check with timer"
 when
    Item myLightItem changed to OFF 
 then
     if (Night_Time.state == ON ) {
            myTimer?.cancel
            myTimer = createTimer(now.plusMinutes(30), [ |  // You can have any number of Seconds, Minutes or Hours
                myLightItem.sendCommand (ON)
            ])
        }
 end

Please also note that it is better to have the
var Timer myTimer = null
line, at the top of your rules file before any rule in order to avoid parsing errors.

@gustav. So the Night_Time in Night_Time.sendCommand(ON) is not an item. Also can I put all the rules in one file. By the way thanks for helping out a newbie.

The Night_Time IS an item of type Switch that must be created separately in a *. items file. For example,
Switch Night_Time “Night time state”

Yes. You can put all the rules in one file.
No problem. Glad to help if I can.

I think this bit is very helpful and crucial information. By creating switch items for nighttime (or even ‘away’, ‘sleep’, ‘holiday’ etc) you can then use the state of these switches in other rules/automations. Advantage is that you have the actual logic for determining whether it is day or night in one single location. At first I would copy this in each separate rule which made changes cumbersome and prone to errors.

As said in my very first post in this thread.

1 Like

Got it all working now. Thanks for all your contribution. Some us just really need simple operations and your rules are pretty much all i need for this part of my project. Thanks again.

Glad to be of assistance :+1: