@rlkoshak I’m a little bit confused now with this rule, can you please help me?
Somehow, today it seemed that this rule stopped working. I have restarted OH, now it is working again (or it seems), but now it says that the current time of day is afternoon… However I can’t see an afternoon tag in your example (and I never had before), but when I looked into the rule, there is a case for afternoon… How does this works? Why I get AFTERNOON now if I except to be EVENING?
For each time period you define a state. In the Rule above we have
State
Start
End
MORNING
06:00
Sunrise
DAY
Sunrise
Sunset - 90 minutes
AFTERNOON
Sunset - 90 minutes
Sunset
EVENING
Sunset
11:00
NIGHT
11:00
06:00
The Rule first gets the start time for each of these time periods:
val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
vMorning_Time.postUpdate(morning_start.toString)
val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
vNight_Time.postUpdate(night_start.toString)
val bed_start = now.withTimeAtStartOfDay
vBed_Time.postUpdate(bed_start.toString)
// Convert the Astro Items to Joda DateTime
val day_start = new DateTime(vSunrise_Time.state.toString)
val evening_start = new DateTime(vSunset_Time.state.toString)
val afternoon_start = new DateTime(vEvening_Time.state.toString)
Notice that last line, that is where we get the start of AFTERNOON.
Then we determine between which start and end time now is.
var curr = "UNKNOWN"
switch now {
case now.isAfter(morning_start) && now.isBefore(day_start): curr = "MORNING"
case now.isAfter(day_start) && now.isBefore(afternoon_start): curr = "DAY"
case now.isAfter(afternoon_start) && now.isBefore(evening_start): curr = "AFTERNOON"
case now.isAfter(evening_start) && now.isBefore(night_start): curr = "EVENING"
case now.isAfter(night_start): curr = "NIGHT"
case now.isAfter(bed_start) && now.isBefore(morning_start): curr = "BED"
}
Finally we send the new state to vTimeOfDay.
Create a table like the above for all of YOUR time periods. For each of your time periods create a DateTime for the start of each as I did above. Then test to see which time period now is to determine the time of day.
I am trying to add time of day to my environment but somehow I’ve got lost with this long thread and I am not sure what is the latest and greatest version of the rule.
Will appreciate if you can post here the most updated version (OH 2.3 & up).
The original post is edited frequently to reflect any updates. The original post is the latest and greatest.
Probably not. You will also get a runtime error.
Try just calling getDayOfWeek which should resolve the ambiguity.
I’m still using a switch statement in the most recent top posting. The very original version of the DP used if statements so some of the older posts may still use if statements, but it has used switch for quite some time.
I don’t actually use the trinary operator in the top posting, but indeed, if there are only two options I will use the trinary operation either inline or to set a variable instead of if/else or switch statements.
In the rule, the items are not protected for null value:
val day_start = new DateTime(vSunrise_Time.state.toString)
val evening_start = new DateTime(vSunset_Time.state.toString)
val afternoon_start = new DateTime(vEvening_Time.state.toString)
In my system, after restart, the sunset item not yet set and I get error (of course later when it is set, it is working). Do u also get error after system starts?
If the Rule starts running before the Astro binding has loaded and calculated the new Times then this will happen. I’ve never experienced this happening in my Rules but I know it does happen.
One way you could deal with it is to:
remove the System started trigger
add a trigger on changes to those three Items
check up front to see if any of the three Items are NULL and exit the Rule if they are.
Hi Rich ive added your rule and the astro binding and im getting the sunrise/sunset times but I’m not getting values for the calculated items, like Time of Day.
rule "Calculate time of day state"
when
System started or // run at system start in case the time changed when OH was offline
Channel 'astro:sun:home:rise#event' triggered START or
Channel 'astro:sun:home:set#event' triggered START or
Channel 'astro:sun:minus90:set#event' triggered START or
Time cron "0 1 0 * * ? *" or // one minute after midnight so give Astro time to calculate the new day's times
Time cron "0 0 6 * * ? *" or
Time cron "0 0 23 * * ? *"
then
logInfo(logName, "Calculating time of day...")
// Calculate the times for the static tods and populate the associated Items
// Update when changing static times
// Jump to tomorrow and subtract to avoid problems at the change over to/from DST
val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
vMorning_Time.postUpdate(morning_start.toString)
val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
vNight_Time.postUpdate(night_start.toString)
val bed_start = now.withTimeAtStartOfDay
vBed_Time.postUpdate(bed_start.toString)
// Convert the Astro Items to Joda DateTime
val day_start = new DateTime(vSunrise_Time.state.toString)
val evening_start = new DateTime(vSunset_Time.state.toString)
val afternoon_start = new DateTime(vEvening_Time.state.toString)
// Calculate the current time of day
var curr = "UNKNOWN"
switch now {
case now.isAfter(morning_start) && now.isBefore(day_start): curr = "MORNING"
case now.isAfter(day_start) && now.isBefore(afternoon_start): curr = "DAY"
case now.isAfter(afternoon_start) && now.isBefore(evening_start): curr = "AFTERNOON"
case now.isAfter(evening_start) && now.isBefore(night_start): curr = "EVENING"
case now.isAfter(night_start): curr = "NIGHT"
case now.isAfter(bed_start) && now.isBefore(morning_start): curr = "BED"
}
// Publish the current state
logInfo(logName, "Calculated time of day is " + curr)
vTimeOfDay.sendCommand(curr)
end
Note there are two Things, one names astro:sun:home and astro:sun:minus90. By default I think OH creates a Thing names astro:sun:local so you need to create these two Things.
What version of OH are you running? If you are not seeing at least “Calculating time of day…” in the log then the Rule isn’t triggering which means the System started trigger is not working.
It might work when one of the times in the tirggers occurs, but the fact that it isn’t triggering on System started is a problem and not one I’ll be able to help with. I think I saw a posting that yesterday’s build broke System started triggers but I might be mistaken.
Do you have any other System started rules? Do you have any Thread::sleeps in any of them? These used to cause problems.
But ultimately vTimeOfDay isn’t getting set because the Rule is never running.
10:00:47.262 [ERROR] [untime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'Calculate time of day state': Invalid format: "NULL"
Rich, you need to update your OP because its missing the THING definition, your post assumes manual creation of things but provides no examples of how to create them.
Here is the THING definition you require to make this work:
You also should update it to say you MUST create a things file, because auto discovery using the Binding does not work.
10:40:49.430 [INFO ] [del.core.internal.ModelRepositoryImpl] - Refreshing model 'timeofday.things'
10:40:57.032 [INFO ] [se.smarthome.model.script.Time Of Day] - Calculating time of day...
10:40:57.042 [INFO ] [se.smarthome.model.script.Time of Day] - Calculated time of day is DAY
10:40:57.045 [INFO ] [smarthome.event.ItemCommandEvent ] - Item 'vTimeOfDay' received command DAY
10:40:57.047 [INFO ] [smarthome.event.ItemStateChangedEvent] - vTimeOfDay changed from NULL to DAY
a DP is not a comprehensive example. They are a template that one can follow to solve a given class of problems one may encounter while developing Rules.
The example code that is included with the DPs may not be fully explained. The purpose of the example code is to illustrate the DP only. But since the DPs are only templates and not complete in and of themselves, the example code will necessarily include additional code.
Fully documenting the Astro binding, how to create Astro Things, how to link Channels to Items, etc is documented elsewhere and out of scope for a DP. I can’t fully document every single teeny tiny detail or else I’d be reproducing half the official docs on every post and reach past would be dozens of pages long.
Consequently, and as it also says in that link
Because a DP is not a complete solution, the reader needs to possess a few skills in order to apply them to their situation:
the basics of how to define Items and use them in Rules code
Rule syntax
the ability to follow a block of Rules code and understand at a basic level what the code does
the ability to recognize and deal with code in a block that is not fully explained or defined in the DP text (e.g. reference to Items not defined in the current DP)
the ability to generalize an example to multiple situations
I suppose in the case I can add how to create and use Things for the relevant bindings.
You don’t have to create a .things file. You can create Astro Things manually through PaperUI.