OpenRemote Rules examples

MDAR Ltd edited this page Oct 31, 2017 · 19 revisions

The head of every​ rules file you create needs to be formatted correctly, the following rules all have this text :

package org.openremote.controller.protocol;

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

import java.util.*;
import java.util.regex.*;

The following rules have been created for real world situations and are presented here as a resource.

If, Then, Else

This rule shows a sensor that must match a text string before a command is executed. And what to do when the sensor does not match the text

package org.openremote.controller.protocol;

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

import java.util.*;
import java.util.regex.*;


  Rule "if then else"

    Event( source == "A Sensor", value == "on" )
then
  execute.command( "Something ON" );

else
  execute.command( "Something OFF" );

end

A similar rule, but where a sensor has a numeric value that must be matched before a command is executed

package org.openremote.controller.protocol;

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

import java.util.*;
import java.util.regex.*;


Rule "if then when equal or greater"

    Event( source == "A Numeric Sensor", value > 8 )
then
  execute.command( "Something ON" );

end

Push a value from a rule into a command

This rule makes use of the ${param} variable that is deployable in some device protocols

package org.openremote.controller.protocol;

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

import java.util.*;
import java.util.regex.*;


rule "A sensor triggers a rule to inject a value into a command" 
when
  Event( source == "A Sensor", value == "on" )
then
  execute.command( "Dim to a level", 25 );

end

In a similar way, a text string can be injected into a ${param} variable

rule "A sensor triggers a rule to inject a text string into a command" 
when
  Event( source == "A Sensor", value == "on" )
then
  execute.command( "Show this text", "Hello World" );

end

Take a 0 to 255 decimal value and inject a 2 digit HEX

This rule watches the sensor that is used in an In-Memory slider.

The modeler slider is linked to a command that sets the In-Memory state and a sensor that shows the value. The sensor in use is of the "Range Sensor" type, where the range has been set from 0 to 255

The command that is being executed is DMX over HTML, where the ${param} variable has been placed to accept the HEX value. For example - http://2.0.0.2/pixel.api?uni=0&ordercolour=RGB&onecolour=${param}&start=1&end=20

package org.openremote.controller.protocol;

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

import java.util.*;





rule "255 dec to hex" when

  $evt:Event( source == "Decimal_Slider_255", $val : value)

then

  String valStr = $val.toString();
  
  if (valStr != null ) {

	      
      // Convert int to hex value
      
	  	  
	  	  String hex = String.format("%02X", Integer.parseInt(valStr));

      execute.command( "DMX_Channel-set-by-HEX", hex.toString() );
   

  }
end

Extract a text string from a custom sensor and pass to a command

The aim of this rule is that each Velbus glass panel will have a numbered custom Temperature mode sensor with the following fields mapped in a Custom Sensor {Replace 'Hallway' with the name of the area the glass panel is in}

Defined as value being what is to be matched and name being what would be passed within the rule, or displayed in the UI.

Layout - value = name

  • "heat_comfort"= "Hallway in Comfort mode"
  • "heat_day"= "Hallway in day mode"
  • "heat_night"= "Hallway in night mode"
  • "heat_safe"= "Hallway in safe mode"

Custom Sensor mapping

The aim was to get an android device to say "The heating mode has changed, Hallway in comfort mode"

The rule uses a regex pattern to monitor Multi sensors.

Examples of sensors that would be picked up are : -

  • Hallway_Temp_Mode-Status
  • Landing_Temp_Mode-State
  • Dining_Temp_Mode-sensor
  • Anything_Temp_Mode-something
  • House_Temp_Mode-31

There is no limit to how many sensors could be matched.

package org.openremote.controller.protocol;

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

import java.util.*;
import java.util.regex.*;
 
 
 // TTS Test rules
   
 rule "TTS heating mode"
 
 when
     $evt:Event(source matches "^.*_Temp_Mode-\\d+$", $source : source)
 then
 
 
 // This next line will extract the value of the sensor and hold it in a string
 
     String ModeStatus = $evt.getValue().toString();
 
     System.out.println("TTS - Temperature Mode Status Change '" + $source + "': " + ModeStatus);
 
 
    try {
 
      
       execute.command("TextToSpeech_01_param", "The heating mode has changed," + ModeStatus);
    
    } catch (Exception e) {
       System.out.println("############## TTS heating mode exception: " + e.getMessage() + " #################");
       return;
    }
 
 end

