[Deprecated] Design Pattern: Time Of Day

Hello Rich,

Having switched to openhab3, I noticed that the method for calculating time used in the Design Pattern is not supported anymore. Specifically, these lines:

val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
vMorning_Time.postUpdate(morning_start.toString)

The solution seems to be to use the Java Class ZonedDateTime, however, I am unable to figure out how that needs to be formatted exactly to be read by the openhab-items.

Does anyone have a hint on how to calculate the times for the “Time of Day” Design Pattern?

Thanks!

If you are on OH 3 I would recommend switching to the MainUI JavaScript implementation (link and description now in the top post). I don’t use Rules DSL any more and have not yet decided whether I’m going to go through all the DPs and update the Rules DSL versions for all of them. And the JavaScript and Python version are so much easier for you to use as is without code changes.

But the ZonedDateTime equivalent to that line of code would be

val morning_start = now.withHour(6)

That should handle the change in daylight savings without needing to jump forward than subtract back.

Rich,

thank you very much, I will have a look at the MainUI Javascript version (just as I was getting proficient in DSL rules…).

If I see this correctly, this is all driven by the different TimesOfDay items (Morning, Day, etc.), right? So I just need to figure out a way to populate those. Currently, I don’t think I have grasped the concept far enough to tell where that is done. Where or how do I define when Bedtime for a weekday is? Or for a weekend?

I’m not sure if that “How to boot strap the state of an Item” is what I need here.

I figured the ZoneDateTime variables out last night, but got stuck on importing the astro time in a correct format, kept getting all sorts of “cannot compare date” errors. So I’m definitively going to give the JavaScript a try.

Thanks!

You don’t have to abandon the Rules DSL code. The advantage of the the JavaScript and Jython versions is that you never have to even look at the code. You just import them to your OH and configure your Items. So you can import those that are useful to you and use them and write your own stuff in Rules DSL if that suits you.

