How to check if an item is a member of a group?

I’m trying to set up a system with groups and ruels to change lights depending on HouseMode

Group gMode
Group gAway (gMode)
Group gHome (gMode)
Group gSleep (gMode)

The idea is that an item (switch) can belong to one or more groups, and the groups are “ON”, meaning if a item belongs to gHome it is supposed to be ON when home but not otherwise.

And the rule

rule "Change of HouseMode"
when
	Item HouseMode received update
then
	//Away
	if (HouseMode.state == 0) {
		// Turn off all lights that not belongs to gAway
		gMode.members.forEach[item | 
			if (ITEM NOT MEMBER OF gAway){
				item.sendCommand(OFF)
			}
		]
		// Turn on lights for Group gAway
		gAway.members.forEach[item | item.sendCommand(ON)]
	}
	//Home
	if (HouseMode.state == 1) {
		// Turn off all lights that not belongs to gHome
		gMode.members.forEach[item | 
			if (ITEM NOT MEMBER OF gHome){
				item.sendCommand(OFF)
			}
		]
		// Turn on lights for Group gHome
		gHome.members.forEach[item | item.sendCommand(ON)]
	}
	//Sleep
	if (HouseMode.state == 2) {
		// Turn off all lights that not belongs to gSleep
		gMode.members.forEach[item | 
			if (ITEM NOT MEMBER OF  gSleep){
				item.sendCommand(OFF)
			}
		]
		// Turn on lights for Group gSleep
		gSleep.members.forEach[item | item.sendCommand(ON)]		
	}
end

As you can see I have an IF statement with ITEM NOT MEMBER OF … that I don’t know how to do.

You could just turn OFF the hole group gMode and then turn on corresponding group but that would make a light turn off and then on if belonging to two or more groups.

Any idea? Thanks!

gMode.members.filter[light | !light.getGroupNames.contains("gAway")].forEach[ light | light.sendCommand(OFF) ]

In words:

For the Group gMode, filter the members using the criteria !light.getGroupNames.contains(“gAway”) which returns true when “gAway” is not among the Groups light belongs to. We then loop through them and send OFF to them.

1 Like

Is .getGroupNames just a string or is it a list? Or can one use the list as a string in this case?

getGroupNames returns a list

A quick/easy way I found to check for class is .getClass

 logDebug("Rules", "test: [{}], [{}]",DS_Kitchen_Sink_Switch.getGroupNames,`DS_Kitchen_Sink_Switch.getGroupNames.getClass)`

Returns

[[gDS_Kitchen, gLight]], [class com.google.common.collect.RegularImmutableList]

I use something similar…

gDS_FamilyRoom.members.filter(light | gLight.members.contains(light)).forEach[light |

… in a number of my rules. I recently saw a post of yours with the .getGroupNames method but forgot about it. Glad you brought it up again… after a quick test, .getGroupNames was 0.6 milliseconds faster on average over 10,000 iterations. Not much, but an improvement! Thank you!

1 Like

It is a list and you can do all the collections chaining operations on it. The above could also be implemented using something like

filter[light | light.getGroupNames.findFirst[grp | grp.name == "gAway"] == null ].forEach...

If performance is a problem for you, you should seriously look into the JSR223 add-on. I did some work with a user awhile back and we found about an order of magnitude improvement by writing roughly equivalent code in Jython over Rules DSL for at least the case we tested. It wasn’t really a fair test but it is clear that Jython at least is much faster.

With so many Item it might be worthwhile to take advantage of some additional features of a more generic programming language.

http://docs.openhab.org/configuration/jsr223.html

It’s in my backlog, but planned to take a look at the new rules engine first. I’m not experiencing performance issues… but I do everything I can to get my motion sensor>light rules to fire as quickly as possible!

Unfortunately, I found an odd bug in getGroupNames that broke my rules! The names returned do not include groups where the item was added through GroupItem.addMember. I use this method to store light Items in a group that are in rooms where motion is active, so I can adjust lights when the lux changes. I’m still looking into it, but I’m pretty confident at this point that this is a bug and I’ll get it reported. Here is a simple test rule to illustrate:

rule "Test"
when
    Item Virtual_Switch_1 changed to ON
then
    gActive.removeMember(gDS_FamilyRoom_Bulb)
    logDebug("Rules", "test:gDS_FamilyRoom_Bulb.getGroupNames=[{}], gActive.members.contains(gDS_FamilyRoom_Bulb)=[{}]",gDS_FamilyRoom_Bulb.getGroupNames,gActive.members.contains(gDS_FamilyRoom_Bulb))
    gActive.addMember(gDS_FamilyRoom_Bulb)
    logDebug("Rules", "test:gDS_FamilyRoom_Bulb.getGroupNames=[{}], gActive.members.contains(gDS_FamilyRoom_Bulb)=[{}]",gDS_FamilyRoom_Bulb.getGroupNames,gActive.members.contains(gDS_FamilyRoom_Bulb))
    gActive.removeMember(gDS_FamilyRoom_Bulb)
    logDebug("Rules", "test:gDS_FamilyRoom_Bulb.getGroupNames=[{}], gActive.members.contains(gDS_FamilyRoom_Bulb)=[{}]",gDS_FamilyRoom_Bulb.getGroupNames,gActive.members.contains(gDS_FamilyRoom_Bulb))
end

OUTPUT

2017-12-08 17:05:02.188 [DEBUG] [org.eclipse.smarthome.model.script.Rules          ] - test:gDS_FamilyRoom_Bulb.getGroupNames=[[gLight, gDS_FamilyRoom]], gActive.members.contains(gDS_FamilyRoom_Bulb)=[false]
2017-12-08 17:05:02.189 [DEBUG] [org.eclipse.smarthome.model.script.Rules          ] - test:gDS_FamilyRoom_Bulb.getGroupNames=[[gLight, gDS_FamilyRoom]], gActive.members.contains(gDS_FamilyRoom_Bulb)=[true]
2017-12-08 17:05:02.190 [DEBUG] [org.eclipse.smarthome.model.script.Rules          ] - test:gDS_FamilyRoom_Bulb.getGroupNames=[[gLight, gDS_FamilyRoom]], gActive.members.contains(gDS_FamilyRoom_Bulb)=[false]

Thanks! This was exactly was I was looking for.

Hello,
I am also trying to check if an item is a member of a group. The item’s name is stored in a variable as a String and I am going to set value of a variable based on the result. Following lines don’t work for me:

val String demand_name = baseName + "_heating_demand"
if (demand_name.getGroupNames.contains("floor_heatings")){
          hysteresis == hysteresis_floor_heating
          logInfo("rules","Hello world")
}

I always getting the following error: "‘getGroupNames’ is not a member of ‘java.lang.String’; line 81, column 37, length 25" Do you have any idea how I should solve this?

You have a string that represents the item’s name, now you need to get the item to check it’s group membership…