Sonos: New Features and bugfixes. See Changelog.
git-svn-id: https://svn.fhem.de/fhem/trunk@14279 2b470e98-0d58-463d-a4d8-8e2adae1ed80
@ -1,6 +1,6 @@
|
|||||||
########################################################################################
|
########################################################################################
|
||||||
#
|
#
|
||||||
# SONOSPLAYER.pm (c) by Reiner Leins, April 2017
|
# SONOSPLAYER.pm (c) by Reiner Leins, Mai 2017
|
||||||
# rleins at lmsoft dot de
|
# rleins at lmsoft dot de
|
||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
@ -58,6 +58,13 @@ sub Log($$);
|
|||||||
sub Log3($$$);
|
sub Log3($$$);
|
||||||
sub SONOSPLAYER_Log($$$);
|
sub SONOSPLAYER_Log($$$);
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Standards aus FHEM einbinden
|
||||||
|
########################################################
|
||||||
|
use vars qw{%modules %defs};
|
||||||
|
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
# Variable Definitions
|
# Variable Definitions
|
||||||
########################################################################################
|
########################################################################################
|
||||||
@ -99,6 +106,8 @@ my %sets = (
|
|||||||
'StartRadio' => 'radioname',
|
'StartRadio' => 'radioname',
|
||||||
'PlayURI' => 'songURI [Volume]',
|
'PlayURI' => 'songURI [Volume]',
|
||||||
'PlayURITemp' => 'songURI [Volume]',
|
'PlayURITemp' => 'songURI [Volume]',
|
||||||
|
'LoadHandle' => 'Handle',
|
||||||
|
'StartHandle' => 'Handle',
|
||||||
'AddURIToQueue' => 'songURI',
|
'AddURIToQueue' => 'songURI',
|
||||||
'Speak' => 'volume(0..100) language text',
|
'Speak' => 'volume(0..100) language text',
|
||||||
'OutputFixed' => 'state',
|
'OutputFixed' => 'state',
|
||||||
@ -178,8 +187,13 @@ sub SONOSPLAYER_Initialize ($) {
|
|||||||
$hash->{SetFn} = "SONOSPLAYER_Set";
|
$hash->{SetFn} = "SONOSPLAYER_Set";
|
||||||
$hash->{StateFn} = "SONOSPLAYER_State";
|
$hash->{StateFn} = "SONOSPLAYER_State";
|
||||||
$hash->{AttrFn} = 'SONOSPLAYER_Attribute';
|
$hash->{AttrFn} = 'SONOSPLAYER_Attribute';
|
||||||
|
$hash->{NotifyFn} = 'SONOSPLAYER_Notify';
|
||||||
|
|
||||||
$hash->{AttrList} = "disable:1,0 generateVolumeSlider:1,0 generateVolumeEvent:1,0 generateSomethingChangedEvent:1,0 generateInfoSummarize1 generateInfoSummarize2 generateInfoSummarize3 generateInfoSummarize4 stateVariable:TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,TrackProvider,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackProvider,nextTrackURI,nextAlbumArtURI,nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,OutputFixed,Shuffle,Repeat,CrossfadeMode,Balance,HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,InfoSummarize2,InfoSummarize3,InfoSummarize4 model minVolume maxVolume minVolumeHeadphone maxVolumeHeadphone VolumeStep getAlarms:1,0 buttonEvents getTitleInfoFromMaster:1,0 stopSleeptimerInAction:1,0 saveSleeptimerInAction:1,0 ".$readingFnAttributes;
|
$hash->{FW_detailFn} = 'SONOSPLAYER_Detail';
|
||||||
|
$hash->{FW_deviceOverview} = 1;
|
||||||
|
#$hash->{FW_addDetailToSummary} = 1;
|
||||||
|
|
||||||
|
$hash->{AttrList} = "disable:1,0 generateVolumeSlider:1,0 generateVolumeEvent:1,0 generateSomethingChangedEvent:1,0 generateInfoSummarize1 generateInfoSummarize2 generateInfoSummarize3 generateInfoSummarize4 stateVariable:TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,TrackProvider,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackProvider,nextTrackURI,nextAlbumArtURI,nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,OutputFixed,Shuffle,Repeat,CrossfadeMode,Balance,HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,InfoSummarize2,InfoSummarize3,InfoSummarize4 model minVolume maxVolume minVolumeHeadphone maxVolumeHeadphone VolumeStep getAlarms:1,0 buttonEvents getTitleInfoFromMaster:1,0 stopSleeptimerInAction:1,0 saveSleeptimerInAction:1,0 simulateCurrentTrackPosition:0,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60 simulateCurrentTrackPositionPercentFormat suppressControlButtons:1,0 ".$readingFnAttributes;
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -194,8 +208,6 @@ sub SONOSPLAYER_Initialize ($) {
|
|||||||
sub SONOSPLAYER_Define ($$) {
|
sub SONOSPLAYER_Define ($$) {
|
||||||
my ($hash, $def) = @_;
|
my ($hash, $def) = @_;
|
||||||
|
|
||||||
# $hash->{NotifyFn} = 'SONOSPLAYER_Notify';
|
|
||||||
|
|
||||||
# define <name> SONOSPLAYER <udn>
|
# define <name> SONOSPLAYER <udn>
|
||||||
# e.g.: define Sonos_Wohnzimmer SONOSPLAYER RINCON_000EFEFEFEF401400
|
# e.g.: define Sonos_Wohnzimmer SONOSPLAYER RINCON_000EFEFEFEF401400
|
||||||
my @a = split("[ \t]+", $def);
|
my @a = split("[ \t]+", $def);
|
||||||
@ -209,15 +221,66 @@ sub SONOSPLAYER_Define ($$) {
|
|||||||
# check syntax
|
# check syntax
|
||||||
return "SONOSPLAYER: Wrong syntax, must be define <name> SONOSPLAYER <udn>" if(int(@a) < 3);
|
return "SONOSPLAYER: Wrong syntax, must be define <name> SONOSPLAYER <udn>" if(int(@a) < 3);
|
||||||
|
|
||||||
|
$hash->{NOTIFYDEV} = $name;
|
||||||
|
$hash->{helper}->{simulateCurrentTrackPosition} = 0;
|
||||||
|
|
||||||
readingsSingleUpdate($hash, "state", 'init', 1);
|
readingsSingleUpdate($hash, "state", 'init', 1);
|
||||||
readingsSingleUpdate($hash, "presence", 'disappeared', 0); # Grund-Initialisierung, falls der Player sich nicht zurückmelden sollte...
|
readingsSingleUpdate($hash, "presence", 'disappeared', 0); # Grund-Initialisierung, falls der Player sich nicht zurückmelden sollte...
|
||||||
|
|
||||||
|
# RoomDarstellung für alle Player festlegen
|
||||||
|
$modules{$hash->{TYPE}}->{FW_addDetailToSummary} = (AttrVal(SONOS_getSonosPlayerByName()->{NAME}, 'deviceRoomView', 'Both') =~ m/(Both)/i);
|
||||||
|
|
||||||
$hash->{UDN} = $udn;
|
$hash->{UDN} = $udn;
|
||||||
readingsSingleUpdate($hash, "state", 'initialized', 1);
|
readingsSingleUpdate($hash, "state", 'initialized', 1);
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
#
|
||||||
|
# SONOSPLAYER_Detail - Returns the Detailview
|
||||||
|
#
|
||||||
|
########################################################################################
|
||||||
|
sub SONOSPLAYER_Detail($$$;$) {
|
||||||
|
my ($FW_wname, $d, $room, $withRC) = @_;
|
||||||
|
$withRC = 1 if (!defined($withRC));
|
||||||
|
|
||||||
|
my $hash = $defs{$d};
|
||||||
|
|
||||||
|
return '' if (!ReadingsVal($d, 'IsMaster', 0) || (ReadingsVal($d, 'playerType', '') eq 'ZB100'));
|
||||||
|
|
||||||
|
# Open incl. Inform-Div
|
||||||
|
my $html .= '<html><div informId="'.$d.'-display_covertitle">';
|
||||||
|
|
||||||
|
# Cover-/TitleView
|
||||||
|
$html .= '<div style="border: 1px solid gray; border-radius: 10px; padding: 5px;">';
|
||||||
|
$html .= SONOS_getCoverTitleRG($d);
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
# Close Inform-Div
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
# Control-Buttons
|
||||||
|
if (!AttrVal($d, 'suppressControlButtons', 0) && ($withRC)) {
|
||||||
|
$html.= '<div class="rc_body" style="border: 1px solid gray; border-radius: 10px; padding: 5px;">';
|
||||||
|
$html .= '<table style="text-align: center;"><tr>';
|
||||||
|
$html .= '<td><a onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' Previous\')">'.FW_makeImage('rc_PREVIOUS.svg', 'Previous', 'rc-button').'</a></td>
|
||||||
|
<td><a style="padding-left: 10px;" onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' Play\')">'.FW_makeImage('rc_PLAY.svg', 'Play', 'rc-button').'</a></td>
|
||||||
|
<td><a onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' Pause\')">'.FW_makeImage('rc_PAUSE.svg', 'Pause', 'rc-button').'</a></td>
|
||||||
|
<td><a style="padding-left: 10px;" onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' Next\')">'.FW_makeImage('rc_NEXT.svg', 'Next', 'rc-button').'</a></td>
|
||||||
|
<td><a style="padding-left: 20px;" onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' VolumeD\')">'.FW_makeImage('rc_VOLDOWN.svg', 'VolDown', 'rc-button').'</a></td>
|
||||||
|
<td><a onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' MuteT\')">'.FW_makeImage('rc_MUTE.svg', 'Mute', 'rc-button').'</a></td>
|
||||||
|
<td><a onclick="FW_cmd(\'?XHR=1&cmd.dummy=set '.$d.' VolumeU\')">'.FW_makeImage('rc_VOLUP.svg', 'VolUp', 'rc-button').'</a></td>';
|
||||||
|
$html .= '</tr></table>';
|
||||||
|
$html .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
# Close
|
||||||
|
$html .= '</html>';
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
#
|
#
|
||||||
# SONOSPLAYER_Attribute - Implements AttrFn function
|
# SONOSPLAYER_Attribute - Implements AttrFn function
|
||||||
@ -262,7 +325,6 @@ sub SONOSPLAYER_State($$$$) {
|
|||||||
my ($hash, $time, $name, $value) = @_;
|
my ($hash, $time, $name, $value) = @_;
|
||||||
|
|
||||||
# Die folgenden Readings müssen immer neu initialisiert verwendet werden, und dürfen nicht aus dem Statefile verwendet werden
|
# Die folgenden Readings müssen immer neu initialisiert verwendet werden, und dürfen nicht aus dem Statefile verwendet werden
|
||||||
#return 'Reading '.$hash->{NAME}."->$name must not be used out of statefile. This is not an error! This happens due to restrictions of Fhem." if ($name eq 'presence') || ($name eq 'LastActionResult') || ($name eq 'AlarmList') || ($name eq 'AlarmListIDs') || ($name eq 'AlarmListVersion');
|
|
||||||
if (($name eq 'presence') || ($name eq 'LastActionResult') || ($name eq 'AlarmList') || ($name eq 'AlarmListIDs') || ($name eq 'AlarmListVersion')) {
|
if (($name eq 'presence') || ($name eq 'LastActionResult') || ($name eq 'AlarmList') || ($name eq 'AlarmListIDs') || ($name eq 'AlarmListVersion')) {
|
||||||
SONOSPLAYER_Log undef, 4, 'StateFn-Call. Ignore the following Reading: '.$hash->{NAME}.'->'.$name.'('.(defined($value) ? $value : '').')';
|
SONOSPLAYER_Log undef, 4, 'StateFn-Call. Ignore the following Reading: '.$hash->{NAME}.'->'.$name.'('.(defined($value) ? $value : '').')';
|
||||||
|
|
||||||
@ -280,24 +342,62 @@ sub SONOSPLAYER_State($$$$) {
|
|||||||
# SONOSPLAYER_Notify - Implements NotifyFn function
|
# SONOSPLAYER_Notify - Implements NotifyFn function
|
||||||
#
|
#
|
||||||
########################################################################################
|
########################################################################################
|
||||||
sub SONOSPLAYER_Notify() {
|
sub SONOSPLAYER_Notify($$) {
|
||||||
my ($hash, $notifyhash) = @_;
|
my ($hash, $notifyhash) = @_;
|
||||||
|
|
||||||
return undef;
|
my $events = deviceEvents($notifyhash, 1);
|
||||||
|
return if(!$events);
|
||||||
|
|
||||||
# Das folgende habe ich erstmal wieder entfernt, da man ja öfter im laufenden Betrieb die Einstellungen speichert, und den Sonos-Komponenten dann immer wichtige Informationen für den Betrieb fehlen (nicht jedes Save wird vor dem Neustart von Fhem ausgeführt)
|
foreach my $event (@{$events}) {
|
||||||
#if (($notifyhash->{NAME} eq 'global') && (($notifyhash->{CHANGED}[0] eq 'SAVE') || ($notifyhash->{CHANGED}[0] eq 'SHUTDOWN'))) {
|
next if(!defined($event));
|
||||||
# SONOSPLAYER_Log undef, 3, $hash->{NAME}.' has detected a global:'.$notifyhash->{CHANGED}[0].'-Event. Clear out some readings before...';
|
|
||||||
#
|
if ($event =~ m/transportState: (.+)/i) {
|
||||||
# # Einige Readings niemals speichern
|
SONOSPLAYER_Log $hash->{NAME}, 5, 'Notify: '.$event;
|
||||||
# delete($defs{$hash->{NAME}}{READINGS}{presence});
|
if ($1 eq 'PLAYING') {
|
||||||
# delete($defs{$hash->{NAME}}{READINGS}{LastActionResult});
|
$hash->{helper}->{simulateCurrentTrackPosition} = AttrVal($hash->{NAME}, 'simulateCurrentTrackPosition', 0);
|
||||||
# delete($defs{$hash->{NAME}}{READINGS}{AlarmList});
|
|
||||||
# delete($defs{$hash->{NAME}}{READINGS}{AlarmListIDs});
|
# Wiederholungskette für die Aktualisierung sofort anstarten...
|
||||||
# delete($defs{$hash->{NAME}}{READINGS}{AlarmListVersion});
|
InternalTimer(gettimeofday(), 'SONOSPLAYER_SimulateCurrentTrackPosition', $hash, 0);
|
||||||
#}
|
} else {
|
||||||
#
|
$hash->{helper}->{simulateCurrentTrackPosition} = 0;
|
||||||
#return undef;
|
|
||||||
|
# Einmal noch etwas später aktualisieren...
|
||||||
|
InternalTimer(gettimeofday() + 0.1, 'SONOSPLAYER_SimulateCurrentTrackPosition', $hash, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
#
|
||||||
|
# SONOSPLAYER_SimulateCurrentTrackPosition - Implements the Simulation for the currentTrackPosition
|
||||||
|
#
|
||||||
|
########################################################################################
|
||||||
|
sub SONOSPLAYER_SimulateCurrentTrackPosition() {
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
return undef if (AttrVal($hash->{NAME}, 'disable', 0));
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
my $trackDurationSec = SONOS_GetTimeSeconds(ReadingsVal($hash->{NAME}, 'currentTrackDuration', 0)) - 1;
|
||||||
|
my $trackPositionSec = time - SONOS_GetTimeFromString(ReadingsTimestamp($hash->{NAME}, 'currentTrackPositionSec', 0)) + ReadingsVal($hash->{NAME}, 'currentTrackPositionSec', 0);
|
||||||
|
readingsBulkUpdate($hash, 'currentTrackPositionSimulated', SONOS_ConvertSecondsToTime($trackPositionSec));
|
||||||
|
readingsBulkUpdate($hash, 'currentTrackPositionSimulatedSec', $trackPositionSec);
|
||||||
|
|
||||||
|
if ($trackDurationSec) {
|
||||||
|
readingsBulkUpdateIfChanged($hash, 'currentTrackPositionSimulatedPercent', sprintf(AttrVal($hash->{NAME}, 'simulateCurrentTrackPositionPercentFormat', '%.1f'), 100 * $trackPositionSec / $trackDurationSec));
|
||||||
|
} else {
|
||||||
|
readingsBulkUpdateIfChanged($hash, 'currentTrackPositionSimulatedPercent', sprintf(AttrVal($hash->{NAME}, 'simulateCurrentTrackPositionPercentFormat', '%.1f'), 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsEndUpdate($hash, 1);
|
||||||
|
|
||||||
|
if ($hash->{helper}->{simulateCurrentTrackPosition}) {
|
||||||
|
InternalTimer(gettimeofday() + $hash->{helper}->{simulateCurrentTrackPosition}, 'SONOSPLAYER_SimulateCurrentTrackPosition', $hash, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
@ -787,6 +887,18 @@ sub SONOSPLAYER_Set($@) {
|
|||||||
$udn = $hash->{UDN};
|
$udn = $hash->{UDN};
|
||||||
|
|
||||||
SONOS_DoWork($udn, 'playURITemp', $value, $value2);
|
SONOS_DoWork($udn, 'playURITemp', $value, $value2);
|
||||||
|
} elsif ($key =~ m/(start|load)handle/i) {
|
||||||
|
$hash = SONOSPLAYER_GetRealTargetPlayerHash($hash);
|
||||||
|
$udn = $hash->{UDN};
|
||||||
|
|
||||||
|
# Hier die komplette restliche Zeile in den Text-Parameter packen, da damit auch Leerzeichen möglich sind
|
||||||
|
my $text = '';
|
||||||
|
for(my $i = 2; $i < @a; $i++) {
|
||||||
|
$text .= ' ' if ($i > 2);
|
||||||
|
$text .= $a[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
SONOS_DoWork($udn, 'startHandle', $text, (lc($key) eq 'loadhandle'));
|
||||||
} elsif (lc($key) eq 'adduritoqueue') {
|
} elsif (lc($key) eq 'adduritoqueue') {
|
||||||
$hash = SONOSPLAYER_GetRealTargetPlayerHash($hash);
|
$hash = SONOSPLAYER_GetRealTargetPlayerHash($hash);
|
||||||
$udn = $hash->{UDN};
|
$udn = $hash->{UDN};
|
||||||
@ -1453,6 +1565,8 @@ sub SONOSPLAYER_Log($$$) {
|
|||||||
</a><br /> One of (0,1). Enables a slider for volumecontrol in detail view.</li>
|
</a><br /> One of (0,1). Enables a slider for volumecontrol in detail view.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_getAlarms"><b><code>getAlarms <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_getAlarms"><b><code>getAlarms <int></code></b>
|
||||||
</a><br /> One of (0..1). Initializes a callback-method for Alarms. This included the information of the DailyIndexRefreshTime.</li>
|
</a><br /> One of (0..1). Initializes a callback-method for Alarms. This included the information of the DailyIndexRefreshTime.</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_suppressControlButtons"><b><code>suppressControlButtons <int></code></b>
|
||||||
|
</a><br /> One of (0,1). Enables the control-section shown under the Cover-/Titleview.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_volumeStep"><b><code>volumeStep <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_volumeStep"><b><code>volumeStep <int></code></b>
|
||||||
</a><br /> One of (0..100). Defines the stepwidth for subsequent calls of <code>VolumeU</code> and <code>VolumeD</code>.</li>
|
</a><br /> One of (0..100). Defines the stepwidth for subsequent calls of <code>VolumeU</code> and <code>VolumeD</code>.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@ -1467,6 +1581,10 @@ sub SONOSPLAYER_Log($$$) {
|
|||||||
</a><br /> Generates the reading 'InfoSummarize4' with the given format. More Information on this in the examples-section.</li>
|
</a><br /> Generates the reading 'InfoSummarize4' with the given format. More Information on this in the examples-section.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_getTitleInfoFromMaster"><b><code>getTitleInfoFromMaster <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_getTitleInfoFromMaster"><b><code>getTitleInfoFromMaster <int></code></b>
|
||||||
</a><br /> One of (0, 1). Gets the current Playing-Informations from the Masterplayer (if one is present).</li>
|
</a><br /> One of (0, 1). Gets the current Playing-Informations from the Masterplayer (if one is present).</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_simulateCurrentTrackPosition"><b><code>simulateCurrentTrackPosition <int></code></b>
|
||||||
|
</a><br /> One of (0,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60). Starts an internal Timer which refreshs the current trackposition into the Readings <code>currentTrackPositionSimulated</code> and <code>currentTrackPositionSimulatedSec</code>. At the same time the Reading <code>currentTrackPositionSimulatedPercent</code> (between 0.0 and 100.0) will also be refreshed.</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_simulateCurrentTrackPositionPercentFormat"><b><code>simulateCurrentTrackPositionPercentFormat <Format></code></b>
|
||||||
|
</a><br /> Defines the format of the percentformat in the Reading <code>currentTrackPositionSimulatedPercent</code>.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_stateVariable"><b><code>stateVariable <string></code></b>
|
<li><a name="SONOSPLAYER_attribut_stateVariable"><b><code>stateVariable <string></code></b>
|
||||||
</a><br /> One of (TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,<br />Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,<br />nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,RepeatOne,CrossfadeMode,Balance,<br />HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,<br />InfoSummarize2,InfoSummarize3,InfoSummarize4). Defines, which variable has to be copied to the content of the state-variable.</li>
|
</a><br /> One of (TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,<br />Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,<br />nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,RepeatOne,CrossfadeMode,Balance,<br />HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,<br />InfoSummarize2,InfoSummarize3,InfoSummarize4). Defines, which variable has to be copied to the content of the state-variable.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@ -1828,6 +1946,9 @@ Here an event is defined, where in time of 2 seconds the Mute-Button has to be p
|
|||||||
</a><br /> One of (0,1). Aktiviert einen Slider für die Lautstärkekontrolle in der Detailansicht.</li>
|
</a><br /> One of (0,1). Aktiviert einen Slider für die Lautstärkekontrolle in der Detailansicht.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_getAlarms"><b><code>getAlarms <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_getAlarms"><b><code>getAlarms <int></code></b>
|
||||||
</a><br /> One of (0..1). Richtet eine Callback-Methode für Alarme ein. Damit wird auch die DailyIndexRefreshTime automatisch aktualisiert.</li>
|
</a><br /> One of (0..1). Richtet eine Callback-Methode für Alarme ein. Damit wird auch die DailyIndexRefreshTime automatisch aktualisiert.</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_suppressControlButtons"><b><code>suppressControlButtons <int></code></b>
|
||||||
|
</a><br /> One of (0,1). Gibt an, ob die Steuerbuttons unter der Cover-/Titelanzeige angezeigt werden sollen (=1) oder nicht (=0).</li>
|
||||||
|
</ul></li>
|
||||||
<li><a name="SONOSPLAYER_attribut_volumeStep"><b><code>volumeStep <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_volumeStep"><b><code>volumeStep <int></code></b>
|
||||||
</a><br /> One of (0..100). Definiert die Schrittweite für die Aufrufe von <code>VolumeU</code> und <code>VolumeD</code>.</li>
|
</a><br /> One of (0..100). Definiert die Schrittweite für die Aufrufe von <code>VolumeU</code> und <code>VolumeD</code>.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@ -1841,7 +1962,11 @@ Here an event is defined, where in time of 2 seconds the Mute-Button has to be p
|
|||||||
<li><a name="SONOSPLAYER_attribut_generateInfoSummarize4"><b><code>generateInfoSummarize4 <string></code></b>
|
<li><a name="SONOSPLAYER_attribut_generateInfoSummarize4"><b><code>generateInfoSummarize4 <string></code></b>
|
||||||
</a><br /> Erzeugt das Reading 'InfoSummarize4' mit dem angegebenen Format. Mehr Informationen dazu im Bereich Beispiele.</li>
|
</a><br /> Erzeugt das Reading 'InfoSummarize4' mit dem angegebenen Format. Mehr Informationen dazu im Bereich Beispiele.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_getTitleInfoFromMaster"><b><code>getTitleInfoFromMaster <int></code></b>
|
<li><a name="SONOSPLAYER_attribut_getTitleInfoFromMaster"><b><code>getTitleInfoFromMaster <int></code></b>
|
||||||
</a><br /> Eins aus (0, 1). Bringt das Device dazu, seine aktuellen Abspielinformationen vom aktuellen Gruppenmaster zu holen, wenn es einen solchen gibt.</li>
|
</a><br /> Eins aus (0,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60). Bringt das Device dazu, seine aktuellen Abspielinformationen vom aktuellen Gruppenmaster zu holen, wenn es einen solchen gibt.</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_simulateCurrentTrackPosition"><b><code>simulateCurrentTrackPosition <int></code></b>
|
||||||
|
</a><br /> Eins aus (0, 1). Bringt das Device dazu, seine aktuelle Abspielposition simuliert weiterlaufen zu lassen. Dazu werden die Readings <code>currentTrackPositionSimulated</code> und <code>currentTrackPositionSimulatedSec</code> gesetzt. Gleichzeitig wird auch das Reading <code>currentTrackPositionSimulatedPercent</code> (zwischen 0.0 und 100.0) gesetzt.</li>
|
||||||
|
<li><a name="SONOSPLAYER_attribut_simulateCurrentTrackPositionPercentFormat"><b><code>simulateCurrentTrackPositionPercentFormat <Format></code></b>
|
||||||
|
</a><br /> Definiert das Format für die sprintf-Prozentausgabe im Reading <code>currentTrackPositionSimulatedPercent</code>.</li>
|
||||||
<li><a name="SONOSPLAYER_attribut_stateVariable"><b><code>stateVariable <string></code></b>
|
<li><a name="SONOSPLAYER_attribut_stateVariable"><b><code>stateVariable <string></code></b>
|
||||||
</a><br /> One of (TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,<br />Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,<br />nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,RepeatOne,CrossfadeMode,Balance,<br />HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,I<br />nfoSummarize2,InfoSummarize3,InfoSummarize4). Gibt an, welche Variable in das Reading <code>state</code> kopiert werden soll.</li>
|
</a><br /> One of (TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,<br />Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,<br />nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,RepeatOne,CrossfadeMode,Balance,<br />HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,I<br />nfoSummarize2,InfoSummarize3,InfoSummarize4). Gibt an, welche Variable in das Reading <code>state</code> kopiert werden soll.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
|
@ -78,11 +78,25 @@ sub new {
|
|||||||
$self->{_subscriptionPort} = $self->{_subscriptionSocket}->sockport();;
|
$self->{_subscriptionPort} = $self->{_subscriptionSocket}->sockport();;
|
||||||
|
|
||||||
# Create the socket on which we'll listen for SSDP Notifications.
|
# Create the socket on which we'll listen for SSDP Notifications.
|
||||||
$self->{_ssdpMulticastSocket} = IO::Socket::INET->new(
|
# First try with ReusePort...
|
||||||
Proto => 'udp',
|
eval {
|
||||||
Reuse => 1,
|
$self->{_ssdpMulticastSocket} = IO::Socket::INET->new(
|
||||||
LocalPort => SSDP_PORT) ||
|
Proto => 'udp',
|
||||||
croak("Error creating SSDP multicast listen socket: $!\n");
|
Reuse => 1,
|
||||||
|
ReusePort => 1,
|
||||||
|
LocalPort => SSDP_PORT) ||
|
||||||
|
carp("Error creating SSDP multicast listen socket: $!\n");
|
||||||
|
};
|
||||||
|
if ($@ =~ /Your vendor has not defined Socket macro SO_REUSEPORT/i) {
|
||||||
|
$self->{_ssdpMulticastSocket} = IO::Socket::INET->new(
|
||||||
|
Proto => 'udp',
|
||||||
|
Reuse => 1,
|
||||||
|
LocalPort => SSDP_PORT) ||
|
||||||
|
carp("Error creating SSDP multicast listen socket: $!\n");
|
||||||
|
} else {
|
||||||
|
# Weiterwerfen...
|
||||||
|
carp($@);
|
||||||
|
}
|
||||||
my $ip_mreq = inet_aton(SSDP_IP) . INADDR_ANY;
|
my $ip_mreq = inet_aton(SSDP_IP) . INADDR_ANY;
|
||||||
setsockopt($self->{_ssdpMulticastSocket},
|
setsockopt($self->{_ssdpMulticastSocket},
|
||||||
IP_LEVEL,
|
IP_LEVEL,
|
||||||
|
BIN
fhem/FHEM/lib/UPnP/sonos_bibliothek_quadratic.jpg
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_bibliothek_round.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_dock_quadratic.jpg
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_dock_round.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_leer.gif
Normal file
After Width: | Height: | Size: 814 B |
BIN
fhem/FHEM/lib/UPnP/sonos_linein_quadratic.jpg
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_linein_round.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_playbar_quadratic.jpg
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_playbar_round.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_tunein_quadratic.jpg
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
fhem/FHEM/lib/UPnP/sonos_tunein_round.png
Normal file
After Width: | Height: | Size: 1.9 KiB |