mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00
Sonos: Fix some bugs and adds attribute disable to Sonos.
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@7575 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
a8538fd3ff
commit
7cb0ea2175
252
FHEM/00_SONOS.pm
252
FHEM/00_SONOS.pm
@ -7,9 +7,10 @@
|
|||||||
#
|
#
|
||||||
# FHEM module to commmunicate with a Sonos-System via UPnP
|
# FHEM module to commmunicate with a Sonos-System via UPnP
|
||||||
#
|
#
|
||||||
# !WARNING!
|
########################################################################################
|
||||||
|
# !ATTENTION!
|
||||||
# This Module needs additional Perl-Libraries.
|
# This Module needs additional Perl-Libraries.
|
||||||
# Installation of:
|
# Install:
|
||||||
# * LWP::Simple
|
# * LWP::Simple
|
||||||
# * LWP::UserAgent
|
# * LWP::UserAgent
|
||||||
# * HTTP::Request
|
# * HTTP::Request
|
||||||
@ -19,19 +20,42 @@
|
|||||||
# * LWP::Simple-Packagename (incl. LWP::UserAgent and HTTP::Request): libwww-perl
|
# * LWP::Simple-Packagename (incl. LWP::UserAgent and HTTP::Request): libwww-perl
|
||||||
# * SOAP::Lite-Packagename: libsoap-lite-perl
|
# * SOAP::Lite-Packagename: libsoap-lite-perl
|
||||||
#
|
#
|
||||||
|
# e.g. as Windows ActivePerl (via Perl-Packagemanager)
|
||||||
|
# * Install Package LWP (incl. LWP::UserAgent and HTTP::Request)
|
||||||
|
# * Install Package SOAP::Lite
|
||||||
|
# * SOAP::Lite-Special for Versions after 5.18:
|
||||||
|
# * Add another Packagesource from suggestions or manual: Bribes de Perl (http://www.bribes.org/perl/ppm)
|
||||||
|
# * Install Package: SOAP::Lite
|
||||||
#
|
#
|
||||||
# define <name> SONOS <host:port> [[[interval] waittime] delaytime]
|
# Windows ActivePerl 64Bit is not functioning due to missing SOAP::Lite
|
||||||
#
|
#
|
||||||
# where <name> may be replaced by any name string
|
########################################################################################
|
||||||
|
# Configuration:
|
||||||
|
# define <name> SONOS <host:port> [interval [waittime [delaytime]]]
|
||||||
|
#
|
||||||
|
# where <name> may be replaced by any fhem-devicename string
|
||||||
# <host:port> is the connection identifier to the internal server. Normally "localhost" with a locally free port e.g. "localhost:4711".
|
# <host:port> is the connection identifier to the internal server. Normally "localhost" with a locally free port e.g. "localhost:4711".
|
||||||
# interval is the interval in s, for checking the existence of a ZonePlayer after definition
|
# interval is the interval in s, for checking the existence of a ZonePlayer
|
||||||
# waittime is the time to wait for the subprocess. defaults to 8.
|
# waittime is the time to wait for the subprocess. defaults to 8.
|
||||||
# delaytime is the Time for delaying the network- and subprocess-part of this module. If the port is longer than neccessary blocked on the subprocess-side, it may be useful.
|
# delaytime is the Time for delaying the network- and subprocess-part of this module. If the port is longer than neccessary blocked on the subprocess-side, it may be useful.
|
||||||
#
|
#
|
||||||
|
##############################################
|
||||||
|
# Example:
|
||||||
|
# define Sonos SONOS localhost:4711 30
|
||||||
|
#
|
||||||
########################################################################################
|
########################################################################################
|
||||||
# Changelog
|
# Changelog
|
||||||
#
|
#
|
||||||
# SVN-History:
|
# SVN-History:
|
||||||
|
# 15.01.2015
|
||||||
|
# Beim Anlegen der neuen Devices werden die Aliasnamen nun mit der Funktion im Team erweitert
|
||||||
|
# Der Mechanismus zum Starten des SubProzesses wurde angepasst, um auf Synology-Begebenheiten Rücksicht zu nehmen
|
||||||
|
# Die Coverdarstellung für einige Spotify-Titel wurde korrigiert, indem eine andere Spotify-API verwendet wird
|
||||||
|
# Bei Playlist-Covern wird nun das Cover des ersten Titels mit AlbumArt angezeigt
|
||||||
|
# Bei Favourite-Covern werden nun Album-Favoriten auch mit Cover dargestellt (das Cover des ersten Titels mit AlbumArt)
|
||||||
|
# Ein Album aus der lokalen Bibliothek konnte mittels "StartFavourite" nicht korrekt gestartet werden (es wurde nicht als Liste übertragen, sondern als Titel gestartet)
|
||||||
|
# LogLevel für die "Connection accepted"-Meldungen auf 3 hochgesetzt
|
||||||
|
# Es gibt jetzt ein Attribut "disable" am Sonos-Device. Wird es auf 1 gesetzt, wird der SubProzess beendet und verarbeitet somit keine Sonos-Nachrichten mehr. Wird es auf 0 gesetzt (oder gelöscht), wird der SubProzess wieder gestartet.
|
||||||
# 08.01.2015
|
# 08.01.2015
|
||||||
# Bei der Wiedergabeanweisung "PlayURI" gab es einen Fehler
|
# Bei der Wiedergabeanweisung "PlayURI" gab es einen Fehler
|
||||||
# 05.01.2105
|
# 05.01.2105
|
||||||
@ -443,7 +467,7 @@ sub SONOS_Initialize ($) {
|
|||||||
$hash->{GetFn} = 'SONOS_Get';
|
$hash->{GetFn} = 'SONOS_Get';
|
||||||
$hash->{SetFn} = 'SONOS_Set';
|
$hash->{SetFn} = 'SONOS_Set';
|
||||||
$hash->{AttrFn} = 'SONOS_Attribute';
|
$hash->{AttrFn} = 'SONOS_Attribute';
|
||||||
$hash->{NotifyFn} = 'SONOS_Notify';
|
# $hash->{NotifyFn} = 'SONOS_Notify';
|
||||||
|
|
||||||
# CGI
|
# CGI
|
||||||
my $name = "sonos";
|
my $name = "sonos";
|
||||||
@ -455,7 +479,7 @@ sub SONOS_Initialize ($) {
|
|||||||
eval {
|
eval {
|
||||||
no strict;
|
no strict;
|
||||||
no warnings;
|
no warnings;
|
||||||
$hash->{AttrList}= 'pingType:'.join(',', @SONOS_PINGTYPELIST).' targetSpeakDir targetSpeakURL targetSpeakFileTimestamp:0,1 targetSpeakFileHashCache:0,1 Speak1 Speak2 Speak3 Speak4 SpeakCover Speak1Cover Speak2Cover Speak3Cover Speak4Cover generateProxyAlbumArtURLs:0,1 proxyCacheTime proxyCacheDir characterDecoding '.$readingFnAttributes;
|
$hash->{AttrList}= 'disable:1,0 pingType:'.join(',', @SONOS_PINGTYPELIST).' targetSpeakDir targetSpeakURL targetSpeakFileTimestamp:1,0 targetSpeakFileHashCache:1,0 Speak1 Speak2 Speak3 Speak4 SpeakCover Speak1Cover Speak2Cover Speak3Cover Speak4Cover generateProxyAlbumArtURLs:1,0 proxyCacheTime proxyCacheDir characterDecoding '.$readingFnAttributes;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
};
|
};
|
||||||
@ -707,13 +731,15 @@ sub SONOS_getGroupsRG() {
|
|||||||
sub SONOS_FhemWebCallback($) {
|
sub SONOS_FhemWebCallback($) {
|
||||||
my ($URL) = @_;
|
my ($URL) = @_;
|
||||||
|
|
||||||
|
SONOS_Log undef, 5, 'FhemWebCallback: '.$URL;
|
||||||
|
|
||||||
# Einfache Grundprüfungen
|
# Einfache Grundprüfungen
|
||||||
return ("text/html; charset=UTF8", 'Fehlerhafte Anfrage: '.$URL) if ($URL !~ m/^\/sonos\//i);
|
return ("text/html; charset=UTF8", 'Forbidden call: '.$URL) if ($URL !~ m/^\/sonos\//i);
|
||||||
$URL =~ s/^\/sonos//i;
|
$URL =~ s/^\/sonos//i;
|
||||||
|
|
||||||
# Proxy-Features...
|
# Proxy-Features...
|
||||||
if ($URL =~ m/^\/proxy\//i) {
|
if ($URL =~ m/^\/proxy\//i) {
|
||||||
return ("text/html; charset=UTF8", 'Proxybetrieb nicht aktiviert: '.$URL) if (!AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'generateProxyAlbumArtURLs', 0));
|
return ("text/html; charset=UTF8", 'No Proxy configured: '.$URL) if (!AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'generateProxyAlbumArtURLs', 0));
|
||||||
|
|
||||||
my $proxyCacheTime = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'proxyCacheTime', 0);
|
my $proxyCacheTime = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'proxyCacheTime', 0);
|
||||||
my $proxyCacheDir = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'proxyCacheDir', '/tmp');
|
my $proxyCacheDir = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'proxyCacheDir', '/tmp');
|
||||||
@ -721,6 +747,7 @@ sub SONOS_FhemWebCallback($) {
|
|||||||
|
|
||||||
# Zurückzugebende Adresse ermitteln...
|
# Zurückzugebende Adresse ermitteln...
|
||||||
my $albumurl = uri_unescape($1) if ($URL =~ m/^\/proxy\/aa\?url=(.*)/i);
|
my $albumurl = uri_unescape($1) if ($URL =~ m/^\/proxy\/aa\?url=(.*)/i);
|
||||||
|
$albumurl =~ s/'/'/ig;
|
||||||
|
|
||||||
# Nur für Sonos-Player den Proxy spielen (und für Spotify-Links)
|
# Nur für Sonos-Player den Proxy spielen (und für Spotify-Links)
|
||||||
my $ip = '';
|
my $ip = '';
|
||||||
@ -731,7 +758,7 @@ sub SONOS_FhemWebCallback($) {
|
|||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ("text/html; charset=UTF8", 'Anfrage für Nicht-Sonos-Player: '.$URL) if (defined($ip) && $albumurl !~ /\/original\//i && $albumurl !~ /\/music\/image\?/i);
|
return ("text/html; charset=UTF8", 'Call for No-Sonos-Player: '.$URL) if (defined($ip) && $albumurl !~ /\.cloudfront.net\//i && $albumurl !~ /\.scdn.co\/image\//i && $albumurl !~ /\/music\/image\?/i);
|
||||||
|
|
||||||
# Generierter Dateiname für die Cache-Funktionalitaet
|
# Generierter Dateiname für die Cache-Funktionalitaet
|
||||||
my $albumHash;
|
my $albumHash;
|
||||||
@ -778,6 +805,11 @@ sub SONOS_FhemWebCallback($) {
|
|||||||
$albumHash =~ m/(.*)\/(.*)\.(.*)/;
|
$albumHash =~ m/(.*)\/(.*)\.(.*)/;
|
||||||
FW_serveSpecial($2, $3, $1, 1);
|
FW_serveSpecial($2, $3, $1, 1);
|
||||||
|
|
||||||
|
return (undef, undef);
|
||||||
|
} else {
|
||||||
|
SONOS_Log undef, 1, 'Cover couldn\'t be loaded: '.$albumurl;
|
||||||
|
|
||||||
|
FW_serveSpecial('sonos_empty', 'jpg', $attr{global}{modpath}.'/FHEM/lib/UPnP', 1);
|
||||||
return (undef, undef);
|
return (undef, undef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,6 +818,8 @@ sub SONOS_FhemWebCallback($) {
|
|||||||
if ($URL =~ m/^\/cover\//i) {
|
if ($URL =~ m/^\/cover\//i) {
|
||||||
$URL =~ s/^\/cover//i;
|
$URL =~ s/^\/cover//i;
|
||||||
|
|
||||||
|
SONOS_Log undef, 5, 'Cover: '.$URL;
|
||||||
|
|
||||||
if ($URL =~ m/^\/empty.jpg/i) {
|
if ($URL =~ m/^\/empty.jpg/i) {
|
||||||
FW_serveSpecial('sonos_empty', 'jpg', $attr{global}{modpath}.'/FHEM/lib/UPnP', 1);
|
FW_serveSpecial('sonos_empty', 'jpg', $attr{global}{modpath}.'/FHEM/lib/UPnP', 1);
|
||||||
return (undef, undef);
|
return (undef, undef);
|
||||||
@ -813,7 +847,7 @@ sub SONOS_FhemWebCallback($) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Wenn wir hier ankommen, dann konnte nichts verarbeitet werden...
|
# Wenn wir hier ankommen, dann konnte nichts verarbeitet werden...
|
||||||
return ("text/html; charset=UTF8", 'Fehlerhafte Anfrage: '.$URL);
|
return ("text/html; charset=UTF8", 'Call failure: '.$URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
@ -871,10 +905,12 @@ sub SONOS_Define($$) {
|
|||||||
$hash->{DELAYTIME} = $delaytime;
|
$hash->{DELAYTIME} = $delaytime;
|
||||||
$hash->{STATE} = 'waiting for subprocess...';
|
$hash->{STATE} = 'waiting for subprocess...';
|
||||||
|
|
||||||
|
if (AttrVal($hash->{NAME}, 'disable', 0) == 0) {
|
||||||
if ($hash->{DELAYTIME}) {
|
if ($hash->{DELAYTIME}) {
|
||||||
InternalTimer(gettimeofday() + $hash->{DELAYTIME}, 'SONOS_DelayStart', $hash, 0);
|
InternalTimer(gettimeofday() + $hash->{DELAYTIME}, 'SONOS_DelayStart', $hash, 0);
|
||||||
} else {
|
} else {
|
||||||
SONOS_DelayStart($hash);
|
InternalTimer(gettimeofday() + 1, 'SONOS_DelayStart', $hash, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
@ -888,6 +924,8 @@ sub SONOS_Define($$) {
|
|||||||
sub SONOS_DelayStart($) {
|
sub SONOS_DelayStart($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
return undef if (AttrVal($hash->{NAME}, 'disable', 0));
|
||||||
|
|
||||||
# Prüfen, ob ein Server erreichbar wäre, und wenn nicht, einen Server starten
|
# Prüfen, ob ein Server erreichbar wäre, und wenn nicht, einen Server starten
|
||||||
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName});
|
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName});
|
||||||
|
|
||||||
@ -914,15 +952,76 @@ sub SONOS_DelayOpenDev($) {
|
|||||||
sub SONOS_Attribute($$$@) {
|
sub SONOS_Attribute($$$@) {
|
||||||
my ($mode, $devName, $attrName, $attrValue) = @_;
|
my ($mode, $devName, $attrName, $attrValue) = @_;
|
||||||
|
|
||||||
|
my $disableChange = 0;
|
||||||
|
|
||||||
if ($mode eq 'set') {
|
if ($mode eq 'set') {
|
||||||
if ($attrName eq 'verbose') {
|
if ($attrName eq 'verbose') {
|
||||||
SONOS_DoWork('undef', 'setVerbose', $attrValue);
|
SONOS_DoWork('undef', 'setVerbose', $attrValue);
|
||||||
|
} elsif ($attrName eq 'disable') {
|
||||||
|
if ($attrValue && AttrVal($devName, $attrName, 0) != 1) {
|
||||||
|
SONOS_Log(undef, 5, 'Neu-Disabled');
|
||||||
|
$disableChange = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attrValue && AttrVal($devName, $attrName, 0) != 0) {
|
||||||
|
SONOS_Log(undef, 5, 'Neu-Enabled');
|
||||||
|
$disableChange = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($mode eq 'del') {
|
||||||
|
if ($attrName eq 'disable') {
|
||||||
|
if (AttrVal($devName, $attrName, 0) != 0) {
|
||||||
|
SONOS_Log(undef, 5, 'Deleted-Disabled');
|
||||||
|
$disableChange = 1;
|
||||||
|
$attrValue = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($disableChange) {
|
||||||
|
my $hash = SONOS_getDeviceDefHash(undef);
|
||||||
|
|
||||||
|
# Wenn der Prozess beendet werden muss...
|
||||||
|
if ($attrValue) {
|
||||||
|
SONOS_Log undef, 5, 'Call AttributeFn: Stop SubProcess...';
|
||||||
|
|
||||||
|
InternalTimer(gettimeofday() + 1, 'SONOS_StopSubProcess', $hash, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wenn der Prozess gestartet werden muss...
|
||||||
|
if (!$attrValue) {
|
||||||
|
SONOS_Log undef, 5, 'Call AttributeFn: Start SubProcess...';
|
||||||
|
|
||||||
|
InternalTimer(gettimeofday() + 1, 'SONOS_DelayStart', $hash, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
#
|
||||||
|
# SONOS_StopSubProcess - Tries to stop the subprocess
|
||||||
|
#
|
||||||
|
########################################################################################
|
||||||
|
sub SONOS_StopSubProcess($) {
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
# Den SubProzess beenden, wenn wir ihn selber gestartet haben
|
||||||
|
if ($SONOS_StartedOwnUPnPServer) {
|
||||||
|
# DevIo_OpenDev($hash, 1, undef);
|
||||||
|
DevIo_SimpleWrite($hash, "shutdown\n", 0);
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
setReadingsVal($hash, "state", 'disabled', TimeNow());
|
||||||
|
$hash->{STATE} = 'disabled';
|
||||||
|
|
||||||
|
# Alle SonosPlayer-Devices disappearen
|
||||||
|
for my $player (SONOS_getAllSonosplayerDevices()) {
|
||||||
|
SONOS_readingsSingleUpdateIfChanged($player, 'presence', 'disappeared', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
#
|
#
|
||||||
# SONOS_Notify - Implements NotifyFn function
|
# SONOS_Notify - Implements NotifyFn function
|
||||||
@ -932,24 +1031,6 @@ sub SONOS_Notify() {
|
|||||||
my ($hash, $notifyhash) = @_;
|
my ($hash, $notifyhash) = @_;
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
|
|
||||||
#if (($notifyhash->{NAME} eq 'global') && ($notifyhash->{CHANGED}[0] eq 'REREADCFG')) {
|
|
||||||
# SONOS_Log undef, 0, 'Detecting rereadcfg. Restart Sonos-Subprocess...';
|
|
||||||
#
|
|
||||||
# # Vorab warten, da im Hintergrund der Thread noch läuft und auch erstmal fertig werden muss...
|
|
||||||
# select(undef, undef, undef, $hash->{WAITTIME});
|
|
||||||
#
|
|
||||||
# # Verbindung beenden, damit der SubProzess die Chance hat neu initialisiert zu werden...
|
|
||||||
# RemoveInternalTimer($hash);
|
|
||||||
# DevIo_SimpleWrite($hash, "disconnect\n", 0);
|
|
||||||
# DevIo_CloseDev($hash);
|
|
||||||
#
|
|
||||||
# # Neu anstarten...
|
|
||||||
# SONOS_StartClientProcessIfNeccessary($hash->{DeviceName}) if ($SONOS_StartedOwnUPnPServer);
|
|
||||||
# InternalTimer(gettimeofday() + $hash->{WAITTIME}, 'SONOS_DelayOpenDev', $hash, 0);
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
#return undef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
@ -980,6 +1061,7 @@ sub SONOS_Read($) {
|
|||||||
|
|
||||||
# Wenn hier gar nichts gekommen ist, dann diesen Aufruf beenden...
|
# Wenn hier gar nichts gekommen ist, dann diesen Aufruf beenden...
|
||||||
if (!defined($buf) || ($buf eq '')) {
|
if (!defined($buf) || ($buf eq '')) {
|
||||||
|
if (!AttrVal($hash->{NAME}, 'disable', 0)) {
|
||||||
SONOS_Log undef, 1, 'Nothing could be read from TCP-Channel (the first level) even though the Read-Function was called.';
|
SONOS_Log undef, 1, 'Nothing could be read from TCP-Channel (the first level) even though the Read-Function was called.';
|
||||||
|
|
||||||
# Verbindung beenden, damit der SubProzess die Chance hat neu initialisiert zu werden...
|
# Verbindung beenden, damit der SubProzess die Chance hat neu initialisiert zu werden...
|
||||||
@ -990,6 +1072,7 @@ sub SONOS_Read($) {
|
|||||||
# Neu anstarten...
|
# Neu anstarten...
|
||||||
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName}) if ($SONOS_StartedOwnUPnPServer);
|
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName}) if ($SONOS_StartedOwnUPnPServer);
|
||||||
InternalTimer(gettimeofday() + $hash->{WAITTIME}, 'SONOS_DelayOpenDev', $hash, 0);
|
InternalTimer(gettimeofday() + $hash->{WAITTIME}, 'SONOS_DelayOpenDev', $hash, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1000,6 +1083,7 @@ sub SONOS_Read($) {
|
|||||||
|
|
||||||
# Wenn hier gar nichts gekommen ist, dann diesen Aufruf beenden...
|
# Wenn hier gar nichts gekommen ist, dann diesen Aufruf beenden...
|
||||||
if (!defined($newRead) || ($newRead eq '')) {
|
if (!defined($newRead) || ($newRead eq '')) {
|
||||||
|
if (!AttrVal($hash->{NAME}, 'disable', 0)) {
|
||||||
SONOS_Log undef, 1, 'Nothing could be read from TCP-Channel (the second level) even though the Read-Function was called. The client is now directed to shutdown and the connection should be re-initialized...';
|
SONOS_Log undef, 1, 'Nothing could be read from TCP-Channel (the second level) even though the Read-Function was called. The client is now directed to shutdown and the connection should be re-initialized...';
|
||||||
|
|
||||||
# Verbindung beenden, damit der SubProzess die Chance hat neu initialisiert zu werden...
|
# Verbindung beenden, damit der SubProzess die Chance hat neu initialisiert zu werden...
|
||||||
@ -1010,6 +1094,7 @@ sub SONOS_Read($) {
|
|||||||
# Neu anstarten...
|
# Neu anstarten...
|
||||||
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName}) if ($SONOS_StartedOwnUPnPServer);
|
SONOS_StartClientProcessIfNeccessary($hash->{DeviceName}) if ($SONOS_StartedOwnUPnPServer);
|
||||||
InternalTimer(gettimeofday() + $hash->{WAITTIME}, 'SONOS_DelayOpenDev', $hash, 0);
|
InternalTimer(gettimeofday() + $hash->{WAITTIME}, 'SONOS_DelayOpenDev', $hash, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1292,12 +1377,10 @@ sub SONOS_Read($) {
|
|||||||
|
|
||||||
my $srcURI = '';
|
my $srcURI = '';
|
||||||
if (defined($tempURI) && $tempURI ne '') {
|
if (defined($tempURI) && $tempURI ne '') {
|
||||||
if ($tempURI =~ m/getaa.*?x-sonos-spotify.*?(spotify.*)%3f/i) {
|
if ($tempURI =~ m/getaa.*?x-sonos-spotify%3aspotify%3atrack%3a(.*)%3f/i) {
|
||||||
my $infos = get('https://embed.spotify.com/oembed/?url='.$1);
|
my $infos = SONOS_getSpotifyCoverURL($1);
|
||||||
|
if ($infos ne '') {
|
||||||
if ($infos =~ m/"thumbnail_url":"(.*?)cover(.*?)"/i) {
|
$srcURI = $infos;
|
||||||
$srcURI = $1.'original'.$2;
|
|
||||||
$srcURI =~ s/\\//g;
|
|
||||||
$currentValue = $attr{global}{modpath}.'/www/images/default/SONOSPLAYER/'.$name.'_'.$nextName.'AlbumArt.jpg';
|
$currentValue = $attr{global}{modpath}.'/www/images/default/SONOSPLAYER/'.$name.'_'.$nextName.'AlbumArt.jpg';
|
||||||
SONOS_Log undef, 4, "Transport-Event: Spotify-Bilder-Download: SONOS_DownloadReplaceIfChanged('$srcURI', '".$currentValue."');";
|
SONOS_Log undef, 4, "Transport-Event: Spotify-Bilder-Download: SONOS_DownloadReplaceIfChanged('$srcURI', '".$currentValue."');";
|
||||||
} else {
|
} else {
|
||||||
@ -1473,7 +1556,8 @@ sub SONOS_StartClientProcessIfNeccessary($) {
|
|||||||
my $verboselevel = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'verbose', $attr{global}{verbose});
|
my $verboselevel = AttrVal(SONOS_getDeviceDefHash(undef)->{NAME}, 'verbose', $attr{global}{verbose});
|
||||||
|
|
||||||
# Prozess anstarten...
|
# Prozess anstarten...
|
||||||
exec('perl '.substr($0, 0, -7).'FHEM/00_SONOS.pm '.$port.' '.$verboselevel.' '.(($attr{global}{mseclog}) ? '1' : '0'));
|
# exec('perl '.substr($0, 0, -7).'FHEM/00_SONOS.pm '.$port.' '.$verboselevel.' '.(($attr{global}{mseclog}) ? '1' : '0'));
|
||||||
|
exec("$^X $attr{global}{modpath}/FHEM/00_SONOS.pm $port $verboselevel ".(($attr{global}{mseclog}) ? '1' : '0'));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1603,6 +1687,8 @@ sub SONOS_InitClientProcess($) {
|
|||||||
sub SONOS_IsSubprocessAliveChecker() {
|
sub SONOS_IsSubprocessAliveChecker() {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
return undef if (AttrVal($hash->{NAME}, 'disable', 0));
|
||||||
|
|
||||||
my $answer;
|
my $answer;
|
||||||
my $socket = new IO::Socket::INET(PeerAddr => $hash->{DeviceName}, Proto => 'tcp');
|
my $socket = new IO::Socket::INET(PeerAddr => $hash->{DeviceName}, Proto => 'tcp');
|
||||||
if ($socket) {
|
if ($socket) {
|
||||||
@ -2454,7 +2540,7 @@ sub SONOS_Discover() {
|
|||||||
|
|
||||||
if (SONOS_CheckProxyObject($udn, $SONOS_AVTransportControlProxy{$udn})) {
|
if (SONOS_CheckProxyObject($udn, $SONOS_AVTransportControlProxy{$udn})) {
|
||||||
# Entscheiden, ob eine Abspielliste geladen und gestartet werden soll, oder etwas direkt abgespielt werden kann
|
# Entscheiden, ob eine Abspielliste geladen und gestartet werden soll, oder etwas direkt abgespielt werden kann
|
||||||
if ($resultHash{$favouriteName}{METADATA} =~ m/<upnp:class>object.container.playlistContainer<\/upnp:class>/i) {
|
if ($resultHash{$favouriteName}{METADATA} =~ m/<upnp:class>object.container.(playlistContainer|album.musicAlbum)<\/upnp:class>/i) {
|
||||||
|
|
||||||
SONOS_Log $udn, 5, 'StartFavourite AddToQueue-Res: "'.$resultHash{$favouriteName}{RES}.'", -Meta: "'.$resultHash{$favouriteName}{METADATA}.'"';
|
SONOS_Log $udn, 5, 'StartFavourite AddToQueue-Res: "'.$resultHash{$favouriteName}{RES}.'", -Meta: "'.$resultHash{$favouriteName}{METADATA}.'"';
|
||||||
|
|
||||||
@ -3069,15 +3155,31 @@ sub SONOS_Discover() {
|
|||||||
sub SONOS_MakeCoverURL($$) {
|
sub SONOS_MakeCoverURL($$) {
|
||||||
my ($udn, $resURL) = @_;
|
my ($udn, $resURL) = @_;
|
||||||
|
|
||||||
if ($resURL =~ m/^(x-rincon-cpcontainer|x-sonos-spotify).*?(spotify.*?)(\?|$)/i) {
|
SONOS_Log $udn, 5, 'MakeCoverURL-Before: '.$resURL;
|
||||||
my $infos = get('https://embed.spotify.com/oembed/?url='.$2);
|
|
||||||
|
|
||||||
if ($infos =~ m/"thumbnail_url":"(.*?)cover(.*?)"/i) {
|
if ($resURL =~ m/^x-rincon-cpcontainer.*?(spotify.*?)(\?|$)/i) {
|
||||||
$resURL = $1.'original'.$2;
|
$resURL = SONOS_getSpotifyCoverURL($1, 1);
|
||||||
$resURL =~ s/\\//g;
|
} elsif ($resURL =~ m/^x-sonos-spotify:spotify%3atrack%3a(.*?)(\?|$)/i) {
|
||||||
}
|
$resURL = SONOS_getSpotifyCoverURL($1);
|
||||||
} elsif($resURL =~ m/savedqueues/i) {
|
} elsif (($resURL =~ m/x-rincon-playlist:.*?#(.*)/i) || ($resURL =~ m/savedqueues.rsq(#\d+)/i)) {
|
||||||
|
my $search = $1;
|
||||||
|
$search = 'SQ:'.$1 if ($search =~ m/#(\d+)/i);
|
||||||
|
|
||||||
|
# Default, if nothing could be retreived...
|
||||||
$resURL = '/fhem/sonos/cover/playlist.jpg';
|
$resURL = '/fhem/sonos/cover/playlist.jpg';
|
||||||
|
|
||||||
|
if (SONOS_CheckProxyObject($udn, $SONOS_ContentDirectoryControlProxy{$udn})) {
|
||||||
|
my $result = $SONOS_ContentDirectoryControlProxy{$udn}->Browse($search, 'BrowseDirectChildren', '', 0, 5, '');
|
||||||
|
if ($result) {
|
||||||
|
my $tmp = $result->getValue('Result');
|
||||||
|
|
||||||
|
if (defined($tmp) && $tmp =~ m/<item id=".+?".*?>.*?<upnp:albumArtURI>(.*?)<\/upnp:albumArtURI>.*?<\/item>/i) {
|
||||||
|
$resURL = $1;
|
||||||
|
|
||||||
|
$resURL = $1.$resURL if (SONOS_Client_Data_Retreive($udn, 'reading', 'location', '') =~ m/^(http:\/\/.*?:.*?)\//i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
my $stream = 0;
|
my $stream = 0;
|
||||||
$stream = 1 if ($resURL =~ /x-sonosapi-stream/);
|
$stream = 1 if ($resURL =~ /x-sonosapi-stream/);
|
||||||
@ -3087,9 +3189,40 @@ sub SONOS_MakeCoverURL($$) {
|
|||||||
# Alles über Fhem als Proxy laufen lassen?
|
# Alles über Fhem als Proxy laufen lassen?
|
||||||
$resURL = '/fhem/sonos/proxy/aa?url='.uri_escape($resURL) if (($resURL !~ m/^\//) && SONOS_Client_Data_Retreive('undef', 'attr', 'generateProxyAlbumArtURLs', 0));
|
$resURL = '/fhem/sonos/proxy/aa?url='.uri_escape($resURL) if (($resURL !~ m/^\//) && SONOS_Client_Data_Retreive('undef', 'attr', 'generateProxyAlbumArtURLs', 0));
|
||||||
|
|
||||||
|
SONOS_Log $udn, 5, 'MakeCoverURL-After: '.$resURL;
|
||||||
|
|
||||||
return $resURL;
|
return $resURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
########################################################################################
|
||||||
|
#
|
||||||
|
# SONOS_getSpotifyCoverURL - Generates the approbriate cover-url for Spotify-Cover
|
||||||
|
#
|
||||||
|
########################################################################################
|
||||||
|
sub SONOS_getSpotifyCoverURL($;$) {
|
||||||
|
my ($trackID, $oldStyle) = @_;
|
||||||
|
$oldStyle = 0 if (!defined($oldStyle));
|
||||||
|
|
||||||
|
my $infos = '';
|
||||||
|
if ($oldStyle) {
|
||||||
|
$infos = $1 if (get('https://embed.spotify.com/oembed/?url='.$trackID) =~ m/"thumbnail_url":"(.*?)"/i);
|
||||||
|
} else {
|
||||||
|
$infos = $1 if (get('https://api.spotify.com/v1/tracks/'.$trackID) =~ m/"images".*?:.*?\[.*?{.*?"height".*?:.*?640,.*?"url".*?:.*?"(.*?)",.*?"width"/is);
|
||||||
|
}
|
||||||
|
|
||||||
|
$infos =~ s/\\//g;
|
||||||
|
$infos = $1.'original'.$3 if ($infos =~ m/(.*?\/)(cover|default)(\/.*)/i);
|
||||||
|
|
||||||
|
# Falls es ein Standardcover von Spotify geben soll, lieber das Thumbnail von Sonos verwenden...
|
||||||
|
return '' if ($infos =~ m/\/static\/img\/defaultCoverL.png/i);
|
||||||
|
|
||||||
|
if ($infos ne '') {
|
||||||
|
return $infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
#
|
#
|
||||||
# SONOS_GetSpeakFileExtension - Retrieves the desired fileextension
|
# SONOS_GetSpeakFileExtension - Retrieves the desired fileextension
|
||||||
@ -4065,13 +4198,24 @@ sub SONOS_Discover_Callback($$$) {
|
|||||||
|
|
||||||
$master = !$invisible || $isZoneBridge;
|
$master = !$invisible || $isZoneBridge;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Für den Aliasnamen schöne Bezeichnungen ermitteln...
|
||||||
|
my $aliasSuffix = '';
|
||||||
|
$aliasSuffix = ' - Hinten Links' if ($topoType eq '_LR');
|
||||||
|
$aliasSuffix = ' - Hinten Rechts' if ($topoType eq '_RR');
|
||||||
|
$aliasSuffix = ' - Links' if ($topoType eq '_LF');
|
||||||
|
$aliasSuffix = ' - Rechts' if ($topoType eq '_RF');
|
||||||
|
$aliasSuffix = ' - Subwoofer' if ($topoType eq '_SW');
|
||||||
|
$aliasSuffix = ' - Mitte' if ($topoType eq '_LF_RF');
|
||||||
|
|
||||||
# Wenn der aktuelle Player der Master ist, dann kein Kürzel anhängen,
|
# 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
|
# damit gibt es immer einen Player, der den Raumnamen trägt, und die anderen enthalten Kürzel
|
||||||
if ($master) {
|
if ($master) {
|
||||||
$topoType = '';
|
$topoType = '';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
# Raumnamen erweitern
|
||||||
$name .= $topoType;
|
$name .= $topoType;
|
||||||
$saveRoomName .= $topoType;
|
$saveRoomName .= $topoType;
|
||||||
|
|
||||||
@ -4124,7 +4268,7 @@ sub SONOS_Discover_Callback($$$) {
|
|||||||
# Define SonosPlayer-Device with attributes
|
# Define SonosPlayer-Device with attributes
|
||||||
SONOS_Client_Notifier('CommandDefine:'.$name.' SONOSPLAYER '.$udn);
|
SONOS_Client_Notifier('CommandDefine:'.$name.' SONOSPLAYER '.$udn);
|
||||||
SONOS_Client_Notifier('CommandAttr:'.$name.' room '.$SONOS_Client_Data{SonosDeviceName});
|
SONOS_Client_Notifier('CommandAttr:'.$name.' room '.$SONOS_Client_Data{SonosDeviceName});
|
||||||
SONOS_Client_Notifier('CommandAttr:'.$name.' alias '.$roomName);
|
SONOS_Client_Notifier('CommandAttr:'.$name.' alias '.$roomName.$aliasSuffix);
|
||||||
SONOS_Client_Notifier('CommandAttr:'.$name.' group '.$groupName);
|
SONOS_Client_Notifier('CommandAttr:'.$name.' group '.$groupName);
|
||||||
SONOS_Client_Notifier('CommandAttr:'.$name.' icon '.$iconPath);
|
SONOS_Client_Notifier('CommandAttr:'.$name.' icon '.$iconPath);
|
||||||
SONOS_Client_Notifier('CommandAttr:'.$name.' sortby 1');
|
SONOS_Client_Notifier('CommandAttr:'.$name.' sortby 1');
|
||||||
@ -6174,7 +6318,7 @@ if (defined($SONOS_ListenPort)) {
|
|||||||
my ($port, $iaddr) = sockaddr_in($addrinfo);
|
my ($port, $iaddr) = sockaddr_in($addrinfo);
|
||||||
my $name = gethostbyaddr($iaddr, AF_INET);
|
my $name = gethostbyaddr($iaddr, AF_INET);
|
||||||
|
|
||||||
SONOS_Log undef, 1, "Connection accepted from $name:$port";
|
SONOS_Log undef, 3, "Connection accepted from $name:$port";
|
||||||
|
|
||||||
# Von dort kommt die Anfrage, dort finde ich den Telnet-Port von Fhem :-)
|
# Von dort kommt die Anfrage, dort finde ich den Telnet-Port von Fhem :-)
|
||||||
$SONOS_UseTelnetForQuestions_Host = $name;
|
$SONOS_UseTelnetForQuestions_Host = $name;
|
||||||
@ -6663,7 +6807,7 @@ You can start this client on your own (to let it run instantly and independent f
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSdefine"></a>
|
<a name="SONOSdefine"></a>
|
||||||
<h4>Define</h4>
|
<h4>Define</h4>
|
||||||
<code>define <name> SONOS [upnplistener] [[[interval] waittime] delaytime]</code>
|
<code>define <name> SONOS [upnplistener [interval [waittime [delaytime]]]]</code>
|
||||||
<br /><br /> Define a Sonos interface to communicate with a Sonos-System.<br />
|
<br /><br /> Define a Sonos interface to communicate with a Sonos-System.<br />
|
||||||
<p>
|
<p>
|
||||||
<code>[upnplistener]</code><br />The name and port of the external upnp-listener. If not given, defaults to <code>localhost:4711</code>. The port has to be a free portnumber on your system. If you don't start a server on your own, the script does itself.<br />If you start it yourself write down the correct informations to connect.</p>
|
<code>[upnplistener]</code><br />The name and port of the external upnp-listener. If not given, defaults to <code>localhost:4711</code>. The port has to be a free portnumber on your system. If you don't start a server on your own, the script does itself.<br />If you start it yourself write down the correct informations to connect.</p>
|
||||||
@ -6712,10 +6856,13 @@ The order in the sublists are important, because the first entry defines the so-
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSattr"></a>
|
<a name="SONOSattr"></a>
|
||||||
<h4>Attributes</h4>
|
<h4>Attributes</h4>
|
||||||
|
'''Attention'''<br />The most of the attributes can only be used after a restart of fhem, because it must be initially transfered to the subprocess.
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Common</b><ul>
|
<li><b>Common</b><ul>
|
||||||
<li><a name="SONOS_attribut_characterDecoding"><code>attr <name> characterDecoding <codingname></code>
|
<li><a name="SONOS_attribut_characterDecoding"><code>attr <name> characterDecoding <codingname></code>
|
||||||
</a><br />With this attribute you can define a character-decoding-class. E.g. <UTF-8>. Default is <CP-1252>.</li>
|
</a><br />With this attribute you can define a character-decoding-class. E.g. <UTF-8>. Default is <CP-1252>.</li>
|
||||||
|
<li><a name="SONOS_attribut_disable"><code>attr <name> disable <value></code>
|
||||||
|
</a><br />One of (0,1). With this value you can disable the whole module. Works immediatly. If set to 1 the subprocess will be terminated and no message will be transmitted. If set to 0 the subprocess is again startet.<br />It is useful when you install new Sonos-Components and don't want any disgusting devices during the Sonos setup.</li>
|
||||||
<li><a name="SONOS_attribut_pingType"><code>attr <name> pingType <string></code>
|
<li><a name="SONOS_attribut_pingType"><code>attr <name> pingType <string></code>
|
||||||
</a><br /> One of (none,tcp,udp,icmp,syn). Defines which pingType for alive-Checking has to be used. If set to 'none' no checks will be done.</li>
|
</a><br /> One of (none,tcp,udp,icmp,syn). Defines which pingType for alive-Checking has to be used. If set to 'none' no checks will be done.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
@ -6788,7 +6935,7 @@ Man kann den Server unabhängig von FHEM selbst starten (um ihn dauerhaft und un
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSdefine"></a>
|
<a name="SONOSdefine"></a>
|
||||||
<h4>Definition</h4>
|
<h4>Definition</h4>
|
||||||
<code>define <name> SONOS [upnplistener] [[[interval] waittime] delaytime]</code>
|
<code>define <name> SONOS [upnplistener [interval [waittime [delaytime]]]]</code>
|
||||||
<br /><br /> Definiert das Sonos interface für die Kommunikation mit dem Sonos-System.<br />
|
<br /><br /> Definiert das Sonos interface für die Kommunikation mit dem Sonos-System.<br />
|
||||||
<p>
|
<p>
|
||||||
<code>[upnplistener]</code><br />Name und Port eines externen UPnP-Client. Wenn nicht angegebenen wird <code>localhost:4711</code> festgelegt. Der Port muss eine freie Portnummer ihres Systems sein. <br />Wenn sie keinen externen Client gestartet haben, startet das Skript einen eigenen.<br />Wenn sie einen eigenen Dienst gestartet haben, dann geben sie hier die entsprechenden Informationen an.</p>
|
<code>[upnplistener]</code><br />Name und Port eines externen UPnP-Client. Wenn nicht angegebenen wird <code>localhost:4711</code> festgelegt. Der Port muss eine freie Portnummer ihres Systems sein. <br />Wenn sie keinen externen Client gestartet haben, startet das Skript einen eigenen.<br />Wenn sie einen eigenen Dienst gestartet haben, dann geben sie hier die entsprechenden Informationen an.</p>
|
||||||
@ -6837,12 +6984,15 @@ Dabei ist die Reihenfolge innerhalb der Unterlisten wichtig, da der erste Eintra
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSattr"></a>
|
<a name="SONOSattr"></a>
|
||||||
<h4>Attribute</h4>
|
<h4>Attribute</h4>
|
||||||
|
'''Hinweis'''<br />Die Attribute werden erst bei einem Neustart von Fhem verwendet, da diese dem SubProzess initial zur Verfügung gestellt werden müssen.
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Grundsätzliches</b><ul>
|
<li><b>Grundsätzliches</b><ul>
|
||||||
<li><a name="SONOS_attribut_characterDecoding"><code>attr <name> characterDecoding <codingname></code>
|
<li><a name="SONOS_attribut_characterDecoding"><code>attr <name> characterDecoding <codingname></code>
|
||||||
</a><br />Hiermit kann die Zeichendekodierung eingestellt werden. Z.b. <UTF-8>. Standardmäßig wird <CP-1252> verwendet.</li>
|
</a><br />Hiermit kann die Zeichendekodierung eingestellt werden. Z.b. <UTF-8>. Standardmäßig wird <CP-1252> verwendet.</li>
|
||||||
|
<li><a name="SONOS_attribut_disable"><code>attr <name> disable <value></code>
|
||||||
|
</a><br />Eines von (0,1). Hiermit kann das Modul abgeschaltet werden. Wirkt sofort. Bei 1 wird der SubProzess beendet, und somit keine weitere Verarbeitung durchgeführt. Bei 0 wird der Prozess wieder gestartet.<br />Damit kann das Modul temporär abgeschaltet werden, um bei der Neueinrichtung von Sonos-Komponenten keine halben Zustände mitzubekommen.</li>
|
||||||
<li><a name="SONOS_attribut_pingType"><code>attr <name> pingType <string></code>
|
<li><a name="SONOS_attribut_pingType"><code>attr <name> pingType <string></code>
|
||||||
</a><br /> One of (none,tcp,udp,icmp,syn). Gibt an, welche Methode für die Ping-Überprüfung verwendet werden soll. Wenn 'none' angegeben wird, dann wird keine Überprüfung gestartet.</li>
|
</a><br /> Eines von (none,tcp,udp,icmp,syn). Gibt an, welche Methode für die Ping-Überprüfung verwendet werden soll. Wenn 'none' angegeben wird, dann wird keine Überprüfung gestartet.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li><b>Proxy-Einstellungen</b><ul>
|
<li><b>Proxy-Einstellungen</b><ul>
|
||||||
<li><a name="SONOS_attribut_generateProxyAlbumArtURLs"><code>attr <name> generateProxyAlbumArtURLs <int></code>
|
<li><a name="SONOS_attribut_generateProxyAlbumArtURLs"><code>attr <name> generateProxyAlbumArtURLs <int></code>
|
||||||
|
@ -181,7 +181,7 @@ sub SONOSPLAYER_Initialize ($) {
|
|||||||
$hash->{StateFn} = "SONOSPLAYER_State";
|
$hash->{StateFn} = "SONOSPLAYER_State";
|
||||||
$hash->{NotifyFn} = 'SONOSPLAYER_Notify';
|
$hash->{NotifyFn} = 'SONOSPLAYER_Notify';
|
||||||
|
|
||||||
$hash->{AttrList}= "disable:0,1 generateVolumeSlider:0,1 generateVolumeEvent:0,1 generateSomethingChangedEvent:0,1 generateInfoSummarize1 generateInfoSummarize2 generateInfoSummarize3 generateInfoSummarize4 stateVariable:TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,CrossfadeMode,Balance,HeadphoneConnected,SleepTimer,Presence,RoomName,SaveRoomName,PlayerType,Location,SoftwareRevision,SerialNum,InfoSummarize1,InfoSummarize2,InfoSummarize3,InfoSummarize4 model minVolume maxVolume minVolumeHeadphone maxVolumeHeadphone VolumeStep getAlarms:0,1 buttonEvents ".$readingFnAttributes;
|
$hash->{AttrList}= "disable:1,0 generateVolumeSlider:1,0 generateVolumeEvent:1,0 generateSomethingChangedEvent:1,0 generateInfoSummarize1 generateInfoSummarize2 generateInfoSummarize3 generateInfoSummarize4 stateVariable:TransportState,NumberOfTracks,Track,TrackURI,TrackDuration,Title,Artist,Album,OriginalTrackNumber,AlbumArtist,Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,nextTitle,nextArtist,nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,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 ".$readingFnAttributes;
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -648,7 +648,13 @@ sub SONOSPLAYER_Set($@) {
|
|||||||
for(my $i = 4; $i < @a; $i++) {
|
for(my $i = 4; $i < @a; $i++) {
|
||||||
$text .= ' '.$a[$i];
|
$text .= ' '.$a[$i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $sonosName = SONOS_getDeviceDefHash(undef)->{NAME};
|
||||||
|
if ((ReadingsVal($sonosName, 'targetSpeakDir', '') eq '') || (ReadingsVal($sonosName, 'targetSpeakURL', '') eq '')) {
|
||||||
|
return $key.' not possible. Please define valid "targetSpeakDir" and "targetSpeakURL" for Device "'.$sonosName.'" first.';
|
||||||
|
} else {
|
||||||
SONOS_DoWork($udn, lc($key), $value, $value2, $text);
|
SONOS_DoWork($udn, lc($key), $value, $value2, $text);
|
||||||
|
}
|
||||||
} elsif (lc($key) eq 'alarm') {
|
} elsif (lc($key) eq 'alarm') {
|
||||||
# Hier die komplette restliche Zeile in den zweiten Parameter packen, da damit auch Leerzeichen möglich sind
|
# Hier die komplette restliche Zeile in den zweiten Parameter packen, da damit auch Leerzeichen möglich sind
|
||||||
my $text = '';
|
my $text = '';
|
||||||
@ -1082,6 +1088,7 @@ sub SONOSPLAYER_Log($$$) {
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSPLAYERattr"></a>
|
<a name="SONOSPLAYERattr"></a>
|
||||||
<h4>Attributes</h4>
|
<h4>Attributes</h4>
|
||||||
|
'''Attention'''<br />The attributes can only be used after a restart of fhem, because it must be initially transfered to the subprocess.
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Common</b><ul>
|
<li><b>Common</b><ul>
|
||||||
<li><a name="SONOSPLAYER_attribut_disable"><code>attr <name> disable <int></code>
|
<li><a name="SONOSPLAYER_attribut_disable"><code>attr <name> disable <int></code>
|
||||||
@ -1361,6 +1368,7 @@ Here an event is defined, where in time of 2 seconds the Mute-Button has to be p
|
|||||||
<br />
|
<br />
|
||||||
<a name="SONOSPLAYERattr"></a>
|
<a name="SONOSPLAYERattr"></a>
|
||||||
<h4>Attribute</h4>
|
<h4>Attribute</h4>
|
||||||
|
'''Hinweis'''<br />Die Attribute werden erst bei einem Neustart von Fhem verwendet, da diese dem SubProzess initial zur Verfügung gestellt werden müssen.
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Grundsätzliches</b><ul>
|
<li><b>Grundsätzliches</b><ul>
|
||||||
<li><a name="SONOSPLAYER_attribut_disable"><code>attr <name> disable <int></code>
|
<li><a name="SONOSPLAYER_attribut_disable"><code>attr <name> disable <int></code>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user