Triggering a rule in Paper UI causes an exception if the rule has not already been triggered elsewhere

Continuing discussion from here…

You weren’t talking about the Experimental Rules Engine then, but creation of rules through the Paper UI. Let’s take a step back and clarify some terminology. JSR223 creates rules through the Java (Automation) API, and Paper UI creates rules through JSON, but both are using the ERE. The actual rules, if they have the same Triggers, Conditions and Actions, are exactly the same, from the rule engine’s perspective. Also, the Javascript in a rule Action is interchangeable between JSR223-JS and JSON rules. Hopefully, Jython support will also be added to JSON rules.

I only see the one line in your example. Without an import, you will not be able to use executeCommandLine, createTimer, or other core Actions. One of the people using JS might have another option for you, but this worked just fine for me in both a JSR223-JS script and in a Paper UI rule…

'use strict';
var log = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");
var Exec = Java.type("org.eclipse.smarthome.model.script.actions.Exec");
var test = Exec.executeCommandLine("echo hello world", 5000);
log.info("JSR223: JS: Test executeCommandLine [" + test + "]");

As I explained above, if it works in JSR223, then it is working in the ERE. If it works in the ERE, but not in Paper UI, then there is a bug in Paper UI, the resource bundles (JSON files), or the classes that consume the resource bundles. To verify that a JS Action is functional, you could try it in JSR223 by saving the script in /automation/jsr223/ and checking the logs. If there is an error, then your script has an issue. If it works, but doesn’t work in a rule created in Paper UI, then there is likely a bug that should be reported.

Hopefully this helped to clarify the terminology a bit, and this thread can bring more questions about Javascript Actions.

2 Likes

A couple issues here then.

  1. Where is/should this documented? Right now to indicate that the ERE rules and JSR223 Rules are the same. They are created differently (ERE uses PaperUI, JSR223 uses text files), stored differently (ERE Rules are stored in the JSONDB), and neither docs (unless I missed it) reference the other. As far as most users will be concerned, the PaperUI UI IS the ERE. As far as I was concerned, the JSON that gets saved to JSONDB for each Rule is the ERE (or at least the code the ERE runs).
    So knowing that both use the same run time engine is helpful information to know. However, from a practical perspective this distinction is one that will only be important and only make sense for users who are working at a very low level in OH. The types of people who are trying to use the ERE right now are going to think that the PaperUI Rules entry forms are the ERE. So do we need to invent a new name to avoid this confusion? Because for the most part, I suspect that at this point in time only you and the devs working with the ERE and JSR223 will think JSR223 when they see ERE. The rest of us will think either the PaperUI UI or JSONDB Rules that it produces.

  2. For the JSON Rules, why do I have to import anything? Everything else about this Rule is already done for us, defining the trigger, defining the conditions under which the Rule can run (but only if), etc. Everything I need to define the body of the Rule should already be there and I should only have to start writing my script.

In short, I should only need to have that one line to write a Rule in the ERE UI and use core OH Actions. All of that proforma type stuff should already be there and all I should have to write are the actions that do what needs to be done when that Rule is triggered.

I copied and pasted that code and I get exceptions:

2018-10-24 09:15:19.955 [WARN ] [omation.core.internal.RuleEngineImpl] - Fail to execute action: 2
java.lang.RuntimeException: java.lang.ClassNotFoundException: org.eclipse.smarthome.model.script.actions.Exec cannot be found by com.eclipsesource.jaxrs.publisher_5.3.1.201602281253
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:397) ~[?:?]
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:449) ~[?:?]
...

That is why I was assuming that the JSON DB Rules and JSR223 are fundamentally different. I did try.

Then I’ll need more help to explain what I’m doing wrong. Because everything I try to replicate from https://github.com/lewie/openhab2-javascript fails to work when entered into the PaperUI scripts. Particularly since the code you pasted in above works for you and an exact copy and paste of it throws ClassNotFoundExceptions for me.

