Custom Sonos HabPanel template

Beeing a complete html novice I found a post in this community by Christian for a custom built SONOS
HabPanel template.

original post by Christian

The post inspired me to learn about html and improve Christian’s template, I happily share those back to you.

The template now includes the following changes/improvements:

  1. icon size is now more responsive (scales fitting to handhelds and PC-screens)
  2. play/pause button do toggle - so you can see whether it’s playing or not
  3. using sonos favorites
  4. using sonos playlists
  5. changed the way to group multiple speakers (reducing the items required for grouping)
  6. now showing to which speaker another speaker is grouped to
  7. use a background image instead of simple gray background

OpenHab Version is: 2.5

Screen shots
currently:
Wohnzimmer (living room) and Badezimmer (master bathroom) both grouped to Buero (office) - all three playing
Pool: not grouped and not playing

On PC screen:
The template now looks like this (actually 4 of them on one panel):

On cell phone:
scrolled up:

scrolled down:

Translation
Büro = office,
Wohnzimmer = livingroom,
Badezimmer (short: Bad) = master bathroom)
verknüpft mit = linked to

Template Code (for pool as an example)

<style>
   .sonosbutton {width: 90%; height: 4em; border: 0; color: white; background-color: transparent;}
   .sonosctrl {width: 90%; height: 3em; border: 0; color: white; background-color: transparent;}
   .sonosbuttontxt_white {width: 100%;height: 4em; border: 0; color: white;font-size: 10pt; background-color: transparent;}
   .sonosbuttontxt_red {width: 100%;height: 4em; border: 0; color: red;font-size: 10pt; background-color: transparent;}
   .modgrid {padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;}
   .butticon {font-size:1em;}
 </style>
 <div id="sonos-control"  class="table" style="background-image: url('/static/background/dark15.jpg'); background-repeat: no-repeat; background-size: 100% 100%;" >
   <div class="row" style="height:4%">
      <p style="font-size:3vw;">
           {{ itemValue("sonos_CONNECTAMP_RINCON_000E58DA60BC01400_zonename")}}
         </p>
    </div>
    <div class="row" style="height:30px">    
      <p style="font-size:1vw;" ng-if="itemValue('str_sonos_pool_linked_to') != '' && itemValue('str_sonos_pool_linked_to') != 'undefiniert' && itemValue('str_sonos_pool_linked_to') != 'NULL'" >
         ( verkn&uumlpft mit: {{ itemValue("str_sonos_pool_linked_to")}} )
      </p>
   </div>
    <div  class="row" style="height:150px;" ng-if="itemValue('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_currentalbumart') != 'UNDEF'" >
       <img style="max-width: 90%; max-height: 90%;" ng-src="{{itemValue('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_currentalbumart')}}" aria-hidden="false"/> 
    </div>
    <div class="row" style="height:150px;" ng-if="itemValue('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_currentalbumart') == 'UNDEF'" >
       <img style="max-width: 90%; max-height: 90%;" ng-src="../static/sonos/sonos_logo.png"/> 
    </div>
    <div class="row" style="height:3%; font-size:1vw;">
      {{ itemValue("sonos_CONNECTAMP_RINCON_000E58DA60BC01400_currenttrack") | limitTo: 80 }}{{itemValue("sonos_CONNECTAMP_RINCON_000E58DA60BC01400_currenttrack").length > 80 ? '...' : ''}}
   </div>
   <div  class="row">
      <div class="col-xs-4 modgrid">
         <button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat;background-position: center center;font-size:3vw;" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_control', 'PREVIOUS')">
         <i class="glyphicon glyphicon-step-backward butticon" alt="Step Backward"></i>
         </button>
      </div>
      <div class="col-xs-4 modgrid">
         <button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat;background-position: center center;font-size:3vw;" 
            ng-if="itemValue('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_state') == 'PLAYING'" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_control', 'PAUSE')">
         <i class="glyphicon glyphicon-pause butticon" alt="PAUSE"></i>
         </button>       
         <button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat;background-position: center center;font-size:3vw;" 
            ng-if="itemValue('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_state') != 'PLAYING'" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_control', 'PLAY')">
         <i class="glyphicon glyphicon-play butticon" alt="Play"></i>
         </button>
      </div>
      <div class="col-xs-4 modgrid">
         <button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat;background-position: center center;font-size:3vw;" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_control', 'NEXT')">
         <i class="glyphicon glyphicon-step-forward butticon" alt="Step Forward"></i>
         </button>
      </div>
   </div>      
    <div  class="row">
       <div class="col-xs-12">
          <div ng-init="slider = {
             'item': 'sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume',
             'vertical': false,
             'floor': 0,
             'ceil': 100,
             'step': 2,
             'precision': 1,
             'unit': '%',
             'hidelabel': true,
             'hidelimits': false,
             'hidepointer': false,
             'showticks': false,
             'bigslider': false
             }">
          </div>
          <widget-slider ng-model="slider"/>
       </div>
    </div>
    <div  class="row">
       <div class="col-xs-3 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/WDR5.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_tuneinstationid', '20301')">
          </button>
       </div>
       <div class="col-xs-3 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/WDR2.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_tuneinstationid', '213886')">
          </button>
       </div>
       <div class="col-xs-3 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/SWR3.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_tuneinstationid', '24896')">
          </button>
       </div>
       <div class="col-xs-3 modgrid">
         <button class="sonosbutton" style="background-image: url(/static/sonos/dlf.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_tuneinstationid', '42828)">
         </button>
      </div>
    </div>
    <div  class="row">
      <div class="col-xs-3 modgrid">
         <button class="sonosbutton" style="background-image: url(/static/sonos/ChillOut.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_favorite', 'Chillout')">
         </button>
      </div>
      <div class="col-xs-3 modgrid">
         <button class="sonosbutton" style="background-image: url(/static/sonos/summer_lounge.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_favorite', 'Summer Lounge')">
         </button>
      </div>
      <div class="col-xs-3 modgrid">
         <button class="sonosbutton" style="background-image: url(/static/sonos/DailyMix.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
            ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_playlist', 'Daily Mix 2')">
         </button>
      </div>
      <div class="col-xs-3 modgrid">
         <button class="sonosbutton" style="background-image: url(/static/sonos/PartyClassics.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_playlist', 'Party Classics')">
          </button>
       </div>
    </div>
   
    <div  class="row">
       <div class="col-xs-4 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/BlankAndJones.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_favorite', 'Blank and Jones Relax')">
          </button>
       </div>
       <div class="col-xs-4 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/Karneval.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_playlist', 'Karneval')">
          </button>
       </div>
       <div class="col-xs-4 modgrid">
          <button class="sonosbutton" style="background-image: url(/static/sonos/Party.png); background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('sonos_CONNECTAMP_RINCON_000E58DA60BC01400_playlist', 'Party')">
          </button>
       </div>
    </div>   

    <hr style="border-top: 1px solid #ccc; background: transparent;">
   
    <div  class="row">
       <div class="col-xs-3 modgrid">
          <button class="sonosbuttontxt_red" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
            ng-click="sendCmd('str_sonos_pool_linked_to', '')">      
          <i class="glyphicon glyphicon-fullscreen" alt="Step Backward"></i><br>
          <b>Ungroup</b>
          </button>
       </div>
       <div class="col-xs-3 modgrid">
          <button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('str_sonos_wohnzimmer_linked_to', 'Pool')"> 
          <i class="glyphicon glyphicon-plus-sign butticon" alt="Step Backward"></i><br>
          <b>Wohnzimmer</b>
          </button>
       </div>
       <div class="col-xs-3 modgrid">
          <button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
             ng-click="sendCmd('str_sonos_bad_linked_to', 'Pool')">        
          <i class="glyphicon glyphicon-plus-sign butticon" alt="Step Backward"></i><br>
          <b>Bad</b>
          </button>
       </div>
       <div class="col-xs-3 modgrid">
        <button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
           ng-click="sendCmd('str_sonos_buero_linked_to', 'Pool')">        
        <i class="glyphicon glyphicon-plus-sign butticon" alt="Step Backward"></i><br>
        <b>Buero</b>
        </button>
     </div>
    </div>
 </div>

