Set theory operations on groups

Is it possible to do set operations, like union, intersection and difference on item groups?
My initial goal is as follows:
Have a subset of lights in the Livingroom, be dimmed. All the other lights in the livingroom should be turned off. Both the subset is a group, and all the lights in the livingroom are also a group.
How I had to solve it now, is first send an OFF command to all lights in the livingroom, and then reenable/dimm the subset of lights I want ON. However this has non-deterministic effects, it seems that the z-wave network commands are not always sent in order, i.e., sometimes all the lights remain off.

of course I could put a sleep command in between the two commands, however this seems poor coding. Ideally I’d want to be able to say something like this:

(livingroom_lights - tv_lights).sendCommand(OFF)
(tv_lights).sendCommand(30)

Other elegant solutions are also welcome of course.

1 Like

Classic programming: have a loop through all members of the livingroom_lights group, then for each such item check if it’s a member of tv_lights. Search the forum for ‘forEach’ to find examples.

See Design Pattern: Working with Groups in Rules for many of the useful Group operations.

The Rule’s DSL is more geared towards pipelining than set theory unfortunately. So you have filter, map, reduce, sort, etc but not native set theory operations. But you can get there from here.

livingroom_lights.members.filter[light | !light.getGroupNames.contains("tv_lights")].forEach[light | light.sendCommand(OFF)]
tv_lights.sendCommand(30) // assumes it is defined as Group:Dimmer tv_lights

Not as elegant as it could be but not too bad either.

1 Like

As the subset was a childgroup of the LivingRoom group, so in the end the command would be:

Light_FirstFloor.members.filter[ light | light.getType != "Group" && !light.getGroupNames.contains("Light_LivingRoom")].forEach[ light | light.sendCommand(0) ]
Light_LivingRoom.sendCommand(30)

The names deviate from the opening post, but note the extra check if the light is a group. This becomes less and less elegant, imagine having multi level groups (as in, more than 2).
Can we extend the syntax of the script language? Or would we have to reimplement the Group class? Such that we might be able to do group1.minus(group2) ?

Then you can either avoid such nesting or filter out the groups as a separate filter which would be a little easier to read.

Light_FirstFloor.members.filter[light | !light instanceof GroupItem].filter[light | !light.getGroupNames.contains("tv_lights")].forEach[light | light.sendCommand(OFF)]

But like I said, the language isn’t designed with set theory in mind (few are).

Unlikely. All the maintainers are focusing on the Experimental Rules Engine and I suspect would be unwilling to make changes to the language syntax at this point. Not to mention Kai mentioned before that doing so without breaking everything is exceptional challenging.

It is worth discussion but to be truly useful and consistent with the underlying language you would have to reimplement the core java.lang Collections classes because MyItem.members returns a class of type java.lang.List. This can theoretically be done but it is going to impact a lot more of OH than just the rules.

But it is worth discussion. I’m sure if you opened a feature request issue on the ESH repo you will get some opinions from the maintainers.

1 Like