I’d like to get this stuff working because, try as we might to prevent it, new users keep trying to use PaperUI Rules and there are no docs and no experience from the users on this forum to help and this will only get worse. I’d like to get out in front of this and start generating some docs.

I should note that log import and call does work. It is dumb but I’ve never tried just a basic hello world logging Rule. So logging works and works the same as JSR223 JavaScript. But executeCommandLine, at least for me, does not work and I’d really love to know why. If I can log, create Timers (I’m about to experiment with that), call the core Actions, and access the implicit variables (or the JS equivalents) I’ll have enough to start building comprehensive documentation.

Oh, and how to import JS libraries would be terribly helpful as well.

Thanks for the info. You have been very helpful. Getting the logger to work might be just enough to help me figure some of these things out on my own.

Update: I tried to create a Timer with

'use strict';
var log = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");
log.info("test", "Hello world")

var ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution");
ScriptExecution.createTimer(now().plusSeconds(2), function(){log.info("test", "timer log");});

And I get a ClassNotFoundException for org.eclipse.smarthome.model.script.actions.ScriptExecution.

The log import and log.info works.

I’ll post more later, but I can reproduce the exception using snapshot 1392. This looks to be recently introduced, since 1390 does not have the issue. You might want to try that build while this is being resolved…

I’m on build 1380.

Ug… I got it. At least I really think I got it this time. I got 1392 working without the exception, and can then reproduce it.

Try modifying the rule, doesn’t matter what you change… could be the name. Save the rule and DON"T execute from Paper UI. Trigger the rule though the Item. I use smarthome:send Test_Switch_1 ON from Karaf. No exception. Then try triggering the rule through Paper UI. No exception.

To reproduce the exception, modify/save the rule, then execute through Paper UI. Exception. Trigger through Item. Exception.

Seems the first trigger must not be through Paper UI, or you will get the exception. Once triggered from something other than Paper UI, you can then trigger through Paper UI. AND I have only see the exception if the Rule Action contains Javascript with a Core Action, but I expect it has something to do with imports than specifically Core Action imports.

How’s them apples!

Before spending too much more time on this I’m learning a bunch of stuff through my experiments. I’m about to post a big long posting with all my results and turn it into a wiki to gather more data from others. That’s why I created a new post instead of replying here.

But my most recent discovery (copied from the posting in progress):

Get a list of all available Properties

'use strict';

function getProps(obj) {
  var result = [];
  for(var propName in obj) {
    result.push(propName);
  }
  return result;
}

var myLog = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");

myLog.info("---------------------------")
myLog.info(getProps(this).join("\n"));
2018-10-24 14:07:28.275 [INFO ] [eclipse.smarthome.model.script.Rules] - ---------------------------
2018-10-24 14:07:28.279 [INFO ] [eclipse.smarthome.model.script.Rules] - se
scriptExtension
voice
audio
DOWN
FileUtils
StringType
rules
NextPreviousType
PLAY
ImperialUnits
INCREASE
OpenClosedType
things
UP
RawType
StringListType
events
SIUnits
itemRegistry
NULL
STOP
UnDefType
ir
RewindFastforwardType
DateTimeType
QuantityType
State
DecimalType
IncreaseDecreaseType
File
items
CLOSED
MetricPrefix
DECREASE
OFF
StopMoveType
PREVIOUS
PAUSE
StringUtils
NEXT
REWIND
URLEncoder
HSBType
ON
SmartHomeUnits
UpDownType
PercentType
FilenameUtils
OPEN
Command
OnOffType
MOVE
PlayPauseType
FASTFORWARD
PointType
UNDEF
ctx
ruleUID
getProps
getMethods
myLog

So what do we see here. The majority of the Objects are Item commands and State Types. What else do we have?

