Migrate from Nashorn to JSScripting for UI Rules

That must be it! Do you need to install it manually? I click settings > automation > + and there I see the following: oooh…you know what? My upgrade to 3.2 must have failed. I’m still running 3.1.1. The plugin version number should have been a hint, but I thought they were not in tandem.

My apologies for not investigating this more thoroughly. Thank you for that last comment, it made me see the light. :+1:t2:

No worries, glad we could sort it out :+1:

Is there a way to check if or where certain Java features are available?

Specifically, I’m looking if I can still execute other scripts, which in Nashorn worked like this:

var BundleCtx = Java.type('org.osgi.framework.FrameworkUtil').getBundle(scriptExtension.class).getBundleContext()
var RuleMgr = BundleCtx.getService(BundleCtx.getServiceReference('org.openhab.core.automation.RuleManager'))
RuleMgr.runNow('123456789a')

which will result in:

org.graalvm.polyglot.PolyglotException: ReferenceError: “scriptExtension” is not defined

Although Java.type is working fine and scriptExtension throws the error so technically my question may be incorrect. Note that I am importing the suggested scopes, i.e.:

Object.assign(this, require('@runtime'))
Object.assign(this, require('openhab'))

I have also some minor problems with rounding :slight_smile:

i tried this little function:

var num = 5.56789;
var n = num.toFixed(2);

Error:
failed: org.graalvm.polyglot.PolyglotException: TypeError: [object Object] is not a function

Same when using
toPrecision(2);

I agree with the question where there is an overview of functions. @Redsandro

@rlkoshak @jpg0

EDIT:
my fault, it works but i had heap errors like other people here with JSS

Anything Nashorn can do JSScripting can do too except for the equivalent of Thread.sleep.

Sometimes the best source of examples will be by looking at the code for the helper library openhab-js. In this case, if you go to openhab-js and look at the part of the library that works with rules, you’ll see that osgi has a getService function.

 ​let​ ​RuleManager​ ​=​ ​osgi​.​getService​(​"org.openhab.core.automation.RuleManager"​)​;

If you don’t want to use the helper library, you need to use something besides scriptExtension. For example:

this.ScriptHandler = Java.type("org.openhab.core.automation.module.script.rulesupport.shared.ScriptedHandler");
    var _bundle = FrameworkUtil.getBundle(ScriptHandler.class);

Please be sure to read the docs for the add-on. Everything you need is imported by default, unless you turn that off in the bibding’s settings. Also note that runtime and the helper libraries are not compatible. For example, in runtime items is a dict of item name/current states. But in the helper library it’s your one stop shop for all things item related including sending commands and such.

You never want to include both as they will overwrite parts of tech other. You only want to include runtime if you have a Nashorn script you want to run on JS Scripting with minimal changes. In that case, I’d argue just leave it as Nashorn. You really are not getting much benefit from JSScripting in that case.

The docs for the add-on has a decent reference and you can click through to reach comprehensive reference docs and even get to the code for the helper library. Everything else is going to be standard GraalVM JavaScript. I’d guess that this might be a place where GraalVM differs from native. I bet that your num is not a standard JavaScript Number but something else that can work for both JS and Java at the same time (this is running in Java after all) but I’m far from an expert on that part of it.

1 Like

Thank you for showing me how to import RuleManager in GraalJS.

I think I’m doing something wrong. I’m getting the following message when trying to execute a rule:

[ERROR] [internal.handler.ScriptActionHandler]
Script execution failed:
org.graalvm.polyglot.PolyglotException:
TypeError:
invokeMember (runNow) on org.openhab.core.automation.internal.RuleEngineImpl@35d1667c failed due to:
no applicable overload found
(overloads:
[Method[public void org.openhab.core.automation.internal.RuleEngineImpl.runNow(java.lang.String,boolean,java.util.Map)],
Method[public void org.openhab.core.automation.internal.RuleEngineImpl.runNow(java.lang.String)]],
arguments: [123456789a (String), DynamicObject (Nullish), DynamicObject (DefaultLayout)])


For the people to came here using search: The answer to “Is there a way to check where certain Java features are?” is “not as a list, but check the helper source.”

I’ve not done this from JSScripting so there might be something different in how it works. All my rules that call other roles are written to be compatible with both Nashorn and JSScripting so I’m not using the helper library osgi for that part yet.

It should work though but I can’t tell you why it didn’t work nor how to fix it. But it does look like you called runNow with the wrong number of arguments. The error isn’t saying that you didn’t get the Rule manager, but that the runNow call you tried to make doesn’t match the runNow functions available.

1 Like

Thank you, I know I had the right amount of arguments, but you provided some helpful perspective on where to look. This is how I figured out I can no longer use undefined as a second parameter. In GraalJS it (whether or not to assess rule conditions) needs to be explicitly true or false when set.