The above rule could make use of the sensor name and it's value in the executed command by using the following

execute.command("TextToSpeech_01_param", "Sensor with the name " + $Source + "reports the mode as " + ModeStatus);

Splitting the colour picker RGB HEX value into seperate sections

Richard Turner created a rule that seperates an RGB HEX colour value In-Memory command status (where the value is set by another In-Memory command linked to a colour picker UI element) into 3 seperate % values for use with 3 Velbus dimmer channels.

  • In-Memory command "186_RGB_Colour_Picker_Set" > linked to Colour Picker UI element

  • In-Memory status command linked to Sensor "186_RGB_Colour_Picker_Status"

3 seperate Velbus dimmer_level commands

  • 186-4DC-Ch1R-Dim100

  • 186-4DC-Ch2G-Dim100

  • 186-4DC-Ch3B-Dim100

         rule "186-RGB To 3 Channels"
         
         when
          
          
      // SOURCE here is an In-Memory status sensor that shows the RGB HEX value from a colour picker "186_RGB_Colour_Picker_Status"
      
        $evt:Event( source == "186_RGB_Colour_Picker_Status", $val : value)
      
      then
          
        String valStr = $val.toString();
        
        if (valStr != null && valStr.length() == 6) {
        
            // Split a single 6 digit HEX RGB colour value into 3 seperate RGB values (in HEX format)
            String rStr = valStr.substring(0,2);
            String gStr = valStr.substring(2,4);
            String bStr = valStr.substring(4,6);
            
            // Convert 2 digit HEX values into DEC int values
            Integer r = Integer.parseInt(rStr, 16);
            Integer g = Integer.parseInt(gStr, 16);
            Integer b = Integer.parseInt(bStr, 16);
    
            // Convert 0-255 value to 0-100 whole number
            r = (int)Math.round(((double)r / 255d) * 100);
            g = (int)Math.round(((double)g / 255d) * 100);
            b = (int)Math.round(((double)b / 255d) * 100);
    
            execute.command( "Red_Set", r.toString() );. // In-Memory command used as a reference in the UI for debugging
            execute.command( "186-4DC-Ch1R-Dim100", r.toString() ); // A channel of a VMB4DC that is used to drive the Red elements of an RGB fixture
    
    
            execute.command( "Green_Set", g.toString() );. // In-Memory command used as a reference in the UI for debugging
            execute.command( "186-4DC-Ch2G-Dim100", g.toString() ); // A channel of a VMB4DC that is used to drive the Green elements of an RGB fixture
    
    
            execute.command( "Blue_Set", b.toString() ); // In-Memory command used as a reference in the UI for debugging
            execute.command( "186-4DC-Ch3B-Dim100", b.toString() ); // A channel of a VMB4DC that is used to drive the Blue elements of an RGB fixture
        }
          end
    

Generating random numbers to inject into commands

Michal took this a step further when I started playing around with the HTTP driven DMX device by creating random HEX values to use as RGB strings.

Where a pulsing status is used to trigger the rule. (Not the output state of an 'Interval Timer' relay channel in Velbus as this would give a constant state of "timer", I linked the interval timer relay channel to another relay (momentary action) so that the slave relay showed on and off states)

An interval timer in Rules might be a better option, but I wanted to be able to vary the interval pulse time in VelbusLink or use multiple actions wth different times.

This rule sees 1 trigger and creates 6 different RGB HEX values to be sent to 6 seperate SPi pixels, using the same single HTTP command to address the SPi / DMX adapter. Where the %{param} is used to (only) transfer the HEX value, the start pixel and end pixel information.

Rule shown with header

package org.openremote.controller.protocol;

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

import java.util.*;


rule "Ch5 slave interval timer"

when

  Event( source == "01_VMB1RYNOS_ch5", value == "on" )

then

            java.util.Random randomGenerator = new java.util.Random();

            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=2&end=2");
            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=3&end=3");
            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=4&end=4");
            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=5&end=5");
            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=6&end=6");
            execute.command("DMX_Universal_Uni0",String.format("%06X", randomGenerator.nextInt(0x1000000)) + "&start=7&end=7");                
                


end

Regex query to match multiple sensors and extract unique elements

This rule was developed specifically for use with the Alarm Protocol

It uses a Regex to monitor multiple sensors with command names.

