JRule - openHAB Rules using Java

Thanks for checking. I was able to get the group trigger running by changing the definition:

2021-11-07 12:23:52.110 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'groupKontakte' changed from CLOSED to OPEN through openCloseFensterBad

The problem is, that this is different from what Member of does.

  • Member of capturs triggers for each member of the group. In my case it triggers every time a window is opened or closed.
  • For the group definition Group:Contact:OR(OPEN,CLOSED) groupKontakte, it only triggers when the “sum state” changes, which makes sense, since the group state is an aggregate. So in my case, the rule is triggered only when the first window is opened or the last one is closed.

The internal rule engine seems to have some custom implementation for Member of.
According to the code it reacts on ItemStateEvent and ItemStateChanged events and checks if the item is part of the group. Looks like we would need an additional implementation in JRule.

1 Like

I’ve added a BETA2 build, with some of the PRs as well as a new annotation
for setting a logger on the rule method. Now you are not forced to implement a logname method, you either do nothing (the log will be prefilex with the @JRuleName value), or you can use the @JRuleLogName annotation. It is also possible to override the getRuleLogName method (like it was before).

Regarding removing item when specifying @JRuleWhen , It is more work than I thought since it is used by the engine to determine which items on the eventbus to listen on. So from an efficiency point of view I don’t want to remove it. The trigger names could contain the item names, and then they could be parsed in order to make the same functionality (populate a hasmap with item names, to be able to determine what to listen on the eventbus), but that parsing is somewhat ugly from my point of view. I will leave it like this for now.

BR S

Hi,
wonderful solution. I got it working on 3.2 Milestone 4 in 2 hours until the first automatic rule execution. I was about to jumpstart into Jython Rule programing but this seems to be much more future oriented.

Some observations:
1.) I installed it via the MainUI Automations. No need to copy the latest release manually from github. I hope this automatically pulls the latest version. The engine is working but where can I check the installed version?
2.) In the first run directly after install I can find the generate messages in the openhab.log. After creating new items I did not see any engine execution entries in the log. Discovered only by chance when looking at the timestamp that a new jrules-items.jar file was produced.
Can you also please create log entries for updates of items?
3. The example of the first HelloWorld example needs to be corrected. Line 2 should be:

import static org.openhab.automation.jrule.rules.value.JRuleOnOffValue.ON;

Thank you

Yes it should. You can connect to the karaf console and run bundle:list to list all bundles.
In next release it will also be displayed on startup.

Yes I have changed some of the debug entries to info.

Thanks I have fixed this now.

Regards S

275 │ Active │  80 │ 3.2.0.202111151957    │ openHAB Add-ons :: Bundles :: Standalone Java Rules Automation

Thanks - I was trying the features command and could not identify it. Looks to be the most current one as your last commit is 8 days old
Martin

Just released a BETA3 with refactored logging. I plan on making a lot of stuff configurable (including logging, generated class character etc).

Br S

Thanks for creating JRule @Seaside! I’ve been following this thread for a while, and today I decided it was time to try it out.

I got the example up and running, and started to migrate my first DSL rule. The WAF on testing fire, water and burglar alarm rules is quite low in my household, and a huge problem with the existing DSL rules is the lack of testability. So when you mentioned JUnit support I was sold!

Looking through your examples and source code I could not find any examples of a working JUnit test. jrule/JRuleTest.java at main · seaside1/jrule · GitHub appears to be incomplete.

Maybe I looked in the wrong places, but if not; is it on your radar in the near future? :slight_smile:

Thanks for your great work!
Arne

Hi!
I have some unittests for my own rules. I plan on “releasing” it. Basically what I have done is mocking the eventbus and by publishing events on the bus I can test if my rules trigger etc.
I run the test right now manually in my IDEA, but I can you could create a pom file and run “mvn test”.
You could create your own tests to test your rules, especially if you are using some logic. It makes sense to break those parts out in that case so you can test them.

Br S

I’ve been fiddeling around with JRule over the weekend, trying to port my existing DSL rules. I do love the idea of typesafe rules & testability.

