JRule - openHAB Rules using Java

Strange. And after a full openhab restart?

There is a sample user project here using Maven as build tool, but not anything specific for your choice of editor: GitHub - seaside1/jrule-user: JRule User Demo and Test Project - but I suspect it might not be fully up2date. @Seaside can confirm

Itā€™s on my big todo list :frowning: . But yes you should still be able to use it as a guidline for setting it up.

I am back on trying to get this to work now.
I am on a Debian machine, and installed OpenHab 4.1.2 via package. No Docker or other containers on the machine.

I normally watch the logs via openhab-cli log:tail.
I have done a service openhab restart, and get

11:23:54.870 [INFO ] [.internal.events.JRuleEventSubscriber] - [JRuleSubscriber] Event processing paused, queueing event Item 'gHumidity' changed from 64.4 to 64.5 through statusHumidity_CCSW

If I restart the bundle via bundle:restart 405, which I assume is the correct incantation where 405 is

405 ā”‚ Active ā”‚  80 ā”‚ 4.0.0.202404081933     ā”‚ openHAB Add-ons :: Bundles :: Standalone Java Rules Automation

I wonā€™t get any JRule messages:

11:28:55.335 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'statusHumidity_CCSW' changed from 71 to 70
11:28:55.337 [INFO ] [nhab.event.GroupItemStateChangedEvent] - Item 'gHumidity' changed from 64.5 to 64.4 through statusHumidity_CCSW
11:30:11.251 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'statusTemperature_CCN1' changed from 77 Ā°F to 76 Ā°F

I am suspecting Iā€™m missing some dependencies.

ā€¦ tracking down why this isnā€™t getting called:


    @Nullable
    private synchronized Boolean compileAndReloadRules() {
        eventSubscriber.pauseEventDelivery();
        compiler.compileRules();
        JRuleEngine.get().reset();
        createRuleInstances();
        logInfo("JRule Engine Rules Reloaded! {}", JRuleEngine.get().getRuleLoadingStatistics());
        eventSubscriber.resumeEventDelivery();
        return true;
    }

Turned up debugging

2024-05-09 12:04:16.637 [DEBUG] [internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/statusHumidity_CCNW/state' and payload '{"type":"Decimal","value":"66"}'
2024-05-09 12:04:16.639 [DEBUG] [on.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'statusHumidity_CCNW'? -> false
2

restarting the bundle, it looks like the class reloading doesnā€™t complete

12:07:03.784 [INFO ] [jrule.internal.compiler.JRuleCompiler] - [JRuleCompiler] Number of classes to load in to memory: 1 folder: /etc/openhab/automation/jrule/rules
12:07:03.785 [DEBUG] [jrule.internal.compiler.JRuleCompiler] - [+JRuleCompiler+] Attempting to load class: org.openhab.automation.jrule.rules.user.BkmTest
12:07:15.875 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/statusHumidity_SSSE/state' and payload '{"type":"Decimal","value":"60"}'
12:07:15.876 [DEBUG] [ion.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'statusHumidity_SSSE'? -> false

Maybe a problem with OSGI?

14:24:56.795 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Dependency Manager created osgi.ds.satisfying.conditioninterface=org.osgi.service.condition.Condition, filter=(osgi.condition.id=true), policy=dynamic, cardinality=1..1, bind=null, unbind=null, updated=null, field=null, field-option=null, collection-type=null, parameter=null
14:24:56.800 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Component created: DS=DS14, implementation=org.openhab.automation.jrule.internal.JRuleFactory, immediate=true, default-enabled=true, factory=null, configuration-policy=optional, activate=activate, deactivate=dispose, modified=null configuration-pid=[automation.jrule]
14:24:56.800 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Component Properties: {osgi.ds.satisfying.condition.target=(osgi.condition.id=true)}
14:24:56.800 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Querying state disabled
14:24:56.801 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Querying state disabled
14:24:56.801 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Component can not be activated since it is in state disabled
14:24:56.801 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory] : Querying state disabled
14:24:56.801 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : Updating target filters
14:24:56.802 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : No change in target property for dependency $001: currently registered: false
14:24:56.802 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] :  No existing service listener to unregister for dependency $001
14:24:56.802 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : Setting target property for dependency $001 to null
14:24:56.803 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : New service tracker for $001, initial active: false, previous references: {}, classFilter: (objectClass=org.openhab.automation.jrule.internal.events.JRuleEventSubscriber), initialReferenceFilter (objectClass=org.openhab.automation.jrule.internal.events.JRuleEventSubscriber)
14:24:56.803 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : dm $001 tracker reset (closed)
14:24:56.804 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : dm $001 tracker opened
14:24:56.804 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : registering service listener for dependency $001
14:24:56.804 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : No change in target property for dependency $002: currently registered: false
14:24:56.804 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] :  No existing service listener to unregister for dependency $002
14:24:56.805 [DEBUG] [utomation.jrule.internal.JRuleFactory] - bundle org.openhab.automation.jrule:4.0.0.202404081933 (405)[org.openhab.automation.jrule.internal.JRuleFactory(446)] : Setting target property for dependency $002 to null