You define a DateTime Item for the start time of each time of day. If you want a different set of times for different types of day (as defined in Ephemeris: https://www.openhab.org/docs/configuration/actions.html#configuration) you define a set of DateTime Items for each type of day. The example in the top post shows a set of DateTime Items for deafult, weekend, a custom day set called trash, holiday, and a custom holiday defined in the /openhab/conf/services/custom1.xml. See the Ephemeris docs (link above) for how to configure Ephemeris and define a custom dayset or custom holidays.

Each Item is a member of the TimesOfDay.

Each Item has an etod metadata. The etod metadata defines the name of the time of day that starts at that time, and what type of day type it applies to. If using a custom dayset or custom holiday there are additional parameters.

Everything is defined at the Item. The start time is the state of the Item. The rest is metadata defined on the Item.

You would need to bootstrap the state of the Item if it doesn’t have a state and doesn’t get a state from somewhere else (e.g. the Astro binding). Somehow the Item needs to get a valid date time value.

To get a ZonedDateTime from a DateTimeType just call zonedDateTime. For example MyDateTime.state.zonedDateTime. You might need to cast it to DateTimeType first. (MyDateTime.state as DateTimeType).zonedDateTime.

But you don’t have to mess with any of this with the JavaScript or Jython version. It’s already implemented for you.

Everything is defined at the Item. The start time is the state of the Item. The rest is metadata defined on the Item.

Yes, that’s how I understood it. So for those times that do not get updated automatically (like Astro) I still need a rule of some sort that updates the state of the (fixed) items, preferably once at the start of the day. I suppose that has to run daily to update the states with the correct date/time. But I think I can figure that out with ZonedDateTime, as I already did with the original rule.

I can see that the use of Ephemeris expands the usefulness of this to different types of days (weekends, holidays, even trash days).

Thanks!

Only the time has to be right. The JavaScript and Python rule will automatically move the date time to today for you.

If you are running OH 3, see OH 3 Examples: How to boot strap the state of an Item. You can define a card that lets you enter the DateTime from the UI. Then you can change it later without messing with Rules.

Of course you can do it with a rule too, but that’s not the only nor even the best way.

Even better. That way it could even be static. But yes, defining a card (or sitemap section) to set these times from the UI has a neat touch to it, too.

I’m running OH3 Milestone 4, btw.

Ultimately, I decided against using the JavaScript. It really seemed to be a lot of hassle to get it working, not all of it applicable to everybody:

  • no real proficiency with JavaScript
  • Necessity to install and test script plus three helper routines
  • Necessity to dive into the use of metadata for items and go away from file-based items/modify them for metadata
  • Find a way to populate/initialize the items (bootstrapping with metadata again)

TBH, that seemed to be a lot of issues just to get the TimeOfDay. I do realize that the new method gives much more possibilities (weekends/holidays and such), though.
And as I was able to McGyver the DSL script with ZonedDateTime and get the Astro items in the right format (not pretty, but works), I guess I’ll stick with the old script for now.
But thanks for the explanation.

The whole point of a library like this is you don’t need to know JavaScript. You should never have to even look at the code.

There is no test script required. The readme should be clear on that. The helper libraries are required though.

??? You don’t have move away from file based .items files at all. You can define metadata using .items files. It goes in between the { }, just like the metadata required for Google Assistant and Alexa goes.

If it works for you that’s great. But I’m eventually going to be unable/unwilling to support Rules DSL at some point in the not too distant future. At that time I’ll probably be removing them Rules DSL examples from all of my Design Patterns.

I might think about it.
For me, a rather simple DSL rule plus a few items is a lot simpler and easier to understand what it does. Maybe that’s just me :wink:

I understand that the DSL rules might not be supported anymore in the future since you’re focused on a different approach.

2 Likes

Hi Rich,

Ok, so I gave it another shot and seem to come back to my conclusion that while I do understand some JavaScript, obviously not enough to troubleshoot OH3. Or maybe it’s a bug in M4 I can’t do anything about.

I tried to get your time_utils as one of the required libraries to run.
While I understand what the JS testscript is trying to do, it fails halfway:

18:51:01.753 [INFO ] [org.openhab.model.script.Rules.Tests ] - parsing the duration
18:51:02.175 [INFO ] [org.openhab.model.script.Rules.Tests ] - PT26H10S
18:51:02.325 [INFO ] [org.openhab.model.script.Rules.Tests ] - 2020-12-03T20:51:12.206312-06:00[America/Chicago]
18:51:02.413 [INFO ] [org.openhab.model.script.Rules.Tests ] - PT243H0.2S
18:51:02.449 [INFO ] [org.openhab.model.script.Rules.Tests ] - It's ISO8601!
18:51:02.462 [INFO ] [org.openhab.model.script.Rules.Tests ] - It's not ISO8601!
18:51:02.477 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timetest' failed: ReferenceError: "ZonedDateTime" is not defined in <eval> at line number 21

So it gets to the point of “dt = ZonedDateTime.now()” where the current date/time is written into the variable dt, but I really don’t get why it thinks that ZonedDateTime.now() would need to be defined.

commenting out those two lines:
//dt = ZonedDateTime.now()
//logger.info("Already ZDT: " + toDateTime(dt));

lets the script complete.

I usually don’t give up easy, but I feel that as this is probably just the first hiccup getting this to run, I really cannot expect your time to help me limp along :wink:

(And out of curiosity, isn’t that line 21 missing its semicolon at the end?)

Well, again, why mess with the test scripts in the first place? Those are for testing and indeed this is something I need to look into (are you on the latest milestone? it makes a difference as the way you trigger a rule on earlier versions of OH 3 can cause certain things to not be available). But it’s not something you need to worry about. The Time of Day rule doesn’t use that part of the library anyway. It only uses the toToday function. The TimerMgr class uses the toDateTime function.

The tests may be failing but they are irrelevant to getting the rule running. And I know the library code and the rule work because I’m using the timeUtils.js library in about half a dozen of my currently running rules, the timerMgr class in four rules, and of course I’m using the Time of Day rule itself.

All you need to do is (assuming you’ve cloned the repo successfully and created the Items):

  1. (from the time_utils folder) cp automation/* /etc/openhab2/automation
  2. from the timer_mgr folder) cp automation/* /etc/openhab2/automation
  3. Create a rule and paste the contents of the YAML file into the code tab of the new rule

You may be running into a hickup, but it’s not a hickup that is related to anything that you should be messing with in the first place.

Thanks.
Being the cautious type, I learned that if part of a system doesn’t run, chances are good that the whole thing itself doesn’t run, either. So, understandably, I was worried when the test didn’t complete…
It was the latest Milestone (M4), btw.
(so $OPENHAB_CONF points to /etc/openhab with out a “2”)

Hmm, seems to work partly. It switched to the fixed-time items, but failed on the dynamic ones from the astro binding. Also, the logs show:

10:20:46.301 [ERROR] [re.automation.internal.RuleEngineImpl] - Failed to execute rule 'timesofdayjs': Fail to execute action: 3

Failed how?

If you know how, put the TimeOfDay logger into DEBUG mode. If not, you can do a find and replace all instances of “logger.debug” with “logger.info” in the rule itself.

And just to make sure, this is OH 3 M4 or later, right? There were some issues with earlier OH 3 versions and the JS rule won’t work in OH 2.5 at all.

I downgraded to M3 because some other isse (which didn’t work with M3, either, so I’m currently on the latest snapshot, which seems to run quite stable).

With “failed”, I mean that the astro-based items are populated, show the correct time, but the script does not change the TimeOfDay item when they happen. When I manually run the script, it does, but not upon the astro trigger. This is what I have, for example:

DateTime Default_Evening "Default Evening [%s]"<time> (TimesOfDay) { channel="astro:sun:local:set#end", etod="EVENING"[type="default"] }
That is initialized correctly to 16:58h.
Openhab correctly triggered the sunset:
Log:
16:58:00.004 [INFO ] [smarthome.event.ChannelTriggeredEvent] - astro:sun:local:set#event triggered END

But no log entry from the JavaScript. I will set that into debug and see if I can find anything.

Running the script manually gives me:
17:06:20.794 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - Today is a default day.
17:06:21.814 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - The current time of day is EVENING
17:06:21.819 [INFO ] [smarthome.event.ItemCommandEvent ] - Item 'TimeOfDay' received command EVENING
17:06:21.821 [INFO ] [smarthome.event.ItemStateChangedEvent] - Item 'TimeOfDay' changed from DAY to EVENING

Edit: Just confirmed that fixed items work and update TimeOfDay correctly.

Very interesting. Can you look in events.log and see if those Items are updating (it usually occurs around 30 seconds after midnight). Do you see any evidence of the rule running more than once at around that time or at all? Or does the rule not run until one minute after midnight?

The way the rule works is it triggers when ever one of the members of TimesOfDay changes (which should occur when Astro updates the Items), then at one minute after midnight (to handle those users who do not use Astro for any of their Items). Finally it runs at openHAB startup. And you can manually run it if you want by pressing the play button on the rule’s page in MainUI. Though this latter method might not work on M3. It’ll complain about some openHAB Actions not existing.

In my system this is what is looks like in events.log

2020-12-04 00:00:30.356 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Holiday_Day' changed from 2020-12-03T07:03:00.000-0700 to 2020-12-04T07:04:00.000-0700
2020-12-04 00:00:30.991 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Day' changed from 2020-12-03T07:03:00.000-0700 to 2020-12-04T07:04:00.000-0700
2020-12-04 00:00:31.022 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Weekend_Day' changed from 2020-12-03T07:03:00.000-0700 to 2020-12-04T07:04:00.000-0700
2020-12-04 00:00:31.101 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Evening' changed from 2020-12-03T16:05:00.000-0700 to 2020-12-04T16:05:00.000-0700
2020-12-04 00:00:31.112 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Holiday_Evening' changed from 2020-12-03T16:05:00.000-0700 to 2020-12-04T16:05:00.000-0700
2020-12-04 00:00:31.114 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Weekend_Evening' changed from 2020-12-03T16:05:00.000-0700 to 2020-12-04T16:05:00.000-0700
2020-12-04 00:00:31.125 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Weekend_Afternoon' changed from 2020-12-03T15:41:00.000-0700 to 2020-12-04T15:41:00.000-0700
2020-12-04 00:00:31.125 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Holiday_Afternoon' changed from 2020-12-03T15:41:00.000-0700 to 2020-12-04T15:41:00.000-0700
2020-12-04 00:00:31.129 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Afternoon' changed from 2020-12-03T15:41:00.000-0700 to 2020-12-04T15:41:00.000-0700
2020-12-04 00:00:31.190 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Bed' changed from 2020-12-03T23:46:00.000-0700 to 2020-12-04T23:46:00.000-0700
2020-12-04 00:00:31.261 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Night' changed from 2020-12-03T23:00:00.000-0700 to 2020-12-04T23:00:00.000-0700
2020-12-04 00:00:46.220 [INFO ] [marthome.event.ChannelTriggeredEvent] - astro:sun:local:morningNight#event triggered START

and this is what it looks like in openhab.log

2020-12-04 00:00:30.835 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Today is a default day.
2020-12-04 00:00:30.932 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Bed to today.
2020-12-04 00:00:30.977 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Night to today.
2020-12-04 00:00:30.979 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Afternoon to today.
2020-12-04 00:00:30.980 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Evening to today.
2020-12-04 00:00:31.989 [INFO ] [openhab.model.script.Rules.TimeOfDay] - The current time of day is EVENING
2020-12-04 00:01:00.810 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Today is a default day.
2020-12-04 00:01:01.829 [INFO ] [openhab.model.script.Rules.TimeOfDay] - The current time of day is EVENING

You can see Astro start updating the Items at 30 seconds after midnight. And 30 seconds after midnight you can see the rule trigger in response to one of those changes and see it moving the static Items to today and then finally figuring out what the current time of day is. Then you can see the rule trigger again at one minute after midnight where all it does is recalculate the current time of day as all the other Items are already forwarded.

Your Item definition looks right. The Item is a member of the TimesOfDay Group and the metadata looks correct. When you run it manually I don’t see it trying to adjust the Astro times of day so they must have a date of today. So the question is whether the Group membership is wrong or the Astro binding is not doing something.

Note that this rule does not depend on the Astro events. It sets it’s own timers to trigger when the time in the DateTime Item occurs. So the fact that the Channel event triggers isn’t informative in this case. We need to see if the Item is changing 30 seconds after midnight to reflect the new time for today.

Hmm, it looks like it’s doing exactly what it should. The TimeOfDay script as well as the Astro binding. This is the events.log:

2020-12-04 00:00:30.193 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Sunrise_Time' changed from 2020-12-03T06:48:00.000-0600 to 2020-12-04T06:49:00.000-0600
2020-12-04 00:00:30.194 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Day' changed from 2020-12-03T06:48:00.000-0600 to 2020-12-04T06:49:00.000-0600
2020-12-04 00:00:30.194 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Sunset_Time' changed from 2020-12-03T16:58:00.000-0600 to 2020-12-04T16:58:00.000-0600
2020-12-04 00:00:30.194 [INFO ] [marthome.event.ChannelTriggeredEvent] - astro:sun:local:morningNight#event triggered START
2020-12-04 00:00:30.202 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Evening' changed from 2020-12-03T16:58:00.000-0600 to 2020-12-04T16:58:00.000-0600
2020-12-04 00:00:30.220 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Bed' changed from 2020-12-03T22:00:00.000-0600 to 2020-12-04T22:00:00.000-0600
2020-12-04 00:00:30.221 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Morning' changed from 2020-12-03T05:15:00.000-0600 to 2020-12-04T05:15:00.000-0600
2020-12-04 00:00:30.221 [INFO ] [marthome.event.ItemStateChangedEvent] - Item 'Default_Night' changed from 2020-12-03T21:00:00.000-0600 to 2020-12-04T21:00:00.000-0600

And this the openhab.log:

2020-12-04 00:00:30.212 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Today is a default day.
2020-12-04 00:00:30.215 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Bed to today.
2020-12-04 00:00:30.217 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Morning to today.
2020-12-04 00:00:30.220 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Moved Default_Night to today.
2020-12-04 00:00:31.228 [INFO ] [openhab.model.script.Rules.TimeOfDay] - The current time of day is NIGHT
2020-12-04 00:01:00.326 [INFO ] [openhab.model.script.Rules.TimeOfDay] - Today is a default day.
2020-12-04 00:01:01.345 [INFO ] [openhab.model.script.Rules.TimeOfDay] - The current time of day is NIGHT

Looks identical to me. And yes, the items are part of the TimesOfDay group.

Still no change. For testing I added triggers to run the script at the astro times, but strangely at sunset it transitioned from “DAY” straight to “BED”, missing out “EVENING” and “NIGHT” entirely.
When I ran it manually some time after that, it transitioned correctly to “EVENING”.

ok, I’m going to need debug logs so I can see which toners it’s creating for those items.

You can configure the logger used by the rule.rule, put everything into debug level logging, or do a find and replace on the rule relaxing replacing the logger.info with logger.debug.

I’ve tried a few things and so far can’t reproduce the problem on my setup.