Switch wireless devices reliable through Drools in OpenRemote

This post summarises my experience with having a wireless appliance switched on and off at certain parts of a day. This is a nice example of using Drools timers and internal facts.

Wireless suffers the problem of unreliable communication in a noisy, long distance environment. Even in the same room sometimes the transmission fails, this is my experience with EnOcean, Z-wave and WeMo. Luckily, this problem can be solved in Openremote in a smart way by sensing back the switch state and deciding if retransmission is necessary. This is an unique characteristics of Openremote architecture not commonly found in other home automation controllers. The algorithm presented below addresses this problem and is in my humble opinion a must have for everyone who has a need of reliable wireless switching.

First I’ve declared a fact which will be used by the switching algorithm state machine.

declare SocketState
  @role(event)
  on : int
  // -1: idle
  //  0: switching off
  //  1: switching on 
end

rule "Init SocketState"
when
then
  insert(new SocketState(-1));
end

Next, the rule for initiating switching on the appliance every Friday at 6:10 AM:

rule "Lamp on"
  timer(cron: 0 10 6 ? * fri) 
when
  Event(source=="SocketSwitching1.STATE", value=="off")
  $s: SocketState(on!=1)
then
  $s.setOn(1);
  update($s);
end

Note that the rule is executed only when socket is not yet turned on and not in switching StcketState. All it does is setting the SocketState fact into switching on state and pass it to other rules with update() statement.

Now, we will be sending wireless telegrams to the switching socket every 5 seconds as long as its state is off. Usually the light go on immediately, however when it is noisy few retransmissions are necessary.

rule "Lamp on execute"
  timer(int: 0s 5s) // repeat every 5 seconds
when
  $s: SocketState(on==1)
  Event(source=="SocketSwitching1.STATE", value=="off")
then
  execute.command("SocketSwitching1.ON"); // Light ON
end

Finally when the socket state is changed to on it is marked by SocketState fact:

rule "Lamp on executed"
when
  $s: SocketState(on==1)
  Event(source=="SocketSwitching1.STATE", value=="on")
then
  $s.setOn(-1);
  update($s);
end

The same algorithm is used for switching the socket off on 6:25 AM.

rule "Lamp off"
  timer(cron: 0 25 6 ? * fri) 
when
  Event(source=="SocketSwitching1.STATE", value=="on")
  $s: SocketState(on!=0)
then
  $s.setOn(0);
  update($s);  
end

rule "Lamp off execute"
  timer(int: 0s 5s)
when
  $s: SocketState(on==0)
  Event(source=="SocketSwitching1.STATE", value=="on")
then
  execute.command("SocketSwitching1.OFF"); // Light OFF
end

rule "Lamp off executed"
when
  $s: SocketState(on==0)
  Event(source=="SocketSwitching1.STATE", value=="off")
then
  $s.setOn(-1);
  update($s);
end

Because ON and OFF states sent by socket can easily be missed in noisy environment an extra bit of robustness is achieved by declaring the ON state in case when non-zero power measurement message arrives:

rule "SocketSwitching1 state ON through power"
// Set state ON when power is not 0
when
  Event(source=="SocketSwitching1.POWER", value!="0")
  Event(source=="SocketSwitching1.STATE", value!="on")
then
  execute.command("SocketSwitching1.ON");
end

The last touch is to retract the last power measurement fact so the repeating same values are processed by the rules engine. Without this rule when power measurement value stays the same the “SocketSwitching1 state ON through power” rule will be triggered only once (this is due to implementation of Drools engine within Openremote).

rule "SocketSwitching1 retract last power measurement"
salience -100 // Because of retracting of the event
when
  $s : Event(source=="SocketSwitching1.POWER",$v:value)
then
  retract($s);
end

8 thoughts on “Switch wireless devices reliable through Drools in OpenRemote

  1. Michal,
    Intriguing post again. I was intrigued by your statement: “Even in the same room sometimes the transmission fails, this is my experience with EnOcean, Z-wave and WeMo”. Do you have data on failure rate of each of these protocols in your mixed environment?
    Pieter

    • Hi Pieter,
      I don’t have statistics about failure rate of each protocols because for me one fail is already too much ;).

      • I was curious which one of the three was failing least. I understand that hard statistics is impossible at this scale. Thanks.

        • In my experiments, the most fragile are WeMo’s. Although they use IP/TCP/UPnP based protocol, which should be very reliable, they are bit ‘over-engineered’ and devices are frequently lost. You should also be very careful which wireless protection are you using with them as not every one is stable.
          EnOcean and Z-wave are in the same league. The only problem with Z-wave is when I move devices around. Frequently they don’t work in a new place where EnOcean has no problems. Probably I would need to re-mesh but this is quite cumbersome, therefore my choice are EnOcean removable sockets. Different story would be for stationary devices for sure. However, during my experiments, when things are regularly moved around, EnOcean is the best.

          • Thanks for the update.
            As my main goal for HA is energy conservation, my sympathy is with Enocean, At present I focus on Z-wave on RaZberry. It is easy to do a “re-mesh” there. I do new inclusions close to the zwave controller, than move to the final place, followed by the re-establishment of the routes. Works like a charm. As I said at other occasions the stability of Z-Wave does increase with the number of devices.
            Recently I learned that the Razberry people are working on the addition of the Enocean protocol.

  2. hi michal ,
    i got your rule how you writing but i am not getting one thing how i need to write class for that rule .

    rule “Lamp off”
    timer(cron: 0 25 6 ? * fri)
    when
    Event(source==”SocketSwitching1.STATE”, value==”on”)
    $s: SocketState(on!=0)
    then
    $s.setOn(0);
    update($s);
    end

    rule “Lamp off execute”
    timer(int: 0s 5s)
    when
    $s: SocketState(on==0)
    Event(source==”SocketSwitching1.STATE”, value==”on”)
    then
    execute.command(“SocketSwitching1.OFF”); // Light OFF
    end

    rule “Lamp off executed”
    when
    $s: SocketState(on==0)
    Event(source==”SocketSwitching1.STATE”, value==”off”)
    then
    $s.setOn(-1);
    update($s);
    end

  3. because i create simple hello drools program i am not able to satisfied this condition

Comments are closed.