This page last changed on Oct 07, 2013 by thenetstriker.

I would like to configure a heating control using OpenRemote based on rules. But I don't just want to just set a fixed variable for the target temperature, I want to have a variable based on some sort of calendar where I can enter different events. (e.g. when I am home the temperature has to be higher as when I'am away or on vacation) Are there any examples on how a calendar can be accessed in such a way using OpenRemote rules?

Use timer cron syntax.

timer(cron: * * * * * ?)

Posted by atamariya at Oct 08, 2013 07:32

Second example of Advanced Rule Examples deals with the "vacation" thing. Maybe a good starting point?
Just for my curiosity: Do I interpret your post correctly that you want to get your "vacation data" from an external calendaring program?

Posted by pz1 at Oct 08, 2013 08:10

I already found those examples, but they are not exactly what I am looking for. I would like to get the events from e.g. one of my Google calendars and have the heat ajusted to the value (parsed from the title) of the current event. For the Google calendar there is a Phyton based library that could be used to get the events. Is is possible to call Phython libraries out of rules or is there some other way I could get the current event of my calendar in the rules?

Edit: There is also a Java based library to access Google calendar: https://developers.google.com/google-apps/calendar/v2/developers_guide_java
Can maybe this library be used in the rules?

Posted by thenetstriker at Oct 08, 2013 08:48

Here a newer v3 reference: https://developers.google.com/google-apps/calendar/v3/reference/. I am not a programmer so I can't say how complex it is to use. It looks as if one could use the http protocol to get events.

Posted by pz1 at Oct 08, 2013 09:36

You can use any Java API in Drools as it's Java based.

Posted by atamariya at Oct 08, 2013 10:04

I did take a look at the Google Api and I think there might be a better solution. (Google api requests are limited as far as I now) I found some free calendar servers based on the CalDav protocol. There is also a CalDav library for java called CalDAV4j. I will take a look at this library if it can be accessed from a Drools rule.

Posted by thenetstriker at Oct 08, 2013 12:25

I've tried different CalDav servers and different methods for reading the calendar events and I think the best solution would be to use the ical4j library and directly load the ical file. The ical4j library seams to have support for synchronisation or maybe even some sort of event system. (I'm not sure at the moment, the documentation of the library is not very good)

To choose the right method I need to know some facts about the possibities in drools:

  • Is it possible to declare static objects in the java libraries? (So I don't have to parse the iCal file on every call)
  • Is it possible to raise a rule based on an event from a java library in drools?
Posted by thenetstriker at Oct 10, 2013 13:34

Is it possible to declare static objects in the java libraries? (So I don't have to parse the iCal file on every call)

The answer is yes.

Is it possible to raise a rule based on an event from a java library in drools?

Have a look at following thread: http://www.openremote.org/pages/viewpage.action?pageId=22877256&focusedCommentId=22877947#comment-22877947

Posted by atamariya at Oct 11, 2013 05:59

Thanks for your help. I've managed it to create a java class which provides the current event and parses the temperature out of the event notes: http://pastebin.com/XR7aJRwL

I've copied this class in a jar file and the files ical4j-1.0.5.jar, backport-util-concurrent-3.1.jar, commons-lang-2.6.jar and commons-logging-1.1.3.jar to webapps/controller/WEB-INF/lib. Now I am able to get the current target temperature using this drl code: http://pastebin.com/b2jXsThp

Now I have some addidional questions:
1) How can I display the value of Temperature.getTargetTemperature() on the UI?
2) My current Java class cannot trace changes in the ical file. In Java 7 there is a new function called WatchService which would be perfect to monitor changes in the ical file. When will Java 7 be supported by OpenRemote?

Posted by thenetstriker at Oct 12, 2013 17:50

1) How can I display the value of Temperature.getTargetTemperature() on the UI?

You can use Sensor.update(val) in the rule which should be attached to a label in the UI.

2) My current Java class cannot trace changes in the ical file. In Java 7 there is a new function called WatchService which would be perfect to monitor changes in the ical file. When will Java 7 be supported by OpenRemote?

People have been reporting using JDK8 on RPi. Not sure what's the problem you are facing while using JRE7.

Posted by atamariya at Oct 13, 2013 07:30