It extracts 2 unique elements in the sensor names and uses those to define which command is executed. ("Zone name" and "Time slot" from "Hall_Seditary_Status-query-01")

Examples ensors being matched : -

  • Hall_Seditary_Status-query-01
  • Hall_Seditary_Status-query-02
  • Hall_Seditary_Status-query-03
  • Zone2_Seditary_Status-query-01
  • Zone2_Seditary_Status-query-02
  • Zone2_Seditary_Status-query-03
  • Zone2_Seditary_Status-query-04
  • Zone3_Seditary_Status-query-01
  • Zone3_Seditary_Status-query-02
  • Zone3_Seditary_Status-query-03
  • Zone3_Seditary_Status-query-04

Commands to be matched with

  • Hall_Active_Time_Set_01
  • Hall_Active_Time_Set_02
  • Hall_Active_Time_Set_03
  • Zone2_Active_Time_Set_01
  • Zone2_Active_Time_Set_02
  • Zone2_Active_Time_Set_03
  • Zone2_Active_Time_Set_04
  • Zone3_Active_Time_Set_01
  • Zone3_Active_Time_Set_02
  • Zone3_Active_Time_Set_03
  • Zone3_Active_Time_Set_04

It also takes the time value from the sensor, adds 30 minutes and injects that new time value into the executed command.

(I'm not totally sure about how this dark magic works, but I'm very grateful that it does, it reduced 42 rules down to just one)

rule "Alarm Synchroniser"
when
    $evt:Event(source matches "^.*_Seditary_Status-query-\\d+$", $source : source)
then
   // The sensor value is the time of the seditary alarm as HH:MM
   String strValue = $evt.getValue().toString();
   String[] values = strValue.split(":");
        
   if (values.length != 2) {
      return;
   }

   int sensorNumber = 0;
   int hours = 0;
   int mins = 0;
   String alarmPrefix = "";

   try {
      // Extract the number from the sensor name
      Pattern p = Pattern.compile("^(.*)_Seditary_Status-query-(\\d+)$");
      Matcher m = p.matcher($source);
      m.matches();
      alarmPrefix = m.group(1);
      sensorNumber = new Integer(m.group(2));
      hours = new Integer(values[0]);
      mins = new Integer(values[1]);
      
      // Add 30 mins to the time and set this as the time for the active alarm
      mins += 30;
      execute.command(alarmPrefix + "_Active_Time_Set_" + sensorNumber, hours + ":" + mins);
   
   } catch (Exception e) {
      System.out.println("############## Alarm synchroniser exception: " + e.getMessage() + " #################");
      return;
   }

end

Count number of active sensors

Michal created this rule that counts a regex selection of active sensors and pushes that number into an In-Memory command.

Where sensors are named : -

  • Bed1-heatcall

  • Bed2-heatcall

  • Bed3-heatcall

  • WC-heatcall

  • Bathroom-heatcall

  • Landing-heatcall

  • Front-heatcall

  • Hallway-heatcall

  • Dayroom-heatcall

  • Dining-heatcall

  • Kitchen-heatcall

      rule"heatcall_count"
      when
        Number($count: intValue) from accumulate($i:Event(source matches "^.*-heatcall$", value=="pressed"), count($i))
      then
       execute.command("heatdemend",$count);
      end
    

Trigger a count down and execute events on start and finish

This rules uses an In-Memory register to hold a value, that once triggered, will be decreased to 0.

The absolute minimum you need to get this rule working is 2 modeller commands and a level sensor.

One modeller command will be used to set the number for the countdown to start at, while the other will be used to pass the stored value to the rule, via the sensor.

Create a modeller In-Memory command using any value greater than 1 and a unique identifier. This command can be used in the UI to start the countdown. It will also be used in the rule, where the command value will be replaced by the output from the rule.

The other modeller In-Memory command must use "status" as it's value, it is this command that will be used in the level sensor that the rule monitors.

If you wish, you can create a slider with these three items to start the rule in your UI. The slider will reduce as the countdown progresses

In the example, the sensor is

Holiday_Days_Status

The command being executed is

Holiday_Days_Set

HolidayVR_ON And HolidayVR_OFF

can be replaced with any command you wish to use.

 // Block of Rules for Holiday away days
  
 rule "Holiday_mode_Off"
    timer (int: 1s)
when
    Event( source == "Holiday_Days_Status", value == "0")
