Design Pattern: Simple State Machine (e.g. Time Of Day)

:see_no_evil: :see_no_evil: :see_no_evil: oh sorry you’re right
 I use TimeOfDay that way already
 but also show them in sitemap. so I need them anyway

my old db was older than 5 years and I changed a lot of Item names and changed their persistence quite often :wink: it wasn’t inconsistent but with many unused fields full of old crap
 So it was the easiest way to get rid of that old stuff


Thanks again @rlkoshak, makes sense now and confirmed with the neccessary additional items.

Cheers
James

I need help with the new OpenHAB3 JavaScript time of Day rule. So far I’ve done the Time of Day rule with the java script. It setup the 3 instances to run the script. I did not know how to set a schedule tag. I also setup the TimeOfDay String and the TimesOfDay Group. Do I have to copy all the DateTime items into the items folder like I would in OpenHAB2. Any help would be appreciated. Thanks!!!

You need one DateTime item for each transition that you want, not all of them.
Those have to be member of the group and have the ephemeris metatags set.

To initialize them for the first time I’d recommend using “openhab:send” from the console. Just the time is sufficient.

Not sure what you mean by “3 instances/schedule tag”, though.

In addition to Michael’s excellent advice, did you also install the time_utils and time_mgr libraries? Those are required as well.

Setting it up should be something like the following:

  1. copy the timeUtils.js and timerMgr.js files from my repo and place them in $OH_CONF/automation/lib/javascript/community.
  2. copy the YAML from the repo and paste it into a new rule in MainUI
  3. create the TimesOfDay Group and TimeOfDay String Item
  4. Create a set of DateTime Items for a given type of day. You need a set for default at a minimum but can add a set for weekend and holiday as well. These Items need to have metadata set (see the readme for the rule or the original post for details) to identify the Item as a Time of Day Item and which type of day it’s for and other config info as necessary.
  5. Populate these Items with a value. There are lots of ways to do this including from a binding like Astro, from the console as Michael indicates. You can create an input card, update it from a rule, etc. I particularly like opening the -Scratchpad- from the developer sidebar (alt-shift-d in main UI) and can write some quick commands to execute in there.
  6. Add the Items to the TimesOfDay Group.

Thanks for both your replies.

  1. I used the openhabian install of OpenHAB3. I can’t find the $OH_CONF/automation/lib/javascript/community directory to put the .js files

  2. I did put the YAML in a new rule. It created the following:
    When:
    When a member of TimesOfDay changed
    When the system has reached start level 20
    One minute after midnight
    Then:
    execute a given script

I did create the TimesOfDay and TimeOfDay string items

  1. Configure ephemeris (MainUI - Settings - ephemeris)

The $OH_CONF/automation/lib/javascript/community directory does not exist by default, but it’s where the script looks for its helper scripts. For a standard install, $OH_CONF is “/etc/openhab”. Not sure if that’s the same with openhabian. Just create it and put the scripts there.

Hi,
got the TOD rule Working and everything ist fine until i restart OH. All TOD Items that are astro related are OK but the static times that are set via UI or CLI command are not populatet by the persistence.

I am using rrd4j DB as a persitance service wit the following setup. Could somebody be so good to check if there is an error that is screwing up the restorOnRestart of my TOD items.

Strategies {
everyMinute : "0 * * * * ?"
everyHour : "0 0 * * * ?"
everyDay : "0 0 0 * * ?"
default = everyChange }

Items {
// persist items every minute and on Startup
EnergyUsage_Washer_CE_Utilityroom, EnergyUsage_TVLights_SF_Livingroom : strategy = everyMinute, restoreOnStartup
Weather_Temperature, Temperature_CE_Cellar, Temperature_GF_Entrance, Temperature_FF_Stairs, Temperature_SF_Stairs : strategy = everyChange, restoreOnStartup
TimesOfDay* : strategy = everyChange, restoreOnStartup
Default_Morning : strategy = everyChange, restoreOnStartup
Default_Bed : strategy = everyChange, restoreOnStartup
Default_Night : strategy = everyChange, restoreOnStartup
Holiday_Day : strategy = everyChange, restoreOnStartup
Weekend_Day : strategy = everyChange, restoreOnStartup
Weekend_Bed : strategy = everyChange, restoreOnStartup
Holiday_Bed : strategy = everyChange, restoreOnStartup }

Thank you in advance

Hmm, that “TimesOfDay*” line should be sufficient, as that persists all members of the group.
I use MapDB as the startup persistance service, so I really don’t know if that’s a rrd4j problem or not.
But your config file looks good to me.

Again thank you @Tron for your input. Just checked which values rrd4j is able to store and the winner is “numeric values”. I will try mapDB!

Ok, I think I’m all set except for the meta tags on my time of day items. I do have emphersis setup with my location. I’ve looked around the forums for awhile and can’t figure it out.

DateTime types are not yet supported by rrd4j. There was an issue filed to add it and if I remember correctly it was even worked on. For all I know it’s working in the snapshots. But for the release you need to use MapDB for DateTime Items.

What part can’t you figure out? The namespace, value, and configuration required are described in the original post with examples from .items files.

Should the following work then if I paste it in the “add metadata” section of the “Night Time” time of day:

value=astro:sun:local:set#start

No you have to follow the format presented.

value: BED
config:
  type: default

As demonstrated in the original post and explained in the github readme:

The state machine is driven by DateTime Items with etod metadata defined.

etod="STATE"[type="daytype", set="dayset", file="uri"]
Argument Values Purpose
"STATE" The name of the state that starts at the date/time stored in this Item’s state. The String that gets commanded to the TimeOfDay Item which indicates the current time of day state.
type The Ephemeris type (see below) Indicates what sort of day type is defined in Ephemeris, defaults to default.
set The name of the custom dayset Only valid when type is dayset.
file Path to Ephemeris XML file Only valid when type is custom, the path to the custom Ephemeris holiday configuration.