Items

//Items for creating Sonos-Groups:
String str_sonos_wohnzimmer_linked_to 
String str_sonos_buero_linked_to      
String str_sonos_bad_linked_to        
String str_sonos_pool_linked_to

Rules

// Bad:        sonos_PLAY1_RINCON_B8E937558D8801400
// Buero:      sonos_PLAY1_RINCON_949F3E0A6EEA01400
// Wohnzimmer: sonos_PLAYBAR_RINCON_000E58B18BEF01400
// Pool:       sonos_CONNECTAMP_RINCON_000E58DA60BC01400
 

rule "Link_Buero_to"
when 
    Item str_sonos_buero_linked_to received update
then
    if ( str_sonos_buero_linked_to.state == "Wohnzimmer" )
    {
        var Number v_volume = sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume.state as DecimalType    //hole Wohnzimmer Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume, v_volume)                          //setze Buero Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_add, "RINCON_949F3E0A6EEA01400")         //add Buero to Wohnzimmer
    }
    if ( str_sonos_buero_linked_to.state == "Bad" )
    {
        var Number v_volume = sonos_PLAY1_RINCON_B8E937558D8801400_volume.state as DecimalType      //hole Bad Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume, v_volume)                          //setze Buero Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_add, "RINCON_949F3E0A6EEA01400")           //add Buero to Bad
    }
    if ( str_sonos_buero_linked_to.state == "Pool" )
    { 
        var Number v_volume = sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume.state as DecimalType //hole Pool Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume, v_volume)                          //setze Buero Volume 
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_add, "RINCON_949F3E0A6EEA01400")      //add Buero to Pool
    }
    if ( str_sonos_buero_linked_to.state == "" )
    {
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_standalone, "ON") 
    }
    if ( str_sonos_buero_linked_to.state == "" || str_sonos_buero_linked_to.state == "undefiniert" )
    {
        switch "Buero"
        {
            case str_sonos_wohnzimmer_linked_to.state:  postUpdate( str_sonos_wohnzimmer_linked_to, "" )
            case str_sonos_bad_linked_to.state:         postUpdate( str_sonos_bad_linked_to, ""        )
            case str_sonos_pool_linked_to.state:        postUpdate( str_sonos_pool_linked_to, ""       )
        }
    }
end

rule "Link_Wohnzimmer_to"
when 
    Item str_sonos_wohnzimmer_linked_to received update
then
    if ( str_sonos_wohnzimmer_linked_to.state == "Buero" )
    {
        var Number v_volume = sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume.state as DecimalType      //hole Buero Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume, v_volume)                        //setze Wohnzimmer Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_add, "RINCON_000E58B18BEF01400")           //add Wohnzimmer to Buero
    }
    if ( str_sonos_wohnzimmer_linked_to.state == "Bad" )
    {
        var Number v_volume = sonos_PLAY1_RINCON_B8E937558D8801400_volume.state as DecimalType      //hole Bad Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume, v_volume)                        //setze Wohnzimmer Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_add, "RINCON_000E58B18BEF01400")           //add Wohnzimmer to Bad
    }
    if ( str_sonos_wohnzimmer_linked_to.state == "Pool" )
    { 
        var Number v_volume = sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume.state as DecimalType //hole Pool Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume, v_volume)                        //setze Wohnzimmer Volume
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_add, "RINCON_000E58B18BEF01400")      //add Wohnzimmer to Pool        
    }
    if ( str_sonos_wohnzimmer_linked_to.state == "" )
    {
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_standalone, "ON") 
    }
    if ( str_sonos_wohnzimmer_linked_to.state == "" || str_sonos_wohnzimmer_linked_to.state == "undefiniert" )
    {
        switch "Wohnzimmer"
        {
            case str_sonos_buero_linked_to.state:       postUpdate( str_sonos_buero_linked_to, "" )
            case str_sonos_bad_linked_to.state:         postUpdate( str_sonos_bad_linked_to, ""        )
            case str_sonos_pool_linked_to.state:        postUpdate( str_sonos_pool_linked_to, ""       )
        }
    }
end

rule "Link_Bad_to"
when 
    Item str_sonos_bad_linked_to received update