I see the same.

If youā€™re able to add some logging statements to JRule in the class loading section and/or connect a debugger we might find the culprit and can issue a fix :slight_smile:

I can do that, I need to set up some infrastructure. Iā€™m deploying this instance over SSHFS. What I need to do is upgrade my home OH to the latest and debug locally.

I have never looked, but I assume thereā€™s a howto for developers, or on how to debug a plugin. OR, can I just upload the JAR and attach a debugger to that instance?

Development is easiest done on a local test instance. Just clone the repo, build the project (mvn clean verify), then copy the resulting jar file into the local addons folder.

Run OH with ./start_debug.sh or similar, then connect your debugger. Iā€™ve probably forgotten a step or three, but it is fairly straight foward :innocent:

Understood. I will get around to this, but I fear that I wonā€™t be able to duplicate the problem on my workstation.

Hey, guys.

Iā€™m trying to implement the time series + forecast support from OpenWeatherMap but Iā€™m hitting a wall and Iā€™m wondering if you can guide me.

I made sure that the items are being populated with the forecasted data:

I checked the examples to see how can the data be retrieved, but there is only an example with persisting, not retrieving, so I tried it myself like this:

var now = ZonedDateTime.now()
val rain03 = JRuleItems.Weather_Temperature_Hourly.getHistoricState(now.plusHours(3)).get().toString().toFloat

image

But I get the following error on that line:

Caused by: java.lang.NoClassDefFoundError: scala/collection/StringOps$
	at org.openhab.automation.jrule.rules.user.Tests.Lights_Test(Tests.scala:29)
	... 14 more

Here is the complete error message:

05/31/2024 10:13:00.904 [ERROR] [ion.jrule.internal.engine.JRuleEngine] - [JRuleEngine] Error in rule: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$61(JRuleEngine.java:513)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.invokeRuleInternal(JRuleEngine.java:473)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$56(JRuleEngine.java:444)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.invokeDelayed(JRuleEngine.java:490)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$55(JRuleEngine.java:443)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NoClassDefFoundError: scala/collection/StringOps$
	at org.openhab.automation.jrule.rules.user.Tests.Lights_Test(Tests.scala:29)
	... 14 more
Caused by: java.lang.ClassNotFoundException: scala.collection.StringOps$
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
	at org.openhab.automation.jrule.internal.handler.JRuleHandler$JRuleClassLoader.loadClass(JRuleHandler.java:545)
	... 15 more

target: java.lang.NoClassDefFoundError: scala/collection/StringOps$
	at org.openhab.automation.jrule.rules.user.Tests.Lights_Test(Tests.scala:29)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$61(JRuleEngine.java:513)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.invokeRuleInternal(JRuleEngine.java:473)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$56(JRuleEngine.java:444)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.invokeDelayed(JRuleEngine.java:490)
	at org.openhab.automation.jrule.internal.engine.JRuleEngine.lambda$55(JRuleEngine.java:443)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassNotFoundException: scala.collection.StringOps$
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
	at org.openhab.automation.jrule.internal.handler.JRuleHandler$JRuleClassLoader.loadClass(JRuleHandler.java:545)
	... 15 more

Any suggestions?

