Faster sendCommand() execution?

I have a series of three LIFX bulbs, and two Orvibo switches that I have placed in a single group, FF_Bed. In all, there are six items (each mapped to a channel) that are in this group.

I’ve created a virtual switch item (FF_Bed_All_Sw) that triggers them all ON or OFF based on a rule:

rule "FF_Bed_All_Sw On"
when 
	Item FF_Bed_All_Sw changed from OFF to ON
then 
	FF_Bed.sendCommand(ON)
end
rule "FF_Bed_All_Sw Off"
when 
	Item FF_Bed_All_Sw changed from ON to OFF
then 
	FF_Bed.sendCommand(OFF)
end

This process takes about 2 seconds, and the lights and switches turn off progressively.

Is there any way do to this in parallel? I’d ideally like everything to turn off at once. These are all WiFi devices, so there is no middle-man device that is rate limiting.

You can never achieve simultaneous. Two seconds seems really long though. There are a number of hacks I’ve come up with, few really tested. Ultimately you will get the best performance using JSR233 and coffee the rule in Jython. It runs fast enough to get the delay week below a second.

Things to try in the Rules DSL:

  • Instead of sending the command to the group, send it to reach member individually. MyGroup.members.forEach[i | I.sendCommand(OFF)]

  • Create a separate rule fur each light that triggers on the same event. Each rule runs in parallel.

  • Create a timer that goes off in 50 msec or so and send the command from the timer. Timers run in a separate thread.

  • Execute the commanding of the lights in an external program that is better and to run in parallel.

Thanks for these helpful suggestions rlkoshak.

I suppose I was exaggerating a little when I claimed 2 seconds… To toggle power on three LIFX bulbs, it takes a little over .5 seconds. Add in the two outlets and we’re at more like 1 second. The speed is a frustration, but more-so that all the Items switch at different times.

The goals for this exercise:

LIFX Lights: function similar to the LIFX app - very quick and exactly simultaneous switching of Items. Third-party apps using the LIFX LAN Protocol can also accomplish this (LIFX Tasker Plugin, AutoHue on Android).

Orbivo Switches: quick and reliable execution, does not need to be exactly simultaneous.


  1. Instead of sending the command to the group, send it to reach member individually. MyGroup.members.forEach[i | I.sendCommand(OFF)]
    This appears to be equivalent to MyGroup.sendCommand(). The Items fire in the same order, and in (as far as I can tell) the same speed.

  2. Create a separate rule fur each light that triggers on the same event. Each rule runs in parallel.
    This is very slightly faster than MyGroup.sendCommand(). The Items fire in random order and at random intervals.

  3. Create a timer that goes off in 50 msec or so and send the command from the timer. Timers run in a separate thread.
    I tried a few solutions here:

3.1

	var DateTime targetTime = now.plusMillis(1000)
	createTimer(targetTime) [| sendCommand(LIFX_63_color, receivedCommand) ]
	createTimer(targetTime) [| sendCommand(LIFX_00_color, receivedCommand) ]
	createTimer(targetTime) [| sendCommand(LIFX_2C_color, receivedCommand) ]
	createTimer(targetTime) [| sendCommand(Orvibo_58, receivedCommand)]
	createTimer(targetTime) [| sendCommand(Orvibo_C8, receivedCommand)]

With this code, only Orvibo_C8 fired.

3.2

	createTimer(now.plusMillis(50)) [| sendCommand(LIFX_63_color, receivedCommand) ]
	createTimer(now.plusMillis(50)) [| sendCommand(LIFX_00_color, receivedCommand) ]
	createTimer(now.plusMillis(50)) [| sendCommand(LIFX_2C_color, receivedCommand) ]
	createTimer(now.plusMillis(50)) [| sendCommand(Orvibo_58, receivedCommand)]
	createTimer(now.plusMillis(50)) [| sendCommand(Orvibo_C8, receivedCommand)]

This code worked, but not well. This appears to be the slowest solution, probably because of the delay. Items fire in random order. It also seems that if an Item hasn’t fired by 50ms (with each of these solutions there are occasionally longer than normal delays) that it won’t fire at all.

3.4 (createTimers in separate rules)

var DateTime targetTime = null

Setting a single targetTime for all Timers

when
	Item FF_Bed_Lights_Sw5 received command /* this is the switch in sitemap */
then
	targetTime = now.plusMillis(2000)
	sendCommand(FF_Bed_Lights_Sw6, receivedCommand) /* this switch only triggers other rules */
end

Multiple rules run in parallel creating Timers based on the original targetTime (one example, total is three LIFX and two Orvibo)

when 
	Item FF_CB_Bed_Lights_Sw6 received command /* switch triggered above */
then
	createTimer(targetTime) [| sendCommand(LIFX_2C_color, receivedCommand)]
end

This fires only one of the Items at random.


My learning from this testing:

  • Timers aren’t a good method of creating parallel actions, since only one timer (apparently) can execute at the same time and the rest will silently fail
  • OH2 probably internally converts MyGroup.sendCommand() to iterative commands across the group
  • It’s possible that the LIFX or Orvibo bindings are restricting the parallel execution. Maybe there is a function on the LAN Protocol that simultaneously changes lights, but the LIFX binding uses iterative changing instead?

I’m not familiar with JSR233, coffee, and Jython. Can you point me in the direction of more info?

Thanks for all your help.

After doing (a lot of) digging, my interpretation is that OH2 is setup to allow either

synchronous events via sendCommand (requiring a response from the Item)

or

asynchronous events via postCommand (not requiring a response)

Asynchronous events are possible to execute in parallel threads on the Event Bus, and synchronous events are not.

Sources:


https://groups.google.com/forum/#!topic/openhab/rlcTJgZAT9U
https://code.google.com/archive/p/openhab/issues/454

Trying to use postCommand in the Designer IDE throws an error for the ColorItem type, so it looks like the LIFX binding has not implemented this command.

I think OH2 may now have support for this natively now. “Coffee” should have been “copy”. Typing on my phone while the preschooler wants attention…

Don’t take Designer errors as the final word, particularly with new capabilities like postCommand. Designer tends to lag. Run it and see if works.

Took a look at the JSR223 wiki, unfortunately this is beyond my coding abilities. It still looks like all commands are sent through the OH2 Event Bus which would be the bottleneck.

Tested postCommand, it doesn’t work with LIFX. It seems like the OH devs are recommending Binding devs use one or the other.

I also tried connecting channels from multiple LIFX bulbs to a single Item, hoping to maybe get around the Event Bus single-threading, but no luck.

I’m starting a new thread focused on parallelism and the Event Bus, which seems to be the core challenge.

According the the experience of the JSR233 folks, the event bus is definitely not the bottleneck for this. They have seen massive speedups when it comes to how quickly a group of lights can be switched.

The bottleneck for faster command handling in openHAB 2.0 is the sequential way that commands/updates are handled by the ESH ThingManager.

I’ve made a proof of concept for concurrent command handling because I ran into it with LIFX bulbs as well. It works actually pretty well for me. No real issues so far with concurrent command handling and the LIFX binding! :smile: Your milage may vary for other bindings though.

This issue is addressed in ESH #2221: ThingManager should notify handlers about commands/updates fully asynchronously.