JRule Java Rules in OpenHAB 3 (alpha)

J Rule

Write OpenHAB Rules using Java

This automation package aims to enable Java development of OpenHAB Rules. The addon will allow the user to create custom OpenHAB rules
in one or several .java-files. The Java Rules will need defined triggers in order for the engine to know how and when to execute them. The triggers
are very similar to the triggers in Rules DSL but expressed using java annotations. In order to execute rules based on items defined in OpenHAB either in .items-files or the GUI. The addon needs to know about these items and this is realized by the Rule Engine where it generates a .java and a .class file for each item in the system. The class files are then packaged in a .jar-file which the user can use as dependency when doing Rules Development.
For the addon to be able to pick up rules, they first need to be compiled by the addon. The source .java rules-files are placed in a specific rules folder and
will be automatically compiled and loaded into OpenHAB when the addon is started. The syntax for rules as well as the design and thinking behind the addon is to provide something that is similar to Rules DSL but more powerful and customizable.

Limitations

  • Currently only working for OpenHAB installations under Linux / Unix Operating Systems, not supported in Windows (for rules development its fine to use windows)
  • Not supporting OH3 GUI rules, script actions and script conditions

Why?

  • You will be able to use a standard Java IDE to develop your rules.
  • Full auto completion (Shift space) for all items, less chance of errors and typos
  • Take full advantage of all java design patters
  • Share and reuse code for you rules
  • Advanced timers and locks are built in and can be used without cluttering the code
  • Possibility to write junit-tests to test your rules
  • Use any 3rd party dependencies and libraries in your rules
  • You will be able to use JRule in parallell with any other Rules engine if you want to give it a try

Who?

This addon is not for beginners, you should have knowledge in writing java-programs or a desire to do so.

Maturity

Alpha, you can expect big changes in syntax and everything else. Please contribute if you can

Download

Prebuilt jar file is available in the bin folder under https://github.com/seaside1/jrule

Java Rule Engine

Input rules files
will be placed under:
/etc/automation/jrule/rules/org/openhab/automation/jrule/rules/user/

Output jar files to be added by the user as dependencies when doing rule development will be located under:
/etc/openhab/automation/jrule/jar

The following jar files can be found under the jrule/jar-folder:

Jar File Description
jrule-items.jar Contains all generated items, which will be used when developing rules
jrule.jar JRule Addon classes neeed as dependency when doing development

Get started with the JRule Automation Addon

  • Install the addon by copying the org.openhab.automation.jrule-3.x.x-ALPHAX.jar to openhab-addons folder
    Download latest release from https://github.com/seaside1/jrule/tree/main/bin
  • In default location is /etc/openhab/automation/jrule
  • When the addon is started it will:
  1. Create JAVA source files for all items
  2. Compile java source files and create a resulting jrule.jar file under /etc/openhab/automation/jrule/jar
  3. Compile any java rules file under /etc/openhab/automation/jrule/rules/org/openhab/automation/jrule/rules/user/
  4. Create jar files with dependencies to be used when creating your java-rules (jrule-items.jar).
    The two jar files needed for Java rules development can be found under /etc/openhab/automation/jrule/jar

