Converting DSL rule to GraalJS script

This is my first attempt to convert one of my DSL rules to the new JS engine.
Rules DSL:

gLampen.members.filter(g | (g.getStateAs(OnOffType)) == ON).forEach[g | g.sendCommand(OFF)]

JS:

var OnOffType = Java.type("org.openhab.core.library.types.OnOffType");
items.getItem("gLampen").members.filter(i => i.getStateAs(OnOffType) == ON).forEach(function(i) {i.sendCommand("OFF");});

I already tried various approaches:

  • OnOffType.class instead of OnOffType
  • i.state.as instead of getStateAs

No matter what I try I always get the following errors:

[WARN ] [.internal.OpenhabGraalJSScriptEngine] - Failed to retrieve script script dependency listener from engine bindings. Script dependency tracking will be disabled.

and either
"OnOffType" is not defined
or
i.state.as is not a function.

I can’t help you with the JS script side (which I know was your ask…). But if you want to use the JRuby library instead, what I think that code is trying to do is turn off any members of gLampen that are currently ON is that correct?

The JRuby with helper library would be:
gLampen.ensure.off

That warning is something you can ignore for now. I get it too and it has something to do with the loading of the helper library as far as I can tell. All it’s telling us is that it’s not going to be able to monitor the library and load a new version should a new version appear. This is unlikely to happen for most users so it can be ignored.

Here it’s going to be important to pay special attention to the docs for the add-on. The library does a very good job of converting everything to native JavaScript Objects and types instead of exposing the Java classes that openHAB uses.

So looking at the docs we see that .members returns a JavaScript Array, not a java.util.Collections. The members of that Array are a JavaScript Item which has a somewhat different set of methods than you might be used to. See JavaScript Scripting - Automation | openHAB.

Unfortunately you will find that getStateAs() isn’t defined. This is indeed a significant omission so I’d request that you file an issue on the openhab-js repo: GitHub - openhab/openhab-js: openHAB JavaScript Library for JavaScript Scripting Automation.

It really should be there.

In the mean time, I think we can still get at the Java Item Object. Looking at the code it looks like the following should work:

items.getItem("gLampen").members
                        .filter(i => i.rawItem.getStateAs(OnOffType) == OnOffType.ON)
                        .forEach( i => i.sendCommand("OFF"));

However, is there a technical reason you wouldn’t want to send OFF commands to lights that are already OFF? If that doesn’t cause problems it might be as simple as

items.getItem("gLampen").sendCommand("OFF");
1 Like

Firt of all let me say that I honestly appreciate your help and that without your help I would not have developed such an enthusiasm about openHAB. If I can buy you a beer, please let me know…

done

Wow.Kudos to you. Would have never accomplished this on my own.
But be sure that the time you spent is a good invest as I am 100% willing to learn and pass on as much as I can to others.

Yes.

  • My device is “reacting” on OFF commands although being in an OFF state
  • If in the future there are 30 devices being controlled, the script takes too much time
  • From a development perspective I think it is better style

Just to mention out of completeness: there is also an interesting new command available:

.sendCommandIfDifferent()

I figured that out by looking at the code for the library. I’ve taken a note to add a comment to the docs that when you need to do something that the library doesn’t support we have access to the raw Java Item Object.

Must be a super duper slow machine. But note that it’s not the script that is processing it, it’s core openHAB. It’s all done on the event bus. Your script will return almost instantly.

I thought there was but couldn’t remember if it was this library or the old Nashorn one.

Anyway, as a reference document, the current docs for the add-on are really quite complete and you can even click through to get to the raw source code. It should be everyone’s first place to look.

I would use the following code:

items.getItem("gLampen").members.filter(i => i.state === "ON").forEach(function(i) {i.sendCommand("OFF");});

Instead of dealing with any raw Java type.

the reason for dealing with rawItem is to use getStateAs(OnOffType) == OnOffType.ON which directly filters also all dimmers where the brightness level is > 0

Thanks for getting back on this :slight_smile:

You could use this code here:

items.getItem("gLampen").members.filter(i => i.state !== "OFF" && i.state !== "0").forEach(function(i) { i.sendCommand("OFF"); });

Yes, and maybe some items might have 0.0, 0.00 or even 0.0000000 as number format which I also need to care of. Me, as a non-coder, I thought getStateAs method is quite elegant. But probably not. Are there any concerns regarding rawItem.getStateAs?

This could be handled by parsing the state to float and comparing with float, but I have to admit that the OnOffType solution is easier then (at least for a “non-coder”).

It is elegant. There are not really larger concerns about using it, just remember that it is a Java Type and you cannot handle it like a JS type. There are some incompatibilities between Java and JS types.

ok. sounds reasonable without not knowing in detail what you mean nor what the consequences might be.
as you seem to be German, too, let me answer with a saying:
dumm lebt sich’s einfacher :slight_smile:

:joy:

I guess it is easier for both of us if I explain in German what I meant to say:

Also du kannst den OnOffType und .rawState.getStateAs benutzen, dass macht deinen Code auf jeden Fall kĂĽrzer da OnOffType.OFF nunmal OFF fĂĽr Switch Items ist aber auch 0 fĂĽr Dimmer Items etc.
In dem Zusammenhang habe ich da keine Bedenken, aber der OnOffType ist halt nunmal ein Java Objekt (openHAB ist ja in Java geschrieben) und kein JavaScript Objekt, dass kann zu Problemen fĂĽhren wenn du dann OnOffType mit JavaScript vergleichen willst, z.B. OnOffType === "ON" funktionier denke ich nicht.