but it do not work, the “Group item definition” will include only the items according to the definition.
2019-06-30 16:48:02.860 [ome.event.ItemCommandEvent] - Item 'SwitchDressing' received command OFF
2019-06-30 16:48:03.307 [vent.ItemStateChangedEvent] - SwitchDressing changed from ON to OFF
2019-06-30 16:48:03.351 [GroupItemStateChangedEvent] - glight changed from ON to OFF through SwitchDressing
That’s probably the least useful capability of a Group (seeing as you cannot control order, colors, widget type etc.)
Quite right. The Group will then copy out the command to each of its members.
It is permissible for Group members to be different types of Items, but of course there are limitations.
I’m not entirely sure what happens when a Group of type Switch passes a command along to a String type member, whether it goes as an OnOffType or a StringType. ON is not the same as “ON”, though you cannot see the difference in the events log.
Anyway, the Group aggregation function - OR(ON, OFF) - is not expected to work properly when you have mixed type members. How could that work with a string set to “banana”?
Maybe you can change your String type Item to a Switch type, or use a proxy Switch.
That is by far the least useful use for Groups. Groups are most powerful when used in Rules and in Persistence. Look at the Design Pattern posts and you will find very few that do not utilize Groups.
And you can indeed control the members of a Group. When you send a command to a Group that command gets forwarded to all of it’s members. So, for example, one can create a Group:Switch:OR(ON,OFF) AllLights and if you AllLights.sendCommand(OFF) all members of AllLights will receive an OFF command.
Oh, and what’s the deal with the OR(ON,OFF)? Groups can aggregate the state of all of it’s members with a set of functions. In this example it means “if any member is ON, the Group’s state is ON, otherwise the Group’s state is OFF”. Put another way, the Group’s state will be ON if any member of the Group is ON.
@nakh_Home, I don’t think you can do this without a Rule. But we might be able to get this to work.
The big thing is that we cannot send ON or OFF as a command to a String Item. But we can send "ON" and "OFF" as a command to a Switch Item. And it does look like you tried to take that into account, at least on your sitemap. But I don’t think there is a way to aggregate the states of the two different types of Items on the one Group because the String will have state “ON” and the Switch ON and “ON” != ON.
In order to handle this I think you will need to create a Proxy Item (make it a Switch) that you send the command to and then a Rule to forward the proper version of the command to the members.
You will probably also want a Rule to update the Proxy Switch when any members of the Group change.
rule "Light's proxy received a command"
when
Item AllLightsProxy received command
then
glight.members.forEach[ light | light.sendCommand(receivedCommand.toString) ]
end
rule "Update AllLightsProxy"
when
Member of glight changed
then
AllLightsProxy.postUpdate(glight.members.map[ state.toString ].reduce[ result, st | if(result == "ON" || st == "ON") "ON" else "OFF" ])
end
The first Rule loops through the members of glight and sends the received command sent to the proxy Item as a command in String format. In the case of Rules, the String will be parsed and converted to OnOffType for you. This is the part that is failing when you just send the command to the Group.
The second Rule triggers when any member of glight changes and loops through all the members of glight and updates the Proxy Item if any one of them is ON or “ON”.
I have well understood the design but i do not understand yet this part
.map[ state.toString ].reduce[ result, st | if(result == "ON" || st == "ON") "ON" else "OFF" ])
My rules
rule "Light's proxy received a command"
when
Item glightProxy received command
then
glight.members.forEach[ i| i.sendCommand(receivedCommand.toString) ]
end
rule "Update glightProxy"
when
Member of glight changed
then
glightProxy.postUpdate(glight.members.map[ state.toString ].reduce[ result, st | if(result == "ON" || st == "ON") "ON" else "OFF" ])
end
rule "Light's proxy received a command"
when
Item gParentsLightProxy received command
then
gParentsLight.members.forEach[ i| i.sendCommand(receivedCommand.toString) ]
end
rule "Update gParentsLightProxy"
when
Member of gParentsLight changed
then
gParentsLightProxy.postUpdate(gParentsLight.members.map[ state.toString ].reduce[ result, st | if(result == "ON" || st == "ON") "ON" else "OFF" ])
end
rule "gParents's proxy received a command"
when
Item gParentsProxy received command
then
gParents.members.forEach[ i| i.sendCommand(receivedCommand.toString) ]
end
rule "Update gParentsProxy"
when
Member of gParents changed
then
gParentsProxy.postUpdate(gParents.members.map[ state.toString ].reduce[ result, st | if(result == "ON" || st == "ON") "ON" else "OFF" ])
end
No. Because that doesn’t work with a mix of String Items and Switch Items as the members of glight, what we are doing is looping through all the members of glight (forEach) and sending the command as a String to each member individually. The sendCommand method is smart enough to convert “ON” to ON for the Switch Items so it bypasses the problem caused by the mix of Item types.
If all the members were Switches then we wouldn’t need the Rule and we could put glight on the sitemap as a Switch and be done.
That’s not a very helpful error.
I explain map/reduce in the Working with Groups in Rules DP I linked above. In short, the map essentially calls a method or performs some operation on all the members of the List and returns a list with the results. In this case the map is returning a List of all the states of the members as Strings. Without the map our reduce would look like:
OK, so what does the reduce mean? The reduce is a way to aggregate all the members of the List into one value. Often it’s used to sum of a bunch of states or build a String out of a List or the like. In this case we want to look at each member of the list and see if any are “ON”.
But now that I look at it, there is a simpler approach. Hopefully this won’t throw an error.
In this line we use filter to get a list of all the members of glight whose String version of the state is “ON”. If there is more than one in the result then we set the Proxy to ON.
That one line if statement is called a trinary operator. The above code written without a trinary operator would be something like
This is really odd because the last line of the Rule is executing according to events.log. So what’s generating the error? Add logging to the top and bottom of the Rule to see if perhaps it’s being triggered multiple times and the first two are generating the errors.
I didn’t mention it before, but typically only Group Items are named with a leading “g”. The “g” stands for Group. It’s a naming convention followed by most OH users.
I think the double ‘null’ report is a clue, it’s failing inside the lambda which happens to be repeated twice in the rule. Error inside lambda is not breaking rule … or even subsequent iterations of the lambda it seems.
This part
[ light | light.state.toString == “ON” ]
I can’t imagine why. Every Item/group should return something for .state.toString, NULL or UNDEF are perfectly acceptable? It’s like there is a broken group member.
I was thinking something along those same lines too but usually just a null error like that implies a Type problem and type problems usually kill the whole Rule, not just one run through the lambda. And like you point out, there shouldn’t be any type errors because the toString should work with any Item state. It’s a real mystery to me.