Once the JAVA rule engine has started and compiled items successfully you can either copy the jar files
form /etc/openhab/automation/jrule/jar/* to the place where you intend to develop the Java- Rules, or share that folder
using samba / CIFS / NFS or similar.

  • Set up your favourite IDE as a standard java IDE.
  • Create a new empty java project
  • Create a package / folder org.openhab.automation.jrule.rules.user
  • Place your Java rules file in this folder

NOTE: The rules will be reloaded if they are modified. Any java file you place under /etc/openhab/automation/jrule/rules/org/openhab/automation/jrule/rules/user/
will be compiled or recompiled, you don’t have to restart OpenHAB.

Designing your Java Rules File (Hello World)

  1. Start by adding an item in Openhab.
    Group JRule
    Switch MyTestSwitch “Test Switch” (JRule)
    Switch MyTestSwitch2 “Test Switch 2” (JRule)

  2. Create the following class

package org.openhab.automation.jrule.rules.user;
import static org.openhab.automation.jrule.rules.JRuleOnOffValue.ON;
import org.openhab.automation.jrule.items.generated._MyTestSwitch;
import org.openhab.automation.jrule.rules.JRule;
import org.openhab.automation.jrule.rules.JRuleName;
import org.openhab.automation.jrule.rules.JRuleWhen;

public class MySwitchRule extends JRule {

    private static final String LOG_NAME="MY_TEST";
    
    @JRuleName("MySwitchRule")
    @JRuleWhen(item = _MyTestSwitch.ITEM, trigger = _MyTestSwitch.TRIGGER_CHANGED_TO_ON)
    public void execOffToOnRule() {
	logInfo("||||| --> Hello World!");
    }
    
    @Override
    protected String getRuleLogName() {
        return LOG_NAME;
    }
}

Make sure you add the Jar-files from /etc/openhab/jrule/jar as dependencies.

Third Party External Dependencies

You can add any 3rd party library as dependency. Copy the jar files needed to /etc/openhab/automation/jrule/ext-lib
The Automation Engine will automatically pick these dependencies up when it is compiling the rules.

Core Actions

Built in Core Actions that can be used

Action Description
say Will use VoiceManager to say action see Example 13
commandLineExecute See Example 14

Examples

Example 1

Use Case: Invoke another item Switch from rule

    @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);
    }

Example 2

Use case: Invoke a Doorbell, but only allow the rule to be invoke once every 20 seconds.
This is done by aquiring a lock getTimedLock(“MyLockTestRule1”, 20).

    @JRuleName("MyLockTestRule1")
    @JRuleWhen(item = _MyTestSwitch2.ITEM, trigger = _MyTestSwitch2.TRIGGER_CHANGED_FROM_OFF_TO_ON)
    public void execLockTestRule() {
        if (getTimedLock("MyLockTestRule1", 20)) {
            _MyDoorBellItem.sendCommand(ON);
            logInfo("||||| --> Got Lock! Ding-dong !");
        } else {
            logInfo("||||| --> Ignoring call to rule it is locked!");
        }
    }

Example 3

Use case: Use the value that caused the trigger
When the rule is triggered, the triggered value is stored in the event.

   @JRuleName("MyEventValueTest")
   @JRuleWhen(item = __MyTestSwitch2.ITEM, trigger = __MyTestSwitch2.TRIGGER_RECEIVED_COMMAND)
   public void myEventValueTest(JRuleEvent event) {
	  logInfo("Got value from event: {}", event.getValue());
   }

Example 4

Use case: Or statement for rule trigger
To add an OR statement we simply add multiple @JRuleWhen statements

   @JRuleName("MyNumberRule1")
   @JRuleWhen(item = _MyTestNumber.ITEM, trigger = _MyTestNumber.TRIGGER_CHANGED, from = "14", to = "10")
   @JRuleWhen(item = _MyTestNumber.ITEM, trigger = _MyTestNumber.TRIGGER_CHANGED, from = "10", to = "12")
   public void myOrRuleNumber(JRuleEvent event) {
	logInfo("Got change number: {}", event.getValue());
   }

Example 5

Use case: Define your own functionality
Create a Rules class that extends: JRuleUser.java
JRuleUser.java should be placed in the same folder as your rules:

package org.openhab.automation.jrule.rules.user;

import org.openhab.automation.jrule.rules.JRule;

public abstract class JRuleUser extends JRule {

	
}

Example 6

Your class rules can now extend the JRuleUser
package org.openhab.automation.jrule.rules.user;

import static org.openhab.automation.jrule.rules.JRuleOnOffValue.ON;
import org.openhab.automation.jrule.items.generated._MyTestSwitch;
import org.openhab.automation.jrule.rules.JRule;
import org.openhab.automation.jrule.rules.user.JRuleUser;
import org.openhab.automation.jrule.rules.JRuleName;
import org.openhab.automation.jrule.rules.JRuleWhen;

public class MySwitchRule extends JRuleUser {

    private static final String LOG_NAME="MY_RULE";
    
    @Override
    protected String getRuleLogName() {
        return LOG_NAME;
    }
}

Example 7

Let’s say we want to add a common function that should be available for all user rules.
We want to add a function that checks if it is ok to send notifications debing on what time it is.
We’ll do this:

package org.openhab.automation.jrule.rules.user;

import org.openhab.automation.jrule.rules.JRule;

public abstract class JRuleUser extends JRule {

	private static final int startDay = 8;
	private static final int endDay = 21;
	
	
	protected boolean timeIsOkforDisturbance() {
		return nowHour() >= startDay && nowHour() <= endDay;
	}
	
}

``
We then extend the rule from the Java Rules file:

package org.openhab.automation.jrule.rules.user;

import org.openhab.automation.jrule.items.generated._MyTestSwitch;
import org.openhab.automation.jrule.rules.JRuleEvent;
import org.openhab.automation.jrule.rules.JRuleName;
import org.openhab.automation.jrule.rules.JRuleWhen;

public class MyTestUserRule extends JRuleUser {
	private static final String MY_LOGNAME = "TEST";

	@JRuleName("TestUserDefinedRule")
	@JRuleWhen(item = _MyTestSwitch.ITEM, trigger = _MyTestSwitch.TRIGGER_RECEIVED_COMMAND)
	public void mySendNotificationRUle(JRuleEvent event) {
		if (timeIsOkforDisturbance()) {
			logInfo("It's ok to send a distrubing notification");
		}
	}
	
    @Override
    protected String getRuleLogName() {
        return MY_LOGNAME;
    }

}

Example 8

Use case create a timer for automatically turning of a light when it is turned on. If it’s running cancel it and schedule a new one.

    @JRuleName("myTimerRule")
    @JRuleWhen(item = _MyLightSwitch.ITEM, trigger = _MyLightSwitch.TRIGGER_CHANGED_TO_ON)
    public synchronized void myTimerRule(JRuleEvent event) {
        logger.info("myTimerRule Turning on light it will be turned off in 2 mins");
        createOrReplaceTimer(_MyLightSwitch.ITEM, 2 * 60, (Void) -> { // Lambda Expression
            logInfo("Time is up! Turning off lights");
            _MyLightSwitch.sendCommand(OFF);
        });
    }

Example 9

Use case: Let’s say we have a 433 MHz wall socket with no ON/OFF feedback and a bit of bad radio reception. We can then create a repeating timer
to send multiple ON statements to be sure it actually turns on.
createOrReplaceRepeatingTimer(“myRepeatingTimer”, 7, 4, will create a repeating timer that will trigger after 0 seconds, 7s, 14s and 21s
If the Timer is already running it will cancel it and create a new one.

    @JRuleName("repeatRuleExample")
    @JRuleWhen(item = _MyTestSwitch.ITEM, trigger = _MyTestSwitch.TRIGGER_CHANGED_TO_ON)
    public synchronized void repeatRuleExample(JRuleEvent event) {
        createOrReplaceRepeatingTimer("myRepeatingTimer", 7, 10, (Void) -> { // Lambda Expression
            final String messageOn = "repeatRuleExample Repeating.....";
            logInfo(messageOn);
            _MyBad433Switch.sendCommand(ON);
        });
    }

Example 10

Use case Create a simple timer. When MyTestSwitch turns on it will wait 10 seconds and then turn MyTestSwitch2 to on. Note that
it will not reschedule the timer, if the timer is already running it won’t reschedule it.

    @JRuleName("timerRuleExample")
    @JRuleWhen(item = _MyTestSwitch.ITEM, trigger = _MyTestSwitch.TRIGGER_CHANGED_TO_ON)
    public synchronized void timerRuleExample(JRuleEvent event) {
        createTimer("myTimer", 10, (Void) -> { // Lambda Expression
            final String messageOn = "timer example.";
            logInfo(messageOn);
            _MyTestWitch2.sendCommand(ON);
        });
    }

Example 11

Use case trigger a rule at 22:30 in the evening to set initial brightness for a ZwaveDimmer to 30%

  @JRuleName("setDayBrightness")
  @JRuleWhen(hours=22, minutes=30)
  public synchronized void setDayBrightness(JRuleEvent event) {
      logInfo("Setting night brightness to 30%");
      int dimLevel = 30;
      _ZwaveDimmerBrightness.sendCommand(dimLevel);
  }

Example 12

Use case: If temperature is below or equals to 20 degrees send command on to a heating fan
It is possible to use:
lte = less than or equals
lt = less than
gt = greater than
gte = greater than or equals
eq = equals

  @JRuleName("turnOnFanIfTemperatureIsLow")
  @JRuleWhen(item = _MyTemperatureSensor.ITEM, trigger = _MyTemperatureSensor.TRIGGER_RECEIVED_UPDATE, lte = 20)
  public synchronized void turnOnFanIfTemperatureIsLow(JRuleEvent event) {
      logInfo("Starting fan since temeprature dropped below 20");
      _MyHeatinFanSwitch.sendCommand(ON);
  }

Example 13

Use case: Using say command for tts

    @JRuleName("testSystemTts")
    @JRuleWhen(item = _TestSystemTts.ITEM, trigger = _TestSystemTts.TRIGGER_CHANGED_TO_ON)
    public synchronized void testSystemTts(JRuleEvent event) {
        logInfo("System TTS Test");
        String message = "Testing tts! I hope you can hear it!";
        say(message, null, "sonos:PLAY5:RINCON_XXYY5857B06E0ZZOO");
    }

Example 14

Use case: Using say command line execute

   

Example 15

Use case: A group of switches, see if status is changed, and also which member in the group changed state

    @JRuleName("groupMySwitchesChanged")
    @JRuleWhen(item = _gMySwitchGroup.ITEM, trigger = _gMySwitchGroup.TRIGGER_CHANGED)
    public synchronized void groupMySwitchGroupChanged(JRuleEvent event) {
        final boolean groupIsOnline = event.getValueAsOnOffValue() == ON;
        final String memberThatChangedStatus = event.getMemberName();
	logInfo("Member that changed the status of the Group of switches: {}", memberThatChangedStatus);
    }

Example 16

Use case: A group of switches , trigger when it’s changed from OFF to ON

    @JRuleName("groupMySwitchesChangedOffToOn")
    @JRuleWhen(item = _gMySwitchGroup.ITEM, trigger = _gMySwitchGroup.TRIGGER_CHANGED, from="OFF", to="ON")
    public synchronized void groupMySwitchesChangedOffToOn(JRuleEvent event) {
	logInfo("Member that changed the status of the Group from OFF to ON: {}", event.getMemberName());
    }

Example 17

Use case: Listen for a Channel Trigger Event

    @JRuleName("channelTriggered")
    @JRuleWhen(channel = "binding:thing:buttonevent")
    public synchronized void channelTriggered(JRuleEvent event) {
	logInfo("Channel triggered with value: {}", event.getValue());
    }

Example 18

Use case: Cron based expression to trigger rule

    @JRuleName("testCron")
    @JRuleWhen(cron = "4 * * * * *")
    public void testCron(JRuleEvent event) {
        logInfo("CRON: Running cron from string every minute when seconds is at 4: {}", event.getValue());
    }

Example 19

Use case: getLastUpdated for an item
Note that JRulePersistenceExtentions.getLastUpdate(_MyCoolItem.ITEM, “mapdb”);
can be called without serviceId argument:
JRulePersistenceExtentions.getLastUpdate(_MyCoolItem.ITEM);

  
    @JRuleName("testLastUpdate")
    @JRuleWhen(cron = "4 * * * * *")
    public  void testLastUpdate(JRuleEvent event) {
        logInfo("CRON: Running cron from string: {}", event.getValue());
        ZonedDateTime lastUpdate = JRulePersistenceExtentions.getLastUpdate(_MyCoolItem.ITEM, "mapdb");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd - HH:mm:ss Z");
        String lastUpdateFormatted = lastUpdate.format(formatter);
        logInfo("Last Update: {}", lastUpdateFormatted);    

Changelog

ALPHA11

  • Added check for working dir via system properties

ALPHA10

  • Added LatUpdate via JRulePresistenceExtensions see example 19

ALPHA9

  • Added cron expressions for rules see example 18
  • Bug fix by @roth for reloading channel triggers

ALPHA8

  • Channel triggers provided by @roth see example 17

ALPHA7

  • Fixed bug with group member value was null for non StringType types

ALPHA6

  • Added group functionality getMember will return who triggered a change for a group

ALPHA5

  • Removed dependencies on slf4japi and eclipse annotations
  • Added logInfo logDebug (to wrap slf4j and remove dep)
  • Fixed compilation of rules to be more robust with internal dependencies

ALPHA4

  • Refactored completable futures
  • Added 5 seconds of delay for initialization of the rule engine to avoid multiple reloads
  • Added support for play & pause for player item
  • Added commandLineExecute

ALPHA3

  • Fixed issue when reloading rules if they are changed with monitored items
  • Fixed classpath issue when executing rules using 3rd party libraries

ALPHA2

  • Added possibility to include 3rd party libraries when developing rules

ALPHA1

  • Refactored internal jar dependencies and jar-generation
  • Added eq comparator for number triggers in rules

Roadmap

  • Locks and timers by annotation
  • Built in expire functionality
8 Likes

I’ve opened up the repository now. It is working ok now I believe. Still expect major updates and changes. Anyone who want to contribute or change stuff please submit a PR.

/S

A few comments on usability for a wide openHAB audience:

  • If only .items files are supported that will be a deal killer for a huge portion of OH 3 users. More and more users are migrating to UI managed Items and new users never use .items files at all. If you were to support managed Items through REST API calls (or internal API calls) then you’d be able to get the Items from both .items files and managed since the .items files Items are reflected in the REST API as well.

  • If the .java files are only picked up when the binding starts, that means one needs to restart OH or at least restart the binding which becomes really awkward if in a develop/test loop working on rules.

  • The standard folder for JavaScript, Python, and Groovy rules (maybe jRuby too?) is /etc/openhab/automation. /etc/openhab/rules and /etc/openhab/scripts is legacy. Speaking only as myself, I’d prefer to see this jrule folder default under automation for consistency.

  • I would have expected this to be an automation type add-on, not a binding. It is counter intuitive to have to create a Thing to enable rules. I believe there is a way to specify add-on configuration through the UI without requiring a Thing.

  • This appears to be completely incompatible with UI created rules. So no Script Conditions or Script Actions appear supported.

It’s nice to see this coming along though and I look forward to see it progress. But I can’t even test it out right now because of the limitations.

1 Like

Hi!
Thanks for the feedback! I appreciate all feedback!

I’m not even sure this is my aim. I guess it depends on how it evolves, if more people are willing / have the interest to develop the binding further. Or if it will be just a handful of people preferring to use java to write rules. I could even see this being developed into something else, maybe we should view this as a Proof of Concept.

The binding connects to the itemRegistry to fetch the items. It should be possible to define
items in the GUI. I have not tested this yet, but should work.

The binding will reload the rules if you modify, add or delete files in the location, no need for restarts.

I agree, I’ll change this in the next changes.

Yes this was my original plan. I could not find a suitable base class to extend for a automation package. The base class used by the other JSR-automations will not work with this binding.
The documentation for automation is very limited (compared with binding documentation), as well as the number of automation addons gave me no apparent options how to add this.
I’ll look into it and see if I can transform it later on, I still expect it to work in a similar manner.

True, and it’s not a priority for me to this. I will add a note about this.

BR S

I guess I’m not sure why someone would bother to develop something for OH that only a small portion of the openHAB userbase could use. But everyone has their own goals. It just becomes really hard to manage all these different subsystems for writing rules when there is so little overlap between who they all work. We already have so many niche rules subsystems it’s unmanageable and really hard for new users to choose “the right one.” But given that’s the case, there probably isn’t any reason why you should stick to the Rules DSL precedent for how to structure the rules if Java pushes you in a different direction.

All Items no matter how they are defined should be available then.

Yes, but if there are a lot of adopters it will be easier to motivate a merge and add the needed functionality that is required for an official automation/binding-addon.
I developed this mostly because it makes my life so much easier being able to write my rules in java. With the approach I’ve chosen here, I find that my rules tend to work straight away, it’s more difficult to make syntax errors and you don’t have to spell the item names correctly (since you are using them as a dependency generated from OpenHAB). I never felt at home using Jython/Python/javascripts for creating rules. Rules DSL was fine but had too many limitations and held me back. I got stuck having so many ideas on how to make cool automations in my home, by not having the right tool for writing rules, I have create more addons than might be necessary and also held back with some work trying figure out if I would go the Python (Habapp) or Jython way.

I’m choosing to share my work because I want give back to the community and also because I find it interesting to develop these type of addons. I’m hoping some more people with pick up this track, and that it can grow with the help of others. If only a handful of people want to use this addon that’s fine. It’s also fine if more people want to use this and it grows into something else and eventually will reach a point where it can be merged.
I never had the intention to reach the wide OpenHAB user base but at the same time I’m sure that there are more people like me who perfer text-based configuration, not using GUI:s for creating rules and in general wants to use Java rather than something else.

This is understandable and probably caused by OpenHAB being such a open, powerful and generic platform. I have written that this is not for beginners and I should probably highlight that more. If you are a new user to OpenHAB this is probably not for you. The target group for this addon would be someone with Programming knowledge (preferably java).
For you, since you tend to be the person everyone asks for help and feedback when it comes to writing rules and automations (as well as design patterns) I can understand your frustration.

I honestly don’t know what language for writing rules I would choose if I began my OH-journey now, but I would probably be confused.

I tried to keep it similar to rules DSL, when I rewrote most of my DSL rules I just copy pasted them into to the java source, and could quite easily convert them into java. But yes probably better to see where Java can be utilized rather than sticking to the limitations and structure of DSL.

/S

As I wrote in the other thread , I am afraid it will never get merged until it is refactored to be an automation bundle.

Probably true, not a big issue as far as I see. The binding is not using much binding stuff and should be easy to convert when I figure out the automation base class to use.

/S

From the developer guide:

A binding is an extension to openHAB that integrates an external system like a software service or a hardware device. The external system is represented as a set of Things and sometimes Bridges with Channels .

There is also a section for automation modules.

Don‘t get me wrong, I don‘t want to disencourage you, but I think it would be better to do it right from the beginning instead of having never ending discussions later on…

Like I said I agree. It should not be a big refactoring since it is not relaying on channels or binding specific things.

/s

Small suggestion with regard to installation/compilation. You might try to simplify integration by removing explicit need for slf4j-api jar. Their packages are available within pax-logging-api (look for specific JAR/version in system/org/ops4j/pax/logging). It is always there if you use Karaf/OH!

The slf4j-api is not used by the binding, it is used when developing java-rules in a standalone Java ide, to be able to log directly from the rules. I could probably remove the dependency by adding a wrapper around slf4j, but I haven’t looked that much into that yet.

/S

I have refactored it from a binding to an automation package instead.
default location is now set to: /etc/openhab/automation/jrule and there is no need to add a jrule thing.

Br S

2 Likes

Out of curiosity and for future developers who come along, what was the right class to inherit from?

I didn’t extend any class. I got locked on extending some factory class due to the fact that’s what you do in bindings as well as the other automation modules I looked at.
Instead I added a @activate and @Deactivate method.

@Component(configurationPid = "automation.jrule")
@NonNullByDefault
public class JRuleFactory {

    private final ItemRegistry itemRegistry;
    private final JRuleEventSubscriber eventSubscriber;
    private final EventPublisher eventPublisher;
    private final VoiceManager voiceManager;
    private final JRuleHandler jRuleHandler;

    @Activate
    public JRuleFactory(Map<String, Object> properties, final @Reference JRuleEventSubscriber eventSubscriber,
            final @Reference ItemRegistry itemRegistry, final @Reference EventPublisher eventPublisher,
            final @Reference VoiceManager voiceManager) {
        this.itemRegistry = itemRegistry;
        this.eventSubscriber = eventSubscriber;
        this.eventPublisher = eventPublisher;
        this.voiceManager = voiceManager;
        jRuleHandler = new JRuleHandler(properties, itemRegistry, eventPublisher, eventSubscriber, voiceManager);
        jRuleHandler.initialize();
    }

    @Deactivate
    public void dispose() {
        jRuleHandler.dispose();
    }
2 Likes

I’ve built a new release, fixing internal dependencies and jar-generation. The previous jar was 7.5mbs :smile: Now 156kb.

Built an ALPHA2 version where you can add 3rd party jar dependencies.

Created and ALPHA3 prebuilt jar. Fixed some issues for 3rd party libraries and reloading rules when they are changed on disk.

Added an ALPHA4 build:

  • Refactored completable futures
  • Added 5 seconds of delay for initialization of the rule engine to avoid multiple reloads
  • Added support for play & pause for player item
  • Added commandLineExecute

Added an ALPHA5 build.

  • Removed dependencies on slf4japi and eclipse annotations
  • Added logInfo logDebug (to wrap slf4j and remove dep)
  • Fixed compilation of rules to be more robust with internal dependencies

You can still use sl4j for logging, but then you need to add it as an external dependency.