openHAB Rules Tools Announcements

I would like to formally announce the release of openhab_rules_tools. Those of you who have followed my postings for awhile will recognize just about everything here, I’ve just made it a bit more formal.

As usual, you can upgrade through openhabian-config or by running npm update.

Releases

v2.0.3

Depends on openhab-js 4.5.1.

Library

  • Updated code with new OH 4 concepts and openhab-js features
  • Added warning level logs to all deprecated functions and features
  • Added a factory function for all classes. Now instead of the old way to import and instantiate:
var { gatekeeper } = require('openhab_rules_tools');
var gk = new gatekeeper.Gatekeeper();

use

var { Gatekeeper } = require('openhab_rules_tools');
var gk = Gatekeeper();

A warning log message occurs if you attempt to import the class instead of using the factory.

  • [testUtils.sleep] Reimplemented to use java.lang.Thread.sleep() instead of a busy wait.

Rule Templates

  • Rewritten all but one of the rule templates for OH 4 using JS Scripting instead of Nashorn (one rule template left to update is Meter Reading)
  • Greatly improved error checking and configuration checking so problems result in meaningful and actionably error messages across all rule templates
  • All my rule templates now depend on openhab_rules_tools being installed and available
  • Added library version checking to all rule templates, an error will occur if too old of a version of a library is detected
Deprecated
  • [To Today] Deprecated with no plans to migrate, use the new Time is <item> timeOnly rule trigger
  • [MQTT Online Status] Deprecated, this feature is now built into the binding. See your MQTT Broker Thing config.
Merged Tempaltes
  • [MQTT Event Bus Publication/Subscription] Merged into a new consolidated rule template
  • [Open Reminder and Threshold Alert] Merged into a new consolidated rule template which additionally supports hysteresis, overriding properties on a per Item basis, and calling an alert rule when the Item first changes to an alerting state, in addition to alerting when it’s been in the alerting state for a time and when it exits the alerting state.
New
  • [Delay Start] A new template that runs at system runlevel 40 and disables the configured rules. It then waits until system runlevel 100 plus a configurable delay to reenable them
  • [Restart Expire] On OH startup, restart Items configured with expire by posting their current state as an update.
  • [Expire Updater] A script that can be called from another rule or a MainUI Widget to replace the expire configuration with a new one.

Changed Behavior

  • [Thing Status Reporting] Now triggers immediately on the Thing status events instead of polling. As a result it calls the processing rule only with the information about the one Thing that changed status.
  • [Debounce] Triggering the rule manually will check the config and report errors
  • [Time Based State Machine] Running the rule manually will cause more information to be logged about configuration checking. The date portion of the date times are ignored.

v2.0.2

Fixed a bug in loopingTimer

v2.0.1

Fixed a bug in the version checking logic in helpers.

v2.0.0

This is the first release that fully requires OH 4.0 and depends on openhab-js 4.1 or later. This update fixes a couple of long standing bugs as well as some additions.

All my rule templates going forward will check the versions of this and openhab-js and throw an exception if one is too old to run the rule.

Library

  • Readme updates by @rkoshak in #79
  • [countdownTimer] Call the function at the end, not the beginning by @rkoshak in #86
  • [loopingTimer] throw exception when looping timer time in past by @rkoshak in #87
  • [helpers] Added helper functions to test library version nums by @rkoshak in #89

Rule Templates

Note: Rule templates do not follow a release cycle. As soon as they are merged they become available on the marketplace.

  • [time_state_machine] Added code to calculate and publish the current state by @rkoshak in #80
  • [mqttEb] Initial reimplementation of MQTT Event Bus by @rkoshak in #81
  • [expire_updater] Added expire_updater rule template by @rkoshak in #82
  • [thingStatus] Changed trigger for thingStatus to support changes in core by @rkoshak in #83
  • [presenceSim] Reimplementation of Presence simulation for OH 4 by @rkoshak in #84
  • [rule tempaltes] Don’t set log level in rule template by @rkoshak in #85
  • [mqttEb] Publishing ONLINE is now handled by the Broker Thing by @rkoshak in #88

v 1.2.0

  • Use createTimer instead of createTimerWithArgument by @florian-h05 in #76
  • Added rewrite of the Thing Status Reporting rule template using ECMAScript 2021 for OH 4 by @rkoshak in #77
  • Added rewrite of the Debounce rule template using ECMAScript 2021 for OH 4 by @rkoshak (I forgot to make a PR and merged straight into main)
  • Added rewrite of the Time Based State Machine using ECMAScript 2021 for OH 4 by @rkoshak (I forgot to make a PR and merged straight into main)
  • Added checkGrpAndMetadata to helpers.js and exposed it to be used by rule templates to validate Item configs for rule templates like Debounce and Time Based State Machine by @rkoshak (I forgot to make a PR and merged straight into main)

