Usage of new ECMA2021 Automation Scripting (GraalVM)

@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);
    }
});

No the log throws the following error:

2021-05-25 15:03:18.716 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: Cannot load CommonJS module: 'ohj'

How can i fix this?

Thanks!

1 Like

@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) [?:?]

Any advice how to get this run would be great!

Thanks!

When you install ohj, it must go in lib, however in a subdir of it called node_modules.

(Not sure if that will fix your other problem, but give it a go.)

@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).

@jpg0 I got it now to run, things I did:

  1. Installed ohj-support Add-on from https://github.com/jpg0/oh-config/files/5745369/org.openhab.automation.ohj-support-3.0.0-SNAPSHOT.jar.zip
  2. A fresh git clone of GitHub - jpg0/ohj: Openhab Javascript Library into “/etc/openhab/automation/lib/javascript/community”
  3. Changed the mentioned function “lookupService” to the fixed one Testing the GraalJS package with OH3 · Issue #2 · jpg0/oh-config · GitHub

After a restart it worked.

What I am wondering is that I do have to use always relative paths for loading the ohj package via require:

const { item, sendIt } = require("../../../lib/javascript/community/ohj/fluent/fluent");
const ohj = require("./../../../lib/javascript/community/ohj");
const LOG = ohj.log("second");
const fluent = ohj.fluent;

with (fluent) {
    when(cron("0/30 * * * * ?")).then(sendOff().toItem("RemoteopenHABServerPROD_ItemSFStudioLichtDecke"));
}

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)?

Thank you very much for your help!

Why is that not working on my setup?

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)?

Looking at the code, for the fluent API, there is something that is defined for rules that trigger on commands send to items; you can see some of my code here: oh-config/automation/jsr223/javascript/personal/fluoro_lights.js at master · jpg0/oh-config · GitHub

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.

1 Like

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.
1 Like

@florian-h05

Works in my ECMA2021 scripts

const screx = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
const ohj = require('./../../../lib/javascript/community/node_modules/ohj');
const actions = ohj.actions;
...
actions.Exec.executeCommandLine("/path/to/script.sh");
1 Like

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)

5 Likes

for what it’s worth, I have the same issue.

There are reports (@opus at openHAB 3.1 Release discussion - #8 by opus) that reboot should help but it did not help on my side.

2 Likes

Did you followed the steps from my post?

I haven’t…

Is that needed even if I don’t use ohj? I am simply trying to use new ecmascript as an “action” in UI rules…

Sorry about hijacking this thread, but how did you manage to run it at all?

I’m running 3.2.0.M1-debian in Docker and getting this:

2021-08-02 21:57:49.315 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/openhab/conf/automation/jsr223/javascript/personal/testRule.js': /openhab/conf/automation/jsr223/javascript/personal/testRule.js:1:0 Expected an operand but found const
const ohj = require("ohj");
^ in /openhab/conf/automation/jsr223/javascript/personal/testRule.js at line number 1 at column number 0

It looks like there is no ES6+ support. What do I need to do to install/activate GraalJS?

A minor update here. After unzipping the ohj-support you also need to take it out of the folder. I got caught with the folder name being the same as the JAR so thought that was it. After taking the actual JAR out of the folder to the root of the add ons directory we are in business. (lockdown has fried my brain).

An additional tip I worked out is that the logger has a hard coded prefix of script.js so for the messages to show in the openhab log you need to update the openhab console with
log:set debug script.js

Happy to write a beginners guide based on my setup from today collecting all the above information

For the record, I filed several issues on jsscripting. The import issue (PolyglotException: TypeError: Access to host class) discussed in this issue here: https://github.com/openhab/openhab-addons/issues/11222

Other issues:

2 Likes

Imports are working now!

With the release of the 3.2.0.M4 Milestone Build the import of classes from org.openhab.core works, as this Issue #11222 was closed by PR #11400.

Please note

The folder openhab-conf/automation/lib/javascript/personal must exist, without that folder the Add-On throws errors.

I have created this Issue #11616 to either mention that in the docs or to create that folder on openHAB start-up/Add-On installation.

Small guide for GraalVM

I have completed a few tests and created a small guide which is hosted at florian-h05/openhab-addons.

Table Of Contents of the Guide

1 Like

Excellent summary! Would be great if you could consider improving the jsscripting addon docs with those.

In the guide you state

Please note that toString() is supported, but toBigDecimal()is not working anymore.

What does this mean exactly? What is the error and is there already a github issue filed?

Thank you, of course I can add those to the jsscripting addon docs.

I thought that the conversion toBigDecimal() is not working anymore (I used to use it when getting item states to make sure they are number and not string), but I checked it again and it is working.

So it does not mean something, I wrote it because I thought it does not work but I just had a typo on my tests.

I have updated my guide to fix my misconception, next I will work on adding it to the addon docs.

1 Like

I have created a PR on GitHub for the docs.

2 Likes