Design Pattern: Time Of Day

Does this have anything to do with ‘Time of Day’?

You’ve ignored the Java 11 requirement, assuming you are using OH3

That’s probably the reason, yes.
I have:
zulu-11-azure-jdk/stable,now 11.50+19-1

Note the dash after “zulu”. I do have a v16 in my repository, but that’s called:

zulu-16-azure-jdk/stable 16.32+15-1

Unfortunately, i couldnt find Java 11 for arm64. The Azul page only lists versions 15 and 16.


Installed Azul 11 for arm64 from here and everythings good.

Hi Rich

This DP in rules has DSL has worked great for me for years. Now using OH3 and it seems joda time has changed


Script execution of rule with UID 'timeofday-8' failed: 'withTimeAtStartOfDay' is not a member of 'java.time.ZonedDateTime'

Do you know the update for this?

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

Thanks!

Kris,

please read through the topic before posting. This has been discussed here several times before, and solutions have been posted.

That’s one of the breaking changes.

Somewhere around the early 700’s in the posts above (I think) there is a version of the Rules DSL version of the rule posted that uses ZonedDateTime. You probably have other rules that use Joda DateTime so be sure to review DateTime Conversion (openHAB 3.x). I’m not really supporting the Rules DSL version myself any more but there are replies above that have the changes.

Since you are reworking things, you might consider using the JavaScript version of the rule. You just need to copy over the code (soon you’ll be able to install it just like an add-on :partying_face:) and set some metadata on your Items.

The advantage is that it supports setting a different set of times of day based on the type of day (e.g. have a different set for weekdays and weekends), the times can come from anywhere (e.g. I use the Android app’s Alarm Item feature to drive one of my times of day) and you don’t have to change the rule to add or remove times of day. You just need to add/remove the Items and set the Item metadata.

1 Like

Thanks Rich, ive configured your Java rule, set the schedule tag, updated the items and set the Empheris.

Lets see!

Make sure to follow all of the instructions on GitHub. You also need to create a TimeOfDay Item and TimesOfDay Group and all your Items that have the “etod” Item metadata on them need to be a member of the TimesOfDay Group.

You can tell if your Items are set up OK by manually running the rule in MainUI and watching the logs. In fact, any time you change your etod Items you’ll want to manually run the rule. Otherwise the changes won’t get picked up until a little after midnight when cron trigger’s the rule. If you set the org.openhab.model.script.Rules.TimeOfDay logger to debug you’ll get back more information.

All the members of TimesOfDay must have etod metadata, that metadata must be valid, and all the Items must have a valid DateTime(i.e. none can be NULL or UNDEF).

Thanks, I used your items from t5he first post which have the tag but the rule fails. Each item has its metadata


06:36:38.885 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID '5ef50ef5f1' failed: <eval>:5:59 Missing close quote
 * Return the value or a key value from the Item's metadata
                                                           ^ in <eval> at line number 5 at column number 59


Group:DateTime TimesOfDay
String TimeOfDay "Current time of day [%s]"

// Default day, initialization for JavaScript should be done thgrough MainUI. See https://community.openhab.org/t/oh-3-examples-how-to-boot-strap-the-state-of-an-item/108234
DateTime Default_Morning (TimesOfDay) { etod="MORNING"[type="default"] }
DateTime Default_Day (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="DAY"[type="default"] }
DateTime Default_Evening (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="EVENING"[type="default"] }
DateTime Default_Night (TimesOfDay) { etod="NIGHT"[type="default"] }
DateTime Default_Bed (TimesOfDay) { etod="BED"[type="default"] }

// Weekend day, notice that not all the states are listed, the unlisted states are skipped
DateTime Weekend_Day (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="DAY"[type="weekend"] }
DateTime Weekend_Evening (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="EVENING"[type="weekend"] }

// Custom dayset
DateTime Trash_Morning (TimesOfDay) { etod="MORNING"[type="dayset", set="trash"] }
DateTime Trash_Trashtime (TimesOfDay) { etod="TRASH"[type="dayset", set="trash"]}
DateTime Trash_Day (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="DAY"[type="dayset", set="trash"] }
DateTime Trash_Evening (TimesOfDay) { channel="astro:sun:ihp:set#start", etod="EVENING"[type="dayset", set="trash"] }
DateTime Trash_Night (TimesOfDay) { etod="NIGHT"[type="dayset", set="trash"] }
DateTime Trash_Bed (TimesOfDay) { etod="BED"[type="dayset", set="trash"] }

You’ll notice that not all of those Items are linked to Astro or any Channel really. You’ll need to set those Items some other way (Karaf console, postUpdate from a rule, OH 3 Examples: How to boot strap the state of an Item, etc).

Also double check the Channel IDs match your Astro Thing’s ID.

The Items there are just an example. I can’t know your setup so I can’t make an example you can just copy and paste and have it work.

I can’t imagine what that error is but need to deal with the obvious. I trust you did not install the GraalVM JavaScript addon. If you did, uninstall it and restart OH. That add-on is not compatible with this code.

No i didnt install GraalVM. Yes some times are null, which is a no no. Ill need to work out how i was populating them previously.

Ill try and do this metadata/input stuff as per your post

Channel IDs match and Ive got values now. I removed alot of the items I didnt need to keep it simple, so these are the only ones ive got.