Object Purpose
se ???
scriptExtension ???
voice ???
audio ??
FileUtils ???
rules ???
ImperialUnits/SIUnits/MetricPrefix/SmartHomeUnits For unit conversion?
things Access to the Things registry?
events ???
itemRegistry Access to the Items registry
ir ???
File ???
items List of all the Items (how different from itemRegistry?)
StringUtils ???
URLEncoder ???
FilenameUtils ???
ctx ???
ruleUID ???
myLog The logger variable I created in my Rule
getProps Function defined in the Rule to get the properties on an Object
getMethods function defined in the Rule to get the accessible methods on an Object

I think I’m about to successfully create a Timer. I just need to figure out the right way to get access to now.

I DON’t need to import everything, I just needed a way to figure out what was already imported. Thank goodness for StackOverflow. :wink: I’ve tagged you in that post and you will see it shortly. We might be in better shape than I thought.

Though it definitely does appear you have uncovered a bug with triggering from within PaperUI. But so far, if I use what is imported for me instead of trying to import it myself I’ve not encountered any problems.

This shows what is included in the default scope (includes JS rule Actions)…

I’ll change the title of this post to just be more specific about this issue.

Never mind, I’m still stuck.

I can confirm part of what you observed. If I trigger the Rule with an Item I just get

Failed to execute rule '8d37ea74-08b7-4c24-b0ab-a5c5ebf91877': Fail to execute action: 2

and when I trigger it from PaperUI I get the class not found exception. But I was not able to successfully trigger the Rule from PaperUI, even after successfully triggering it using an Item.

Check my first post. There were some semicolons missing (wasn’t an issue, but cleaner with them) and the logging at DEBUG. Unless you have org.eclipse.smarthome.model.script.Rules set for DEBUG logging, you wouldn’t see that the rule actually triggered. I’ve set it to info now.

I fixed both issues i mine already:

'use strict';

var myLog = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");

myLog.info("createTimer---------------------------");
myLog.info("creating timer...");
var ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution");
var LocalDateTime = Java.type("java.time.LocalDateTime");
var fnc = function(){
    myLog.info("In timer");
}
scriptExtension.createTimer(LocalDateTime.now().plusSeconds(2), fnc);

I’m sure it is something I’m doing wrong.

My next thing to try will be seeing if I can import the JS library from the automation folder. If I can then perhaps a lot of this stuff becomes moot.

Check scriptExecution call… missing capital S.

Same result.

There are two errors there. Lower case s and it should be ScriptExecution, not ScriptExtension. I fixed both, same errors.

Gotta run, but will do some more testing tonight.

Thanks for the help!

Looks like createTimer expects a org.joda.time.base.AbstractInstant. I didn’t run into this with Jython, because I was already using Joda Time. Strange though, because I thought ESH had already removed Joda Time from everything. This should work. Easy to test by just running it in a script in /automation/jsr223/

'use strict';
var myLog = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");
myLog.info("createTimer---------------------------");
var ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution");
//var LocalDateTime = Java.type("java.time.LocalDateTime");
var DateTime = Java.type("org.joda.time.DateTime");
var fnc = function(){
    myLog.info("Timer completed");
}
myLog.info("Creating timer...");
//ScriptExecution.createTimer(LocalDateTime.now().plusSeconds(5), fnc);
//2018-10-24 20:20:25.622 [ERROR] [org.eclipse.smarthome.automation.module.script.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/opt/openhab2/conf/automation/jsr223/test/testScript2.js': Cannot cast java.time.LocalDateTime to org.joda.time.base.AbstractInstant
ScriptExecution.createTimer(DateTime.now().plusSeconds(5), fnc);

OK, so here is what I’ve done since the last posting.

  1. Upgraded to build 1400
  2. Downloaded the JS library and put it into the automation folder and verified that the scripts get picked up
  3. Tried importing the library and using the logInfo function defined in the library
'use strict';

load('./../conf/automation/jsr223/jslib/JSRule.js');

logInfo("Using the library!");
  1. Just now I tried the code you just posted.
'use strict';

