This page last changed on Nov 25, 2013 by jda.

Can anyone provide an example of how to manipulate a label from rules? For example, I'd like a label to indicate the last time a switch was turned on or off. Thanks!


Boiler_V1_10.png (image/png)
impulse_command.png (image/png)
impulse_sensor.png (image/png)
counter_command.png (image/png)
counter_sensor.png (image/png)
labels_ui_design.png (image/png)
rule_init.png (image/png)
console_init_command.png (image/png)
console_init_command.png (image/png)
Diagram.png (image/png)

Code not tested, so please beware of typos.

package org.openremote.controller.protocol;
import java.util.Date
import java.text.SimpleDateFormat;
import org.openremote.controller.model.event.*
global org.openremote.controller.statuscache.CommandFacade execute;

rule "Time when switch was turned on or off"
when
  Event("mySwitch")
then
  Date now;
  SimpleDateFormat dateFormatter = new SimpleDateFormat("H:mm:ss");
  execute.command("myVCommand", "Switched on "+dateFormatter.format(now));
end

For this to work you need to have in your design:
1. Sensor for reading your switch with the name "mySwitch" - this can be the same which is used inside your switch;
2. In memory virtual command with the name "myVCommand" and command "status";
3. sensor type custom linked to the virtual command from pt. 2
4. Label linked to the sensor from pt. 3

Posted by aktur at Nov 26, 2013 08:48

Thank you! Everything works after this simple change to your code:

  Date now = new Date();
Posted by jda at Dec 05, 2013 23:24

Jack, I haven't got the explanation. Could you please help me to understand the answer?

I would like to make a smart boiler that indicates how much hot water still in it.
Water counter connected directly to boiler out pipe.

Receiving integer values from water counter via 1-wire DS2423.
Quite kickly with help of manual I found the way to make
Command "GetCounter" to read the values.
Then added Command to a Sensor "SensCounter" (type:custom, with Command "GetCounter").
Added this to a Label "liters total" and now it shows total quantity of
liters passed via counter.

And that's all. 10 hours on this forum spent but very few things understood.

At the very first stage I need some way to understand how to interact with buttons and switches.
At least it would be nice to press the Button and save the value to some label and variable.

Then we need trace water counter change in event and to implement a simple formula:
$UsedWater = $CurrentCounterValue - $SavedCounterValue;
$HotWaterInBoiler = 100 - $UsedWater;
After it output $HotWaterInBoiler to a label.

Quite simple task to do in Delphi ot PHP, but really hard to solve with Drools.

I used example MICHAL RUTKA'S
Temperature sensor's calibration http://mqlservice.net/openremote/2013/05/22/temperature-sensors-calibration/
In this example Michael reads real value and outputs corrected - almost
the same I need.

So we have:
SensCounter (Real sensor that reads values from counter)
==CmdGetCounter (reading counter values via 1-wire)

SensConsOpen (sensor, type switch attached to command SaveCounterR)
==SaveCounterR (In-memory virt command, STATUS, address:copycount)

This "virtual" sensor will be used to copy and output the value.
In the article Michal says:
"for the virtual sensor, you would have 2 "in-memory" commands: a
read (command: STATUS) and a
write (command : ON)"
Can't attach 2 commands for one sensor.

Then we need to attach a button to a switch that will triger event for rule, like
in example CHANGING SET TEMPERATURE USING SWITCHES AND BUTTONS: http://www.openremote.org/display/forums/Changing+set+temperature+using+switches+and+buttons?focusedCommentId=22877996#comment-22877996

But this will be another part of job.
First I would appreacite your help with at least reading the value,
calculating it and outup it to another label.


package org.openremote.controller.protocol

global org.openremote.controller.statuscache.CommandFacade execute;
global org.openremote.controller.statuscache.SwitchFacade switches;

rule "Consumption Tracer"
when
== $evt : Event(source=="SensConsOpen", value=="on") // button pressed
== $cnt : Event(source=="SensCounter") // bind $cnt with counter value
== $blr : Event(source=="* * * *") // here we need to bind $blr with output string?
then
double SavedValue = $cnt.getValue().toString();
execute.command("SaveCounterR", String (SavedValue) );
end

Friendly speaking I am shocked with the complexity of such simple task.
Possibly it is only because not knowing Drools and Java.

As I understand Button works this way:

Button (WaterOpened) => Command (ConsuptOpen) => Sensor (SensConsOpen, type:Switch) => Switch (SwConsOpen) => Event(source=="SensConsOpen", value=="on")

Is it correct?

It would be nice to find simple examples for every part if this project, but even the most simple ones, that I found, didn't helped.

Thank you in advance.

Alex

Posted by sattva at Dec 06, 2013 02:05

One more question: Does this document may help with rules language usage?

Drools Expert User Guide
Version 5.4.0.Final
by The JBoss Drools team http://www.jboss.org/drools/team.html

http://docs.jboss.org/drools/release/5.4.0.Final/drools-expert-docs/pdf/drools-expert-docs.pdf

Posted by sattva at Dec 06, 2013 02:10

Forgot to say - I am going to press the button when hot water usage starts and press another button when it stops to reset the variable with hot water. This will make scripts simple.

Posted by sattva at Dec 06, 2013 02:20

OpenRemote is still on Drools 5.1.1. Link to that manual is at the botom of Designer 2.0 - Controller Rules

Posted by pz1 at Dec 06, 2013 08:29

This "virtual" sensor will be used to copy and output the value.
In the article Michal says:
"for the virtual sensor, you would have 2 "in-memory" commands: a
read (command: STATUS) and a
write (command : ON)"
Can't attach 2 commands for one sensor.

This is not true as I discovered that command STATUS can be used as well for read and write.

Posted by aktur at Dec 06, 2013 10:23

Transformation

Thank you for your kind reply Michal.
As there are very few examples, I will try to write an article - step by step guide for my project.

The very first and simple step will be transformation of impulses to litters. It is very close to your article about temperature but now we will try to use only one command STATUS for data read/write.

First we will create
command GetImpulse to read 1-wire impulse data and a
sensor SensImpulse (type: custom) to get data from command GetImpulse:

Then we create In-memory virtual
command MakeCounter for liters conversion and a
sensor SensCounter (type: custom) to get data from MakeCounter:

After it, in UI Designer we create 2 labels
attached to 2 our sensors:

Then we save the project in online designer and sync it with the server.
It is fun but at this stage Android application crashes.
It works fine only if both labels are attached to working
real sensor SensImpulse. If I use SensCounter for the second label,
Android app crashes. But I am sure - everything done correctly.

Michal please confirm that everything fine and I will proceed to create the rule.

Thank you in advance.

Alex

Posted by sattva at Dec 06, 2013 14:39

It looks OK to me. I have no idea why Android app crashes. I test mostly on iOS which is slighty different. Anyway, have you tried this on the webconsole through a web browser?

You can also try to initialize the virtual mem variable during startup of the controller:

rule "init adrcount"
when
then
  execute.command("adrcount", "0");
end
Posted by aktur at Dec 06, 2013 15:04

I entered this code, but it didn't help:

package org.openremote.controller.protocol;
import java.util.Date
import java.text.SimpleDateFormat;
import org.openremote.controller.model.event.*
global org.openremote.controller.statuscache.CommandFacade execute;

rule "init adrcount"
when
then
  execute.command("adrcount", "0");
end

<b>Does it mean - there is no way to continue with rules code developing?</b>

Didn't know about web console. As I see it is here: http://192.168.8.6:8080/webconsole
so the result is also strange -
black hole instead of zero:

Posted by sattva at Dec 06, 2013 15:27

I would think more that the problem is the Android app or the device you are using. Which version do you have? IMHO the latest is 2.1.0 beta. Anyway, please try the design in web console or/and if you can on iOS device.

Posted by aktur at Dec 06, 2013 15:38

OpenRemote was downloaded yesterday.

So it is: OpenRemContr_2_1_0.
System: Windows XP, Java version.
OWServer: under Cygwin.
Phone: Samsung Galaxy Nexus.

Anyway, please try the design in web console
//
You mean here: http://192.168.8.6:8080/webconsole
It is tested. The result is black hole:

As for iOS - I will find next week one.
But if it doesn't work in webconsole, so iOS hardly helps...

Posted by sattva at Dec 06, 2013 16:11

I had a black hole initially and found it was a typo in my code. Remember all names are case-sensitive.

Posted by jda at Dec 06, 2013 16:50

Jack,
Thank you for your reply.

There is no code and Android app crash/ Webconsole black hole.

Michal recommended to add code just to init the variable and see if crash/black hole will be solved:

rule "init adrcount"
when
then
  execute.command("adrcount", "0");
end

No place for typo.

Posted by sattva at Dec 06, 2013 17:14

Can you get the virtual command to store a dummy value such as "Test" and then see it in the label? That will at least prove you've got the command, sensor, and UI set up correctly. Then it's on to figuring out what breaks in the calculation or passing the value to the command. Try to build and deploy it one step at a time since there is no debugger.

Posted by jda at Dec 06, 2013 17:32

Jack, you are right. This is exactly what Michal recommended to do with rule command:

  execute.command("adrcount", "0");

And it seems "In-memory Virtual Command" doesn't work correctly on my server as it never gives it's value to a label whatever I do.

Real command/censor and slider bind with label - work fine.

I have Java JDK 6 and JRE 7 on the same server with Windows XP. Could it be the problem?

I also have error

Failed to reload configuration and clear cache!

trying to "Reload configuration and clear cache" but found no solution for it.
So just press the button "Sync with Online Designer" and it works fine.

But "In-memory Virtual Command" doesn't work correctly.

I will install OWServer and OpenRemote
on CentOs 5 (if it will be possible) and check the difference.

It seems the problem is in Java or OpenRemote under Windows XP.

Posted by sattva at Dec 06, 2013 18:26

What does "adrcount" for? I would expect the name of one of your virtual status commands there. I did not spot one with that name.

Posted by pz1 at Dec 06, 2013 18:51

Pieter, You are right!

adrcount - is an address for command MakeCounter.
But it should be the name itself: MakeCounter.

After changing the Address of command to its Name, black hole problem solved!
Thank you!

Time to move forward.

Posted by sattva at Dec 06, 2013 19:18

Michal, could you please help with the rules?

First rule "init MakeCounter" works fine if there is no second rule.

package org.openremote.controller.protocol

import java.util.Date;
import java.text.SimpleDateFormat;
import org.openremote.controller.model.event.*

global org.openremote.controller.statuscache.CommandFacade execute;
global org.openremote.controller.statuscache.SwitchFacade switches;

rule "init MakeCounter"
when
then
  execute.command("MakeCounter", "15");
  execute.command("GetLevel", "35");
end

If I set the rule "Make proper counter value" no commands executed at all.

rule "Make proper counter value"
when
  CustomState (source == "SensImpulse", $Imp: value)
then
  execute.command("MakeCounter", "50");
end;

After 4 hours of forum reading and experiments realized,
that for Sensor type: custom we need event:
CustomState (source == "SensImpulse", $Imp: value)

For other sensors - other events. Is there any list?

Thank you for replies.

Posted by sattva at Dec 06, 2013 22:05

In my experience, if I include one rule with bad syntax all the rules stop working. Unfortunately, I don't know java well enough to know what's wrong with your syntax but I would suggest replacing "$Imp: value" with a dummy string and if your rules start working again you know that's where the syntax problem is.

Posted by jda at Dec 06, 2013 22:18

The syntax problem is probably the ; after final end.

Posted by aktur at Dec 07, 2013 00:35

Mea culpa. I have a custom of giving the command the same name as address fieled (just to memorize less and to see in the designer which addresses are there). Anyway, of course it should be "MakeCounter" there.

Posted by aktur at Dec 07, 2013 10:56

Yes, Michal!
The problem was in the last character of the code.
Yes! You are right. Now it finally works!!!
Thank you.

The code is mainly finished. I found how to convert variables
from string to integer and back.

Now I will try to find out how to read the value from
sensor or command without event (not after WHEN). I mean event is already
happened (impulse counter changed its value).
Now it is time to get integer value from sensor (or command)
and copy it into another command.

I tried to use inside the "then" part

  CustomState (source == "SensImpulses", $Impulses: value)

but it didn't help.

Posted by sattva at Dec 07, 2013 18:40

Found your post. Learning.

READING A SENSOR VALUE FROM INSIDE A RULE.
Michal Rutka
On May 26, 2013 15:29

Switch also doesn't work for me.
Moreover it stops working new rules or makes some other problems
even after I delete the SWITCH! - needed to reboot the server.

Posted by sattva at Dec 07, 2013 18:45

As I see, there is now way to read sensor inside the rule.
Only read it after WHEN and that's all. Correct?

Juha didn't gave any special example for this: http://www.openremote.org/display/forums/Reading+a+sensor+value+from+inside+a+rule.?focusedCommentId=22415040