As of this release the library depends on openhab-js 4.0 or later.

v1.1.4

Added the ability to supply a name when creating a timer to make debugging easier. If the name isn’t supplied, the ruleUID will be used. If that isn’t available the filename will be used. Otherwise the name defaults to the name of the library.

Note: v1.1.3 was a mistake and ended up getting out of sync with npm.

v1.1.2

  • Deprecated timeUtils.toDateTime() in favor of openhab-js’ time.toZDT(). There are minor differences in how that library handles Duration strings. It now follows the ISO8601 standard.

v1.1.1

  • Minor bug fixes in timeUtils
  • Added .npmignore to avoid publishing rule templates as part of the npm package

v1.1.0

Initial full release rewritten for the JS Scripting ECMAScript 2021 using the openhab-js library.

History

These started out as contributions to the Jython Helper Libraries. For various reasons they were never accepted so I moved them to my own repo.

When OH 3 came out there was a delay between when Jython support was established so I rewrote them as Nashorn ECMAScript 5.1.

Now that JS Scripting has been added to OH and the helper library openhab-js included as part of the add-on, I’ve rewritten the library as ECMAScript 11. This allows the library to be published and distributed via npm, vastly simplifying the installation process.

I use this same repo as the location for my rule templates.

Installation

Dependencies

This library has a dependency on the openhab-js library. If you want the latest version of openhab-js library it can be installed through openhabian-config menu option 46 | Install openhab-js or by navigating to the $OH_CONF/automation/js folder and running npm install openhab.

For now the library assumes that the settings for JS Scripting are at the default settings which causes openhab-js to automatically be injected into your rules. If you turn that feature off, some of the classes and functions in the library may not work. Please report if this is the case so I can update that. I’d like it to work as is in both cases.

See the release notes above for the latest version of openhab-js that openhab_rules_tools depends upon.

openHABian

The library is now installed and updated by default in openHABian. So if you are running the latest openHABian, you’ve already got it. You can verify this by looking in $OH_CONF/automation/js/node_modules and if there is an openhab_rules_tools folder you are good. If not, update your openHABian and navigate to menu option 47 | Install openhab_rules_tools.

However, as of this writing (2/23/2023) oepnHABian will not upgrade to a new major version number. This works to our advantage as now that version 2.0.1 depends on OH 4, upgrading won’t break your system. When you upgrade to OH 4, uninstall and reinstall and you’ll get the latest 2.X version.

Linux

From the $OH_CONF/automation/js folder run

sudo -u openhab npm i openhab_rules_tools

Look up instructions for running npm on your specific OS if not running on Linux.

To move to a new major version (e.g. v1.2.0 to v2.0.1), remove and then install again.

Docs

Lacking at the moment. Look at the files under tests for examples and the code itself for usage details or ask questions below or on GitHiub.

Implemented Capabilities

