OH3 How to load Javascript rules.js?

I don’t think “smarthome” should be turning up in OH3

This might help

Thanks for your reply. The link to Ivan’s Helper libs is an example of what I was referring to when I wrote “and other instructions that mention that link only befuddle me more.” I certainly installed his software under my /etc/openhab/automation .

Your observation about “smarthome” is interesting. I did buy and deploy eight HS103 Smart Wi-Fi Plug Lites as shown at TP-Link Smart Home - Bindings | openHAB and downloaded and installed the add-on. It worked wonderfully at finding and binding to the smart sockets.

So perhaps the smarthome add-on does not get along with Javascript in the OH3 environment?

The “smarthome” referred to in this context is essentially the openHAB project, and nothing to do with your plugs or binding add-on.

Or rather it was the project for OH2, and references to it have been removed from OH3 and simply won’t work anymore. It’s a history thing from when openHAB was more closely associated with Eclipse Smarthome.

I would imagine you’ve installed an OH2 version of some library, or followed some OH2 instruction, or possibly uncovered some oversight in the library updating from OH2 to OH3.
That’s why I pointed you at @CrazyIvan359 post about OH3 javascript library.

Of note from there -

you need to use the js-rewrite branch, which the link in my paragraph about JS should link to

That branch is a work in progress and contains several breaking changes.

As rossko points to, you will need to use my js-rewrite branch to get your rules working. The problem is the old rules.js file trying to import things from places they aren’t anymore. My update mirrors the behaviour of the Python Helper Libraries in that it looks for them in the OH2 location and the OH3 location and uses the one it finds.

Still no difference. The instructions step 11 say " Download the standalone Jython 2.7.0 jar and copy it to the path specified above in the EXTRA_JAVA_OPTS" yet the link to the jar file is broken. Do I need that file? If so, where to find it?

Thanks!

google for:
jithon standalone 2.7.0.jar

If you read my post that was linked you will find modified instructions. Also follow the ones for JavaScript, you are quoting from the Python instructions.

Thanks for the clarifications. Starting with a fresh install of OH3 “Version: 3.0.1 (Build)” with no bindings added, I believe I followed your instructions using openhab-helper-libraries-js-rewrite.zip which unzipped into a directory of the same name (sans .zip) with a date of “Feb 6 11:08”. I did not try to enable python… Here is the /var/log/openhab/openhab.log after restart:

2021-03-25 15:06:10.179 [INFO ] [.core.internal.i18n.I18nProviderImpl] - Time zone set to 'America/Los_Angeles'.
2021-03-25 15:06:10.193 [INFO ] [.core.internal.i18n.I18nProviderImpl] - Location set to '37.396981135702525,-122.12268233299257'.
2021-03-25 15:06:10.195 [INFO ] [.core.internal.i18n.I18nProviderImpl] - Locale set to 'en_US'.
2021-03-25 15:06:10.738 [DEBUG] [ipt.internal.ScriptEngineManagerImpl] - Initialized a generic ScriptEngineFactory for Oracle Nashorn (11.0.10): supports ECMAScript (ECMA - 262 Edition 5.1) with file extensions [js], names [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript], and mimetypes [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
2021-03-25 15:06:10.746 [DEBUG] [ipt.internal.ScriptEngineManagerImpl] - Initialized a custom ScriptEngineFactory for Oracle Nashorn (11.0.10): supports ECMAScript (ECMA - 262 Edition 5.1) with file extensions [js], names [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript], and mimetypes [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
2021-03-25 15:06:13.234 [DEBUG] [vider.AbstractResourceBundleProvider] - Parse rules from bundle 'org.openhab.core.automation'
2021-03-25 15:06:13.238 [DEBUG] [vider.AbstractResourceBundleProvider] - Parse rules from bundle 'org.openhab.core.automation.module.script.rulesupport'
2021-03-25 15:06:13.251 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added CoreModuleHandlerFactory
2021-03-25 15:06:13.252 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added TimerModuleHandlerFactory
2021-03-25 15:06:13.253 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added ScriptModuleHandlerFactory
2021-03-25 15:06:13.254 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added ScriptedCustomModuleHandlerFactory
2021-03-25 15:06:13.255 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added ScriptedPrivateModuleHandlerFactory
2021-03-25 15:06:13.256 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added AnnotatedActionModuleTypeProvider
2021-03-25 15:06:13.256 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added AnnotatedThingActionModuleTypeProvider
2021-03-25 15:06:13.257 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added EphemerisModuleHandlerFactory
2021-03-25 15:06:14.123 [INFO ] [.core.model.lsp.internal.ModelServer] - Started Language Server Protocol (LSP) service on port 5007
2021-03-25 15:06:14.125 [DEBUG] [ipt.internal.ScriptEngineManagerImpl] - Initialized a custom ScriptEngineFactory for null (null): supports Rule DSL (v1) with file extensions null, names null, and mimetypes [application/vnd.openhab.dsl.rule]
2021-03-25 15:06:14.907 [DEBUG] [e.automation.internal.RuleEngineImpl] - ModuleHandlerFactory added MediaModuleHandlerFactory
2021-03-25 15:06:14.951 [INFO ] [org.openhab.ui.internal.UIService   ] - Started UI on port 8080
2021-03-25 15:06:15.194 [INFO ] [ab.ui.habpanel.internal.HABPanelTile] - Started HABPanel at /habpanel
2021-03-25 15:06:15.302 [INFO ] [ab.core.service.AbstractWatchService] - ScriptEngine for py not available
2021-03-25 15:06:15.302 [INFO ] [ab.core.service.AbstractWatchService] - ScriptEngine for py not available
2021-03-25 15:06:15.303 [INFO ] [ab.core.service.AbstractWatchService] - ScriptEngine for py not available
2021-03-25 15:06:15.303 [INFO ] [ab.core.service.AbstractWatchService] - Loading script '/etc/openhab/automation/jsr223/javascript/personal/HelloWorld.js'
2021-03-25 15:06:15.945 [DEBUG] [ipt.internal.ScriptEngineManagerImpl] - Added ScriptEngine for language 'js' with identifier: file:/etc/openhab/automation/jsr223/javascript/personal/HelloWorld.js
2021-03-25 15:06:16.183 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab/automation/jsr223/javascript/personal/HelloWorld.js': ReferenceError: "JSRule" is not defined in <eval> at line number 7
2021-03-25 15:06:20.304 [INFO ] [e.automation.internal.RuleEngineImpl] - Rule engine started.

I hope I’m headed in the right direction.

This is weird, disturbing, hopefully not related: I could originally get to the Main UI by pointing my browser at “localhost:8080”, but after a reboot and restart, it no longer worked. Using my machine’s non-localhost address, 192.168.1…:8080 did work. I noticed that the OH javascript configuration.js file refernces “localhost”. Changing that file to use my IP address or my host’s DNS name makes no difference to this problem, but I wonder about future ones.

Thanks!

Now you’re getting somewhere! That hello world example won’t work, it uses the old JS rule syntax. If you look at the end of my first post that I linked to you will find the new syntax. I suggest you take the body of the current hello world example and get it working using the new syntax as an exercise to help you down the path of writing your rules.

I never found what you were referring to.

This is what I came up with. You can’t argue with success. Right?

'use strict';

var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
var JS_CORE = OPENHAB_CONF + "/automation/lib/javascript/core/";
load(JS_CORE + "rules.js");
load(JS_CORE + "triggers.js");
load(JS_CORE + "log.js");
var logger = getLogger("HelloWorld.js");

var execute = function() {
	logger.warn("Hello World! argc=" + arguments.length);
	for (var i = 0; i < arguments.length; i++) {
		logger.warn(i + ": " + typeof arguments[i]);
	}
};
execute.triggers = [ CronTrigger("10,20,40 * * * * ?", "cronTrigger") ];

var hwRule = rule(
	"Javascript Hello World",
	"mutated from HelloWorld.js example"
)(execute);

logger.warn("Is a rule just a glommed-upon function?: " + (hwRule === execute));

Thanks for your help.

There is a little section that expands at the end of the post.

Your rule works but you’re doing it the hard way. The libraries are meant to make writing rules easier.

So, I would not know how to submit an official gripe about the source code, but wrt line 56 of automation/lib/javascript/core/utils.js,

           if (itemRegistry.getItems(item) === []) {

comparing anything to a literal array can never yield a true value.

(subsequently edited code fragment to achieve correct rendering…)

itemRegistry.getItems() returns an array, if it did not find any matches that array will be empty. I have not done exhaustive tests on my work in JS, but I believe that check is used by validateItem and I have tested that function. If you are actually getting errors you can open an issue on the github repository linked to in my Helper Libraries post.

As for your other question, that has to do with formatting in the forum. Maybe you need to specify the language of your code block like this:

```javascript

// code goes here

```

I’ll add opening an issue to my todo list once I fathom gitHub.

Thank you for the formatting specification information. I edited my original posting to reflect it. It looks much better.

Do you have evidence of this comparison not working though?

I was not invoking validate_item. I was grepping around the Javascript code trying to find examples of invoking a sendCommand method after mapping a name to an item. Line 56 simply caught my eye.

If this is real Javascript, then I don’t have to demonstrate the assertion. However, I learned decades ago not to waste my superiors’ time (the rule also works with subordinates and peers), and since I remain suspicious of my understanding of openHab, I tested it before messaging you. I used the Scripts tab to demonstrate the assertion:

var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
var JS_CORE = OPENHAB_CONF + "/automation/lib/javascript/core/";
load(JS_CORE + "utils.js");
var logger = getLogger("validate_item_test");
var name = "aintNoOneByThatName";
var myItem = validate_item(name);
logger.warn("myItem=" + myItem);

Your paragraph was a little vague on whether the code you show did or did not fail to catch the non-existent item and you haven’t included the logs it would have generated.

I think you’re saying it did not work, so how would we fix it? My javascript knowledge and experience is limited, bear in mind this is ECMA Script 5 running in Nashorn. The function in question is a Java function and it returns a collection of some kind (a Set if I recall correctly) which will be empty if the item wasn’t found. How would we check for an empty Collection/Set/Array in javascript?

Yes, the test fails to catch the non-existent item. Here is a log of a failure:

2021-04-11 11:11:42.294 [WARN ] [e.automation.internal.RuleEngineImpl] - Fail to execute action: script
java.lang.RuntimeException: org.openhab.core.items.ItemNotFoundException: Item 'aintNoOneByThatName' could not be found in the item registry
	at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:531) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:456) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:413) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:409) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:162) ~[jdk.scripting.nashorn:?]
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264) ~[java.scripting:?]
	at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.lambda$0(ScriptActionHandler.java:62) ~[?:?]
	at java.util.Optional.ifPresent(Optional.java:183) ~[?:?]
	at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.execute(ScriptActionHandler.java:59) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1179) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.runNow(RuleEngineImpl.java:1031) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.runNow(RuleEngineImpl.java:1047) [bundleFile:?]
	at org.openhab.core.automation.rest.internal.RuleResource.runNow(RuleResource.java:314) [bundleFile:?]
	at jdk.internal.reflect.GeneratedMethodAccessor50.invoke(Unknown Source) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) [bundleFile:1.0.9]
	at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) [bundleFile:1.0.9]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) [bundleFile:1.0.9]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) [bundleFile:1.0.9]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) [bundleFile:1.0.9]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) [bundleFile:1.0.9]
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) [bundleFile:1.0.9]
	at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) [bundleFile:1.0.9]
	at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:216) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:301) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:220) [bundleFile:1.0.9]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) [bundleFile:3.1.0]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:276) [bundleFile:1.0.9]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:852) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:544) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:536) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1581) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1307) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) [bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:482) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1549) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1204) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [bundleFile:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.Server.handle(Server.java:494) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:374) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:268) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) [bundleFile:9.4.20.v20190813]
	at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: org.openhab.core.items.ItemNotFoundException: Item 'aintNoOneByThatName' could not be found in the item registry
	at org.openhab.core.internal.items.ItemRegistryImpl.getItem(ItemRegistryImpl.java:86) ~[?:?]
	at jdk.nashorn.internal.scripts.Script$Recompilation$167$1650A$utils.L:26#validate_item(/etc/openhab/automation/lib/javascript/core/utils.js:60) ~[?:?]
	at jdk.nashorn.internal.scripts.Script$Recompilation$4793$\^eval\_$cu1$restOf/0x00000007c1567040.:program(<eval>:6) ~[?:?]
	at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:655) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:527) ~[jdk.scripting.nashorn:?]
	... 65 more

I have zero Java experience and zero knowledge of how Java and Javascript can be glued together. Thus, I have no clues regarding a “Collection” or a “Set”. I am not anywhere near experienced enough with openHab for us to fix anything. But in ECMA Script 5 if you want to know if an Array is empty, then check its property length for 0.

If you are unsure that a value is an Array (it’s Javascript afterall…), then you can test it using the Array.isArray function.

Thanks for posting the log, you’re definitely right that the comparison is failing because that error is caused by calling itemRegistry.getItemwith an item name that doesn’t exist. validate_item doesn’t do that if the comparison in question fails.

Since the JS version of the libraries you are using is not merged yet, I decided a comment on that Pull Request made more sense. You can see it here and watch for progress on it. In the mean time, you could modify your file to use the correct way to check that an array is empty if you want.

I followed the link to the gitHub discussion and comprehended almost none of it. ES6 seems like a logical step in evolving Javascript into APL. -)

Thank you for your attention and toleration.