Posted by sattva at Dec 07, 2013 19:17

Could you please look at this during the week?

This is very strange, but when I try to acces the value via

rule "Make proper counter value"
when
  CustomState (source == "SensWaterStartL", $UsageStartLit: value)
  // Trying to get SensWaterStartL value and compare it with the current counter value.
then

it triggers

rule "Trace water usage starts"
when
  CustomState (source == "SensLiters", $Liters: value) // Get value
  //SensWaterStartL created here to trace usage start.
then

and refreshes (destroyes) value of SensWaterStartL.

Complete code and diagram.

package org.openremote.controller.protocol

import java.util.Date;
import java.text.SimpleDateFormat;
import org.openremote.controller.model.event.*

global org.openremote.controller.statuscache.CommandFacade execute;
global org.openremote.controller.statuscache.SwitchFacade switches;

//---------------------------------------
rule "init Command Values"
when
then
  execute.command("MakeLitersValue", "0");
  execute.command("WaterVolumeInBoiler", "100");
  execute.command("WaterStartLit", "0");
  execute.command("WaterStartTime", "0:00");
  execute.command("BoilerOff", "Off");
  execute.command("TemperIn", "0");
  execute.command("TemperOut", "0");
end

// Transform impulses to liters and show last impulse time
//---------------------------------------
rule "Make proper counter value"
when
  CustomState (source == "SensImpulses", $Impulses: value)
  //CustomState (source == "SensWaterStartL", $UsageStartLit: value)
then
  // Convert sensor data to integer value
  Integer iLitersCnt = Integer.parseInt($Impulses.toString() );
  // 4178 impulses - offset betwen water counter and impulse counter
  iLitersCnt = iLitersCnt - 5311; 
  // Convert from integer to string value, adding L sign at the end
  String sLtCnt = String.format("%,d", iLitersCnt);
  // Set command "MakeLitersValue" to string value sLtCnt
  execute.command("MakeLitersValue",  sLtCnt);

  Date now = new Date();
  SimpleDateFormat dateFormatter = new SimpleDateFormat("H:mm");
  execute.command("LastImpulseTime", dateFormatter.format(now));

/*
  Integer iDeltaLit = Integer.parseInt($UsageStartLit.toString() );
  iDeltaLit = iLitersCnt - iDeltaLit;
  String sDltLit = String.format("%,d", iDeltaLit);
  execute.command("TemperOut",  sDltLit);
*/
end

// Water usage button clicked: Copy liters counter and show start time
//---------------------------------------
rule "Trace water usage starts"
when
  Event (source == "SensBoilerOnOff")
  CustomState (source == "SensLiters", $Liters: value) // Get value
then
  Date now = new Date();
  SimpleDateFormat dateFormatter = new SimpleDateFormat("H:mm");
  execute.command("WaterStartTime", dateFormatter.format(now) );

  execute.command("WaterStartLit",  $Liters.toString() );
end

Posted by sattva at Dec 08, 2013 01:07

It seems there is something wrong with ther sever of OpenRemote bacause my code stopped working. I changed nothing so it 100% sure not me.

Posted by sattva at Dec 08, 2013 23:36

You've created a loop. This is nothing unusual with it. How to prevent loops you can find in this article http://ilesteban.wordpress.com/2012/11/16/about-drools-and-infinite-execution-loops/

Posted by aktur at Dec 09, 2013 11:23

Sometimes it is good to hard reboot your machine. Especially after many updates.

Posted by aktur at Dec 09, 2013 11:24

Michal, thank you very much for an article.

As I see, there is no way to read sensor inside the rule.
Only read it after WHEN and that's all. Correct?

Posted by sattva at Dec 09, 2013 16:01

Thank you. I usually make system reboot.

As I see, there is no way to read sensor inside the rule.
Only read it after WHEN and that's all. Correct?

Posted by sattva at Dec 09, 2013 23:06

As I see, there is no way to read sensor inside the rule.
Only read it after WHEN and that's all. Correct?

Well, it is all Java, therefore with enough hacking everything is possible. However, removing sensor from when statement would make your rule insensitive to the sensor. This has more drawbacks than advantages. If you want simply ignore some values of sensors then you can use simple if(){} statement in the then part.

Posted by aktur at Dec 12, 2013 08:54
Document generated by Confluence on Jun 05, 2016 09:35