Rule errors in script written with UI

  • Platform information:
    • Hardware: Raspberry Pi 3
    • OS: what OS is used and which version
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version:2.5.7

Hello, I am a new enthusiast that started off with the newest HestiaPi image that has Openhab 2.5.7 on it and have been building from there. I have successfully set up an external humidity and temp sensor with mqtt on an ESP32 with Tasmota with the UI and that was mostly trouble free, but now when I am trying to write a script within a rule(also via the UI) that utilizes the values from those item states, I cannot seem to get it working, I have mimicked examples of what I have found on the forum and nothing seems to work. Here is the code I have written, and the errors that show up in the logs. Thank you in advance for any help!

var Number; temp = (ESP32LED_SHT31Temp.state)
var Number; hum = (ESP32LED_SHT3XHumidity.state)

var Number; numeratora = -.076819*temp
var Number; numeratorb = 13.9005+numeratora
var Number; denominatora = 1/hum
var Number; denominatorb = denominatora-1
var Number; exponent = 1/2.96243
var Number; denominatorc = Math.pow(denominatorb,exponent)
2022-03-07 23:00:00.758 [ERROR] [internal.handler.ScriptActionHandler] - Script execution failed: ReferenceError: "ESP32LED_SHT31Temp" is not defined in <eval> at line number 1

remove the ; between Number and your variables.

That’s really old. Beware that most forum traffic for the last couple of years involves OH3. Before that, few people used GUI to enter DSL language rules in OH2. So you are a bit out on a limb here.

If you are sticking with OH2, you should at least consider updating to final version 2.5.12

You may have troubles with any update or add-on installation, because online respositories are no longer available.

Ok, I will try removing the semi colons. I inquired on the hestiapi forum about updating to OH3 when I first started using it but they said that would break many of the rules. I believe I have seen @rlkoshak pretty active over on that forum, I think he’s had a hand in all that so maybe he can chime in as to whether that’s a possibility.rlkoshak

If updating isn’t a possibility, could I set up another OpenHab server with everything I want to do besides run my thermostat, but still be able to view both servers easily from the app?

Tried removing the semi colons and this was the result.

var Number temp = (ESP32LED_SHT31Temp.state)
var Number hum = (ESP32LED_SHT3XHumidity.state)

var Number numeratora = -.076819*temp
var Number numeratorb = 13.9005+numeratora
var Number denominatora = 1/hum
var Number denominatorb = denominatora-1
var Number exponent = 1/2.96243
var Number denominatorc = Math.pow(denominatorb,exponent)
2022-03-08 07:35:01.731 [ERROR] [internal.handler.ScriptActionHandler] - Script execution failed: <eval>:1:11 Expected ; but found temp
var Number temp = (ESP32LED_SHT31Temp.state)
           ^ in <eval> at line number 1 at column number 11

Whatever it is you are doing in GUI, you are not entering into a section that expects DSL language. Javascript perhaps?

I am inputting it into the script portion of the GUI rules. It says it wants ECMA Script, is that my problem? I thought that was supposed to be Javascript and thought that was what I was using but maybe not?

Yes. Most of the old examples you find for general-purpose openHAB are in DSL language, similar looking but different syntax and features.

Exactly what features you get on hestiapi stripped down OH, and what add-on library support you get for javascript - I’ve no idea.
I’d suggest a hard look at existing examples in hestiapi forum.

I don’t know how many rules it will break but it will definitely require reworking most of the Things. I suspect there are a few breaking changes in the rules. For sure executeCommandLine and stuff like that changed.

It’s also not completely clear whether or not OH 3 will perform the same on an RPi 0W. Upgrading from 2.5.7 to 2.5.12 shouldn’t be a problem though.

I think the biggest issue with upgrading to OH 3 is they want to upgrade the whole thing, OS and all, since I think it’s still running on Wheezy. The problem is a lot of the tools and such they use outside of OH don’t support the newer OS. So there’s lots of work still to be done.

The rules need a lot of work to take advantage of capabilities provided by OH like units of measurement and such but I think we are all waiting to see what happens with the upgrade first.

What language are you trying to use there? It looks like a mix of Rules DSL and ECMAScript 5.1.

All the rules in HestiaPi are written in ECMAScript 5.1 in the UI. If you are looking for examples look there first.