then
    execute.command("HolidayVR_OFF");
 //   execute.command("something_else"); // uncomment to activate
end
 

 
rule "Holiday_Mode_On"
    timer (int: 1s)
when
    Event( source == "Holiday_Days_Status", value > 0 )
then
    execute.command("HolidayVR_ON");
end



rule "Holiday_Mode_dec"
    timer (int: 10s) // change this 10s value to 24h when you're happy the rule is working
when
    Event( source == "Holiday_Days_Status", $TimeLeft : value > 0 )
then
    Integer iTl = Integer.parseInt($TimeLeft.toString()) ;
    iTl = iTl - 1 ;
    execute.command("Holiday_Days_set", iTl );
end

Sequence of steps

The following set of rules use the same concept as above, but increase the stored number, then has a command linked to each step.

This way a chase or step sequence can be created.

The sequence is started by a trigger setting the stored value to anything more than 1.

The sequence is stopped by setting the stored value to 0

  // Bathroom RGB on
   
    
   
   
      rule "Loft 7IN Shower temp RGB ON initial " 
     
      
   when

       Event( source == "Loft-7IN_Channel1-Status", value == "pressed" )
      
   then
  
         execute.command("IM_Num01_Set", "7" );
     
  end
   
    
   
      rule "Loft 7IN Shower temp RGB ON " 
    
     
    when
    
         Event( source == "Loft-7IN_Channel1-Status", value == "long_pressed" )
    
    then
     
          execute.command("IM_Num01_Set", "5" );
      
     end
    
     
      // Bathroom RGB Off
      
    
    rule "Loft 7IN Shower Temp RGB  OFF "
   
 
   when
    
       Event( source == "Loft-7IN_Channel1-Status", value == "released" )
   
 then

  
      execute.command("IM_Num01_Set", "0" );
  
  end
  
  
   
  
   // Set the point in the sequence to reset to the start        
   
   
    rule "IM_Num01_reset to 1"
   
  when
      Event( source == "IM_Num01_Status", value > 14 )
  then
      execute.command("IM_Num01_Set", "1" );
  end
   
   
      // In memory number 01 Increment

  
  
 
   rule "IM_Num01_Inc"
     timer (int: 15s)  // ***** This is the interval timer for each step ******
  when
      Event( source == "IM_Num01_Status", $BathroomStep : value > 0 )
  then
      Integer iBath = Integer.parseInt($BathroomStep.toString()) ;
      iBath = iBath + 1 ;
      execute.command("IM_Num01_Set", iBath ) ;
    
  end
  
  
 // Chase steps
 
 
 rule "IM_Num01_0"
 
 when
     Event( source == "IM_Num01_Status", value == "0")
 then
  
     execute.command("191 Bathroom RGB IM SET","000000");
  
  end
  
   
  
    rule "IM_Num01_1"
    
  when
       Event( source == "IM_Num01_Status", value == "1")
  then
    
       execute.command("191 Bathroom RGB IM SET","FF0000");
  
  end
 
   
  
    
    
      rule "IM_Num01_2"
   
  when
     Event( source == "IM_Num01_Status", value == "2")
  then
    
      execute.command("191 Bathroom RGB IM SET","00FF00");
  
  end
   
   
   
       rule "IM_Num01_3"
    
  when
       Event( source == "IM_Num01_Status", value == "3")
  then
     
        execute.command("191 Bathroom RGB IM SET","0000FF");
    
   end
    
   
    
   
        rule "IM_Num01_4"
   
   when
       Event( source == "IM_Num01_Status", value == "4")
   then
      
       execute.command("191 Bathroom RGB IM SET","888800");
    
   end
  
   
   
   
      rule "IM_Num01_5"
    
   when
        Event( source == "IM_Num01_Status", value == "5")
   then
     
        execute.command("191 Bathroom RGB IM SET","008888");
    
   end
   
   
       // ************
   
       // Repeat for each step in your sequence
    
       // **************
    
       
      
      
       rule "IM_Num01_14"
     
   when
       Event( source == "IM_Num01_Status", value == "14")
   then
      
       execute.command("191 Bathroom RGB IM SET","BD96E5");
   
   end
  
  
    
           rule "IM_Num01_15"
     
   when
       Event( source == "IM_Num01_Status", value == "15")
   then
    
       execute.command("191 Bathroom RGB IM SET","FFFFFF");
    
   end

See also

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.