Commands cancel each other out?

Hi,

I have a bunch of 433mhz sockets and control them via an item with attached rule, e.g:

Switch outlet_a “TV” [ “Switchable” ]

rule "Outlet A"
when
Item outlet_a received command
then
if(receivedCommand == ON){
executeCommandLine(“433-send xxxxx 1 1”)
}else{
executeCommandLine(“433-send xxxxx 1 0”)
}

That works pretty well but now I want to create a new item+rule to have “scenarios” where I would, depending on the state of the item, switch on/off multiple sockets. Here is a simply one to turn everything off:

rule "Office Scene: Off"
when
Item scene_office changed to 0
then
Deckenlicht_Brightness.sendCommand(OFF)
office_outlet_a.sendCommand(OFF)
office_outlet_b.sendCommand(OFF)
office_outlet_c.sendCommand(OFF)
end

That doesn’t work. The result isn’t very deterministic but looking at the event log, it seems like only some of the commands get processed. After lots of trial and error, I realize I can ‘fix’ that by springkling Thread::sleep(1000) over the rules. This is how I made it work:

rule "Office Scene: Off"
when
Item scene_office changed to 0
then
Deckenlicht_Brightness.sendCommand(OFF)
Thread::sleep(1000)
office_outlet_a.sendCommand(OFF)
Thread::sleep(1000)
office_outlet_b.sendCommand(OFF)
Thread::sleep(1000)
office_outlet_c.sendCommand(OFF)
end

But this is slow and fragile and I’d really like to understand what is going on. Is executeCommandLine canceled once another executeCommandLine call runs? Can I prevent that?
I’ve already tried the execute bindings but had similar issues with that. executeCommandLine seems easier to use in genal though.

Oh, quite the contrary :slight_smile: In fact the command line is executed 3 or 4 times and so the different commands concurrently so the commands will fail at all.
I would recommend to narrow down the pause to maybe some 100msec.

If choosing the item names in a skillful way, you could minimize the rules with using groups - see Design Pattern: Working with Groups in Rules

What is likely happening is you are trying to send a new command over 433 before the last one is done being sent.

When you call executeCommandLine without a timeout, the call immediately returns and leaves the shell script running in a separate thread. So when you have multiple calls to executeCommandLine in a row without a timeout all three will likely be running at the same time. And since you are dealing with wireless and serial devices (presumably) the commands are stomping on each other.

At a minimum add a timeout to your executeCommandLine calls:

executeCommandLine("433-send xxxx 1 1", 5000)

That will cause executeCommandLine to wait until the script returns or five seconds, whichever comes first. However, I believe that this will not be an adequate solution in this case because you have more than one light connected over this 433 interface so it is not only possible but likely that two lights will be asked to turn on really close together.

I’m going to recommend adjusting your rules a bit to centralize your calls to sending the 433 messages into a single Rule. In that rule you can use a ReentrantLock and brief thread sleep to prevent messages from being sent too close together no matter which outlets are being commanded.

Items

String WirelessController

Rules

import java.util.concurrent.locks.ReentrantLock
var lock = new ReentrantLock

rule "433MHz Controller"
when
    Item WirelessController received command
then
    lock.lock // Ensures only one instance of the Rule can run at a time
    try {
        executeCommandLine(WirelessController.state.toString, 5000)
        Thread::sleep(100) // experiment to find the minimum sleep to obtain reliable switching
    }
    catch(Exception e) {
        logError("433", "Error handling 433MHz command: " + e)
    }
    finally {
        lock.unlock
    }
end

rule "Outlet A"
when
    Item outlet_a received command
then
    if(receivedCommand == ON){
        WirelessController.sendCommand(“433-send xxxxx 1 1”)
    }else{
        WirelessController.sendCommand(“433-send xxxxx 1 0”)
    }
end

Doesn’t such a (OH-)grouping require a command to be send to each real device anyhow? IMHO using the 433mhz transmission is limited in number of messages within a second. Sending messages to several sockets, with each socket-message being retransmitted several times is causing such faulty behaviour.
Using a sleep as described does overcome that.

For some types of sockets there might be the possibility to use a sort of “Group-address” in the 433mhz message in order to trigger more then one device!
See this german page for such decriptions .

1 Like

Ahh! That makes sense. I didn’t though that the gpio stuff might happen in parallel.

Thanks for the WirelessController pattern, that works great!