Looks like you are missing some dependency. Try including the jar file as an external jar (containing the scala.collection.StringOps$

Otherwise try to write the rule in java first, to get it working, and then try it in scala.

Youā€™re right! There might be an issue when compiling.
Iā€™ll continue investigating.

Thank you!

Hi, everyone.

Iā€™m having issues after migrating to OH 4.2 but since no one else is complaining, I guess itā€™s a local issue. There were no changes to the rules working under 4.1.3.

I migrated yesterday to 4.2 stable and all my rules stopped working.
I had previously installed the add-on manually by placing the jar in /usr/share/openhab/addons/, so I deleted it and installed it via the Add-On Store on the MainUI. Yet the rules are not triggered.

After installing the add-on, the following output is printed to the console:

22:07:56.944 [INFO ] [ion.jrule.internal.engine.JRuleEngine] - [JRuleEngine] Initializing Java Rule Engine with Separate Thread Executors min: 2 max: 10
22:08:02.155 [INFO ] [utomation.jrule.internal.JRuleFactory] - [JRuleFactory] Initializing Java Rules Engine v4.0.0.202404081933
22:08:02.157 [INFO ] [n.jrule.internal.handler.JRuleHandler] - [JRuleHandler] Initializing Start Initializing JRule Automation
22:08:02.159 [INFO ] [n.jrule.internal.handler.JRuleHandler] - [JRuleHandler] Initializing JRule writing external Jars: /etc/openhab/automation/jrule/jar
22:08:02.163 [INFO ] [e.internal.compiler.JRuleJarExtractor] - [JRuleJar] Extracting jar: /etc/openhab/automation/jrule/jar/jrule.jar to: /etc/openhab/automation/jrule/jar/jrule.jar
22:08:02.184 [INFO ] [e.internal.compiler.JRuleJarExtractor] - [JRuleJar] Extracting jar: /etc/openhab/automation/jrule/jar/openhab-core.jar to: /etc/openhab/automation/jrule/jar/openhab-core.jar
22:08:02.714 [INFO ] [n.jrule.internal.handler.JRuleHandler] - [JRuleHandler] Compiling generated sources
22:08:06.960 [INFO ] [n.jrule.internal.handler.JRuleHandler] - [JRuleHandler] Creating jrule-generated.jar
22:08:07.534 [INFO ] [n.jrule.internal.handler.JRuleHandler] - [JRuleHandler] Compiling rules
22:08:07.539 [WARN ] [jrule.internal.compiler.JRuleCompiler] - [JRuleCompiler] Found no java rules to compile and use in folder /etc/openhab/automation/jrule/rules/org/openhab/automation/jrule/rules/user/
22:08:07.557 [INFO ] [jrule.internal.compiler.JRuleCompiler] - [JRuleCompiler] Number of classes to load in to memory: 74 folder: /etc/openhab/automation/jrule/gen
22:08:07.645 [INFO ] [n.jrule.internal.handler.JRuleHandler] - Instantiated JRuleItems class
22:08:07.649 [INFO ] [n.jrule.internal.handler.JRuleHandler] - Instantiated JRuleThings class

Yet nothing is mentioned about the precompiled jar under /etc/openhab/automation/jrule/rules-jar/.
I deleted the jar and copied it again but nothing was reported in the console as before (e.g., number of rules, etc.).

Changing the logging level to DEBUG showed some event updates, but nothing related to the precompiled jar:

22:09:48.467 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/systeminfo_computer_openHABianPi_memory_availablePercent/state' and payload '{"type":"Decimal","value":"46.9"}'
22:09:48.469 [DEBUG] [ion.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'systeminfo_computer_openHABianPi_memory_availablePercent'? -> false
22:09:48.469 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/systeminfo_computer_openHABianPi_sensor_CPUtemp/state' and payload '{"type":"Decimal","value":"78.4"}'
22:09:48.470 [DEBUG] [ion.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'systeminfo_computer_openHABianPi_sensor_CPUtemp'? -> false
22:09:48.471 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateChangedEvent' with topic 'openhab/items/systeminfo_computer_openHABianPi_sensor_CPUtemp/statechanged' and payload '{"type":"Decimal","value":"78.4","oldType":"Decimal","oldValue":"76"}'
22:09:48.472 [DEBUG] [ion.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'systeminfo_computer_openHABianPi_sensor_CPUtemp'? -> false
22:09:48.494 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/systeminfo_computer_openHABianPi_storage_availablePercent/state' and payload '{"type":"Decimal","value":"77.3"}'
22:09:48.495 [DEBUG] [ion.jrule.internal.engine.JRuleEngine] - [+JRuleEngine+] watching for item: 'systeminfo_computer_openHABianPi_storage_availablePercent'? -> false
22:09:49.496 [DEBUG] [.internal.events.JRuleEventSubscriber] - [+JRuleSubscriber+] Received event 'ItemStateEvent' with topic 'openhab/items/systeminfo_computer_openHABianPi_memory_availablePercent/state' and payload '{"type":"Decimal","value":"46.9"}'

I had to restart the server for a different reason, but nothing changed.

I donā€™t think the JRule version (v4.0.0.202404081933) is the problem because it also worked under 4.1.3.

Any suggestions?

@Seaside , @seime, do you have any ideas?

I have it working under 4.2, didnā€™t have any problems. My suggestion is:

  • Uninstall the marketplace addon
  • Build the git-repo locally and place the jar in the addons. Seime recently updated the biding to support 4.2, but itā€™s not in any prebuilt versions yet.
  • If you still have problems, install one single java-rule and make sure it works with that before you add all your previous rules

Hi, @Seaside.

Thanks for your suggestions. I just spent around 4 hours trying to make Maven work. I never used it before. I uninstalled the addon from the marketplace and copied the locally compiled one to the addons folder. It ran just like the one from the marketplace without loading the jar.

Iā€™ll get some sleep and then try with the single Java rule.

I just created a new JAR with only 1 Java class with the following code:

import org.openhab.automation.jrule.rules.JRule;
import org.openhab.automation.jrule.rules.JRuleName;
import org.openhab.automation.jrule.rules.JRuleWhenItemReceivedUpdate;
import org.openhab.automation.jrule.generated.items.JRuleItemNames;
import java.time.Duration;

public class testJava extends JRule {

    @JRuleName("myTimerRule")
    @JRuleWhenItemReceivedUpdate(item = JRuleItemNames.MBR_Scene_Study_White)
    public void warnIfThingStaysOffline() {
        createOrReplaceTimer("MY_TIMER", Duration.ofMinutes(3), (Void) -> {
            logInfo("Time is up! Am I supposed to do something?");
        });
    }
}

I deleted all Scala classes, recompiled the JAR, uploaded it to the server, and moved it to the ā€¦/automation/jrule/rules-jar folder but JRule didnā€™t pick it up.
After updating the MBR_Scene_Study_White and waiting for 3 minutes, the rule didnā€™t run.

I even created the testJava.java file with the same code, directly in the server under ā€¦/automation/jrule/rules/org/openhab/automation/jrule/rules/user/ but it didnā€™t work either.

By the way, I didnā€™t change the serverā€™s Java version from 17 to 21.

You tried the most recent marketplace version beta21? If you put that in debug mode, does it show any issues when only this basic rule is used?

Yes, I used the most recent marketplace version as well as locally compiled it from the source code, as suggested by @Seaside. The debug version doesnā€™t mention anything.

When a pre-compiled JAR is stored in the right folder, JRule loads it and prints to the console (Info) information about the loaded rules, e.g., the number of rules it could load.
With that, we know that something was processed. In my case, after migrating to 4.2.0, after JRule is loaded, it doesnā€™t print anything about the precompiled JAR. Itā€™s as if it couldnā€™t find it. From that, I had an indication that something was wrong. Setting JRule to debug mode didnā€™t print anything special when the pre-compiled JAR should have been loaded or when I expected the rule to be executed.

In the most basic form, we can store the .java files directly in another folder and JRule compiles them. I had never done this before (as I donā€™t program in Java but in Scala, so I need to pre-compile the JAR), but that didnā€™t produce any output in the console or execute the rule. There was no indication that a new .java file was compiled by JRule, which is what I would have expected.

The last time JRule was updated in the marketplace was before 4.2.0 was released and my pre-compiled JAR didnā€™t change either. The only different thing is the upgrade from 4.1.3 to 4.2.0.

Iā€™m trying to determine if

  1. The addon was loaded without issues by karaf.
  2. The bindings loads any rule from the folder.

So it is clear that 2 is not doing anything. So need to check 1.

Donā€™t expect it to be a permission isssue, might be. but as it works for others it must be something specific for your setup