My findings so far that could be improved (@weberjn has already pointed out some issues that I support as well):

  • I am not fully convinced about adding a layer over openhab items/types (except for items and typesafe methods based on item type). It appears to me that it must become some sort of union of everything if it is to be complete.
  • QuantityTypes are not supported, all my Number:XXX items are reporting null as state
  • File reloading does not work well, if I update a set of rules the recompilation of all files is triggered multiple times.
  • No openhab types/classes are exposed, so no type conversions can be done using existing methods
  • No package structure is supported for rules (I can create a PR)
  • No transformations available (I can create a PR)
  • As has been discussed earlier; no binding actions are available
  • When writing rules - since I am already inside my IDE (which can compile), is it possible to package rules as a jar and deploy the jar as a bundle - instead of deploying source files to be compiled?
  • Rule testing framework is very much anticipated - so I’m looking forward to some helper classes - ie as you say - mock the event bus, load a set of items with some state, load a (set of) rule(s) and start sending events. Asserts for expected state changes/commands.

Thanks again @Seaside !

Testing is the big thing i am missing in rule development. Can you share one of your tests (How to mock the eventbus?)

I’ll try to work on that, getting some example and functionality for testing and simulating the eventbus.

Regards, S

This is really a great thing. I really like the idea of using simple Java to create rules. I always wondered why this wasn’t implemented when Openhab first started.

So keep up the good work!

Do you think it would be possible to add a system trigger like JS Scripting has?

.system()
    .ruleEngineStarted()
    .rulesLoaded()
	.startupComplete()
	.thingsInitialized()
	.userInterfacesStarted()
	.startLevel(level)

Not sure, could investigate it.

Added a new BETA5 build with support for rules inside jar-files.

Take a look on ready service. As reference I can point own thing I did. First register a ready marker tracker: connectorio-addons/bundles/org.connectorio.addons.norule/src/main/java/org/connectorio/addons/norule/internal/NoRuleRegistry.java at master · ConnectorIO/connectorio-addons · GitHub
Then catch their occurrence and trigger rule execution.
connectorio-addons/bundles/org.connectorio.addons.norule/src/main/java/org/connectorio/addons/norule/internal/NoRuleRegistry.java at master · ConnectorIO/connectorio-addons · GitHub
Anyways, start level or other markers might be a good case for “if” conditions fencing rule execution. :wink:

I have created a sample repo to leverage BETA5’s support for rules jar. It contains a basic gradle.build file that creates the jar to be picked up by jrule. It’s a PoC to show you can place your classes in individual packages now, use external dependencies and unit test your rules.

Is there a way to access actions, i.e. Pushover?

val actions = getActions("pushover", "pushover:pushover-account:account")
actions.sendHtmlMessage("Hello <font color='green'>World</font>!", "openHAB")

(example from Pushover - Bindings | openHAB)

Not supported at the moment. I’m sending pushover using mqtt, but I would suggest until it is supported that you use a proxy rule in rule dsl for invoking it.

Regards, S

sorry, I saw this has already been answered. Another question:

How do get an Item by its name? My “old” Jython rules contain a lot of logic depending on naming conventions like

Number GN_WATER_SOUTH_LAWN_BAT
Switch GN_WATER_SOUTH_LAWN_VALVE
Number GN_WATER_SOUTH_LAWN_DURATION_PLANNED
Number GN_WATER_SOUTH_LAWN_DURATION_TODAY
Number GN_WATER_SOUTH_LAWN_DURATION_YESTERDAY
Number GN_WATER_SOUTH_LAWN_START_MS

Using a few string methods it is easy to replicate logic for multiple GN_WATER_*_* things. How can I do this with JRule?

Not sure what you want to accomplish. I would suggest you group Items you want to invoke together in groups, rather than having logic on the item names.
But you can get the name for an item if you wish to do so

    @JRuleName("MyRuleTurnSwich2On")
    @JRuleWhen(item = _MyTestSwitch.ITEM, trigger = _MyTestSwitch.TRIGGER_CHANGED_TO_ON)
    public void execChangedToRule() {
    	logInfo("||||| --> Executing rule MyRule: changed to on");
        _MySwitch2.sendCommand(ON);
        logInfo("The name of the item is stored in the item variable: {}",_MySwitch2.ITEM);
    }