For a while, I have been thinking about how to replicate the grouping functionality in the Sonos application to OpenHab UI. Previously, I had simple rules that either was based on scenarios or predetermined grouping rules (add/remove A to B etc).
The basic idea was to be able to dynamically add or remove each player from a group (Group 1, Group 2 and Group 3) and use this to both display and control the specific group i the OH app. In addition, I also wanted the OH app to reflect the correct grouping when I control the Sonos system from the native application. I.e. if I group Bathroom with Kitchen in the Sonos app, I wanted the grouping in the OH app to reflect this.
Iāve put quite a bit of work in to this, and after a period of testing, I think it works well enough to post it here so that others might enjoy the fruits of my labor. I am very sure a lot of the code is far from perfect, so feel free to post any optimization ideas.
Screenshots
The 4 players are grouped in two groups.
When pushing āGroup 2ā the control panel for that group is shown. The volume controls will change based on which players are in the specific group. The other controls are those of the local coordinator in the group.
When one or more of the players are not grouped (i.e. standalone), individual control of the single player is shown.
Items
The items is a complete list of the channels available in the Sonos binding, but not all of them ares used in this example. In addition i have three other items that holds various states:
SonosGroupID_Kitc holds the ID of the group (here, the kitchen player).
Sonos_Group1_Number holds the number of players in a group.
Sonos_Group1_Visibility tells the UI if the group controls should be visible and which player is the local coordinator in that group.
The icons can be downloaded here: https://www.dropbox.com/sh/uualcu06oiiq21a/AADhj9uUh5Xbu8IeUbIHKDC3a?dl=0
Group gSonos
Group gSonosKitc (gSonos)
Group gSonosGues (gSonos)
Group gSonosBath (gSonos)
Group gSonosLivi (gSonos)
Group gSonosVolu "Volume" <soundvolume>
Group gSonosMute "Mute" <sonos_mute>
Group gSonosStop "Stop" <sonos_stop> {autoupdate="false"}
String SonosGroupID_Kitc "Kitchen group [%s]"
String SonosGroupID_Gues "Guest room group [%s]"
String SonosGroupID_Bath "Bathroom group [%s]"
String SonosGroupID_Livi "Living room group [%s]"
Number Sonos_Group1_Number "Players in group 1 [%.1f]"
Number Sonos_Group2_Number "Players in group 2 [%.1f]"
Number Sonos_Group3_Number "Players in group 3 [%.1f]"
String Sonos_Group1_Visibility "Group 1 visibility [%s]"
String Sonos_Group2_Visibility "Group 2 visibility [%s]"
String Sonos_Group3_Visibility "Group 3 visibility [%s]"
/* Kitchen */
String Sonos_Kitc_Add "Add [%s]" <sonos_add> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:add"}
Switch Sonos_Kitc_SetAlarm "Set Alarm" <sonos_alarm> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:alarm"}
String Sonos_Kitc_AlarmProperties "Alarm Properties [%s]" <sonos_alarm_prop> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:alarmproperties"}
Switch Sonos_Kitc_AlarmIsrunning "Alarm is running" <sonso_alarm_run> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:alarmrunning"}
Player Sonos_Kitc_Control "Control" <sonos_control> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:control"}
String Sonos_Kitc_CurrentAlbum "Album [%s]" <sonos_album> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currentalbum"}
String Sonos_Kitc_CurrentArtist "Artist [%s]" <sonos_artist> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currentartist"}
String Sonos_Kitc_CurrentTitle "Title [%s]" <sonos_title> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currenttitle"}
String Sonos_Kitc_CurrentTrack "Track [%s]" <sonos_track> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currenttrack"}
Switch Sonos_Kitc_Shuffle "Shuffle" <sonos_shuffle> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:shuffle"}
String Sonos_Kitc_Repeat "Repeat [%s]" <sonos_repeat> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:repeat"}
String Sonos_Kitc_Favorite "Favorite [%s]" <sonos_favorite> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:favorite"}
Switch Sonos_Kitc_Led "Led" <sonos_led> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:led"}
Switch Sonos_Kitc_LocalCoordinator "Local Coordinator" <sonos_coordinator> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:localcoordinator"}
Switch Sonos_Kitc_Mute "Mute" <sonos_mute> (gSonosKitc,gSonosMute) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:mute"}
String Sonos_Kitc_NotificationSound "Notification Sound [%s]" <sonos_notification> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:notificationsound"}
Dimmer Sonos_Kitc_Notificationsoundvolume "Notification Sound Volume" <soundvolume> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:notificationvolume"}
String Sonos_Kitc_PlayPlaylist "Play Playlist [%s]" <sonos_playlist> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:playlist"}
Switch Sonos_Kitc_PlayQueue "Play Queue" <sonos_que> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:playqueue"}
Number Sonos_Kitc_PlayTrack "Play Track" <sonos_play_track> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:playtrack"}
String Sonos_Kitc_PlayURI "Play URI [%s]" <sonos_play_uri> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:playuri"}
Switch Sonos_Kitc_PublicAddress "Public Address" <sonos_publiv> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:publicaddress"}
String Sonos_Kitc_Radio "Radio [%s]" <sonos_radio> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:radio"}
String Sonos_Kitc_Remove "Remove [%s]" <sonos_remove> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:remove"}
Switch Sonos_Kitc_Restore "Restore" <sonos_restore> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:restore"}
Switch Sonos_Kitc_RestoreAll "Restore All" <sonos_restore_all> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:restoreall"}
Switch Sonos_Kitc_Save "Save" <sonos_save> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:save"}
Switch Sonos_Kitc_SaveAll "Save All" <sonos_save_all> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:saveall"}
Number Sonos_Kitc_Snooze "Snooze" <sonos_snooze> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:snooze"}
Switch Sonos_Kitc_StandAlone "Stand Alone" <sonos_stand_alone> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:standalone"}
String Sonos_Kitc_State "State [%s]" <sonos_state> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:state"}
Switch Sonos_Kitc_Stop "Stop" <sonos_stop> (gSonosKitc,gSonosStop) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:stop", autoupdate="false"}
Dimmer Sonos_Kitc_Volume "Kitchen" <soundvolume> (gSonosKitc,gSonosVolu) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:volume"}
String Sonos_Kitc_ZoneGroupID "Zone Group ID [%s]" <sonos_zone> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:zonegroupid"}
String Sonos_Kitc_ZoneName "Zone Name [%s]" <sonos_zone> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:zonename"}
String Sonos_Kitc_Coordinator "Coordinator [%s]" <sonos_coordinator> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:coordinator"}
Number Sonos_Kitc_SleepTimer "Sleep Timer" <sonos_sleep_timer> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:sleeptimer"}
String Sonos_Kitc_CurrentAVtransportURI "AV transport URI [%s]" <sonos_uri> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currenttransporturi"}
String Sonos_Kitc_CurrenttrackURI "track URI [%s]" <sonos_uri> (gSonosKitc) {channel="sonos:PLAY1:RINCON_XXXXXXXXXXXXXXXXX:currenttrackuri"}
Rules
I have only posted one rule per player, but this is easily extended by duplicating the rules to the number of players needed. The two bits of information that the rules relies heavily on, is the playerās zonegroupid and localcoordinator. Actions performed on a group of players, needs to be done on the player that is the local coordinator. I have added some comments to the code, but expect some effort to be invested if you plan to fully understand what is going on.
Since functions only allow a maximum of 6 parameters to be passed, this setup can handle a maximum of 3 separate groups.
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.java.math.*
import org.joda.time.*
var Timer CheckSinglePlayerTimer = null
var Timer SonosGroupVisibility = null
val Functions$Function6 updateSingleGroups = [
NumberItem group1_num,
NumberItem group2_num,
NumberItem group3_num,
StringItem player_a_groupID,
StringItem player_b_groupID,
StringItem player_a_name |
// If the player the updated player has been grouped to is in the "NONE"-group (or is NULL),
// find a group with zero players and update status of both players.
if(player_b_groupID.state=="0" || player_b_groupID.state==NULL) {
if(group1_num.state==0) {
postUpdate(player_a_groupID,"1")
postUpdate(player_b_groupID,"1")
logInfo("openhab", player_a_name + " player + 1 updated to group 1")
} else if(group2_num.state==0) {
postUpdate(player_a_groupID,"2")
postUpdate(player_b_groupID,"2")
logInfo("openhab", player_a_name + " player + 1 updated to group 2")
} else if(group3_num.state==0) {
postUpdate(player_a_groupID,"3")
postUpdate(player_b_groupID,"3")
logInfo("openhab", player_a_name + " player + 1 updated to group 3")
}
// Else set the updated player to the group id of the matched player
} else if(player_a_groupID.state!=player_b_groupID.state) {
postUpdate(player_a_groupID,player_b_groupID.state)
logInfo("openhab", player_a_name + " player updated to group " + player_b_groupID.state.toString)
}
return NULL
]
val Functions$Function6 checkSinglePlayers = [
StringItem CheckZonegroupID,
StringItem ZonegroupID_a,
StringItem ZonegroupID_b,
StringItem ZonegroupID_c,
StringItem UpdatePlayer,
StringItem UpdatePlayerName |
if(CheckZonegroupID.state!=ZonegroupID_a.state && CheckZonegroupID.state!=ZonegroupID_b.state && CheckZonegroupID.state!=ZonegroupID_c.state) {
postUpdate(UpdatePlayer,"0")
logInfo("openhab", UpdatePlayerName + "player updated to group 0")
}
return NULL
]
///// NUMBER OF PLAYERS IN GROUP
//
// A simple count of the number of players
// in each group is made. This is used in
// various rules, e.g. to determine
// if a group should be visible in the UI or not.
//
/////////////////////////////////
rule "Sonos number of players in group"
when
Item SonosGroupID_Kitc received update or
Item SonosGroupID_Gues received update or
Item SonosGroupID_Livi received update or
Item SonosGroupID_Bath received update
then
var Number Group_1 = 0
var Number Group_2 = 0
var Number Group_3 = 0
if(SonosGroupID_Kitc.state=="1"){
Group_1 = Group_1 + 1
}else if(SonosGroupID_Kitc.state=="2"){
Group_2 = Group_2 + 1
}else if(SonosGroupID_Kitc.state=="3"){
Group_3 = Group_3 + 1
}
if(SonosGroupID_Gues.state=="1"){
Group_1 = Group_1 + 1
}else if(SonosGroupID_Gues.state=="2"){
Group_2 = Group_2 + 1
}else if(SonosGroupID_Gues.state=="3"){
Group_3 = Group_3 + 1
}
if(SonosGroupID_Bath.state=="1"){
Group_1 = Group_1 + 1
}else if(SonosGroupID_Bath.state=="2"){
Group_2 = Group_2 + 1
}else if(SonosGroupID_Bath.state=="3"){
Group_3 = Group_3 + 1
}
if(SonosGroupID_Livi.state=="1"){
Group_1 = Group_1 + 1
}else if(SonosGroupID_Livi.state=="2"){
Group_2 = Group_2 + 1
}else if(SonosGroupID_Livi.state=="3"){
Group_3 = Group_3 + 1
}
postUpdate(Sonos_Group1_Number,Group_1)
postUpdate(Sonos_Group2_Number,Group_2)
postUpdate(Sonos_Group3_Number,Group_3)
end
///// GROUPING RULES
//
// The rule will check every other player that the
// (1) Group number of the player beeing added corresponds to the player it is beeing added to
// (2) Zone-ids are not equal (not already grouped)
// (3) That the player beeing checked has a state (not NULL)
//
// Additional nested logic is required to determine in what direction the player shall be grouped (A to B or B to A).
// This is a special case that kicks in when both players are single before grouping: It is not possible
// to add a player that is the local coordinator to a player which is not.
//
/////////////////////////////////
rule "Sonos group kitchen"
when
Item SonosGroupID_Kitc received command
then
// Short sleep to make shure the rule to calculate the number of players in a group has executed before the logic is applied.
Thread::sleep(300)
if(SonosGroupID_Kitc.state==SonosGroupID_Gues.state && SonosGroupID_Kitc.state!="0" && Sonos_Kitc_ZoneGroupID.state!=Sonos_Gues_ZoneGroupID.state && Sonos_Gues_ZoneGroupID.state!=NULL && ((Sonos_Gues_LocalCoordinator.state==ON) || (Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))))){
logInfo("openhab","Entered sonos kitchen grouping rule number 1")
if(Sonos_Gues_LocalCoordinator.state==ON){
Sonos_Gues_Add.sendCommand("RINCON_kitchenplayer")
logInfo("openhab","Kitchen player added to guest room")
}else if(Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))) {
Sonos_Kitc_Add.sendCommand("RINCON_guestroomplayer")
logInfo("openhab","Guest room player added to kitchen")
}
}else if(SonosGroupID_Kitc.state==SonosGroupID_Bath.state && SonosGroupID_Kitc.state!="0" && Sonos_Kitc_ZoneGroupID.state!=Sonos_Bath_ZoneGroupID.state && Sonos_Bath_ZoneGroupID.state!=NULL && ((Sonos_Bath_LocalCoordinator.state==ON) || (Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))))){
logInfo("openhab","Entered sonos kitchen grouping rule number 2")
if(Sonos_Bath_LocalCoordinator.state==ON){
Sonos_Bath_Add.sendCommand("RINCON_kitchenplayer")
logInfo("openhab","Kitchen player added to bathroom")
}else if(Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))) {
Sonos_Kitc_Add.sendCommand("RINCON_bathroomplayer")
logInfo("openhab","Bathroom player added to kitchen")
}
}else if(SonosGroupID_Kitc.state==SonosGroupID_Livi.state && SonosGroupID_Kitc.state!="0" && Sonos_Kitc_ZoneGroupID.state!=Sonos_Livi_ZoneGroupID.state && Sonos_Livi_ZoneGroupID.state!=NULL && ((Sonos_Livi_LocalCoordinator.state==ON) || (Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))))){
logInfo("openhab","Entered sonos kitchen grouping rule number 3")
if(Sonos_Livi_LocalCoordinator.state==ON){
Sonos_Livi_Add.sendCommand("RINCON_kitchenplayer")
logInfo("openhab","Kitchen player added to living room")
}else if(Sonos_Kitc_LocalCoordinator.state==ON && ((SonosGroupID_Kitc.state=="1" && Sonos_Group1_Number.state=="2") || (SonosGroupID_Kitc.state=="2" && Sonos_Group2_Number.state=="2") || (SonosGroupID_Kitc.state=="3" && Sonos_Group3_Number.state=="2"))) {
Sonos_Kitc_Add.sendCommand("RINCON_livingroomplayer")
logInfo("openhab","Living room player added to Kitchen")
}
}else{
Sonos_Kitc_StandAlone.sendCommand("ON")
logInfo("openhab","Kitchen player set to stand alone")
}
end
//// UPDATE GROUPING RULES
//
// The rules will update the appropiate group
// when a sonos player is grouped, either
// in the OH2 UI or within the Sonos app.
//
/////////////////////////////////
rule "Sonos update group membership bathroom"
when
Item Sonos_Bath_ZoneGroupID changed
then
if(Sonos_Bath_ZoneGroupID.state==Sonos_Kitc_ZoneGroupID.state && Sonos_Kitc_ZoneGroupID.state!=NULL) {
updateSingleGroups.apply(Sonos_Group1_Number, Sonos_Group2_Number, Sonos_Group3_Number, SonosGroupID_Bath, SonosGroupID_Kitc, "Bathroom")
} else if(Sonos_Bath_ZoneGroupID.state==Sonos_Gues_ZoneGroupID.state && Sonos_Gues_ZoneGroupID.state!=NULL) {
updateSingleGroups.apply(Sonos_Group1_Number, Sonos_Group2_Number, Sonos_Group3_Number, SonosGroupID_Bath, SonosGroupID_Gues, "Bathroom")
} else if(Sonos_Bath_ZoneGroupID.state==Sonos_Livi_ZoneGroupID.state && Sonos_Livi_ZoneGroupID.state!=NULL) {
updateSingleGroups.apply(Sonos_Group1_Number, Sonos_Group2_Number, Sonos_Group3_Number, SonosGroupID_Bath, SonosGroupID_Livi, "Bathroom")
// The zone-id changed, but is not grouped with any other players (removed from group).
// To allow grouping in the UI without the state being reset to single, a timer is applied.
// This works since grouping in both the OH UI and the Sonos app usually is not performed simultaneously.
} else {
if(CheckSinglePlayerTimer==null) {
CheckSinglePlayerTimer = createTimer(now.plusSeconds(20), [|
checkSinglePlayers.apply(Sonos_Bath_ZoneGroupID, Sonos_Kitc_ZoneGroupID, Sonos_Gues_ZoneGroupID, Sonos_Livi_ZoneGroupID, SonosGroupID_Bath,"Bathroom")
checkSinglePlayers.apply(Sonos_Kitc_ZoneGroupID, Sonos_Bath_ZoneGroupID, Sonos_Gues_ZoneGroupID, Sonos_Livi_ZoneGroupID, SonosGroupID_Kitc,"Kitchen")
checkSinglePlayers.apply(Sonos_Gues_ZoneGroupID, Sonos_Bath_ZoneGroupID, Sonos_Kitc_ZoneGroupID, Sonos_Livi_ZoneGroupID, SonosGroupID_Gues,"Guest room")
checkSinglePlayers.apply(Sonos_Livi_ZoneGroupID, Sonos_Bath_ZoneGroupID, Sonos_Kitc_ZoneGroupID, Sonos_Gues_ZoneGroupID, SonosGroupID_Livi,"Living room")
CheckSinglePlayerTimer = null
])
logInfo("openhab","CheckSinglePlayerTimer scheduled")
} else {
CheckSinglePlayerTimer.reschedule(now.plusSeconds(20))
logInfo("openhab","CheckSinglePlayerTimer rescheduled")
}
}
end
///// GROUP VISIBILITY
//
// The rule is used to control the UI.
// Specifically, it used to determin
// if a group should be hidden and if
// no, which player is to be shown within
// the group. This has to be the local
// coordinator in the group.
//
/////////////////////////////////
rule "Sonos group visibility"
when
Item SonosGroupID_Kitc received update or
Item SonosGroupID_Gues received update or
Item SonosGroupID_Bath received update or
Item SonosGroupID_Livi received update
then
if(SonosGroupVisibility==null) {
SonosGroupVisibility = createTimer(now.plusSeconds(5), [|
if(Sonos_Group1_Number.state<=1){
postUpdate(Sonos_Group1_Visibility,"Hide")
}else if(Sonos_Group1_Number.state>=2){
if(SonosGroupID_Kitc.state=="1" && Sonos_Kitc_LocalCoordinator.state==ON){
postUpdate(Sonos_Group1_Visibility,"Kitchen")
}else if(SonosGroupID_Gues.state=="1" && Sonos_Gues_LocalCoordinator.state==ON){
postUpdate(Sonos_Group1_Visibility,"Guest room")
}else if(SonosGroupID_Bath.state=="1" && Sonos_Bath_LocalCoordinator.state==ON){
postUpdate(Sonos_Group1_Visibility,"Bathroom")
}else if(SonosGroupID_Livi.state=="1" && Sonos_Livi_LocalCoordinator.state==ON){
postUpdate(Sonos_Group1_Visibility,"Living room")
}
}
if(Sonos_Group2_Number.state<=1){
postUpdate(Sonos_Group2_Visibility,"Hide")
}else if(Sonos_Group2_Number.state>=2){
if(SonosGroupID_Kitc.state=="2" && Sonos_Kitc_LocalCoordinator.state==ON){
postUpdate(Sonos_Group2_Visibility,"Kitchen")
}else if(SonosGroupID_Gues.state=="2" && Sonos_Gues_LocalCoordinator.state==ON){
postUpdate(Sonos_Group2_Visibility,"Guest room")
}else if(SonosGroupID_Bath.state=="2" && Sonos_Bath_LocalCoordinator.state==ON){
postUpdate(Sonos_Group2_Visibility,"Bathroom")
}else if(SonosGroupID_Livi.state=="2" && Sonos_Livi_LocalCoordinator.state==ON){
postUpdate(Sonos_Group2_Visibility,"Living room")
}
}
if(Sonos_Group3_Number.state<=1){
postUpdate(Sonos_Group3_Visibility,"Hide")
}else if(Sonos_Group3_Number.state>=2){
if(SonosGroupID_Kitc.state=="3" && Sonos_Kitc_LocalCoordinator.state==ON){
postUpdate(Sonos_Group3_Visibility,"Kitchen")
}else if(SonosGroupID_Gues.state=="3" && Sonos_Gues_LocalCoordinator.state==ON){
postUpdate(Sonos_Group3_Visibility,"Guest room")
}else if(SonosGroupID_Bath.state=="3" && Sonos_Bath_LocalCoordinator.state==ON){
postUpdate(Sonos_Group3_Visibility,"Bathroom")
}else if(SonosGroupID_Livi.state=="3" && Sonos_Livi_LocalCoordinator.state==ON){
postUpdate(Sonos_Group3_Visibility,"Living room")
}
}
])
logInfo("openhab","SonosGroupVisibility scheduled")
SonosGroupVisibility = null
} else {
SonosGroupVisibility.reschedule(now.plusSeconds(5))
logInfo("openhab","SonosGroupVisibility rescheduled")
}
end
(continued in next post)