Beeing a complete html novice I found a post in this community by Christian for a custom built SONOS
HabPanel template.
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:
- icon size is now more responsive (scales fitting to handhelds and PC-screens)
- play/pause button do toggle - so you can see whether it’s playing or not
- using sonos favorites
- using sonos playlists
- changed the way to group multiple speakers (reducing the items required for grouping)
- now showing to which speaker another speaker is grouped to
- 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üpft 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