then
    if ( str_sonos_bad_linked_to.state == "Buero" )
    {
        var Number v_volume = sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume.state as DecimalType      //hole Buero Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_volume, v_volume)                          //setze Bad Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_add, "RINCON_B8E937558D8801400")           //add Bad to Buero
    }
    if ( str_sonos_bad_linked_to.state == "Wohnzimmer" )
    {
        var Number v_volume = sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume.state as DecimalType    //hole Wohnzimmer Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_volume, v_volume)                          //setze Bad Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_add, "RINCON_B8E937558D8801400")         //add Bad to Wohnzimmer 
    }
    if ( str_sonos_bad_linked_to.state == "Pool" )
    { 
        var Number v_volume = sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume.state as DecimalType //hole Pool Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_volume, v_volume)                          //setze Bad Volume
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_add, "RINCON_B8E937558D8801400")      //add Bad to Pool       
    }   
    if ( str_sonos_bad_linked_to.state == "" )
    {
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_standalone, "ON") 
    }
    if ( str_sonos_bad_linked_to.state == "" || str_sonos_bad_linked_to.state == "undefiniert" )
    {
        switch "Bad"
        {
            case str_sonos_buero_linked_to.state:       postUpdate( str_sonos_buero_linked_to, "" )
            case str_sonos_wohnzimmer_linked_to.state:  postUpdate( str_sonos_wohnzimmer_linked_to, "" )
            case str_sonos_pool_linked_to.state:        postUpdate( str_sonos_pool_linked_to, ""       )
        }
    }
end

rule "Link_Pool_to"
when 
    Item str_sonos_pool_linked_to received update
then
    if ( str_sonos_pool_linked_to.state == "Buero" )
    {
        var Number v_volume = sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume.state as DecimalType      //hole Buero Volume
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume, v_volume)                     //setze Pool Volume
        sendCommand(sonos_PLAY1_RINCON_949F3E0A6EEA01400_add, "RINCON_000E58DA60BC01400")           //add Pool to Buero
    }
    if ( str_sonos_pool_linked_to.state == "Wohnzimmer" )
    {
        var Number v_volume = sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume.state as DecimalType    //hole Wohnzimmer Volume
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume, v_volume)                     //setze Pool Volume
        sendCommand(sonos_PLAYBAR_RINCON_000E58B18BEF01400_add, "RINCON_000E58DA60BC01400")         //add Pool to Wohnzimmer 
    }
    if ( str_sonos_pool_linked_to.state == "Pool" )
    { 
        var Number v_volume = sonos_PLAY1_RINCON_B8E937558D8801400_volume.state as DecimalType      //hole Bad Volume
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume, v_volume)                     //setze Pool Volume
        sendCommand(sonos_PLAY1_RINCON_B8E937558D8801400_add, "RINCON_000E58DA60BC01400")           //add Pool to Bad
    }
    if ( str_sonos_pool_linked_to.state == "" )
    {
        sendCommand(sonos_CONNECTAMP_RINCON_000E58DA60BC01400_standalone, "ON") 
    }
    if ( str_sonos_pool_linked_to.state == "" || str_sonos_pool_linked_to.state == "undefiniert" )
    {
        switch "Pool"
        {
            case str_sonos_buero_linked_to.state:       postUpdate( str_sonos_buero_linked_to, "" )
            case str_sonos_wohnzimmer_linked_to.state:  postUpdate( str_sonos_wohnzimmer_linked_to, "" )
            case str_sonos_bad_linked_to.state:         postUpdate( str_sonos_bad_linked_to, "" )
        }
    }
end
4 Likes

Great job. Is it possible for you to post all your items?

Hi.
Thanks for the feedback!

I has been a while since my original post, back then I’ve used the “simple mode item linking” (setting in paper-UI) but changed to manual item creation via items files and ajusted the template code accordingly in the meantime.

I tried to restore the original items used for this template (as posted here) for you:

Switch	sonos_PLAY1_RINCON_949F3E0A6EEA01400_volume				"Volume [%.1f %%]"	<soundvolume>		(Sonos)	{channel="sonos:PLAY1:Buero:volume"}
String	sonos_PLAY1_RINCON_949F3E0A6EEA01400_add				"Add"									(Sonos)	{channel="sonos:PLAY1:Buero:add"}
Switch	sonos_PLAY1_RINCON_949F3E0A6EEA01400_standalone			"Standalone"							(Sonos)	{channel="sonos:PLAY1:Buero:standalone"}

Dimmer	sonos_PLAY1_RINCON_B8E937558D8801400_volume				"Volume [%.1f %%]"	<soundvolume>		(Sonos)	{channel="sonos:PLAY1:Spielzimmer:volume"}
String	sonos_PLAY1_RINCON_B8E937558D8801400_add				"Add"									(Sonos)	{channel="sonos:PLAY1:Spielzimmer:add"}
Switch	sonos_PLAY1_RINCON_B8E937558D8801400_standalone			"Standalone"							(Sonos)	{channel="sonos:PLAY1:Spielzimmer:standalone"}

Dimmer	sonos_PLAYBAR_RINCON_000E58B18BEF01400_volume			"Volume [%.1f %%]"	<soundvolume>		(Sonos)	{channel="sonos:PLAYBAR:Wohnzimmer:volume"}
String	sonos_PLAYBAR_RINCON_000E58B18BEF01400_add				"Add"									(Sonos)	{channel="sonos:PLAYBAR:Wohnzimmer:add"}
Switch	sonos_PLAYBAR_RINCON_000E58B18BEF01400_Standalone		"Standalone"							(Sonos)	{channel="sonos:PLAYBAR:Wohnzimmer:standalone"}

Dimmer	sonos_CONNECTAMP_RINCON_000E58DA60BC01400_volume 		"Volume [%.1f %%]"	<soundvolume>		(Sonos)	{channel="sonos:CONNECTAMP:Pool:volume"}
String 	sonos_CONNECTAMP_RINCON_000E58DA60BC01400_add 	 		"Add"									(Sonos)	{channel="sonos:CONNECTAMP:Pool:add"}
Switch 	sonos_CONNECTAMP_RINCON_000E58DA60BC01400_Standalone	"Standalone"							(Sonos)	{channel="sonos:CONNECTAMP:Pool:standalone"}

Things:

Thing sonos:PLAY1:Buero “Sonos” @ “Büro Ralph” [udn=“RINCON_949F3E0A6EEA01400”, refresh=60, notificationVolume=25] //Buero
Thing sonos:PLAY1:Spielzimmer “Sonos” @ “Kinderschlafzimmer” [udn=“RINCON_B8E937558D8801400”, refresh=60, notificationVolume=25] //Nicklas
Thing sonos:CONNECTAMP:Pool “Sonos” @ “Pool” [udn=“RINCON_000E58DA60BC01400”, refresh=60, notificationVolume=25] //Pool
Thing sonos:PLAYBAR:Wohnzimmer “Sonos” @ “Wohnzimmer” [udn=“RINCON_000E58B18BEF01400”, refresh=60, notificationVolume=25] //Wohnzimmer

Let me know if more detail is needed!