Name What it does
CountdownTimer Class that implements a Timer and updates a passed in Number or Number:Time Item once a second with the amount of time remaining on the timer. Useful for showing how much time is left on a Timer on the UI.
Deferred Class that allows one to schedule a command or update to an Item in the future.
Gatekeeper Schedules a sequence of actions with a time for how long after one action before the next action runs. This can be used to limit how quickly commands are sent to a device or create a schedule (e.g. irrigation).
groupUtils A series of functions that implement some common operations on members of a Group, such as getting a comma separated list of their names. There are also some methods that work on generic Arrays.
LoopingTimer Implements a Timer that keeps calling a function as long as that function doesn’t return null. When the loop should continue, the function must return a when (see timeUtils).
RateLimit Implements a class that ignores events that happen too soon after the most recently processed one. This is useful to filter out alerts that may occur more frequently than you care about (e.g. only remind me the battery is low once a day).
rulesUtils Does not work well in UI scripts. Some functions that will generate a rule triggered by Items with a given tag or given metadata configuration.
TimerMgr Implements all the book keeping required when managing multiple timers in one rule (e.g. one per Item).
timeUtils Mostly Deprecated: most of this functionality is now part of openhab-js. A couple of functions useful to using and manipulating times.
testUtils Implements sleep (wrapper around Thread.sleep() as well as an assert function for testing.
helpers Mostly functions useful internal to the library or by us in rule templates and not of general interest. To get the current version of openhab_rules_tools use helpers.OHRT_VERSION

To Do

  • docs
  • implement better unit tests
  • migrate some capabilities to openhab-js (rulesUtils.runRule and most of timeUtils have already been migrated)
  • migrate the rule templates to JS Scripting

Testing

Most of the capabilities have their own test script in the test folder. These are written as a UI Script (Settings → Scripts). It’s still a todo to migrate to a true unit test framework. These are not part of the node module.

Rule Templates

You will notice a separate rule_templates folder on GitHub. These can only be installed through the marketplace and they are excluded from the node module.

If you want to submit updates to the rule templates, here is where to do it.

11 Likes

it’s installing to the current dir, right ? I could add that to openHABian, what do you think a proper dir would be when doing that?

The command needs to be run from $OH_CONF/automation/js and it will install to ./node_modules/openhab_rules_tools so the full path would be $OH_CONF/automation/js/node_modules/openhab_rules_tools. Right now it doesn’t use any libraries outside of openhab but if that changes in the future npm will install those too.

sudo -u openhab mkdir $OH_CONF/automation/js
cd $OH_CONF/automation/js
sudo -u openhab npm i openhab_rules_tools

Note that folder will not exist until the JS Scripting add-on is installed. It doesn’t hurt if it exists before though so it’ll need to be created by openHABian if it doesn’t exist, which will be the case most of the time.

It would be fantastic to have it included as part of openHABian, though I should warn it’s still very much a work in progress. I’m still refactoring and re-implementing stuff that’s written in other languages right now. I’m hoping to move some of these to openhab-js too so that everyone can get to them, but there is a pretty high bar for additions to that, as there should be.

But if this is included, there should probably also be a menu entry to npm install openhab too so users can get the latest version with changes since the last time the add-on was released.

I’m a bit behind but I’ve made it to a relatively stable state so I’ve cut a release 1.1.0 for openhab_rules_tools. You can get this via npm update if you’ve installed it that way previously or you can find the release on github.

This release includes

  • completed refactoring and rewrite in ECMAScript 2021 which is now on the main branch
  • removed deprecated stuff that is no longer supported (they can still be found in the before-npm branch)

I still need to figure out how to generate the docs from the docstrings in the code and beef up some of the other things.

I will update the OP so it’s always the most recent.

@mstormi, it’s probably at a state now where it’s worth consideration for inclusion with openHABian. I can open an issue for discussion if it will help. It would be really awesome to have it available there. :slight_smile:

Hi, this sounds very interesting. I have already used your code as a tutorial and have rewritten some of my old rules. Realy helpful thanks! Now my question. How should I instal when using openhab on docker (running on a raspberry pi). Should I install it in the container, or should I install it from ‘outside’. The later sounds more logical, but just to be sure.

You should have $OH_CONF mounted as a volume into the container. So where ever its mounted from install it that way. I mount a host local folder into the container so I run npm from that folder on the host (not inside the container). Note that npm does not exist inside the container so if you do it from inside the container you’ll have to install npm first.

Thanks! That clears up that.

When I load the openhab_rulew_tools almost doubles the cpu usage. Is that normal?

Shouldn’t be. Unless you use something in a rule they don’t do anything. There might be a little spike when first loading a rule that uses them since there is more code for OH to parse and get ready to run but that should only be brief and when the rule first loads or, if a managed UI rule when the rule first runs.

What causes this error?

2022-06-11 13:45:25.736 [INFO ] [rulesupport.loader.ScriptFileWatcher] - Loading script '/etc/openhab/automation/js/node_modules/openhab_rules_tools/rulesUtils.js'
2022-06-11 13:45:25.831 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: ReferenceError: "osgi" is not defined
        at <js>.:program(rulesUtils.js:1) ~[?:?]
        at org.graalvm.polyglot.Context.eval(Context.java:379) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:400) ~[?:?]
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:249) ~[java.scripting:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocable.eval(DelegatingScriptEngineWithInvocable.java:56) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable.eval(InvocationInterceptingScriptEngineWithInvocable.java:79) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocable.eval(DelegatingScriptEngineWithInvocable.java:56) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable.eval(InvocationInterceptingScriptEngineWithInvocable.java:79) ~[?:?]
        at org.openhab.core.automation.module.script.internal.ScriptEngineManagerImpl.loadScript(ScriptEngineManagerImpl.java:177) ~[?:?]
        at org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.createAndLoad(ScriptFileWatcher.java:231) ~[?:?]
        at org.openhab.automation.jsscripting.internal.fs.watch.JSScriptFileWatcher.createAndLoad(JSScriptFileWatcher.java:57) ~[?:?]
        at org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.importFile(ScriptFileWatcher.java:211) ~[?:?]
        at org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.lambda$2(ScriptFileWatcher.java:203) ~[?:?]
        at java.util.Optional.ifPresent(Optional.java:183) ~[?:?]
        at org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.importFileWhenReady(ScriptFileWatcher.java:201) ~[?:?]
        at org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.checkFiles(ScriptFileWatcher.java:274) ~[?:?]
        at 
org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher.lambda$8(ScriptFileWatcher.java:296) ~[?:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
        at java.lang.Thread.run(Thread.java:834) [?:?]
2022-06-11 13:45:25.856 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab/automation/js/node_modules/openhab_rules_tools/rulesUtils.js': org.graalvm.polyglot.PolyglotException: ReferenceError: "osgi" is not defined

Note that for all intents and purposes rulesUtils.js is deprecated. You should use the functions provided by openhab-js rules instead.

If you’ve turned off the automatic imports for JS Scripting than the openhab-js libraries will not be imported for you and openhab-rules-tools depends on those imports being there.osgi is one of the names exposed by openhab-js.

I’ve never seen this error so those are my only ideas what could be wrong. But what ever the problem is, you should probably be using the stuff built into openhab-js anyway. At some point in the not too distant future I will be removing almost everything in this utility.

HI @rlkoshak,

Just tried your library and found a small bug.

I was trying the CountdownTimer function and I kept getting Java errors in the Logs.

I found you still had some hard coded time codes (i.e. “1s”) in your code that was causing the error.
I changed this in the CountdownTimer.js file to be “PT1s” and that fixed the problem.

I’m sure this is because you recently changed to the time.toZDT() function in your code.
I suggest checking the rest of the library in case there’s other instances

Thanks for the heads up. I did recently change from my internal timeUtils to using what comes in openhab-js now. * thought I was thorough but clearly at heart one got by. I’ll need to update my unit tests.

I’ll get it patched tomorrow and I’ll release a new version to npm so the fix gets picked up.

Version 1.1.3 has been published to npm. It includes the fix for the bug in countdownTimer and fixed up unit tests. There is no new features or changes in behavior so I won’t edit the OP.

2 Likes

HI Rich.

I’m not a proper programmer but I know enough to be dangerous.
I think I found another Bug in your countdownTimer Class.

From what I understand with

let timer = new countdownTimer(when,function,Item);

The “function” is supposed to get called after the timer “when” finishes.
It currently gets called immediately but otherwise the item counts down correctly.

Looking at your code I think this.

this.timer = actions.ScriptExecution.createTimer(this.start, func);

should be this. (when I changed the code to this it worked)

this.timer = actions.ScriptExecution.createTimer(this.end, func);

and the below screen shot is for context.

Sorry to keep pointing out errors but i’m sure you’d rather know than not.
I’ve seen a lot of your work through the forums and its very helpful.

I absolutely would like to know rather than letting bugs remain.

I don’t use count down timer in my setup but I do have some unit tests that I though covered testing that the function was called at the same time. Apparently not. I’ll look into this and get it fixed (with a proper unit test) as soon as I can.

Thanks for the heads up!

@rlkoshak
got the same behavior like already mentioned. Is it still a bug or is the issue not merged yet?

It’s not merged yet. I created an issue so I don’t forget again.

With all the changes being made to how timers are created and managed in JS Scripting I’m probably going to have to rewrite all my unit tests and I need to make sure this gets tested.

Ok thanks for the update

I’m currently use the JSRule example from the docs and building my rules similar to this:

rules.JSRule({
  name: "Balcony Lights ON at 5pm",
  description: "Light will turn on when it's 5:00pm",
  triggers: [triggers.GenericCronTrigger("0 0 17 * * ?")],
  execute: (event) => {
    items.getItem("BalconyLights").sendCommand("ON");
    actions.NotificationAction.sendNotification(email, "Balcony lights are ON");
  },
  tags: ["Balcony", "Lights"],
  id: "BalconyLightsOn"
});

What do I have to put into the ruleUID variable for the rules_tools?

cache.put(ruleUID, false);

Hmmm. Well, that ruleUID isn’t strictly required. It’s just a convenient way to ensure that the key is unique to that rule. The cache is shared across all rules so if you happen to use the same key in multiple rules, they will overwrite each other.

I don’t think rules in files have a ruleUID variable injected into them. I think there is a filename variable but you can have more than one rule per file so that’s probably not sufficient.

All I can recommend is to make sure that what ever key you use when you put something into the cache is unique across all your rules so there’s no overwriting.

Ok, so I can use the same ID like I do for the rule itself. Thanks.

What impact does this cache have? Why and when is it put to true and when to false?
Can I start for example two Countdown timers in the same rule with different variable name, but only with one cache ruleuid?