Exec binding: Controlling two bluetooth Eqiva EQ3 radiator valves simultaneously

You don’t really have to wait. There’s nothing magic about the release really. Especially the first release.

No, but why wait? You already know what you’ve updated the Item to so log/use that instead of trying to get the state you already know you sent to the Item from the Item. The only real thing you can do is split the rule up. Send the update or command in one Rule and then have another rule trigger when the Item changes state to continue on executing the task.

You’ll have to experiment to see how quickly you can send commands to the device and always have the command received.

No. But you could create a Timer to schedule code to run later after the Rule exits.

That is certainly an option as well. However, remember that it’s asynchronous so if you send the commands too close together, isRunning may still be false when the second command is received and you’ll still be stuck with both running at the same time.

The easiest thing to do would be to experimentally figure out the optimum time and use that in the Gatekeeper to separate the commands by that optimum amount of time.

A harder approach would be to modify the Gatekeeper to watch the running Channel of all the Things and queue up the commands as long as that shows one of the Things is running the command. You’ll have to be very careful to avoid that brief period between issuing the command and the running state updating.

When you pass a timeout parameter to executeCommandLine it waits up to that number of milliseconds before giving up on the command and returning with an error. While the script is executing the rule is blocked from continuing so the script either needs to complete or time out for the rest of the rule to execute. However, this results in long running rules so this can cause problems just like Thread::sleeps can.

In the Gatekeeper design pattern, that is addressed somewhat by moving that long running executeCommandLine (and the sleeps) to a Timer. But that is really just moving the root problem from one thread pool to another so you still have to be careful.

What that specific example in the Gatekeeper DP does is allows up to five seconds for the call to executeCommandLine to execute. Any amount of time it took to run the executeCommandLine is subtracted from the 100 msec buffer and the timer is rescheduled to process the next command from there.

It is perfectly reasonable and expected that the DP would be extended to other use cases, such as basing the loop on the states of the running Items for Exec binding Items. But you’ll still need some locks and timers to deal with the asynchronous updates to those Items.

Timers, or more properly stated the lambdas that are passed to the Timers, inherit the context that existed at the time it was created. All the variables that exist and are accessible when that [ | // timer code ] occurs will be accessible when that lambda is eventually called by the Timer.

I’m not sure how to address the second half. The Gatekeeper is just the one rule. In the examples I show a second rule that shows how to use the Gatekeeper by sending a command to the proxy Item that drives the Gatekeeper rule itself.

The flow is:

  1. The proxy Item Outlet_A receives a command
  2. The “Outlet A” rule triggers
  3. Based on the command a new command is sent to Wireless_Controller. This Item is the proxy Item that drives the Gatekeeper.
  4. The Gatekeeper Rule runs
  5. The command is added to the queue of commands.
    6.a. If the Gatekeeper timer is already running the rule is done and exits. The command will be worked off the queue in time as the timer processes the queue.
    6.b. If the timer is not already running, create the timer. The timer looks to see if there is a command. If so it executes the command and then reschedules the Timer to run again in 100 msecs (minus any overhead time taken up by book keeping in the timer) where the next command it run. This repeats until the queue empties.

I’d need to analyze the rule much more closely. But I don’t want to spend too much time on that if you’re going to take the easier way and just move to OH 3 where most of these problems go away.

== is equivalency
=== is identity

The statement foo == bar is the same as calling foo.equals(bar).

The statement foo === bar is the same as saying "does foo point to the same place in memory as bar?`

null isn’t an Object and therefore it doesn’t have a .equals method and null is a constant so there is only one null in memory that everything in openHAB is pointing to when using the word null. So when we want to compare something to see if it’s null, we want to use the identity comparison instead of the equivalence comparison. You’ll get warnings in the log if you don’t.

Depends on what you mean by “immediately.” Like has been discussed, updating Items is an asynchronous action. If you postUpdate to the Item, it will be some number of milliseconds before MyItem.state will reflect that new state. But in your rule you’ll already have that new state so you can just use that instead of trying to pull it back from the Item.