I found a constructor for the Sensor class, but it needs multiple parameters. Can you provide a simple example on how I can get a reference to a sensor in a drools rule? And how do I have to configure the sensor? (Do I have to set a dummy command to the sensor?)
Can you also provide a simple example on how I can handle a simple button click on the UI using a drools rule? And do I have to configure a dummy command to handle the click? (Until I found a good solution to trigger a rule on changes in the calendar I'd like to add a button to reload the calendar)

I don't use Java 7 because the drools rules don't work at all whit this version. Here is the error i get:

ERROR 2013-10-13 14:28:15,365 : Cannot start event processor 'Drools Rule Engine' : Unable to load dialect 'org.drools.rule.builder.dialect.java.JavaDialectConfiguration:java:org.drools.rule.builder.dialect.java.JavaDialectConfiguration'
org.drools.RuntimeDroolsException: Unable to load dialect 'org.drools.rule.builder.dialect.java.JavaDialectConfiguration:java:org.drools.rule.builder.dialect.java.JavaDialectConfiguration'
at org.drools.compiler.PackageBuilderConfiguration.addDialect(PackageBuilderConfiguration.java:283)
at org.drools.compiler.PackageBuilderConfiguration.buildDialectConfigurationMap(PackageBuilderConfiguration.java:268)
at org.drools.compiler.PackageBuilderConfiguration.init(PackageBuilderConfiguration.java:181)
at org.drools.compiler.PackageBuilderConfiguration.<init>(PackageBuilderConfiguration.java:159)
at org.drools.compiler.PackageBuilder.<init>(PackageBuilder.java:210)
at org.drools.compiler.PackageBuilder.<init>(PackageBuilder.java:143)
at org.drools.builder.impl.KnowledgeBuilderFactoryServiceImpl.newKnowledgeBuilder(KnowledgeBuilderFactoryServiceImpl.java:34)
at org.drools.builder.KnowledgeBuilderFactory.newKnowledgeBuilder(KnowledgeBuilderFactory.java:47)
at org.openremote.controller.statuscache.rules.RuleEngine.getValidKnowledgePackages(RuleEngine.java:484)
at org.openremote.controller.statuscache.rules.RuleEngine.start(RuleEngine.java:253)
at org.openremote.controller.statuscache.EventProcessorChain.start(EventProcessorChain.java:112)
at org.openremote.controller.statuscache.StatusCache.start(StatusCache.java:120)
at org.openremote.controller.deployer.Version20ModelBuilder.buildSensorModel(Version20ModelBuilder.java:659)
at org.openremote.controller.deployer.Version20ModelBuilder.build(Version20ModelBuilder.java:557)
at org.openremote.controller.deployer.AbstractModelBuilder.buildModel(AbstractModelBuilder.java:154)
at org.openremote.controller.service.Deployer.startup(Deployer.java:858)
at org.openremote.controller.service.Deployer.startController(Deployer.java:336)
at org.openremote.controller.spring.SpringContext.initializeController(SpringContext.java:109)
at org.openremote.controller.service.ServiceContext.init(ServiceContext.java:383)
at org.openremote.controller.bootstrap.Startup.loadServiceContext(Startup.java:85)
at org.openremote.controller.bootstrap.servlet.ServletStartup.initializeServiceContext(ServletStartup.java:190)
at org.openremote.controller.bootstrap.servlet.ServletStartup.contextInitialized(ServletStartup.java:109)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4342)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:926)
at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:889)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1149)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.core.StandardService.start(StandardService.java:516)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
Caused by: org.drools.RuntimeDroolsException: value '1.7' is not a valid language level
at org.drools.rule.builder.dialect.java.JavaDialectConfiguration.getDefaultLanguageLevel(JavaDialectConfiguration.java:162)
at org.drools.rule.builder.dialect.java.JavaDialectConfiguration.init(JavaDialectConfiguration.java:57)
at org.drools.compiler.PackageBuilderConfiguration.addDialect(PackageBuilderConfiguration.java:279)

Posted by thenetstriker at Oct 13, 2013 15:35

On second thoughts, you might not be able to update sensors from rule engine. However, you can trigger the action from UI using this logic. Define a new sensor in UI using a virtual command. A sensor can be identified using the event source. You can write something like:

 
When
  Event(source == "sensorname", value == "on")
Then
  // do something
End

For supporting JRE 1.7, looks like Drools have to be upgraded. Check this.

Posted by atamariya at Oct 14, 2013 07:19

The JRE 1.7 fix worked, I will see if the filesystem event also works. Thanks for the link!

Edit: I've managed it to implement a button to manually refresh the calendar. I had to add three virtual commands (for on, off and status) and a sensor for the status command. Now my buttons executes the on command and my rule refreshes the calendar and executes the off command. Using this configuration the user can double click on the button and the command is only executed once. Here is my new rule:

rule "Reload calendar switch click"
when
e : Event( source == "SE_ReloadCalendar", value == "on" )
t : Temperature ( )
then
CalendarProvider.loadCalendarFromUrl(t.getCalendarUrl(), t.getCalendarUsername(), t.getCalendarPassword());
execute.command("ReloadCalendarOff");
end

I also have another idea of how I might be able to set a sensor value from a rule. I've managed it to get a reference to the KnowledgeRuntime of drools:

In the rule I just call:
CalendarProvider.Test(drools.getKnowledgeRuntime());

And here is the test function:
public static void Test(final KnowledgeRuntime knowledgeRuntime) {
Collection<Object> objects = knowledgeRuntime.getObjects();

for (Object obj : objects) {

}
}

In "getObject" I only find my "Temperature" object. Can I somehow get a reference to the configured sensors using this KnowledgeRuntime?

Posted by thenetstriker at Oct 14, 2013 13:26

No, you can't get a reference to sensor without some programming. And if you are willing to code, I suggest you write a command and a commandBuilder implementation for a new email protocol.

Posted by atamariya at Oct 15, 2013 13:27

Thanks for the hint, I made a simple change to the VirtualCommand.java. I've just added this function to the class:

public static void setValue(String address, String value) {
    virtualDevices.put( address, value );
}

Now I can configure a virtual command with an address and command "status" and setup a custom sensor which provides a value for a label on the webinterface. Then I can set the desired value in my rule using this command:
org.openremote.controller.protocol.virtual.VirtualCommand.setValue("address", "value");

The value is immediately displayed on the webinteface. Would it make sense to implement this function in the next release of openremote?

Posted by thenetstriker at Oct 15, 2013 19:46

Glad to hear that it worked for you. However, I don't think this can be included (modification to VirtualCommand) in the distribution as it doesn't conform to OR framework. As I said earlier, if you can write an ExecutableCommand (also EventProducer) implementation, it can surely be included in OR.

Posted by atamariya at Oct 16, 2013 06:53

I've just found out that it is also possible to set the values from a command without my modification. Just call execute.command("MyVirtualCommand", "MyValue") from any rule, so there is no need for a new Command.

Posted by thenetstriker at Oct 21, 2013 15:30
Document generated by Confluence on Jun 05, 2016 09:41