Ich bin gefragt worden, wie die Steuerung von Sonos mit Misterhouse und InfoTerminal Touch konkret umgesetzt ist, daher hier mehr Details.
Man benötigt:
a) Mindestens einen Sonos Player
b) Misterhouse
c) ein InfoTerminal Touch oder sonst welche Schalter die mit dem EIB/KNX Bus kommunizieren
Ich habe erst einmal jede Menge Gruppenadressen definiert (auch wenn davon erst einmal nur ein kleiner Teil benutzt wird
Diese Gruppenadressen werden dann einfach mit den entsprechenden Bedienelementen im InfoTerminal Touch (oder irgendeinem Schalter, etc.) verknüpft.
Hauptproblem beim ITT ist, das je Seite nur 16 Bedienelemente möglich sind, daher muß man sich genau überlegen welche Funktionen man häufig braucht -- alles andere muß ggf. auf weitere Seiten verteilt werden.
Ich habe erst mal drei Seiten für die Steuerung meiner Sonos Boxen spendiert, eine für die Bedienung des ausgewählten Raumes (bzw. Zone), eine zur Auswahl des zu steuernden Raumes (oder Zone) und eine zum Zusammenstellen von Zonen.
Die Seite zur Steuerung mit ihren 16 Bedienelementen ist im Anhang dargestellt, ich habe einfach das fertige Layout als Hintergrundgrafik eingeladen und die Bedienelemente als transparente Elemente ohne Rahmen darüber gelegt (angedeutet mit den grau gestrichelten Boxen).
Die meisten Elemente sind einfache Bedienelemente, nur (14) und (16) sind anders.
(16) zeigt als kombiniertes Anzeige- und Bedienelement den ausgewählten Raum an und beim Drücken wird die Auswahl-Seite angezeigt. (11) ist also eigentlich überflüssig und wird wohl auch noch zugunsten einer Anzeigebox mit dem aktuellen Song/Radiosender entfallen.
(14) kann als Betriebsmodusumschaltung vier Funktionen durch-toggeln (Normal, Repeat, Shuffle, Shuffle Repeat).
Im Perl-Sript für Misterhouse dann ein paar Vorbelegungen der Art:
und dann die mit den jeweiligen Gruppenadressen verknüpften Aktion wie z.B.:
Die Aktionen rufen dann also Unterprogramme für die einzelnen Funktionen auf, denen die Nummer des zu steuernden Players und ggf. weitere benötigte Werte (im Fall der Lautstärkeänderung der Wert für die Lautstärke, der zu spielende Radiosender, etc.) übergeben wird.
In den einzelnen Unterprogrammen wird dann nur der zu sendende String zusammengebaut und per IO::Socket::INET ins LAN gesendet.
Das sieht dann z.B. so aus:
Alle Klarheiten beseitigt?
Man benötigt:
a) Mindestens einen Sonos Player
b) Misterhouse
c) ein InfoTerminal Touch oder sonst welche Schalter die mit dem EIB/KNX Bus kommunizieren
Ich habe erst einmal jede Menge Gruppenadressen definiert (auch wenn davon erst einmal nur ein kleiner Teil benutzt wird

Code:
EIB1, 7/0/0, Sonos_AlleAus, gSonos|gSonos_Command, EIB1, 7/0/1, Sonos_Play, gSonos|gSonos_Command, EIB1, 7/0/2, Sonos_Stop, gSonos|gSonos_Command, EIB1, 7/0/3, Sonos_Rewind, gSonos|gSonos_Command, EIB1, 7/0/4, Sonos_Forward, gSonos|gSonos_Command, EIB1, 7/0/5, Sonos_Lauter, gSonos|gSonos_Command, EIB1, 7/0/6, Sonos_Leiser, gSonos|gSonos_Command, EIB1, 7/0/7, Sonos_Mute, gSonos|gSonos_Command, EIB1, 7/0/40, Sonos_Modeumschaltung, gSonos|gSonos_Command, EIB1, 7/0/41, Sonos_NormalMode, gSonos|gSonos_Command, EIB1, 7/0/42, Sonos_Repeat, gSonos|gSonos_Command, EIB1, 7/0/43, Sonos_Shuffle, gSonos|gSonos_Command, EIB1, 7/0/44, Sonos_ShuffleRepeat, gSonos|gSonos_Command, EIB1, 7/0/61, Sonos_Radio1, gSonos|gSonos_Source, EIB1, 7/0/62, Sonos_Radio2, gSonos|gSonos_Source, EIB1, 7/0/63, Sonos_Radio3, gSonos|gSonos_Source, EIB1, 7/0/64, Sonos_Radio4, gSonos|gSonos_Source, EIB1, 7/0/71, Sonos_Playlist1, gSonos|gSonos_Source, EIB1, 7/0/72, Sonos_Playlist2, gSonos|gSonos_Source, EIB1, 7/0/73, Sonos_Playlist3, gSonos|gSonos_Source, EIB1, 7/0/74, Sonos_Playlist4, gSonos|gSonos_Source, EIB1, 7/0/81, Sonos_Extern1, gSonos|gSonos_Source, EIB1, 7/0/82, Sonos_Extern2, gSonos|gSonos_Source, EIB1, 7/0/83, Sonos_Extern3, gSonos|gSonos_Source, EIB1, 7/0/84, Sonos_Extern4, gSonos|gSonos_Source, EIB1, 7/0/91, Sonos_Zone1, gSonos|gSonos_Player, EIB1, 7/0/92, Sonos_Zone2, gSonos|gSonos_Player, EIB1, 7/0/93, Sonos_Zone3, gSonos|gSonos_Player, EIB1, 7/0/94, Sonos_Zone4, gSonos|gSonos_Player, EIB1, 7/0/96, Sonos_Zone1trennen, gSonos|gSonos_Zone1, EIB1, 7/0/97, Sonos_Zone2trennen, gSonos|gSonos_Zone2, EIB1, 7/0/98, Sonos_Zone3trennen, gSonos|gSonos_Zone3, EIB1, 7/0/99, Sonos_Zone4trennen, gSonos|gSonos_Zone4, EIB15, 7/0/100, Sonos_Playername, gSonos, EIB1, 7/0/101, Sonos_Player1, gSonos|gSonos_Player, EIB1, 7/0/102, Sonos_Player2, gSonos|gSonos_Player, EIB1, 7/0/103, Sonos_Player3, gSonos|gSonos_Player, EIB1, 7/0/104, Sonos_Player4, gSonos|gSonos_Player, EIB1, 7/0/105, Sonos_Player5, gSonos|gSonos_Player, EIB1, 7/0/106, Sonos_Player6, gSonos|gSonos_Player, EIB1, 7/0/107, Sonos_Player7, gSonos|gSonos_Player, EIB1, 7/0/108, Sonos_Player8, gSonos|gSonos_Player, EIB1, 7/0/109, Sonos_Player9, gSonos|gSonos_Player, EIB1, 7/0/111, Sonos_Zone1Player1, gSonos|gSonos_Zone1, EIB1, 7/0/112, Sonos_Zone1Player2, gSonos|gSonos_Zone1, EIB1, 7/0/113, Sonos_Zone1Player3, gSonos|gSonos_Zone1, EIB1, 7/0/114, Sonos_Zone1Player4, gSonos|gSonos_Zone1, EIB1, 7/0/115, Sonos_Zone1Player5, gSonos|gSonos_Zone1, EIB1, 7/0/116, Sonos_Zone1Player6, gSonos|gSonos_Zone1, EIB1, 7/0/117, Sonos_Zone1Player7, gSonos|gSonos_Zone1, EIB1, 7/0/118, Sonos_Zone1Player8, gSonos|gSonos_Zone1, EIB1, 7/0/119, Sonos_Zone1Player9, gSonos|gSonos_Zone1, usw.
Hauptproblem beim ITT ist, das je Seite nur 16 Bedienelemente möglich sind, daher muß man sich genau überlegen welche Funktionen man häufig braucht -- alles andere muß ggf. auf weitere Seiten verteilt werden.
Ich habe erst mal drei Seiten für die Steuerung meiner Sonos Boxen spendiert, eine für die Bedienung des ausgewählten Raumes (bzw. Zone), eine zur Auswahl des zu steuernden Raumes (oder Zone) und eine zum Zusammenstellen von Zonen.
Die Seite zur Steuerung mit ihren 16 Bedienelementen ist im Anhang dargestellt, ich habe einfach das fertige Layout als Hintergrundgrafik eingeladen und die Bedienelemente als transparente Elemente ohne Rahmen darüber gelegt (angedeutet mit den grau gestrichelten Boxen).
Die meisten Elemente sind einfache Bedienelemente, nur (14) und (16) sind anders.
(16) zeigt als kombiniertes Anzeige- und Bedienelement den ausgewählten Raum an und beim Drücken wird die Auswahl-Seite angezeigt. (11) ist also eigentlich überflüssig und wird wohl auch noch zugunsten einer Anzeigebox mit dem aktuellen Song/Radiosender entfallen.
(14) kann als Betriebsmodusumschaltung vier Funktionen durch-toggeln (Normal, Repeat, Shuffle, Shuffle Repeat).
Im Perl-Sript für Misterhouse dann ein paar Vorbelegungen der Art:
Code:
$SonosZoneIP[0] = "192.168.0.101"; # Wohnzimmer $SonosZoneIP[1] = "192.168.0.102"; # Kueche $SonosZoneIP[2] = "192.168.0.103"; # Garten $SonosZoneIP[3] = "192.168.0.104"; # Schlafzimmer $SonosZoneIP[4] = "192.168.0.105"; # Bad $SonosPlayername[0] = "Wohnen"; $SonosPlayername[1] = "Kueche"; $SonosPlayername[2] = "Garten"; $SonosPlayername[3] = "Schlafen"; $SonosPlayername[4] = "Bad"; $SonosExternalInputDevice[0] = "RINCON_000E5123456001400"; $SonosExternalInputTitle[0] = "Satellitenempfänger"; #Radio Wuppertal 107.4 $SonosRadioStation[0] = "x-rincon-mp3radio://www.vtuner.com/vtunerweb/asp/StatLaunchMP3.asp?id=21906&link=1"; $SonosRadioStationID[0] = 27; $SonosRadioStationName[0] = "Radio Wuppertal 107.4"; #WDR 1 Live 103.7 (Top 40 Popmusik) $SonosRadioStation[1] = "x-sonosapi-stream:s100198?sid=254"; $SonosRadioStationID[1] = 2; $SonosRadioStationName[1] = "WDR 1 Live 103.7 (Top 40 Popmusik)"; #Playlist Top 10 $SonosPlaylist[0] = "/mnt/Music/Top10";
Code:
if (state_now $Sonos_AlleAus) { for($i=1;$i<$iAnzPlayer+1;$i++){ Sonos_Pause($i-1); } } if (state_now $Sonos_Radio1) { Sonos_Radio($SonosPlayerNR, 0); } if (state_now $Sonos_Radio2) { Sonos_Radio($SonosPlayerNR, 1); } if (state_now $Sonos_Playlist1) { Sonos_ClearQueue($SonosPlayerNR); Sonos_SetQueue($SonosPlayerNR, 0); @SonosFileList = <$SonosPlaylist[0]/*.mp3>; $i=0; foreach $SonosFileName (@SonosFileList) { $i=$i+1; my $SonosFileName2 = "x-file-cifs://QNAP239-1/Music/Top10".substr($SonosFileName,length($SonosPlaylist[0])); Sonos_AddToQueue($SonosPlayerNR, $SonosFileName2); if($i==1) { Sonos_Play($SonosPlayerNR); } } } if (state_now $Sonos_Rewind) { Sonos_Rewind($SonosPlayerNR); } if (state_now $Sonos_Play) { Sonos_Play($SonosPlayerNR); } if (state_now $Sonos_Stop) { Sonos_Pause($SonosPlayerNR); } if (state_now $Sonos_Forward) { Sonos_Next($SonosPlayerNR); } if (state_now $Sonos_Modeumschaltung) { $SonosModeNR += 1; if($SonosModeNR==1) { set $Sonos_NormalMode OFF; set $Sonos_Repeat ON; } elsif($SonosModeNR==2) { set $Sonos_Repeat OFF; set $Sonos_Shuffle ON; } elsif($SonosModeNR==3) { set $Sonos_Shuffle OFF; set $Sonos_ShuffleRepeat ON; } else { $SonosModeNR = 0; set $Sonos_ShuffleRepeat OFF; set $Sonos_NormalMode ON; } Sonos_PlayMode($SonosPlayerNR, $SonosMode[$SonosModeNR]); } if (state_now $Sonos_Lauter) { for($i=1;$i<6;$i++){ Sonos_Volume($SonosPlayerNR, $SonosVolume+$i); select(undef, undef, undef, 0.4); # sleep 0.4s between every step } $SonosVolume += $i }
In den einzelnen Unterprogrammen wird dann nur der zu sendende String zusammengebaut und per IO::Socket::INET ins LAN gesendet.
Das sieht dann z.B. so aus:
Code:
sub Sonos_Volume { my ($_player,$_volume) = @_; my $_SonosIP =$SonosZoneIP[$_player]; my $_StringLength = 321+length($_volume); my $_Sonos_content='POST /MediaRenderer/RenderingControl/Control HTTP/1.1 CONNECTION: close ACCEPT-ENCODING: gzip HOST: '.$_SonosIP.':1400 CONTENT-LENGTH: '.$_StringLength.' CONTENT-TYPE: text/xml; charset="utf-8" SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#SetVolume" <s:Envelope xmlns:s="[URL]http://schemas.xmlsoap.org/soap/envelope/[/URL]" s:encodingStyle="[URL]http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetVolume[/URL] xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>'.$_volume.'</DesiredVolume></u:SetVolume></s:Body></s:Envelope>'; my $Sonos_socket = new IO::Socket::INET (PeerAddr => $_SonosIP, PeerPort => $SonosPort, Proto => 'tcp',); die "ERROR: Unable to connect to Sonos Player $_SonosIP $!\n" unless $Sonos_socket; print $Sonos_socket $_Sonos_content; close($Sonos_socket); } sub Sonos_Radio { my ($_player,$_station) = @_; my $_SonosIP =$SonosZoneIP[$_player]; my $_SonosRadioStation = encode_entities($SonosRadioStation[$_station]); my $_SonosRadioStationID = $SonosRadioStationID[$_station]; my $_SonosRadioStationName = encode_entities($SonosRadioStationName[$_station]); my $_StringLength = 958+length($_SonosRadioStation)+length($_SonosRadioStationID)+length($_SonosRadioStationName); my $_Sonos_content='POST /MediaRenderer/AVTransport/Control HTTP/1.1 CONNECTION: close HOST: '.$_SonosIP.':1400 CONTENT-LENGTH: '.$_StringLength.' CONTENT-TYPE: text/xml; charset="utf-8" SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI" <s:Envelope xmlns:s="[URL]http://schemas.xmlsoap.org/soap/envelope/[/URL]" s:encodingStyle="[URL]http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetAVTransportURI[/URL] xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><CurrentURI>'.$_SonosRadioStation.'</CurrentURI><CurrentURIMetaData><DIDL-Lite xmlns:dc="[URL]http://purl.org/dc/elements/1.1/"[/URL] xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item id="R:0/0/'.$_SonosRadioStationID.'" parentID="R:0/0" restricted="true"><dc:title>'.$_SonosRadioStationName.'</dc:title><upnp:class>object.item.audioItem.audioBroadcast</upnp:class><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">SA_RINCON65031_</desc></item></DIDL-Lite></CurrentURIMetaData></u:SetAVTransportURI></s:Body></s:Envelope>'; my $Sonos_socket = new IO::Socket::INET (PeerAddr => $_SonosIP, PeerPort => $SonosPort, Proto => 'tcp',); die "ERROR: Unable to connect to Sonos Player $_SonosIP $!\n" unless $Sonos_socket; print $Sonos_socket $_Sonos_content; close($Sonos_socket); Sonos_Play($_player); } sub Sonos_ClearQueue { my ($_player) = @_; my $_SonosIP =$SonosZoneIP[$_player]; my $_Sonos_content='POST /MediaRenderer/AVTransport/Control HTTP/1.1 CONNECTION: close HOST: '.$_SonosIP.':1400 CONTENT-LENGTH: 290 CONTENT-TYPE: text/xml; charset="utf-8" SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#RemoveAllTracksFromQueue" <s:Envelope xmlns:s="[URL]http://schemas.xmlsoap.org/soap/envelope/[/URL]" s:encodingStyle="[URL]http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:RemoveAllTracksFromQueue[/URL] xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:RemoveAllTracksFromQueue></s:Body></s:Envelope>'; my $Sonos_socket = new IO::Socket::INET (PeerAddr => $_SonosIP, PeerPort => $SonosPort, Proto => 'tcp',); die "ERROR: Unable to connect to Sonos Player $_SonosIP $!\n" unless $Sonos_socket; print $Sonos_socket $_Sonos_content; close($Sonos_socket); } sub Sonos_AddToQueue { my ($_player,$_file) = @_; my $_SonosIP =$SonosZoneIP[$_player]; my $_SonosFileName = encode_entities($_file); my $_StringLength = 438+length($_SonosFileName); my $_Sonos_content='POST /MediaRenderer/AVTransport/Control HTTP/1.1 CONNECTION: close HOST: '.$_SonosIP.':1400 CONTENT-LENGTH: '.$_StringLength.' CONTENT-TYPE: text/xml; charset="utf-8" SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#AddURIToQueue" <s:Envelope xmlns:s="[URL]http://schemas.xmlsoap.org/soap/envelope/[/URL]" s:encodingStyle="[URL]http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:AddURIToQueue[/URL] xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><EnqueuedURI>'.$_SonosFileName.'</EnqueuedURI><EnqueuedURIMetaData></EnqueuedURIMetaData><DesiredFirstTrackNumberEnqueued>0</DesiredFirstTrackNumberEnqueued><EnqueueAsNext>1</EnqueueAsNext></u:AddURIToQueue></s:Body></s:Envelope>'; my $Sonos_socket = new IO::Socket::INET (PeerAddr => $_SonosIP, PeerPort => $SonosPort, Proto => 'tcp',); die "ERROR: Unable to connect to Sonos Player $_SonosIP $!\n" unless $Sonos_socket; print $Sonos_socket $_Sonos_content; close($Sonos_socket); }
Kommentar