//load('./../conf/automation/jsr223/jslib/JSRule.js');

//logInfo("Using the library!");

var myLog = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.model.script.Rules");
myLog.info("createTimer---------------------------");
var ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution");
//var LocalDateTime = Java.type("java.time.LocalDateTime");
var DateTime = Java.type("org.joda.time.DateTime");
var fnc = function(){
    myLog.info("Timer completed");
}
myLog.info("Creating timer...");
ScriptExecution.createTimer(DateTime.now().plusSeconds(5), fnc);

In all cases I get the ClassNotFoundException when I attempt to trigger the Rule from PaperUI and I get Failed to execute rule '8d37ea74-08b7-4c24-b0ab-a5c5ebf9 1877': Fail to execute action: 2 when I trigger the Rule by Item.

I’ll also note that one of the test scripts that the library comes with also fails with a complaint that DateTime doesn’t exit:

Error during evaluation of script 'file:/openhab/conf/au
tomation/jsr223/AccessibleFromAutomation.js': ReferenceError: "DateTime" is not defined in <eval> at line number 65

which makes some sense as the line that defines DateTime in helper.js is commented out

helper.js:	//var DateTime 				= Java.type("org.joda.time.DateTime");
helper.js:	var LocalDateTime 			= Java.type("java.time.LocalDateTime");
helper.js:	var OffsetDateTime 			= Java.type("java.time.OffsetDateTime");

I can’t say what this tells us, if anything.

When I uncomment that line the AccessibleFromAutomation.js works as expected.

Me either :smile:

But it seems like you may be complicating things. It might be worth going after correcting the error before adding more layers. And I’m not going to be much help with any of the JS extensions. Maybe @lewie could assist with them.

If you create a new rule using Paper UI with a JS Action, then trigger it with an Item, will it run without an exception? That is what I am seeing. You should hopefully then be able to trigger it through the Paper UI, as long as you don’t edit it. Well, you can edit it, but always trigger it through the Item first or you will get the exception.

BTW, I do not see a build 1400 in Cloudbees, but I’ve seen some people mention it in the forum. It should include the fix I put in for ItemStateTriggerHandler.

Looks like they are moving off of Cloudbees… https://ci.openhab.org/view/Integration%20Builds/builds.

I’m not adding layers. I’m trying different things out in isolation just trying to find something that works. For example I’m not trying to use the code above to create the Timer at the same time as loading the library. I’m testing them separately.

Success! So the bug you identified above totally kills the Rule from running ever. I was assuming that a restart would clear that bug out of the way.

I just had a Timer successfully run, first triggered by an Item and then triggered from PaperUI.

I went in and changed the Rule to use LocalDateTime and I received the ClassNotFoundException again, which I mostly expected to happen. I deleted the Rule and created another one this time using LocalDateTime. As you saw when you ran it I get the exception about wanting the Joda class.

I now edited the Rule again, just for grins to test out the JS library. This time I triggered it first from the Item and it too ran without error.

So it would seem the bug above has been the cause of ALL my problems. Grrr.

I run in Docker so all I know is the build number from whatever snapshot I pulled from Dockerhub today claims build 1400.

It would seem I’m over the hump and can start figuring things out in a more systemized manner.

Thanks!

Excellent! I’m excited that you are drilling in to the ERE. I’m thinking most of the openhab2-Jython repo documentation could be moved into the official docs. But I’m also thinking through how to best share scripts and modules. JSR223-JS and even JS Actions should also be considered. I’m leaning towards GH. IMO, the forum isn’t suitable, although you’ve been able to centralize a lot of the Rules DSL with the DPs. I’m curious what your thoughts are. Probably a good topic to bring to the forum too.

I’ve also been asking the forum admins about creating a category for the new rule engine, with subcategories for JSR223, etc., but haven’t gotten a response yet.

It seems that the builds are no longer there but now here:
https://ci.openhab.org/job/openHAB-Distribution/

I also missed that somehow at first…