mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 16:59:18 +00:00
SONOS: New features ismaster, masterplayer and slaveplayer at sonosplayer-device
git-svn-id: https://svn.fhem.de/fhem/trunk@10737 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
c788d862fa
commit
f5913921d7
@ -1,6 +1,6 @@
|
||||
########################################################################################
|
||||
#
|
||||
# SONOS.pm (c) by Reiner Leins, January 2016
|
||||
# SONOS.pm (c) by Reiner Leins, February 2016
|
||||
# rleins at lmsoft dot de
|
||||
#
|
||||
# $Id$
|
||||
@ -53,6 +53,11 @@
|
||||
# Cover von Amazon funktionieren nicht
|
||||
#
|
||||
# SVN-History:
|
||||
# 06.02.2016
|
||||
# Zusätzlich zu "Mute" (mit Parameter) am Sonos-Device gibt es jetzt auch "MuteOn" und "MuteOff" (jeweils ohne Parameter) zur Verwendung als WebCmd.
|
||||
# Es gibt ein neues Reading "IsMaster" am Sonosplayer-Device, welches angibt, ob der Player gerade ein Masterplayer ist
|
||||
# Es gibt ein neues Reading "MasterPlayer" am Sonosplayer-Device, welches angibt, wie der aktuelle MasterPlayer zu diesem Player heißt. Ist der Player selber der Master (also IsMaster = 1), so steht dort der eigene Name drin.
|
||||
# Es gibt ein neues Reading "SlavePlayer" am Sonosplayer-Device, welches angibt, welche Slaveplayer zu diesem Player zugeordnet sind. Enthält nur Playerdevicenamen, wenn dieser Player ein Masterplayer ist, und dann auch nicht sich selber.
|
||||
# 31.01.2016
|
||||
# Im Modul ControlPoint.pm gab es eine fehlerhafte Bearbeitung des Arrays @LWP::Protocol::http::EXTRA_SOCK_OPTS, welche in manchen Fällen zu der Fehlermeldung "Odd number of elements in hash assignment" geführt hat.
|
||||
# Der Anbieter SoundCloud wird als Quelle erkannt und angezeigt
|
||||
@ -202,6 +207,8 @@ my %sets = (
|
||||
'PauseAll' => '',
|
||||
'Pause' => '',
|
||||
'Mute' => 'state',
|
||||
'MuteOn' => '',
|
||||
'MuteOff' => '',
|
||||
'RescanNetwork' => '',
|
||||
'LoadBookmarks' => '[Groupname]',
|
||||
'SaveBookmarks' => '[GroupName]',
|
||||
@ -1896,7 +1903,7 @@ sub SONOS_Set($@) {
|
||||
$key = $key.':slider,0,1,100' if (lc($key) eq 'volume');
|
||||
$key = $key.':slider,-100,1,100' if (lc($key) eq 'balance');
|
||||
|
||||
$key = $key.':0,1' if ($key =~ m/mute(all|)/i);
|
||||
$key = $key.':0,1' if ($key =~ m/^mute(all|)$/i);
|
||||
|
||||
$setcopy{$key} = $sets{$oldkey};
|
||||
}
|
||||
@ -2027,26 +2034,19 @@ sub SONOS_Set($@) {
|
||||
#}
|
||||
#SONOS_Log undef, 5, "Current after List: ".Dumper(\@current);
|
||||
|
||||
} elsif (lc($key) =~ m/(Stop|Pause|Mute)(All|)/i) {
|
||||
} elsif (lc($key) =~ m/^(Stop|Pause|Mute|MuteOn|MuteOff)(All|)$/i) {
|
||||
my $commandType = lc($1);
|
||||
my $commandValue = $value;
|
||||
|
||||
$commandValue = 0 if ($commandType ne 'mute');
|
||||
$commandType = 'setGroupMute' if ($commandType eq 'mute');
|
||||
$commandValue = 1 if ($commandType eq 'muteon');
|
||||
$commandValue = 0 if ($commandType eq 'muteoff');
|
||||
|
||||
# Aktuellen Zustand holen
|
||||
my @current;
|
||||
my $current = SONOS_Get($hash, qw($hash->{NAME} Groups));
|
||||
$current =~ s/ //g;
|
||||
while ($current =~ m/(\[.*?\])/ig) {
|
||||
my @tmp = split(/,/, substr($1, 1, -1));
|
||||
push @current, \@tmp;
|
||||
}
|
||||
$commandType = 'setGroupMute' if (($commandType eq 'mute') || ($commandType eq 'muteon') || ($commandType eq 'muteoff'));
|
||||
|
||||
# Alle Gruppenkoordinatoren zum Stoppen/Pausieren/Muten aufrufen
|
||||
foreach my $cElem (@current) {
|
||||
my @currentElem = @{$cElem};
|
||||
SONOS_DoWork(SONOS_getDeviceDefHash($currentElem[0])->{UDN}, $commandType, $commandValue);
|
||||
foreach my $cElem (@{eval(ReadingsVal($hash->{NAME}, 'MasterPlayer', '[]'))}) {
|
||||
SONOS_DoWork(SONOS_getDeviceDefHash($cElem)->{UDN}, $commandType, $commandValue);
|
||||
}
|
||||
} elsif (lc($key) eq 'rescannetwork') {
|
||||
SONOS_DoWork('SONOS', 'rescanNetwork');
|
||||
@ -2394,7 +2394,7 @@ sub SONOS_Discover() {
|
||||
}
|
||||
|
||||
# Notwendige Daten vom Player ermitteln...
|
||||
my ($isZoneBridge, $topoType, $fieldType, $master, $aliasSuffix) = SONOS_AnalyzeZoneGroupTopology($udn, $udnShort);
|
||||
my ($isZoneBridge, $topoType, $fieldType, $master, $masterPlayerName, $aliasSuffix, $zoneGroupState) = SONOS_AnalyzeZoneGroupTopology($udn, $udnShort);
|
||||
|
||||
my $roomName = $SONOS_DevicePropertiesProxy{$udn}->GetZoneAttributes()->getValue('CurrentZoneName');
|
||||
|
||||
@ -5212,7 +5212,8 @@ sub SONOS_Discover_Callback($$$) {
|
||||
SONOS_Log undef, 4, 'ControlProxies wurden gesichert';
|
||||
|
||||
# ZoneTopology laden, um die Benennung der Fhem-Devices besser an die Realität anpassen zu können
|
||||
my ($isZoneBridge, $topoType, $fieldType, $master, $aliasSuffix) = SONOS_AnalyzeZoneGroupTopology($udn, $udnShort);
|
||||
my ($isZoneBridge, $topoType, $fieldType, $master, $masterPlayerName, $aliasSuffix, $zoneGroupState) = SONOS_AnalyzeZoneGroupTopology($udn, $udnShort);
|
||||
my @slavePlayerNames = SONOS_AnalyzeTopologyForSlavePlayer($udnShort, $zoneGroupState);
|
||||
|
||||
# Wenn der aktuelle Player der Master ist, dann kein Kürzel anhängen,
|
||||
# damit gibt es immer einen Player, der den Raumnamen trägt, und die anderen enthalten Kürzel
|
||||
@ -5330,6 +5331,11 @@ sub SONOS_Discover_Callback($$$) {
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'softwareRevision', $displayVersion);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'serialNum', $serialNum);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'fieldType', $fieldType);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'IsMaster', $master ? '1' : '0');
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'MasterPlayer', $masterPlayerName);
|
||||
$Data::Dumper::Indent = 0;
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'SlavePlayer', Dumper(\@slavePlayerNames));
|
||||
$Data::Dumper::Indent = 2;
|
||||
|
||||
# Abspielreadings vorab ermitteln, um darauf prüfen zu können...
|
||||
if (!$isZoneBridge) {
|
||||
@ -5578,15 +5584,19 @@ sub SONOS_AnalyzeZoneGroupTopology($$) {
|
||||
my $topoType = '';
|
||||
my $fieldType = '';
|
||||
my $master = 1;
|
||||
my $masterPlayerName;
|
||||
my $isZoneBridge = 0;
|
||||
my $zoneGroupState = '';
|
||||
if ($SONOS_ZoneGroupTopologyProxy{$udn}) {
|
||||
my $zoneGroupState = $SONOS_ZoneGroupTopologyProxy{$udn}->GetZoneGroupState()->getValue('ZoneGroupState');
|
||||
$zoneGroupState = $SONOS_ZoneGroupTopologyProxy{$udn}->GetZoneGroupState()->getValue('ZoneGroupState');
|
||||
SONOS_Log undef, 5, 'ZoneGroupState: '.$zoneGroupState;
|
||||
|
||||
if ($zoneGroupState =~ m/.*(<ZoneGroup Coordinator="(RINCON_[0-9a-f]+)".*?>).*?(<(ZoneGroupMember|Satellite) UUID="$udnShort".*?(>|\/>))/is) {
|
||||
my $coordinator = $2;
|
||||
my $member = $3;
|
||||
|
||||
$masterPlayerName = SONOS_Client_Data_Retreive($coordinator.'_MR', 'def', 'NAME', $coordinator.'_MR');
|
||||
|
||||
# Ist dieser Player in einem ChannelMapSet (also einer Paarung) enthalten?
|
||||
if ($member =~ m/ChannelMapSet=".*?$udnShort:(.*?),(.*?)[;"]/is) {
|
||||
$topoType = '_'.$1;
|
||||
@ -5619,7 +5629,7 @@ sub SONOS_AnalyzeZoneGroupTopology($$) {
|
||||
$aliasSuffix = ' - Subwoofer' if ($topoType eq '_SW');
|
||||
$aliasSuffix = ' - Mitte' if ($topoType eq '_LF_RF');
|
||||
|
||||
return ($isZoneBridge, $topoType, $fieldType, $master, $aliasSuffix);
|
||||
return ($isZoneBridge, $topoType, $fieldType, $master, $masterPlayerName, $aliasSuffix, $zoneGroupState);
|
||||
}
|
||||
|
||||
########################################################################################
|
||||
@ -7307,11 +7317,13 @@ sub SONOS_ZoneGroupTopologyCallback($$) {
|
||||
SONOS_AnalyzeTopologyForMasterPlayer($zoneGroupState);
|
||||
}
|
||||
|
||||
SONOS_Client_Notifier('ReadingsBeginUpdate:'.$udn);
|
||||
|
||||
# ZonePlayerUUIDsInGroup: Welche Player befinden sich alle in der gleichen Gruppe wie ich?
|
||||
my $zonePlayerUUIDsInGroup = SONOS_Client_Data_Retreive($udn, 'reading', 'ZonePlayerUUIDsInGroup', '');
|
||||
if ($properties{ZonePlayerUUIDsInGroup}) {
|
||||
$zonePlayerUUIDsInGroup = $properties{ZonePlayerUUIDsInGroup};
|
||||
SONOS_Client_Data_Refresh('ReadingsSingleUpdateIfChanged', $udn, 'ZonePlayerUUIDsInGroup', $zonePlayerUUIDsInGroup);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'ZonePlayerUUIDsInGroup', $zonePlayerUUIDsInGroup);
|
||||
}
|
||||
|
||||
# ZoneGroupID: Welcher Gruppe gehöre ich aktuell an, und hat sich meine Aufgabe innerhalb der Gruppe verändert?
|
||||
@ -7321,6 +7333,10 @@ sub SONOS_ZoneGroupTopologyCallback($$) {
|
||||
$zoneGroupID = $2;
|
||||
my $member = $3;
|
||||
|
||||
my $master = ($zoneGroupID eq $udnShort);
|
||||
my $masterPlayerName = SONOS_Client_Data_Retreive($zoneGroupID.'_MR', 'def', 'NAME', $zoneGroupID.'_MR');
|
||||
my @slavePlayerNames = SONOS_AnalyzeTopologyForSlavePlayer($udnShort, $zoneGroupState);
|
||||
|
||||
$zoneGroupID .= ':__' if ($zoneGroupID !~ m/:/);
|
||||
|
||||
my $topoType = '';
|
||||
@ -7352,19 +7368,26 @@ sub SONOS_ZoneGroupTopologyCallback($$) {
|
||||
$aliasSuffix = ' - Mitte' if ($topoType eq '_LF_RF');
|
||||
|
||||
my $roomName = SONOS_Client_Data_Retreive($udn, 'reading', 'roomName', '');
|
||||
SONOS_Client_Data_Refresh('ReadingsSingleUpdateIfChanged', $udn, 'roomNameAlias', $roomName.$aliasSuffix);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'roomNameAlias', $roomName.$aliasSuffix);
|
||||
|
||||
SONOS_Client_Data_Refresh('ReadingsSingleUpdateIfChanged', $udn, 'ZoneGroupID', $zoneGroupID);
|
||||
SONOS_Client_Data_Refresh('ReadingsSingleUpdateIfChanged', $udn, 'fieldType', $fieldType);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'ZoneGroupID', $zoneGroupID);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'fieldType', $fieldType);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'IsMaster', $master ? '1' : '0');
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'MasterPlayer', $masterPlayerName);
|
||||
$Data::Dumper::Indent = 0;
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'SlavePlayer', Dumper(\@slavePlayerNames));
|
||||
$Data::Dumper::Indent = 2;
|
||||
}
|
||||
|
||||
# ZoneGroupName: Welchen Namen hat die aktuelle Gruppe?
|
||||
my $zoneGroupName = SONOS_Client_Data_Retreive($udn, 'reading', 'ZoneGroupName', '');
|
||||
if ($properties{ZoneGroupName}) {
|
||||
$zoneGroupName = $properties{ZoneGroupName};
|
||||
SONOS_Client_Data_Refresh('ReadingsSingleUpdateIfChanged', $udn, 'ZoneGroupName', $zoneGroupName);
|
||||
SONOS_Client_Data_Refresh('ReadingsBulkUpdateIfChanged', $udn, 'ZoneGroupName', $zoneGroupName);
|
||||
}
|
||||
|
||||
SONOS_Client_Notifier('ReadingsEndUpdate:'.$udn);
|
||||
|
||||
$SONOS_Client_SendQueue_Suspend = 0;
|
||||
SONOS_Log $udn, 3, 'Event: End of ZoneGroupTopology-Event for Zone "'.$name.'".';
|
||||
|
||||
@ -7378,6 +7401,30 @@ sub SONOS_ZoneGroupTopologyCallback($$) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
########################################################################################
|
||||
#
|
||||
# SONOS_AnalyzeTopologyForSlavePlayer - Topology analysieren, um die Slaveplayer zu
|
||||
# einem Masterplayer zu ermitteln
|
||||
#
|
||||
########################################################################################
|
||||
sub SONOS_AnalyzeTopologyForSlavePlayer($$) {
|
||||
my ($masterUDNShort, $zoneGroupState) = @_;
|
||||
|
||||
my @slavePlayer = ();
|
||||
while ($zoneGroupState =~ m/<ZoneGroup.*?Coordinator="(.*?)".*?>(.*?)<\/ZoneGroup>/gi) {
|
||||
next if ($1 ne $masterUDNShort);
|
||||
|
||||
my $member = $2;
|
||||
while ($member =~ m/<ZoneGroupMember.*?UUID="(.*?)".*?\/>/gi) {
|
||||
next if ($1 eq $masterUDNShort); # Den Master selbst nicht in die Slaveliste reinpacken...
|
||||
|
||||
push @slavePlayer, SONOS_Client_Data_Retreive($1.'_MR', 'def', 'NAME', $1.'_MR');
|
||||
}
|
||||
}
|
||||
|
||||
return sort @slavePlayer;
|
||||
}
|
||||
|
||||
########################################################################################
|
||||
#
|
||||
# SONOS_AnalyzeTopologyForMasterPlayer - Topology analysieren, um das Reading "MasterPlayer"
|
||||
|
@ -1,6 +1,6 @@
|
||||
########################################################################################
|
||||
#
|
||||
# SONOSPLAYER.pm (c) by Reiner Leins, January 2016
|
||||
# SONOSPLAYER.pm (c) by Reiner Leins, February 2016
|
||||
# rleins at lmsoft dot de
|
||||
#
|
||||
# $Id$
|
||||
|
Loading…
x
Reference in New Issue
Block a user