Kind regards,
Ralph…

Thanks I will check it out this weekend.

Hi Ralf, I’m new here in the forum and I like the Sonos widget super well…but I’m in HTML not so the ace! Could you grab me there times under the arms please …
Would it be possible times per emial contact?

About ne info thank you very much

English please, this is an international community.

can you help me about my problem?

It’s been quite a while since I implemented the initial version of the Sonos widget.
Today I took some time to enhance the widget by adding “mute” and “loudness” buttons as well as a “bass slider”. I’ve also changed to entire coding to allow config for all items to control the Sonos rather than hardcoding them.
The look and feel changed slightly due to the added slider and buttons:

The new habpanel widget coding (I’d upload it to the widget gallery if I knew how to do so):

<!-- Gefunden hier: https://community.openhab.org/t/sonos-control-status-favorites-template-widget/28611 -->

<style>
	.sonosbutton {width: 90%; height: 4em; border: 0; color: white; background-color: transparent;}
	.sonosctrl {width: 90%; height: 3em; border: 0; color: light-gray; background-color: transparent;}
	.sonosctrlon {width: 90%; height: 3em; border: 0; color: light-gray; background-color: transparent;}
	.sonosctrloff {width: 90%; height: 3em; border: 0; color: gray; background-color: transparent;}
	.sonosbuttontxt_white {width: 100%;height: 4em; border: 0; color: white;font-size: 10pt; background-color: transparent;}
	.sonosbuttontxt_red {width: 100%;height: 4em; border: 0; color: red;font-size: 10pt; background-color: transparent;}
	.modgrid {padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;}
	.butticon {font-size:1em;}
</style>