ECMAScript is weakly typed. You don’t specify the type when you define a variable. You just assign it.

It’s ECMAScript 5.1 written in PaperUI (painful but required for performance).

You will notice a lot of differences in how to write for that and what you’ve attempted. Something like this might work

var temp = items['ESP32LED_SHT31Temp'].floatValue(); // what if it's NULL or UNDEF? you'll have to handle that, assumes there are no units
var hum = items['ESP32LED_SHT3XHumidity'].floatValue(); // see above

var numeratora = -.076819*temp;
var numeratorb = 13.9005+numeratora;
var denominatora = 1/hum;
var denominatorb = denominatora-1;
var exponent = 1/2.96243;
var denominatorc = Math.pow(denominatorb, exponent);
var result = numeratorb/denominatorc;

events.postUpdate('EMC_Calculation', result.toString());
var Log = java.type('org.openhab.core.model.script.actions.Log');
Log.logInfo('caculation', result); // logInfo takes two arguments, a logger name and the log statement

There are a number of subtile changes. Can you pick them all out? They all have to deal with interactions with Items.

  • Items do not exist by name alone in ECMAScript. You can’t just access an Item by using its name as if it were a defined variable.
  • In ECMAScript the best way to get the state of an Item is through the items dict.
  • The sendCommand or postUpdate you must use events. Both take two strings as arguments, the name of the Item and the string representation of the state or command.
  • When you postUpdate or sendCommand to an Item, the call doesn’t block until the Item changes state. If you try to log out or use the state of an Item immediately after updating it, the Item will almost always still be the old state, not the new one. You already know what state the Item is supposed to be, log that.
  • logInfo always takes two arguments.
  • As previously mentioned, an Item doesn’t exist by name as a variable on it’s own. But even if it did, logging it like that is unlikely to give you what you expect. It will just log “object” because, indeed, it’s an Object. What you want is the .toString() representation of the Object. But a Item is way more than just its state. So when you log the Item’s toString() you’re going to get a whole lot more than just the state. If you just want to log the state, you need to log the toString of the state. As perviously shown, the easiest way to get an Item’s state is from the items dict.

It didn’t like that either, I’m assuming that means that the value is Null for some reason on one of those items? It shouldn’t be because both of those items are updating to the sitemap just fine… So would my best bet for simplicity to use another openhab server and put everything aside from my thermostat on there? Would it be possible to view them both on the same app though if that was the case?