But the error persists :frowning:


07:04:30.364 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'TimeofDay' failed: <eval>:5:59 Missing close quote
 * Return the value or a key value from the Item's metadata
                                                           ^ in <eval> at line number 5 at column number 59

Some older posts indicate I need some java libraries? I cant see any reference to that in this first post hm…

What doesn’t make sense is the line it’s complaining about is a comment. It’s not even executable code.

Even though it’s exactly the same code I’m running on my system I copied it over from Github again and got the same error. Somehow either OH became more strict about white space and new lines or somewhere along the way the top half of the file got messed up.

It should be fixed now. Copy the new version I just checked in over what you have now and it should work.

I’m going to explore ways to make it so you don’t have to copy and paste in the future if the marketplace takes too long to support rule templates.

It is mentioned in the main GitHub readme but not the ephem_tod readme. I need to fix that. You need to download the timerMgr and timeUtils libraries from that same repo.

But that is unrelated to your original error.

Never mind, it’s there:

Requirements

  • Ephemeris configured (see Actions | openHAB)
  • item_init, optional, used for statically defined times of day (see examples below)
  • timer_mgr to manage the Timers
  • time_utils to process DateTimeTypes and it’s needed by timer_mgr
  • rules_utils to dynamically recreate the rule on command when the Item metadata is changed; only required for Jython.

I need to update that though because the JavaScript version does not depend on item_init since there isn’t a JavaScript implementation of item_init yet.

Thanks

Is there some information on HOW to install these libraries? I can see the files on your github but it doesnt say how (at least not that I can see)

It’s on the main README:

JavaScript

For rules, open the YAML file and copy the contents to the code tab of a new rule in MainUI in openHAB 3. The README for those capabilities that require this will indicate when this is necessary.

For library capabilities copy the automation/lib/javascript folder for a given capability to $OH_CONF.

Emphasis added.

I think its working now. That was heavy duty!

07:44:27.948 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - The current time of day is MORNING
07:44:36.456 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - Today is a default day.
07:44:36.461 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - Moved Default_Morning to today.
07:44:36.463 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - Moved Default_Night to today.
07:44:36.465 [INFO ] [.openhab.model.script.Rules.TimeOfDay] - Moved Default_Bed to today.

Yes, but now you have have a lot more flexibility. You can even put a widget on your MainUI and change the times from the UI without ever needing to look at or understand any code.

You also have a pretty useful library to manage timers now. TimerMgr is super powerful and I end up using it in almost all of my rules. And by using it I don’t have to mess with ZonedDateTimes except rarely.

For example, if I have a rule triggered be a member of trigger and I need to keep a separate timer for each Item and I want to do one thing when the timer goes off and something else if the rule triggers when a timer already exists it would take a few dozen lines of code. With TimerMgr

this.OPENHAB_CONF = (this.OPENHAB_CONF === undefined) ? java.lang.System.getenv("OPENHAB_CONF") : this.OPENHAB_CONF; 
load(OPENHAB_CONF+'/automation/lib/javascript/community/timerMgr.js'); 

this.tm = (this.tm === undefined) ? new TimerMgr() : this.tm;

var timerExpired = function(){
  // what to do when the timer expires
}

var timerExists = function() {
  // what to do when the timer already exists
}

this.tm.check(event.itemName, "5m", timerExpired, false, timerExists);

Gatekeeper is another useful one.

var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Irrigation");
var OPENHAB_CONF = java.lang.System.getenv("OPENHAB_CONF");
load(OPENHAB_CONF + "/automation/lib/javascript/community/gatekeeper.js");

this.gk = (this.gk === undefined) ? new Gatekeeper() : this.gk;

if(event.itemCommand = ON) {
  logger.info("Starting Irrigation");
  this.gk.addCommand("5m", function(){ events.sendCommand("Valve1", "ON"); });
  this.gk.addCommand("7m", function(){ events.sendCommand("Valve2", "ON"); });
  this.gk.addCommand("3m", function(){ events.sendCommand("Valve3", "ON"); });
  this.gk.addCommand("5m", function(){ events.sendCommand("Valve4", "ON"); });
  this.gk.addCommand(10, function(){ logger.info("Irrigation complete");});
}
else {
  this.gk.cancelAll();
  events.sendCommand("gValves", "OFF");
}

Trigger the rule with received command. If there is an ON command it will schedule four valves to run for different amounts of time. Send the OFF command and everything is cancelled. That’s roughly 1/3 the number of lines for the Rules DSL version of cascading timers and it’s all in one rule too.

That will set a timer for five minutes for that Item. If a timer already exists the timerExists function will be called and the timer will exit (if you want to reschedule pass true as the fourth argument instead of false). After five minutes, if the function wasn’t called again it will run the timerExpired function.

I guess the point I’m trying to make is that learning to use these libraries like this can greatly simplify your rules in the long run. So even though this was a heavy lift as your first time, it should pay off well in the long run.

Lots of reading to do rich for me! its a huge change, very complex but I see your point. Something to do in COVID19 lock down :slight_smile:

Thank you for your continued help. You’re a valuable resource

Rich, with these items like Default_Morning, after setting the Default Standalone Widget card for its time, is that meant to carry across reboots because what I’ve seen is they all go back to NULL and then the Time of Day scheduled rule fails

Cheers