<div id="sonos-control"  class="table" style="background-image: url('/static/background/dark15.jpg'); background-repeat: no-repeat; background-size: 100% 100%;" >
	<div class="row" style="height:4%">
		<p style="font-size:3vw;">
			{{ itemValue(config.ZoneNameItem)}}
		</p>
	</div>
	<div class="row" style="height:30px">     
		<p style="font-size:1vw;" ng-if="itemValue(config.LinkItem) != '' && itemValue(config.LinkItem) != 'undefiniert' && itemValue(config.LinkItem) != 'NULL'" >
			( verkn&uumlpft mit: {{ itemValue(config.LinkItem)}} )
		</p>
	</div>
	<div class="row" style="height: 150px;" ng-if="itemValue(config.CurrentAlbumartItem) != 'UNDEF'" >
		<img style="max-width: 90%; max-height: 90%;" ng-src="{{itemValue(config.CurrentAlbumartItem)}}" aria-hidden="false"/> 
	</div>
	<div class="row" style="height: 150px;" ng-if="itemValue(config.CurrentAlbumartItem) == 'UNDEF'" >
		<img style="max-width: 90%; max-height: 90%;" ng-src="../static/sonos/sonos_logo.png"/> 
	</div>
	<div class="row" style="height:30px; font-size:1vw;">
		{{ itemValue(config.CurrentTrackItem) | limitTo: 80 }}{{itemValue(config.CurrentTrackItem).length > 80 ? '...' : ''}}
	</div>
  
	<div  class="row">
		<div class="col-xs-4 modgrid">
			<button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat; background-position: center center; font-size:3vw;" 
             	ng-click="sendCmd(config.ControllerItem, 'PREVIOUS')">
				<i class="glyphicon glyphicon-step-backward butticon" alt="Backward">
        </i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat; background-position: center center; font-size:3vw;" 
             	ng-if="itemValue(config.StateItem) == 'PLAYING'" 
             	ng-click="sendCmd(config.ControllerItem, 'PAUSE')">
				<i class="glyphicon glyphicon-pause butticon" alt="PAUSE">
        </i>
			</button>       
			<button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat; background-position: center center; font-size:3vw;" 
      	      ng-if="itemValue(config.StateItem) != 'PLAYING'" 
        	    ng-click="sendCmd(config.ControllerItem, 'PLAY')">
				<i class="glyphicon glyphicon-play butticon" alt="Play">
      	</i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="sonosctrl" style="background-size: contain; background-repeat: no-repeat;background-position: center center;font-size:3vw;" 
           	  ng-click="sendCmd(config.ControllerItem, 'NEXT')">
				<i class="glyphicon glyphicon-step-forward butticon" alt="Forward">
        </i>
			</button>
		</div>
	</div>
  
	<div  class="row">
		<div class="col-xs-10">
			<div ng-init="volumeSlider = {
              'name' : 'Volume',
              'item': config.VolumeItem,
              'vertical': false,
              'floor': 0,
              'ceil': 100,
              'step': 2,
              'precision': 1,
              'unit': '%',
              'hidelabel': true,
              'hidelimits': false,
              'hidepointer': false,
              'showticks': false,
              'bigslider': false
              }">
			</div>
			<widget-slider ng-model="volumeSlider" style="width: 95%; margin-left: 13px; display: block;">
      </widget-slider>
		</div>
    <div class="col-xs-1 modgrid">
      <div ng-if="itemValue(config.MuteItem)=='ON'" 
           class="col-xs-2 modgrid" 
           style="text-align:left; 
                  vertical-align: middle;">
        <button class="sonosctrl" 
                style="background-size: contain; 
                       background-repeat: no-repeat; 
                       background-position: center center; 
                       font-size:35px; 
                       background-color:transparent; 
                       color:light-gray;" 
                ng-click="sendCmd(config.MuteItem, itemValue(config.MuteItem) == 'ON' ? 'OFF' : 'ON')">
          <i class="glyphicon glyphicon-volume-off butticon" alt="Mute OFF"></i>
        </button>
      </div>
      <div ng-if="itemValue(config.MuteItem)=='OFF'" 
           class="col-xs-2 modgrid" 
           style="text-align:left; vertical-align: middle;">
        <button class="sonosctrl" 
                style="background-size: contain; 
                       background-repeat: no-repeat; 
                       background-position: center center; 
                       font-size:35px; 
                       background-color:transparent; 
                       color:light-gray;" 
                ng-click="sendCmd(config.MuteItem, itemValue(config.MuteItem) == 'ON' ? 'OFF' : 'ON')">
          <i class="glyphicon glyphicon-volume-up butticon" alt="Mute ON"></i>
        </button>
      </div>
		</div>
	</div>
    
  <div class="row">
		<div class="col-xs-10 modgrid">
			<div ng-init="bassSlider = {
              'name' : 'Bass',
              'item': config.BassItem,
              'vertical': false,
              'floor': -10,
              'ceil': 10,
              'step': 1,
              'precision': 1,
              'unit': '',
              'hidelabel': true,
              'hidelimits': false,
              'hidepointer': false,
              'showticks': false,
              'bigslider': false
              }">
			</div>
			<widget-slider ng-model="bassSlider" style="width: 95%; margin-left: 13px; display: block;">
      </widget-slider>
		</div>
    <div class="col-xs-1 modgrid">
      <div ng-if="itemValue(config.LoudnessItem)=='ON'" class="col-xs-2 modgrid" style="text-align:left; vertical-align: middle;">
        <button class="sonosctrlon" style="background-size: contain; background-repeat: no-repeat; background-position: center center; font-size:35px; background-color:transparent; color:light-gray;" ng-click="sendCmd(config.LoudnessItem, itemValue(config.LoudnessItem) == 'ON' ? 'OFF' : 'ON')">
          <i class="glyphicon glyphicon-bullhorn butticon" alt="Loudness OFF"></i>
        </button>
      </div>
      <div ng-if="itemValue(config.LoudnessItem)=='OFF'" class="col-xs-2 modgrid" style="text-align:left; vertical-align: middle;">
        <button class="sonosctrloff" style="background-size: contain; background-repeat: no-repeat; background-position: center center; font-size:35px; background-color:transparent; color:gray;" ng-click="sendCmd(config.LoudnessItem, itemValue(config.LoudnessItem) == 'ON' ? 'OFF' : 'ON')">
          <i class="glyphicon glyphicon-bullhorn butticon" alt="Loudness ON"></i>
        </button>
      </div>
		</div>
	</div>

  <div class="row">
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url('https://cdn-radiotime-logos.tunein.com/s{{config.StationID1}}q.png'); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.StationIDItem, config.StationID1)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url('https://cdn-radiotime-logos.tunein.com/s{{config.StationID2}}q.png'); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.StationIDItem, config.StationID2)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url('https://cdn-radiotime-logos.tunein.com/s{{config.StationID3}}q.png'); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.StationIDItem, config.StationID3)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url('https://cdn-radiotime-logos.tunein.com/s{{config.StationID4}}q.png'); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.StationIDItem, config.StationID4)">
			</button>
		</div>
	</div>
  
	<div class="row">
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Favorite1Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.FavoriteItem, config.Favorite1)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Favorite2Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
        	    ng-click="sendCmd(config.FavoriteItem, config.Favorite2)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Favorite3Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.FavoriteItem, config.Favorite3)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Favorite4Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.FavoriteItem, config.Favorite4)">
			</button>
		</div>
	</div>
    
	<div class="row">
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Playlist1Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.PlaylistItem, config.Playlist1)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Playlist2Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.PlaylistItem, config.Playlist2)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Playlist3Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.PlaylistItem, config.Playlist3)">
			</button>
		</div>
		<div class="col-xs-3 modgrid">
			<button class="sonosbutton" style="background-image: url({{config.Playlist4Icon}}); background-size: contain; background-repeat: no-repeat;background-position: center center" 
              ng-click="sendCmd(config.PlaylistItem, config.Playlist4)">
			</button>
		</div>    
	</div>   
    
	<hr style="border-top: 1px solid #ccc; background: transparent;"/>
 		<div class="row">
			<div class="col-xs-3 modgrid">
				<button class="sonosbuttontxt_red" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
        		    ng-click="sendCmd(config.LinkItem, '')">		
					<i class="glyphicon glyphicon-fullscreen" alt="Ungroup">
          </i>
          <b>Ungroup</b>
				</button>
			</div>
			<div class="col-xs-3 modgrid">
				<button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
          	    ng-click="sendCmd(config.OtherLinkItem1, itemValue(config.ZoneNameItem))"> 
          <i class="glyphicon glyphicon-plus-sign butticon" alt="itemValue(config.OtherLinkItem1Name)">
          </i>
          <b>{{ (config.OtherLinkItem1Name)}}</b>
				</button>
			</div>
			<div class="col-xs-3 modgrid">
				<button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
      	   	    ng-click="sendCmd(config.OtherLinkItem2, itemValue(config.ZoneNameItem)))">			
					<i class="glyphicon glyphicon-plus-sign butticon" alt="itemValue(config.OtherLinkItem2Name)">
          </i>
          <b>{{config.OtherLinkItem2Name}}</b>
				</button>
			</div>
			<div class="col-xs-3 modgrid">
				<button class="sonosbuttontxt_white" style="background-size: contain; background-repeat: no-repeat;background-position: center center" 
  	       	    ng-click="sendCmd(config.OtherLinkItem3, itemValue(config.ZoneNameItem)))">			
					<i class="glyphicon glyphicon-plus-sign butticon" alt="itemValue(config.OtherLinkItem3Name)">
          </i>
          <b>{{config.OtherLinkItem3Name}}</b>
				</button>
			</div>
		</div>
    
</div>

The code of the rules to process the grouping of Sonos devices did not change.

Here are all the config parameters now available:


For completion sake here all my items and rules:
items:

Group	gSonosBuero							"Sonos Büro Ralph"	<speaker>			(gEG_Buero1)		["Speaker"]
Group	gSonosBadezimmer					"Sonos Badezimmer"	<speaker>			(gOG_Badezimmer)	["Speaker"]
Group	gSonosWohnzimmer					"Sonos Wohnzimmer"	<speaker>			(gEG_Wohnzimmer)	["Speaker"]
Group	gSonosPool							"Sonos Pool"		<speaker>			(gPool)				["Speaker"]

//Items fuer die Bildung von Sonos-Gruppen (derzeit nur fuer HabPanel genutzt):
String	str_sonos_wohnzimmer_linked_to
String	str_sonos_buero_linked_to
String	str_sonos_bad_linked_to
String	str_sonos_pool_linked_to
 
