This page last changed on Aug 21, 2014 by niraviry.

Hi.

I was out of the business for a long time. No I am trying to do few things I had in mind.
One of them is to manipulate the data coming out of the weather station in order to automatically enable/disable the need to water tank heating.

The is the rule (part of a few of them). I need help in updating the accumulated temp and light as a decision criteria.
I am reading the Weather station each half an hour and would like to accumulate the results into a fact.

rule "Heat WT Factor"  
timer (cron: 0 0/30 10-16 * * ?)
when
    $wt_factors : Water_Tank_Factors()
    CustomState ( source == "Roof Temp (Status)", $val_T : value);
    CustomState ( source == "Roof Brightness (Status)", $val_L : value);
then  
    
    $wt_factors.setAcc_temp() = $wt_factors.getAcc_temp() + $val_T.toLong();  // ******
    $wt_factors.setAcc_light() = $wt_factors.getAcc_light() + $val_L.toLong(); // ******
    insert ($wt_factors);
    System.out.println ( _TimeStamp()+ ":  Water Tank factors logged: " + $val_T.toString() + "  " + $val_L.toString());
    System.out.println ( _TimeStamp()+ ":  Water Tank factors sum: " + $wt_factors.getAcc_temp() + "  " + $wt_factors.getAcc_light());
end

The rule engine runs without any errors but if the 2 lines marked with //***** are not comments, the rule does not do anything but shown no error. If these lines are commented the rule runs nicely and I can see the values each half an hour.

Does anybody have an idea what seems to be the problem.

Need help.

Are you sure you don't have errors? stderrout.log is buffered so you will not get errors immediately. It does not look like correct rule to me, but I am not an expert. I would change the lines either this way:

$wt_factors.setAcc_temp($wt_factors.getAcc_temp() + $val_T.toLong());
$wt_factors.setAcc_light($wt_factors.getAcc_light() + $val_L.toLong());

or this:

$wt_factors.acc_temp = $wt_factors.acc_temp + $val_T.toLong();
$wt_factors.acc_light = $wt_factors.acc_light + $val_L.toLong();
Posted by druciak at Aug 21, 2014 20:13

Hi KRZYSZTOF.