I recommend adding this in the topic start post to a list of things to look out for when migrating.

1 Like

How can I get context, getAttribute or similar?

I’m looking for a way to read the attributes passed to a rule or “script” as specified using the runNow() command. In Nashorn this would be context.getAttribute('someAttribute'). However, in GraalJS, context is not available, and searching in openhab-js yields no helpful hints.

The map is injected straight into the rule. So if you pass a map to the rule with a key “foo”, the called rule will have a variable “foo” available.

However, that behavior is likely to change in the future. This isn’t in the docs yet since it is likely to change.

1 Like

Thank you. That’s convenient.

I understand.

Is there a roadmap or something more abstract than the OH release notes to watch in order to stay apprised of such specific developments, feature freeze or finalized behavior?

Just watch the announcements is the best I can offer. Changes in behavior, make big fixes, and breaking changes are are announced there on milestone or major releases.

Things get implemented when and if someone volunteers to do it so it’s not possible to forecast when something gets done. But this particular behavior has been identified as a potential problem already.

1 Like

I do not understand completely that Jhyton and JS Scripting can run parallel or not. I understand that Jhyton will be depreciated in certain time so we need to change to JS Scription what is not good as I had plenty of work to change to Jhyton (Python) from DSL. I have tried to install JS Scripting:

But it gave the following error:

So I assumed that libraries are missing and I installed it with NPM.
Then after restart of openhab it gave the errors in the following log.
JS and Jhyton scripting startup.log (20.6 KB)
here is my system detailes
system detailes.txt (2.2 KB)
My questions are that two scripting engine can run parallel or I need to wait?
Did I installed something wrong?
What is your suggestion for the change?

Yes the can.

That time is not determined and likely will not be under our control. But I wouldn’t expect it to happen any time soon. There should be no pressure to rush and change to a new language right now.

That’s not what that means I think. That looks like the JSON perfect by the page is malformed. Try restarting OH and refreshing the page to get a lean slate and see if that works. If it doesn’t yet clearing the cache using openhab-cli.

There is a known problem with the latest version of openhab-js on npm which causes some errors in the logs about being unable to load some core libraries. You might be seeing that. But given that I’m pretty sure the problem is not caused by the library I recommend deleting what was installed by npm.

Many thanks for your kind prompt reply!
I do not understand clearly what does it mean page is malformed.
When I installed JS Scripting from binding it had created only empty subfolders in automation folder (JS). After OH restart libraries were not created as well.
That’s why I updated the libraries by NPM. After that I restarted OH 3 times but it frozen due to Java heap error (memory run out). So I had to remove JS Scripting libraries and OH started only after that again.
Catch was not emptied. I can do it but how can I install JS Scripting libraries?

The library is included in the binding, but you can not see it in the folder.

Remove the node_modules folder from automation/js. Then install the JS Scripting binding and DO NOT install the openhab library manually.
Create a script that is using the library and it should work (without manually installing or seeing the library in automation/js).

Ok. I was doing it this way at the very beginning. That was the point when I get this error:

Both try to make a script through UI or create it from file. Same result. If I get the same error, what should I check?
I guessed that Jhyton Scripting set up and new JSS Scripting have conflict, pls bear in mind that I use Ivan’s Helper Libraries: Ivan’s Helper Libraries - OH3, Python, JavaScript

The same error cannot happen if you create .js files because the concept on a Script Action really only exists in a UI rule.

That error is complaining about the JSON that makes up the rule. In specific, it’s complaining that you have a Script Action without a “script” element. It’s not even getting to the point where Jython or JSScripting comes into play.

That’s what I mean by the time being malformed.

If possible, it might be informative to see what’s in the code tab. And anything posted to the logs when you see that error in the UI is always useful.

Despite that error, can you get to the text editor and enter some code? Can you save the rule and come back to edit it?

Theoretically, not only can you have Jython and JSScripting in different rules at the same time, you can use it in the same rule.

So error was due to Script was empty. Now it has green idle status.
This would be my fisrt code:

rules.JSRule({
  name: "Turn on yard decor ligtes in case of double click",
  description: "Turn on yard decor ligtes in case of double click",
  triggers: [triggers.ChannelEventTrigger('Channel mihome:86sw2:286C0785BE33:158d0002fb4e94:ch2', 'DOUBLE_PRESSED')],
  execute: data => {
    items.getItem("LUMILumiRelayC2Acn01200158D00067C96F71Switch").sendCommand("ON");
  }
});

But this is not good for UI scripting. I was looking for some simple examples but I can’t find any suitable for me.

All you define in a UI rule Script Action is the execute part. Everything else is defined in the form. You only use JSRule or the time Builder in .js files.

I have posted all of my complete JSScripting rules at Some JS Scripting UI Rules Examples. Since are simple, some are complex. Skip to the actual rules which come after the libraries.