Player	Sonos_Buero_Controller				"Controller"		<player>			(gSonosBuero)		["Control"]		{channel="sonos:PLAY1:Buero:control"}
String	Sonos_Buero_Zonename				"Zone name"								(gSonosBuero)						{channel="sonos:PLAY1:Buero:zonename"}
Dimmer	Sonos_Buero_Volume					"Volume [%.1f %%]"	<soundvolume>		(gSonosBuero)		["SoundVolume"]	{channel="sonos:PLAY1:Buero:volume"}
Switch	Sonos_Buero_Mute					"Mute"				<soundvolume_mute>	(gSonosBuero)		["Switch"]		{channel="sonos:PLAY1:Buero:mute"}
//Number	Sonos_Buero_HeightLevel				"Höhen"									(gSonosBuero)						{channel="sonos:PLAY1:Buero:heightlevel"} //Nur SONOS ARC und ARC SL
Number	Sonos_Buero_Bass					"Bässe"									(gSonosBuero)						{channel="sonos:PLAY1:Buero:bass"}
Switch	Sonos_Buero_Loudness				"Loudness"								(gSonosBuero)						{channel="sonos:PLAY1:Buero:loudness"}
Switch	Sonos_Buero_Shuffle					"Shuffle"								(gSonosBuero)						{channel="sonos:PLAY1:Buero:shuffle"}
String	Sonos_Buero_CurrentTrack			"Now playing [%s]"	<text>				(gSonosBuero)		["Status"]		{channel="sonos:PLAY1:Buero:currenttrack"}
String	Sonos_Buero_State					"Status [%s]"		<text>				(gSonosBuero)		["Status"]		{channel="sonos:PLAY1:Buero:state"}
String	Sonos_Buero_StationID				"Station [%s]"							(gSonosBuero)						{channel="sonos:PLAY1:Buero:tuneinstationid"}
Image	Sonos_Buero_CurrentAlbumart			"Album"				<text>				(gSonosBuero)		["Status"]		{channel="sonos:PLAY1:Buero:currentalbumart"}
String	Sonos_Bureo_CurrentAlbumartUrl		"Albumart URL"		<text>				(gSonosBuero)						{channel="sonos:PLAY1:Buero:currentalbumarturl"}
String	Sonos_Buero_Playlist				"Playlist"			<text>				(gSonosBuero)		["Status"]		{channel="sonos:PLAY1:Buero:playlist"}
String	Sonos_Buero_Favorite				"Favorite"			<text>				(gSonosBuero)		["Status"]		{channel="sonos:PLAY1:Buero:favorite"}
String	Sonos_Buero_Add						"Add"									(gSonosBuero)						{channel="sonos:PLAY1:Buero:add"}
String	Sonos_Buero_Coordinator				"Coordinator"							(gSonosBuero)						{channel="sonos:PLAY1:Buero:coordinator"}
Switch	Sonos_Buero_LocalCoordinator		"is coordinator"						(gSonosBuero)						{channel="sonos:PLAY1:Buero:localcoordinator"}
Switch	Sonos_Buero_Standalone				"Standalone"							(gSonosBuero)						{channel="sonos:PLAY1:Buero:standalone"}
String	Sonos_Buero_ZoneGroupID				"Zone group ID"							(gSonosBuero)						{channel="sonos:PLAY1:Buero:zonegroupid"}
String	Sonos_Buero_LinkedTo				"Linked to"