2022-03-08 08:58:53.112 [WARN ] [e.automation.internal.RuleEngineImpl] - Fail to execute action: 2
java.lang.IllegalArgumentException: The argument 'state' must not be null.
        at ~[?:?]
        at ~[?:?]
        at ~[?:?]
        at ~[?:?]
        at org.openhab.core.automation.module.script.internal.defaultscope.ScriptBusEvent.postUpdate( ~[?:?]
        at jdk.nashorn.internal.scripts.Script$1018$\^eval\_.:program(<eval>:12) ~[?:?]
        at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke( ~[nashorn.jar:?]
        at jdk.nashorn.internal.runtime.ScriptFunction.invoke( ~[nashorn.jar:?]
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply( ~[nashorn.jar:?]
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl( ~[nashorn.jar:?]
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl( ~[nashorn.jar:?]
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl( ~[nashorn.jar:?]
        at jdk.nashorn.api.scripting.NashornScriptEngine.eval( ~[nashorn.jar:?]
        at javax.script.AbstractScriptEngine.eval( ~[?:1.8.0_222]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.lambda$0( ~[?:?]
        at java.util.Optional.ifPresent( ~[?:1.8.0_222]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.execute( ~[?:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.executeActions( [bundleFile:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.runNow( [bundleFile:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.runNow( [bundleFile:?]
        at [bundleFile:?]
        at sun.reflect.GeneratedMethodAccessor467.invoke(Unknown Source) ~[?:?]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[?:1.8.0_222]
        at java.lang.reflect.Method.invoke( ~[?:1.8.0_222]
        at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke( [bundleFile:?]
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$ [bundleFile:?]
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke( [bundleFile:?]
        at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch( [bundleFile:?]
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch( [bundleFile:?]
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke( [bundleFile:?]
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply( [bundleFile:?]
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply( [bundleFile:?]
        at org.glassfish.jersey.server.ServerRuntime$ [bundleFile:?]
        at org.glassfish.jersey.internal.Errors$ [bundleFile:?]
        at org.glassfish.jersey.internal.Errors$ [bundleFile:?]
        at org.glassfish.jersey.internal.Errors.process( [bundleFile:?]
        at org.glassfish.jersey.internal.Errors.process( [bundleFile:?]
        at org.glassfish.jersey.internal.Errors.process( [bundleFile:?]
        at org.glassfish.jersey.process.internal.RequestScope.runInScope( [bundleFile:?]
        at org.glassfish.jersey.server.ServerRuntime.process( [bundleFile:?]
        at org.glassfish.jersey.server.ApplicationHandler.handle( [bundleFile:?]
        at org.glassfish.jersey.servlet.WebComponent.serviceImpl( [bundleFile:?]
        at org.glassfish.jersey.servlet.WebComponent.service( [bundleFile:?]
        at org.glassfish.jersey.servlet.ServletContainer.service( [bundleFile:?]
        at org.glassfish.jersey.servlet.ServletContainer.service( [bundleFile:?]
        at org.glassfish.jersey.servlet.ServletContainer.service( [bundleFile:?]
        at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service( [bundleFile:?]
        at org.eclipse.jetty.servlet.ServletHolder.handle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler.doHandle( [bundleFile:9.4.20.v20190813]
        at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle( [bundleFile:?]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle( [bundleFile:9.4.20.v20190813]
        at [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.session.SessionHandler.doHandle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle( [bundleFile:9.4.20.v20190813]
        at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle( [bundleFile:?]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.servlet.ServletHandler.doScope( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.session.SessionHandler.doScope( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ContextHandler.doScope( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.handler.ScopedHandler.handle( [bundleFile:9.4.20.v20190813]
        at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle( [bundleFile:?]
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.Server.handle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.HttpChannel.handle( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.server.HttpConnection.onFillable( [bundleFile:9.4.20.v20190813]
        at$ReadCallback.succeeded( [bundleFile:9.4.20.v20190813]
        at [bundleFile:9.4.20.v20190813]
        at$ [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce( [bundleFile:9.4.20.v20190813]
        at [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob( [bundleFile:9.4.20.v20190813]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$ [bundleFile:9.4.20.v20190813]
        at [?:1.8.0_222]
2022-03-08 08:59:00.852 [ERROR] [e.automation.internal.RuleEngineImpl] - Failed to execute rule 'e2814131-2632-4836-8aa9-c9b8411668b5': Fail to execute action: 2

Unfortunately the error doesn’t give the error line but it’s complaining about a “state” argument. The only place in that code where there is a state argument is the call to events.postUpdate(). state is the second argument. So it’s saying that result.toString() is null (do not confuse null with the special Item states NULL and UNDEF which are completely different). That means that counter to my expectation the result of the calculation is a JavaScript primitive (I should have figured that but it’s been months since I’ve worked with the pain of JSR223 JavaScript without a helper library).


events.postUpdate('EMC_Calculation', result);

and if that doesn’t work try

events.postUpdate('EMC_Calculation', ''+result);

Yes, that is what I would recommend. I like to push the smarts out to the edges where possible so I would recommend making the thermostat as stand alone as possible so it can operate on its own even if the network is down. Then the home automation would push “intents” to the thermostat (I want the temp to be X, boost for 20 minutes, etc) and the thermostat takes care of the rest on it’s own.

I really would recommend using OH 3 if possible so for that reason too I’d keep the HestiaPi it’s own thing and host the rest of your home automation on a separate OH instance on a separate machine. Then you can use Blockly or JS Scripting which is a much better experience. Or you can use Rules DSL in the web based rules which will make it easier to use and apply older examples.

There are several options for this. Probably the easiest would be to use the Remote openHAB binding on the OH 3 instance which will let you mirror all the Items on the 2.5 instance. A little more hands off approach would be to use MQTT and publish/subscribe to the MQTT topics that are already used on the HestiaPi to adjust the mode and setpoints and boost mode and such.

Ok, I tried both of those options, and it returned the same error. I have a raspberry pi 4 that I purchased with the intent of moving the thermostat onto, but I will just use that as a separate server to simplify things and make it easier to learn from previous posts so I don’t have to take up a bunch of your time! Thank you for the help and suggestions!!