So the namespace to use is “etod” when you click on “Add custom metadata”. The STATE is replaced with the time of data state (e.g. EVENING).

So the metadata for my BED time of day for a default day is

If you want to have the DateTime set to Astro’s sunset, you need to link that Item to the Astro Thing’s Channel.

I think I have the custom metadata setup now. All my times of day are showing the correct time. However I am seeing the error message below when the YAML script runs.

2021-01-13 09:08:18.732 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘e6414ca5c6’ failed: :5:59 Missing close quote

  • Return the value or a key value from the Item’s metadata
    ^ in at line number 5 at column number 59

Here is the first part of that script:
// Imports var logger = Java.type(“org.slf4j.LoggerFactory”).getLogger(“org.openhab.model.script.Rules.TimeOfDay”); scriptExtension.importPreset(“default”); this.Ephemeris = (this.Ephemeris === undefined) ? Java.type(“org.openhab.core.model.script.actions.Ephemeris”) : this.Ephemeris; this.ZonedDateTime = (this.ZonedDateTime === undefined) ? Java.type(“java.time.ZonedDateTime”) : this.ZonedDateTime; // Get Metadata query stuff this.FrameworkUtil = (this.FrameworkUtil === undefined) ? Java.type(“org.osgi.framework.FrameworkUtil”) : this.FrameworkUtil; this._bundle = (this._bundle === undefined) ? FrameworkUtil.getBundle(scriptExtension.class) : this._bundle; this.bundle_context = (this.bundle_context === undefined) ? this._bundle.getBundleContext() : this.bundle_context; this.MetadataRegistry_Ref = (this.MetadataRegistry_Ref === undefined) ? bundle_context.getServiceReference(“org.openhab.core.items.MetadataRegistry”) : this.MetadataRegistry_Ref; this.MetadataRegistry = (this.MetadataRegistry === undefined) ? bundle_context.getService(MetadataRegistry_Ref) : this.MetadataRegistry; this.Metadata = (this.Metadata === undefined) ? Java.type(“org.openhab.core.items.Metadata”) : this.Metadata; this.MetadataKey = (this.MetadataKey === undefined) ? Java.type(“org.openhab.core.items.MetadataKey”) : this.MetadataKey; // Constants var ETOD_ITEM = “TimeOfDay”; var ETOD_GROUP = “TimesOfDay”; var DAY_TYPES = [“default”, “weekday”, “weekend”, “dayset”, “holiday”, “custom”]; var EXPECTED = "Invalid metadata for Item! "
+ "Expected metadata in the form of etod=“STATE”[type=“daytype”, set=“dayset”, file=“uri”] "
+ “where set is required if type is dayset and file is required if type is custom.”;
var ETOD_NAMESPACE = “etod”; // Load 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’); load(OPENHAB_CONF+’/automation/lib/javascript/community/timeUtils.js’); /**

  • Return the value or a key value from the Item’s metadata
  • @param {string} item name of the item
  • @param {string} namespace metadata namespace to pull
  • @param {string} key index into the configuration dict for the value
  • @return {string} value assocaited with key or null if it doesn’t exist.
    */

Also, where do I link my individual lights to the correct time of day with the correct dimness.
Thanks for the help.

My suggestion would be to get the raw view of the code (I posted the link a while ago here) to make sure no errors sneak in through copy and paste.

As for your lights, you’ll need a rule:

When
TimeOfDay changes
then
if (TimeOfDay.state == "EVENING") dimmer_light_item.postupdate(50) //or whatever
end

Something like this.
You can work with if/elseif/else or with case.

Please use code fences when posting code. I can’t begin to tell what might be going on here with it all munged together on one line like that.

But as Michael suggests, copy a known working version again and see if that works. The error is complaining about syntax so a bad edit or copy and paste is the likely culpret.

I have the following set up which is probably a little more involved than most would want to use when just getting started.

I have a series of Groups for each time of day with names following this patter:

  • TOD_Lights_ON_<TOD>, for example TOD_Lights_ON_DAY
  • TOD_Lights_OFF_<TOD>, for example TOD_Lights_OFF_DAY

I add as members all those lights I want to have turn on at the start of the DAY time period to the first group and all those I want to turn off at the start of the DAY time period to the second.

Then I have this simple rule:

triggers:
  - id: "1"
    configuration:
      itemName: TimeOfDay
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >
        var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.TOD_Lights");


        var offGroupName = "TOD_Lights_OFF_" + items["TimeOfDay"];

        var onGroupName = "TOD_Lights_ON_" + items["TimeOfDay"];


        var switchLights = function(tod, grp, st) {
          logger.info("Turning " + st + " the lights for " + tod);
          ir.getItem(grp)
            .members
            .stream()
            .filter(function(light) { return light.state.toString() != st } )
            .forEach(function(light) { events.sendCommand(light.name, st) });
        }


        switchLights(items["TimeOfDay"], offGroupName, "OFF");

        switchLights(items["TimeOfDay"], onGroupName, "ON");
    type: script.ScriptAction

Sorry about the code fences. I copied the link that Michael mentioned with the raw view of the code. Still getting an error on the code. Here is what the OpenHAB3 log shows:

2021-01-13 10:54:50.452 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'e6414ca5c6' failed: <eval>:2:6 Expected ; but found :

  - id: "1"
       in <eval> at line number 2 at column number 6

Where exactly did you past it? You should have:

  1. created a new rule
  2. opened the “code” tab
  3. pasted the full YAML there
  4. save
  5. manually run the rule by clicking the play icon.

That error looks like you pasted the YAML into a Script Action and not the Code tab.