Actually the syntax you mentioned creates errors. Both my options (original and the following does not.

$wt_factors.setAcc_temp($wt_factors.getAcc_temp() + Float.parseFloat($val_T.toString()));
$wt_factors.setAcc_light($wt_factors.getAcc_light() + Long.parseLong($val_T.toString()));

Without these two lines it runs great and reports the temp and light level every 30 minutes. The LHS has nothing to do with the facts (accumulating temp and Light).

I have set the crone to fire every 1 minute and rule is still asleep.

Need help.

Posted by niraviry at Aug 30, 2014 18:22

As I said, I am not an expert. You need to either debug your rule (more logging) or make changes until it works. Also it will be hard to help you without full listing of the rule, including the fact declaration, imports, etc.

Posted by druciak at Sep 01, 2014 10:23

I add the relevant code.
The issue is that once the RHS calculation are added (marked between the lines with ++++++, the rule stops firing. Without it it works every 30 minutes just fine.
I have tried many ways, some created errors and some where OK, which means no errors and the rule engine runs fine with all other rules.

I really have no idea why a simple calculation is doing such a mess except for a bug.
The code here is a part of a long rules file which a part of this issue works great for many months now.
I will appreciate help from someone.

package org.openremote.controller.protocol

global org.openremote.controller.statuscache.CommandFacade execute;
global org.openremote.controller.statuscache.SwitchFacade switches;
global org.openremote.controller.statuscache.LevelFacade levels;
global org.openremote.controller.statuscache.RangeFacade ranges;

import org.openremote.controller.protocol.*;
import org.openremote.controller.model.event.*;
import org.openremote.controller.Constants;
import org.openremote.controller.utils.Logger;

import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

// import java.io.*;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import java.lang.System;
import java.lang.Float;
import java.lang.Integer;
import java.lang.Long;

import java.text.DecimalFormat;
import java.text.Format;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
//------------------------------------------------------------------------------------------
declare Water_Tank_Factors
    acc_temp : float
    acc_light : long
    heat_needed : int
    acc_zero : int
    acc_lock_reading : int
end
declare Activated_time
    milliseconds : long
    the_time_SS : long
    the_time_MM : long
    the_time_HH : long
    the_time_GMT : int
    fired : int
end
declare Email_Text_Message
    email_text: String
	email_send: int
end
//-----------------------------------------------------------------------------------------
rule "Init eMail"
no-loop
when
    eval ( true )
then
    Email_Text_Message $em_message = new Email_Text_Message();
    $em_message.setEmail_text("");
    $em_message.setEmail_send (0);
    insert ( $em_message );
    System.out.println ( "  " );
    System.out.println ( "eMail Vars Initiated" );
end
//----------------------------------------------------------------------------------------
rule "Init_WT_Factors"
no-loop
when
    eval (true)
then
    Water_Tank_Factors $factors = new Water_Tank_Factors();
    $factors.setAcc_temp(0);
    $factors.setAcc_light(0);
    $factors.setHeat_needed(0);   //  ---- Update:  summer=0, winter=1  !!!!
    $factors.setAcc_zero(0);
    $factors.setAcc_lock_reading(0);
    insert ( $factors );
    System.out.println ( "  " );
    System.out.println ( "Water Timing Factors initiated");
end
//----------------------------------------------------------------------------------------
rule "Init_Time_Stamp"
no-loop
when
    eval ( true )
then
    Activated_time $t = new Activated_time();
    $t.setMilliseconds (0);
    $t.setThe_time_SS (0);
    $t.setThe_time_MM (0);
    $t.setThe_time_HH (0);
    $t.setThe_time_GMT (2);
    $t.setFired (0);
    insert ( $t );
    System.out.println ( "  " );
    System.out.println ( "Time Stamp Var Initiated" );
end
//----------------------------------------------------------------------------------------
rule "Print_Event_Time"
lock-on-active true
when
    $wt_timer : Water_Tank_Timer()
    $t : Activated_time()
    $sw : Irrigation_Control()
    eval ( $wt_timer.getRead_time() > 0)
then
    $t.setMilliseconds ( System.currentTimeMillis());
    $t.setThe_time_SS ( $t.getMilliseconds() / 1000); // Convert to Seconds
    $t.setThe_time_MM ( $t.getThe_time_SS() / 60 ); // Convert to Minutes
    $t.setThe_time_HH ( ( $t.getThe_time_MM() /  60 ) +2 + $sw.getSummer()); // Convert to houres in current time zone
    System.out.println ( "Time was switched at " + ($t.getThe_time_HH() % 24) +":"+ ($t.getThe_time_MM() %60 ) + ":"+ ($t.getThe_time_SS () % 60)+"."+($t.getMilliseconds() % 1000 ));
    System.out.println ( " " );
	modify ($wt_timer)
    {
        setRead_time(0);
    }
end
//----------------------------------------------------------------------------------------
rule "Send Email"
lock-on-active
when
    $em_message : Email_Text_Message()
    eval( $em_message.getEmail_send() == 1)
then
    System.out.println ( _TimeStamp()+ ": Processing eMail !");
    final String username = "AAAAAAAAAAAAA@gmail.com";
    final String password = "XXXXXXXXXXXXX";
    Properties props = new Properties();
    props.put("mail.smtp.host", "smtp.gmail.com"); 
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");

    Session session = Session.getInstance
	(props, new javax.mail.Authenticator()
	{
		protected PasswordAuthentication getPasswordAuthentication()
		{
			return new PasswordAuthentication(username, password);
		}
    }
	);
    try
	{
		Message message = new MimeMessage(session);
		message.setFrom(new InternetAddress("AAAAAAAAAAAAAA@gmail.com"));
		message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("NNNNNNNN@gmail.com"));
		message.setSubject("KNX Activity Message");
        message.setText($em_message.getEmail_text());
		Transport.send(message);
		System.out.println(_TimeStamp()+ " Mail was sent !");
	} 
	catch (MessagingException e)
	{
		throw new RuntimeException(e);
	}
	modify($em_message)
	{
		setEmail_text("");
	}
	modify($em_message)
	{
	    setEmail_send(0);
	}
end
//------------------------------------------------------------------------------------------
rule "Get WT Factors"  
// lock-on-active true
timer (cron: 0 0/30 9-18 * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_lock_reading() == 0 )
    CustomState ( source == "Roof Temp (Status)", $val_T : value)
    CustomState ( source == "Roof Brightness (Status)", $val_L : value)
then
    // +++++++++++++++++++++++++++++++++++++++++++  The RHS problem start
    modify ($wt_factors)
    {
       setAcc_temp ( $wt_factors.getAcc_temp() + Float.valueOf((String)$val_T));
    }
    modify ($wt_factors)
    {
        setAcc_light ( $wt_factors.getAcc_light() + Long.valueOf((String)$val_L));
    }
    //  +++++++++++++++++++++++++++++++++++++++++   The RHS problem end

    System.out.println ( _TimeStamp()+ ":  Water Tank factors logged: " + $val_T.toString() + "  " + $val_L.toString());
    System.out.println ( _TimeStamp()+ ":  Water Tank factors sum: " + $wt_factors.getAcc_temp() + "  " + $wt_factors.getAcc_light());
    modify ($wt_factors)
    {
	setAcc_lock_reading( 1 );
    }
end
//------------------------------------------------------------------------------------------
rule "Clear Single Factors Read"  
timer (cron: 0 2/32 9-18 * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_lock_reading() == 1 )
then
    modify ($wt_factors)
    {
	setAcc_lock_reading( 0 );
    }
    System.out.println ( _TimeStamp()+ ":  Water Tank factors lock reading was zeroed");
end
//------------------------------------------------------------------------------------------
rule "Stop Accomulating"  
lock-on-active true
timer (cron: 0 40 18 * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_zero() == 0)
then
    modify ($wt_factors)
    {
	setAcc_zero( 1 );
    }
    modify ($wt_factors)
    {
	setAcc_lock_reading( 0 );
    }
end
//------------------------------------------------------------------------------------------
rule "Calc if Heat Needed"  
lock-on-active true
timer (cron: 0 35 18 * * ?)

when
    $wt_factors : Water_Tank_Factors()
    eval (($wt_factors.getAcc_light() + ($wt_factors.getAcc_temp() * 4000)) < 1500000)
    eval (($wt_factors.getAcc_light() + ($wt_factors.getAcc_temp() * 4000)) > 0)
    eval ($wt_factors.getAcc_zero() == 0 )
then
    modify ($wt_factors)
    {
	setHeat_needed(1);
    }
    System.out.println ( _TimeStamp()+ ":  Water Tank Heat was set to On");
end
//------------------------------------------------------------------------------------------
rule "Zero_WT_Factor"  
lock-on-active true
timer (cron: 0 0 07 * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_zero() == 1 )
then
    modify ($wt_factors)
    {
	setAcc_temp(0);
    }
    modify ($wt_factors)
    {
	setAcc_light(0);
    }
    modify ($wt_factors)
    {
	setHeat_needed(0);
    }
    modify ($wt_factors)
    {
	setAcc_zero(0);
    }
    System.out.println ( _TimeStamp()+ ":  Daily cleared WT factors");
end
//------------------------------------------------------------------------------------------
function String _TimeStamp(){
  Date now;
  now = new Date();
  SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss");
  return(dateFormatter.format(now));
}

Posted by niraviry at Sep 04, 2014 15:38

Wow, this is really impressive! I thought you are a beginner, but definitely I was wrong.
Anyway I take out a part of your script and it worked, so not sure what is wrong. Here is the code:

package org.openremote.controller.protocol

import org.openremote.controller.model.event.*;

import java.util.Date;
import java.text.SimpleDateFormat;

declare Water_Tank_Factors
    acc_temp : float
    acc_light : long
    heat_needed : int
    acc_zero : int
    acc_lock_reading : int
end

rule "Init_WT_Factors"
no-loop
when
    eval (true)
then
    Water_Tank_Factors $factors = new Water_Tank_Factors();
    $factors.setAcc_temp(0);
    $factors.setAcc_light(0);
    $factors.setHeat_needed(0);   //  ---- Update:  summer=0, winter=1  !!!!
    $factors.setAcc_zero(0);
    $factors.setAcc_lock_reading(0);
    insert ( $factors );
    System.out.println ( "  " );
    System.out.println ( "Water Timing Factors initiated");
end

rule "Get WT Factors"  
no-loop
timer (cron: 0/10 * * * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_lock_reading() == 0 )
    CustomState(source == "TempP00", $val_T: value)
then
    modify ($wt_factors)
    {
	setAcc_lock_reading( 1 );
    }
    String val_L = "1";
    // +++++++++++++++++++++++++++++++++++++++++++  The RHS problem start
    modify ($wt_factors)
    {
        setAcc_temp ($wt_factors.getAcc_temp() + Float.valueOf($val_T.toString()));
    }
    modify ($wt_factors)
    {
        setAcc_light ($wt_factors.getAcc_light() + Long.valueOf(val_L));
    }
    //  +++++++++++++++++++++++++++++++++++++++++   The RHS problem end

    System.out.println ( _TimeStamp() + ":  Water Tank factors sum: " + $wt_factors.getAcc_temp() + "  " + $wt_factors.getAcc_light());
end

rule "Clear Single Factors Read"  
no-loop
timer (cron: 5/10 * * * * ?)
when
    $wt_factors : Water_Tank_Factors()
    eval ($wt_factors.getAcc_lock_reading() == 1 )
then
    modify ($wt_factors)
    {
	setAcc_lock_reading( 0 );
    }
    System.out.println ( _TimeStamp()+ ":  Water Tank factors lock reading was zeroed");
end

function String _TimeStamp()
{
  Date now;
  now = new Date();
  SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss");
  return(dateFormatter.format(now));
}

The only important difference is "$val_T.toString()" instead of "(String) $val_T".
However it does not work well, as rules sometimes get fired more than once at the time. Here's the output:

Water Timing Factors initiated
20:59:50:  Water Tank factors sum: 23.1875  1
20:59:55:  Water Tank factors lock reading was zeroed
21:00:00:  Water Tank factors sum: 46.375  2
21:00:05:  Water Tank factors lock reading was zeroed
21:00:10:  Water Tank factors sum: 69.5625  3
21:00:15:  Water Tank factors lock reading was zeroed
21:00:15:  Water Tank factors lock reading was zeroed
21:00:20:  Water Tank factors sum: 92.75  4
21:00:25:  Water Tank factors lock reading was zeroed
21:00:25:  Water Tank factors lock reading was zeroed
21:00:30:  Water Tank factors sum: 115.9375  5
21:00:30:  Water Tank factors sum: 139.125  6
21:00:35:  Water Tank factors lock reading was zeroed
21:00:35:  Water Tank factors lock reading was zeroed
21:00:40:  Water Tank factors sum: 162.3125  7
21:00:40:  Water Tank factors sum: 185.5  8
21:00:40:  Water Tank factors sum: 208.6875  9

Not sure what is the reason, maybe after clean controller start it would work better, but didn't have more time check that.

Posted by druciak at Sep 04, 2014 20:23

Hi.

Thanks. I think I have tried that but I will have a look and let you know in a few minutes.

Posted by niraviry at Sep 05, 2014 16:38

Hi.
It does work the way you put it. I am pretty sure this was my 1st version.
The only thing that is different is the name of the sensor but mine is fine as the my LHS is the same as was originally.

Now I have set the light accumulation as well and it looks like this is the reason the rule does not work.

Long.valueOf($val_L.toString())

This code does not generate an error but it stops this rule from running.
Digging into it, it looks like I always work on it during the evening. I did not notice the the light during the evening is X.X and conversion to long does not work.
During the day it is around XXXXX and it appears as an integer. I need to use a float as well.
Now it works.
Thanks.

Now I can move to the shades challenge as a macro is the only way I found way back to tackle the problem but now I got a new idea - using the duration attribute to distinguish between a short and a long press of a button. This is what the H/W is doing in my KNX system.

Posted by niraviry at Sep 05, 2014 17:18

I'm glad you finally get it working. This is really big piece of code and not easy to debug. Good luck with this new challenge.

Posted by druciak at Sep 05, 2014 22:22

BTW: I just noticed you have GMail credentials in your code. You should remove that and immediately change your password on that account, before somebody takes over it.

Posted by druciak at Sep 08, 2014 18:25
Document generated by Confluence on Jun 05, 2016 09:36