As the lastest OH3.1 snapshot officially supports ECMA2021 Java Scripting I am wondering how to use the new functionality.
Until now I do use the syntax of the OH scripters to watch an item and fire the rule:
function rule_test(event) {
// Operations when rule is fired
}
when("Item HO_Date changed")(rule_test);
rule(
"Rule Test",
"No desc"
)(rule_test);
Can i simply use this scripting with the new ECMA2021 Automation Add on?
Because I tried to and got the following error in the log:
2021-05-24 00:39:10.782 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: ReferenceError: "when" is not defined
at <js>.:program(/etc/openhab/automation/jsr223/javascript/personal/graal_test.js:33) ~[?:?]
It is highly unlikely that the existing Helper Libraries will work as is. Iâm sure there will be some incompatibilities and breaking changes between the various versions. Youâll have to create rules using the raw openHAB Scripting API, an example of which you can find at JSR223 Scripting | openHAB. Notice how you need to create a Rule class which defines an execute function and then you need to create and add the rule triggers to that class using a TriggerBuilder.
Doing so (using the mentioned Raw JS example) I get the following entry in the log:
2021-05-24 18:51:27.461 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab/automation/jsr223/javascript/personal/graal_test_js.js': org.graalvm.polyglot.PolyglotException: ReferenceError: "scriptExtension" is not defined
Any ideas how to proceed?
Or does someone do have a running ECMA2021 example script?
I know that @jpg0 tends to error on the side of not including things into the rule rather than injecting references to things that would be of use just in case. I suspect youâll have to load something or do a Java.type to bring in access to a lot of things, though I donât know how that would work for something like the scriptExtension since I think that is how we gain access to the OH internals like the ItemRegistry and the like.
Over all, I suspect weâll need to wait for some examples and docs to explain how to access these OH specific things and use this for rules.
Apologies, but Iâm late adding docs for the new engine. @rlkoshak is correct, things are not injected, this is to preserve compatibility with 3rd parties libraries which would not expect them to be there.
If you want to bring in an object which was previously included by default, you can import it like so:
const myObject = import('@runtime').myObject (or you can use destructuring to reference multiple of them, etc)
This package is available on npm if you want to use it (you can install with npm if you like, or just directly from GitHub, just make sure it goes into the lib directory in openHAB). This is my own library which I wrote to replace the helper libraries; youâre welcome to use it (others do), but itâs not official or anything.
Also is there aa possibility to use the Helper Libraries within the new jsscripting add on?
You may be able to use the existing helper libraries, but they would require rework. There are a few issues I had with them:
They rely on things being injected into the context by the runtime (which doesnât happen as you now know)
They also rely on setting things into global scope, where one lib may set it and another read it. This isnât a good way to do things, and isnât easy to do with a module system which deliberately tries to keep things isolated
They didnât use a module system, nor any ES6+ features, as they were not available.
This is what led me to write ohj - I did attempt to port the helper libraries (e.g. allowing loading in both mechanisms) but ultimately it was too hard to keep compatibility to I completely rewrote them into ohj.
(I accept that we will probably need a new version of the helper libraries - Iâm happy for that to be ohj, but it currently makes no attempt to mirror the python ones or anything.)
@jpg0 I cloned your ohj repo to the folder â/etc/openhab/automation/lib/javascript/personal/ohjâ and tryed to use it with a modified example from your personal rule:
const log = require('ohj').log("minimal_test");
const { rules, triggers, items } = require('ohj');
//create a rule to handle scenes
rules.JSRule({
name: "Roller Scenes",
description: "Applies selected scenes to Rollers",
triggers: [
triggers.ItemStateChangeTrigger('RemoteopenHABServerPROD_ItemSFStudioLichtDecke')
],
execute: function () {
let status = items.getItem('RemoteopenHABServerPROD_ItemSFStudioLichtDecke').state;
log.info("Setting scene for rollers: {}", status);
}
});
@jpg0 with the following code it seems that I was able to load the ohj package via require:
const ohj = require("./../../../lib/javascript/community/node_modules/ohj");
let rules = ohj.rules;
But now the log throws the following:
2021-05-26 07:19:43.485 [DEBUG] [rt.internal.loader.ScriptFileWatcher] - Dequeued file:/etc/openhab/automation/jsr223/javascript/personal/first.js
2021-05-26 07:19:43.487 [INFO ] [rt.internal.loader.ScriptFileWatcher] - Loading script '/etc/openhab/automation/jsr223/javascript/personal/first.js'
2021-05-26 07:19:43.490 [DEBUG] [ipt.internal.ScriptEngineManagerImpl] - Added ScriptEngine for language 'js' with identifier: file:/etc/openhab/automation/jsr223/javascript/personal/first.js
2021-05-26 07:19:43.668 [WARN ] [script.js.osgi ] - Failed to get service org.openhab.core.items.MetadataRegistry: [object Error] [osgi at source <unknown>, line 53]
2021-05-26 07:19:43.675 [WARN ] [script.js.osgi ] - Failed to get service org.eclipse.smarthome.core.items.MetadataRegistry: [object Error] [osgi at source <unknown>, line 53]
2021-05-26 07:19:43.681 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: Error: Failed to get any services of type(s): org.openhab.core.items.MetadataRegistry,org.eclipse.smarthome.core.items.MetadataRegistry
at <js>.getService(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/osgi.js:71) ~[?:?]
at <js>.:anonymous(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/metadata/metadata.js:13) ~[?:?]
at <js>.:anonymous(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/items/managed.js:6) ~[?:?]
at <js>.:anonymous(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/items/items.js:8) ~[?:?]
at <js>.:anonymous(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/rules.js:11) ~[?:?]
at <js>.get rules(/etc/openhab/automation/lib/javascript/community/node_modules/ohj/index.js:13) ~[?:?]
at <js>.:program(/etc/openhab/automation/jsr223/javascript/personal/first.js:30) ~[?:?]
at org.graalvm.polyglot.Context.eval(Context.java:345) ~[?:?]
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:379) ~[?:?]
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:343) ~[?:?]
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:172) ~[?:?]
at org.openhab.core.automation.module.script.rulesupport.internal.loader.ScriptFileWatcher.importFile(ScriptFileWatcher.java:214) ~[?:?]
at org.openhab.core.automation.module.script.rulesupport.internal.loader.ScriptFileWatcher.lambda$1(ScriptFileWatcher.java:193) ~[?:?]
at java.util.Optional.ifPresent(Optional.java:183) ~[?:?]
at org.openhab.core.automation.module.script.rulesupport.internal.loader.ScriptFileWatcher.importFileWhenReady(ScriptFileWatcher.java:191) ~[?:?]
at org.openhab.core.automation.module.script.rulesupport.internal.loader.ScriptFileWatcher.processWatchEvent(ScriptFileWatcher.java:168) ~[?:?]
at org.openhab.core.service.WatchQueueReader.lambda$3(WatchQueueReader.java:322) ~[?:?]
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) [?:?]
@jpg0 the ohj package was installed (with ânpm i ohjâ) into the â/etc/openhab/automation/lib/javascript/communityâ folder:
[12:39:24] openhabian@ubuntu:/etc/openhab/automation/lib/javascript/community/node_modules$ ll
insgesamt 536K
drwxr-xr-x 129 openhabian openhab 4,0K Mai 25 21:33 ./
drwxr-xr-x 3 openhabian openhab 4,0K Mai 25 22:01 ../
drwxr-xr-x 6 openhabian openhab 4,0K Mai 25 21:33 acorn/
...
drwxr-xr-x 6 openhabian openhab 4,0K Mai 25 21:33 ohj/
...
However I get the above mentioned error in the log âorg.graalvm.polyglot.PolyglotException: Error: Failed to get any services of type(s): org.openhab.core.items.MetadataRegistry,org.eclipse.smarthome.core.items.MetadataRegistryâ
So something seems to be wrong, I do have a clean automation/* installation there are no other *.js files within except the mentioned ânode_modulesâ package and two test scripts within the folder â/etc/openhab/automation/jsr223/javascript/personalâ.
Here is the fix: Testing the GraalJS package with OH3 · Issue #2 · jpg0/oh-config · GitHub - specifically the bundle context part I believe. Although I thought I had merged that already; maybe not. Note that you will likely require the ohj-support bundle too (which is referenced in that comment chain).
When I am going through your personal git repo you always use ââŠrequire(âohjâ);â.
Why is that not working on my setup?
Also I am wondering if there is something like the âevent.itemStateâ property like it is available in the definition of âclassicâ oh scripters ECMA5 rules (when using JSRule with ohj)?
Hmm, looking at the current implementation, you need to put ohj in personal, not community. The problem is that node cannot use multiple library paths, so I hardcoded it to this. TBH I believe that the right option is to not use âlibâ at all and instead to follow the node standard of a relative â./node_modulesâ folder (hence within the jsr233 folder), but this deviates from openHAB current, and requires some more work.
Also I am wondering if there is something like the âevent.itemStateâ property like it is available in the definition of âclassicâ oh scripters ECMA5 rules (when using JSRule with ohj)?
The fluent API was very much to satisfy what I have needed for bulk rules, and even then for more complex rules Iâve switched to the JSRule style rule declaration, so I expect there to be missing features. Saying that, Iâm happy to accept PRs if you want to add any features.
Thank you very much, now I know how to import services like itemRegistry and events.
But how can I import:
types, as I would like to do the HSBType.fromRGB(r, g, b) conversion
openHAB core actions, like Exec.executeCommandLine(), HTTP actions and NotificationAction
Java classes from openHAB, e.g. org.openhab.core.model.script.actions.Exec â I can import normal Java classes like java.time.Duration, but importing openHAB classes causes errors like:
org.graalvm.polyglot.PolyglotException: TypeError: Access to host class org.openhab.core.model.script.actions.Exec is not allowed or does not exist.
I am facing exactly the same error
i tried with a quite simple rule
//'use strict';
//const LoggerFactory = Java.type('org.slf4j.LoggerFactory');
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.rule." + ctx.ruleUID);
logger.info("Hello world!");
logger.info(JSON.stringify(ctx));
//var Exec = Java.type("org.openhab.core.model.script.actions.Exec");
//const JavaThingBuilder = Java.type('org.openhab.core.thing.binding.builder.ThingBuilder');
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
// timer = createTimer(now.plusMinutes(3), function() { logger.info("Hello from Timer") })
timer = ScriptExecution.createTimer(ZonedDateTime.now().plusSeconds(10), function() { logger.info("Hello from Timer") });
but as soon as it comes to the Java.type("org.openhab... line i get a error, other types can be imported, also i observed that my ctx.ruleUID is undefinded
23:54:11.323 [INFO ] [openhab.event.RuleUpdatedEvent ] - Rule '334a42598c' has been updated.
23:54:12.367 [DEBUG] [ript.internal.ScriptEngineManagerImpl] - Added ScriptEngine for language 'application/javascript' with identifier: 402f3e2d-dcb4-4392-987b-893844574a3e
23:54:12.427 [WARN ] [g.internal.OpenhabGraalJSScriptEngine] - Failed to retrieve script script dependency listener from engine bindings. Script dependency tracking will be disabled.
23:54:12.453 [INFO ] [org.openhab.rule.undefined ] - Hello world!
23:54:12.465 [INFO ] [org.openhab.rule.undefined ] - {}
23:54:12.487 [ERROR] [ab.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: Access to host class org.openhab.core.model.script.actions.ScriptExecution is not allowed or does not exist.
at <js>.:program(<eval>:13) ~[?:?]
at org.graalvm.polyglot.Context.eval(Context.java:345) ~[?:?]
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:379) ~[?:?]
at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:356) ~[?:?]
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264) ~[java.scripting:?]
at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocable.eval(DelegatingScriptEngineWithInvocable.java:51) ~[?:?]
in the meanwhile i read so many post here, but nothing really helped me.
i reinstaled the jsscript automation i restarted/rebooted but nothing helped
(runinning an openhabian on a RPI)