Player	Sonos_Badezimmer_Controller			"Controller"		<player>			(gSonosBadezimmer)	["Control"]		{channel="sonos:One:Badezimmer:control"}
String	Sonos_Badezimmer_Zonename			"Zone name"								(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:zonename"}
Dimmer	Sonos_Badezimmer_Volume				"Volume [%.1f %%]"	<soundvolume>		(gSonosBadezimmer)	["SoundVolume"]	{channel="sonos:One:Badezimmer:volume"}
Switch	Sonos_Badezimmer_Mute				"Mute"				<soundvolume_mute>	(gSonosBadezimmer)	["Switch"]		{channel="sonos:One:Badezimmer:mute"}
Number	Sonos_Badezimmer_Bass				"Bässe"									(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:bass"}
Switch	Sonos_Badezimmer_Loudness			"Loudness"								(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:loudness"}
String	Sonos_Badezimmer_CurrentTrack		"Now playing [%s]"	<text>				(gSonosBadezimmer)	["Status"]		{channel="sonos:One:Badezimmer:currenttrack"}
String	Sonos_Badezimmer_State				"Status [%s]"		<text>				(gSonosBadezimmer)	["Status"]		{channel="sonos:One:Badezimmer:state"}
String	Sonos_Badezimmer_StationID			"Station [%s]"							(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:tuneinstationid"}
Image	Sonos_Badezimmer_CurrentAlbumart	"Album"				<text>				(gSonosBadezimmer)	["Status"]		{channel="sonos:One:Badezimmer:currentalbumart"}
String	Sonos_Badezimmer_Playlist			"Playlist"			<text>				(gSonosBadezimmer)	["Status"]		{channel="sonos:One:Badezimmer:playlist"}
String	Sonos_Badezimmer_Favorite			"Favorite"			<text>				(gSonosBadezimmer)	["Status"]		{channel="sonos:One:Badezimmer:favorite"}
String	Sonos_Badezimmer_Add				"Add"									(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:add"}
String	Sonos_Badezimmer_Coordinator		"Coordinator"							(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:coordinator"}
Switch	Sonos_Badezimmer_LocalCoordinator	"is coordinator"						(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:localcoordinator"}
Switch	Sonos_Badezimmer_Standalone			"Standalone"							(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:standalone"}
String	Sonos_Badezimmer_ZoneGroupID		"Zone group ID"							(gSonosBadezimmer)					{channel="sonos:One:Badezimmer:zonegroupid"}
String	Sonos_Badezimmer_LinkedTo			"Linked to"

Player	Sonos_Wohnzimmer_Controller			"Controller"		<player>			(gSonosWohnzimmer)	["Control"]		{channel="sonos:PLAYBAR:Wohnzimmer:control"}
String	Sonos_Wohnzimmer_Zonename			"Zone name"								(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:zonename"}
Dimmer	Sonos_Wohnzimmer_Volume				"Volume [%.1f %%]"	<soundvolume>		(gSonosWohnzimmer)	["SoundVolume"]	{channel="sonos:PLAYBAR:Wohnzimmer:volume"}
Switch	Sonos_Wohnzimmer_Mute				"Mute"				<soundvolume_mute>	(gSonosWohnzimmer)	["Switch"]		{channel="sonos:PLAYBAR:Wohnzimmer:mute"}
Number	Sonos_Wohnzimmer_Bass				"Bässe"									(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:bass"}
Switch	Sonos_Wohnzimmer_Loudness			"Loudness"								(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:loudness"}
String	Sonos_Wohnzimmer_CurrentTrack		"Now playing [%s]"	<text>				(gSonosWohnzimmer)	["Status"]		{channel="sonos:PLAYBAR:Wohnzimmer:currenttrack"}
String	Sonos_Wohnzimmer_State				"Status [%s]"		<text>				(gSonosWohnzimmer)	["Status"]		{channel="sonos:PLAYBAR:Wohnzimmer:state"}
String	Sonos_Wohnzimmer_StationID			"Station [%s]"							(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:tuneinstationid"}
Image	Sonos_Wohnzimmer_CurrentAlbumart	"Album"				<text>				(gSonosWohnzimmer)	["Status"]		{channel="sonos:PLAYBAR:Wohnzimmer:currentalbumart"}
String	Sonos_Wohnzimmer_Playlist			"Playlist"			<text>				(gSonosWohnzimmer)	["Status"]		{channel="sonos:PLAYBAR:Wohnzimmer:playlist"}
String	Sonos_Wohnzimmer_Favorite			"Favorite"			<text>				(gSonosWohnzimmer)	["Status"]		{channel="sonos:PLAYBAR:Wohnzimmer:favorite"}
String	Sonos_Wohnzimmer_Add				"Add"									(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:add"}
String	Sonos_Wohnzimmer_Coordinator		"Coordinator"							(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:coordinator"}
Switch	Sonos_Wohnzimmer_LocalCoordinator	"is coordinator"						(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:localcoordinator"}
Switch	Sonos_Wohnzimmer_Standalone			"Standalone"							(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:standalone"}
String	Sonos_Wohnzimmer_ZoneGroupID		"Zone group ID"							(gSonosWohnzimmer)					{channel="sonos:PLAYBAR:Wohnzimmer:zonegroupid"}
String	Sonos_Wohnzimmer_LinkedTo			"Linked to"

Player	Sonos_Pool_Controller				"Controller"		<player>			(gSonosPool)		["Control"]		{channel="sonos:CONNECTAMP:Pool:control"}
String	Sonos_Pool_Zonename					"Zone name"								(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:zonename"}
Dimmer	Sonos_Pool_Volume					"Volume [%.1f %%]"	<soundvolume>		(gSonosPool)		["SoundVolume"]	{channel="sonos:CONNECTAMP:Pool:volume"}
Switch	Sonos_Pool_Mute						"Mute"				<soundvolume_mute>	(gSonosPool)		["Switch"]		{channel="sonos:CONNECTAMP:Pool:mute"}
Number	Sonos_Pool_Bass						"Bässe"									(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:bass"}
Switch	Sonos_Pool_Loudness					"Loudness"								(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:loudness"}
String	Sonos_Pool_CurrentTrack				"Now playing [%s]"	<text>				(gSonosPool)		["Status"]		{channel="sonos:CONNECTAMP:Pool:currenttrack"}
String	Sonos_Pool_State					"Status [%s]"		<text>				(gSonosPool)		["Status"]		{channel="sonos:CONNECTAMP:Pool:state"}
String	Sonos_Pool_StationID				"Station [%s]"							(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:tuneinstationid"}
Image	Sonos_Pool_CurrentAlbumart			"Album"				<text>				(gSonosPool)		["Status"]		{channel="sonos:CONNECTAMP:Pool:currentalbumart"}
String	Sonos_Pool_Playlist					"Playlist"			<text>				(gSonosPool)		["Status"]		{channel="sonos:CONNECTAMP:Pool:playlist"}
String	Sonos_Pool_Favorite					"Favorite"			<text>				(gSonosPool)		["Status"]		{channel="sonos:CONNECTAMP:Pool:favorite"}
String	Sonos_Pool_Coordinator				"Coordinator"							(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:coordinator"}
Switch	Sonos_Pool_LocalCoordinator			"is coordinator"						(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:localcoordinator"}
String	Sonos_Pool_Add						"Add"									(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:add"}
Switch	Sonos_Pool_Standalone				"Standalone"							(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:standalone"}
String	Sonos_Pool_ZoneGroupID				"Zone group ID"							(gSonosPool)						{channel="sonos:CONNECTAMP:Pool:zonegroupid"}
String	Sonos_Pool_LinkedTo					"Linked to"

and the rules to control the grouping (and ungrouping) of Sonos devices:

// Badezimmer:  sonos_One_RINCON_542A1BF5E7E201400
// Buero:       sonos_PLAY1_RINCON_949F3E0A6EEA01400
// Wohnzimmer:  sonos_PLAYBAR_RINCON_000E58B18BEF01400
// Pool:        sonos_CONNECTAMP_RINCON_000E58DA60BC01400
 

rule "Link_Buero_to"
when  
    Item str_sonos_buero_linked_to received update
then
    if ( str_sonos_buero_linked_to.state == "Wohnzimmer" )
	{
		var Number v_volume = Sonos_Wohnzimmer_Volume.state as DecimalType		//hole Wohnzimmer Volume
		sendCommand(Sonos_Buero_Volume, v_volume)								//setze Buero Volume
	    sendCommand(Sonos_Wohnzimmer_Add, "RINCON_949F3E0A6EEA01400")			//add Buero to Wohnzimmer
	}
	if ( str_sonos_buero_linked_to.state == "Bad" )
	{
		var Number v_volume = Sonos_Badezimmer_Volume.state as DecimalType		//hole Bad Volume
	    sendCommand(Sonos_Buero_Volume, v_volume)								//setze Buero Volume
	    sendCommand(Sonos_Badezimmer_Add, "RINCON_949F3E0A6EEA01400")			//add Buero to Bad
    }
	if ( str_sonos_buero_linked_to.state == "Pool" )
	{ 
		var Number v_volume = Sonos_Pool_Volume.state as DecimalType 			//hole Pool Volume
	    sendCommand(Sonos_Buero_Volume, v_volume)								//setze Buero Volume 
	    sendCommand(Sonos_Pool_Add, "RINCON_949F3E0A6EEA01400")					//add Buero to Pool
    }
	if ( str_sonos_buero_linked_to.state == "" )
	{
	    sendCommand(Sonos_Buero_Standalone, "ON") 
	}
	if ( str_sonos_buero_linked_to.state == "" || str_sonos_buero_linked_to.state == "undefiniert" )
	{
		switch "Büro"
		{
			case str_sonos_wohnzimmer_linked_to.state: 	postUpdate( str_sonos_wohnzimmer_linked_to, "" )
			case str_sonos_bad_linked_to.state: 		postUpdate( str_sonos_bad_linked_to, ""  	   )
			case str_sonos_pool_linked_to.state: 	   	postUpdate( str_sonos_pool_linked_to, "" 	   )
		}
	}
end

rule "Link_Wohnzimmer_to"
when 
    Item str_sonos_wohnzimmer_linked_to received update
then
    if ( str_sonos_wohnzimmer_linked_to.state == "Büro" )
	{
		var Number v_volume = Sonos_Buero_Volume.state as DecimalType		//hole Buero Volume
		sendCommand(Sonos_Wohnzimmer_Volume, v_volume)						//setze Wohnzimmer Volume
	    sendCommand(Sonos_Buero_Add, "RINCON_000E58B18BEF01400")           	//add Wohnzimmer to Buero
	}
	if ( str_sonos_wohnzimmer_linked_to.state == "Bad" )
	{
        var Number v_volume = Sonos_Badezimmer_Volume.state as DecimalType	//hole Bad Volume
		sendCommand(Sonos_Wohnzimmer_Volume, v_volume)						//setze Wohnzimmer Volume
	    sendCommand(Sonos_Badezimmer_Add, "RINCON_000E58B18BEF01400")		//add Wohnzimmer to Bad
    }
	if ( str_sonos_wohnzimmer_linked_to.state == "Pool" )
	{ 
        var Number v_volume = Sonos_Pool_Volume.state as DecimalType		//hole Pool Volume
		sendCommand(Sonos_Wohnzimmer_Volume, v_volume)						//setze Wohnzimmer Volume
	    sendCommand(Sonos_Pool_Add, "RINCON_000E58B18BEF01400")				//add Wohnzimmer to Pool	    
    }
	if ( str_sonos_wohnzimmer_linked_to.state == "" )
	{
	    sendCommand(Sonos_Wohnzimmer_Standalone, "ON") 
	}
	if ( str_sonos_wohnzimmer_linked_to.state == "" || str_sonos_wohnzimmer_linked_to.state == "undefiniert" )
	{
		switch "Wohnzimmer"
		{
			case str_sonos_buero_linked_to.state: 		postUpdate( str_sonos_buero_linked_to, "" )
			case str_sonos_bad_linked_to.state: 		postUpdate( str_sonos_bad_linked_to, "" )
			case str_sonos_pool_linked_to.state: 	   	postUpdate( str_sonos_pool_linked_to, "")
		}
	}
end

rule "Link_Bad_to"
when 
	Item str_sonos_bad_linked_to received update
then
	if ( str_sonos_bad_linked_to.state == "Büro" )
	{
		var Number v_volume = Sonos_Buero_Volume.state as DecimalType		//hole Buero Volume
		sendCommand(Sonos_Badezimmer_Volume, v_volume)						//setze Bad Volume
	    sendCommand(Sonos_Buero_Add, "RINCON_542A1BF5E7E201400")			//add Bad to Buero
	}
	if ( str_sonos_bad_linked_to.state == "Wohnzimmer" )
	{
		var Number v_volume = Sonos_Wohnzimmer_Volume.state as DecimalType	//hole Wohnzimmer Volume
		sendCommand(Sonos_Badezimmer_Volume, v_volume)						//setze Bad Volume
	    sendCommand(Sonos_Wohnzimmer_Add, "RINCON_542A1BF5E7E201400")		//add Bad to Wohnzimmer 
    }
	if ( str_sonos_bad_linked_to.state == "Pool" )
	{ 
		var Number v_volume = Sonos_Pool_Volume.state as DecimalType		//hole Pool Volume
		sendCommand(Sonos_Badezimmer_Volume, v_volume)						//setze Bad Volume
	    sendCommand(Sonos_Pool_Add, "RINCON_542A1BF5E7E201400")				//add Bad to Pool	    
    }	
	if ( str_sonos_bad_linked_to.state == "" )
	{
	    sendCommand(Sonos_Badezimmer_Standalone, "ON") 
	}
	if ( str_sonos_bad_linked_to.state == "" || str_sonos_bad_linked_to.state == "undefiniert" )
	{
		switch "Bad"
		{
			case str_sonos_buero_linked_to.state: 		postUpdate( str_sonos_buero_linked_to, "" )
			case str_sonos_wohnzimmer_linked_to.state: 	postUpdate( str_sonos_wohnzimmer_linked_to, "" )
			case str_sonos_pool_linked_to.state: 	   	postUpdate( str_sonos_pool_linked_to, "" 	   )
		}
	}
end

rule "Link_Pool_to"
when 
    Item str_sonos_pool_linked_to received update
then
    if ( str_sonos_pool_linked_to.state == "Büro" )
	{
		var Number v_volume = Sonos_Buero_Volume.state as DecimalType			//hole Buero Volume
		sendCommand(Sonos_Pool_Volume, v_volume)								//setze Pool Volume
	    sendCommand(Sonos_Buero_Add, "RINCON_000E58DA60BC01400")				//add Pool to Buero
	}
	if ( str_sonos_pool_linked_to.state == "Wohnzimmer" )
	{
		var Number v_volume = Sonos_Wohnzimmer_Volume.state as DecimalType		//hole Wohnzimmer Volume
		sendCommand(Sonos_Pool_Volume, v_volume)								//setze Pool Volume
	    sendCommand(Sonos_Wohnzimmer_Add, "RINCON_000E58DA60BC01400")			//add Pool to Wohnzimmer 
    }
	if ( str_sonos_pool_linked_to.state == "Pool" )
	{ 
		var Number v_volume = Sonos_Badezimmer_Volume.state as DecimalType		//hole Bad Volume
		sendCommand(Sonos_Pool_Volume, v_volume)								//setze Pool Volume
	    sendCommand(Sonos_Badezimmer_Add, "RINCON_000E58DA60BC01400")			//add Pool to Bad
    }
	if ( str_sonos_pool_linked_to.state == "" )
	{
	    sendCommand(Sonos_Pool_Standalone, "ON") 
	}
	if ( str_sonos_pool_linked_to.state == "" || str_sonos_pool_linked_to.state == "undefiniert" )
	{
		switch "Pool"
		{
			case str_sonos_buero_linked_to.state: 		postUpdate( str_sonos_buero_linked_to, "" )
			case str_sonos_wohnzimmer_linked_to.state: 	postUpdate( str_sonos_wohnzimmer_linked_to, "" )
			case str_sonos_bad_linked_to.state: 	   	postUpdate( str_sonos_bad_linked_to, "" )
		}
	}
end

Here’s the json to import into your habpanel in case anyone wants to give it a try:
Sonos_Control.widget.json (19.3 KB)

Enjoy and let me know what you think!

In case there’s anyone out there who can tell me how to contribute this widget to the habpanel gallery: Any help is highliy appreciated!