diff --git a/contrib/98_SB_PLAYER.pm b/contrib/98_SB_PLAYER.pm index dc5b6c6ee..48d9a53cf 100644 --- a/contrib/98_SB_PLAYER.pm +++ b/contrib/98_SB_PLAYER.pm @@ -64,6 +64,7 @@ use constant { true => 1, false => 0 }; sub SB_PLAYER_SonginfoHandleQueue($); # CD 0075 sub SB_PLAYER_RemoveInternalTimers($); # CD 0078 sub SB_PLAYER_ftuiMedialist($); # CD 0082 +sub SB_PLAYER_TTSLogPlayerState($$); # CD 0097 # the list of favorites # CD 0010 moved to $hash->{helper}{SB_PLAYER_Favs}, fixes problem on module reload @@ -110,7 +111,7 @@ my %ttsstates = ( 0 =>'idle', 80 =>'stopped', 90 =>'restore state', 100 =>'sync', - 1000=>'active', + 1000=>'active (sync group)', 2004=>'Text2Speech busy, waiting', 2006=>'Text2Speech active'); @@ -175,6 +176,8 @@ sub SB_PLAYER_Initialize( $ ) { $hash->{AttrList} .= "statusRequestInterval "; # CD 0037 $hash->{AttrList} .= "syncedNamesSource:LMS,FHEM "; # CD 0055 $hash->{AttrList} .= "ftuiSupport:multiple-strict,1,0,medialist,favorites,playlists "; # CD 0065 neu # CD 0086 Auswahl hinzugefügt + $hash->{AttrList} .= "amplifierMode:exclusive,shared "; # CD 0088 + $hash->{AttrList} .= "disable:0,1 "; # CD 0091 $hash->{AttrList} .= $readingFnAttributes; # CD 0036 aus 37_sonosBookmarker @@ -195,6 +198,7 @@ sub SB_PLAYER_Attr( @ ) { Log( 4, "SB_PLAYER_Attr($name): called with @args" ); if( $args[ 0 ] eq "syncVolume" ) { + return "$name: device is disabled, setting syncVolume is not possible" if(IsDisabled($name)); # CD 0091 if( $cmd eq "set" ) { if (defined($args[1])) { if($args[1] eq "1") { @@ -215,7 +219,7 @@ sub SB_PLAYER_Attr( @ ) { InternalTimer( gettimeofday() + 0.01, "SB_PLAYER_tcb_DelayAmplifier", # CD 0014 Name geändert "DelayAmplifier:$name", - 0 ); + 0 ) unless(IsDisabled($name)); # CD 0091 bei disable Timer nicht starten } # CD 0043 start elsif( $args[ 0 ] eq "amplifierDelayOff" ) { @@ -298,7 +302,7 @@ sub SB_PLAYER_Attr( @ ) { InternalTimer( gettimeofday() + $args[1], "SB_PLAYER_GetStatus", $hash, - 0 ) if $args[1]>0; + 0 ) if (($args[1]>0) && !IsDisabled($name)); } else { return "missing value for statusRequestInterval"; } @@ -306,12 +310,12 @@ sub SB_PLAYER_Attr( @ ) { InternalTimer( gettimeofday() + 5, "SB_PLAYER_GetStatus", $hash, - 0 ); + 0 ) unless(IsDisabled($name)); # CD 0091 bei disable Timer nicht starten } } # CD 0055 start elsif( $args[ 0 ] eq "syncedNamesSource" ) { - IOWrite( $hash, "$hash->{PLAYERMAC} status 0 500 tags:Kcu\n" ) if ($init_done>0); + IOWrite( $hash, "$hash->{PLAYERMAC} status 0 500 tags:Kcu\n" ) if (($init_done>0) && !IsDisabled($name)); } # CD 0055 end # CD 0064 start @@ -322,7 +326,7 @@ sub SB_PLAYER_Attr( @ ) { InternalTimer( gettimeofday() + $args[1], "SB_PLAYER_tcb_QueryElapsedTime", "QueryElapsedTime:$name", - 0 ); + 0 ) unless(IsDisabled($name)); # CD 0091 bei disable Timer nicht starten } } } @@ -343,10 +347,31 @@ sub SB_PLAYER_Attr( @ ) { } } # CD 0064 end + # CD 0091 start + elsif( $args[ 0 ] eq "disable" ) { + if( $cmd eq "set" ) { + if( $args[1] eq "0" ) { + InternalTimer( gettimeofday() + 0.01, + "SB_PLAYER_GetStatus", + $hash, + 0 ); + } else { + SB_PLAYER_RemoveInternalTimers($hash); + } + } else { + InternalTimer( gettimeofday() + 0.01, + "SB_PLAYER_GetStatus", + $hash, + 0 ); + } + } + # CD 0091 end # CD 0065 start elsif( $args[ 0 ] eq "ftuiSupport" ) { my $dodelete=0; + return "$name: device is disabled, changing ftuiSupport is not possible" if(IsDisabled($name)); # CD 0091 + if( $cmd eq "set" ) { # CD 0086 Readings einzeln aktivierbar my @options=split(',',$args[1]); @@ -453,10 +478,15 @@ sub SB_PLAYER_Define( $$ ) { # the MAC adress is valid $hash->{PLAYERMAC} = lc($a[ 0 ]); # CD 0026 lc added } else { - my $msg = "SB_PLAYER_Define: playerid ist keine MAC Adresse " . - "im Format xx:xx:xx:xx:xx:xx oder xx-xx-xx-xx-xx-xx"; - Log3( $hash, 1, $msg ); - return( $msg ); + # CD 0089 auf IP-Adresse prüfen + if( SB_PLAYER_IsValidIPV4( $a[ 0] ) == 1 ) { + $hash->{PLAYERMAC} = $a[ 0 ]; + } else { + my $msg = "SB_PLAYER_Define: playerid ist keine MAC Adresse " . + "im Format xx:xx:xx:xx:xx:xx oder xx-xx-xx-xx-xx-xx"; + Log3( $hash, 1, $msg ); + return( $msg ); + } } # shift the MAC away @@ -735,6 +765,7 @@ sub SB_PLAYER_Define( $$ ) { $hash->{helper}{amplifierDelayOffPower}=0; # CD 0043 $hash->{helper}{amplifierDelayOffPause}=0; # CD 0043 $hash->{helper}{lmsvolume}=0; # CD 0065 + $hash->{helper}{amplifierLastStatus}='x'; # CD 0087 } $hash->{helper}{songinfoquery}=''; # CD 0084 @@ -747,17 +778,41 @@ sub SB_PLAYER_Define( $$ ) { $hash, 0 ); + # CD 0091 statusRequest beim Server auslösen damit Favoriten und Wiedergabelisten übertragen werden + InternalTimer( gettimeofday() + 15, + "SB_PLAYER_tcb_ServerStatusRequest", + "ServerStatusRequest:$name", + 0 ); + notifyRegexpChanged($hash, "global"); # CD 0080 return( undef ); } +# CD 0091 start +sub SB_PLAYER_tcb_ServerStatusRequest($) { + my($in ) = shift; + my(undef,$name) = split(':',$in); + my $hash = $defs{$name}; + + return if(IsDisabled($name)); + + if (defined($hash->{IODev}) && defined($hash->{IODev}->{NAME})) { + if(ReadingsVal($hash->{IODev}->{NAME},'state','x') eq 'opened') { + fhem('set '.($hash->{IODev}->{NAME}).' statusRequest'); + } + } +} +# CD 0091 end + # CD 0002 start sub SB_PLAYER_tcb_QueryCoverArt($) { # CD 0014 Name geändert my($in ) = shift; my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + #Log 0,"delayed cover art query"; IOWrite( $hash, "$hash->{PLAYERMAC} status - 1 tags:Kcu\n" ); # CD 0030 u added to tags @@ -779,12 +834,15 @@ sub SB_PLAYER_tcb_DeleteRecallPause($) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; - delete($hash->{helper}{recallPause}); + delete($hash->{helper}{recallPause}) if (defined($hash->{helper}{recallPause})); + delete($hash->{helper}{pauseAfterPlay}) if (defined($hash->{helper}{pauseAfterPlay})); # CD 0095 } sub SB_PLAYER_QueryElapsedTime($) { my ($hash) = @_; + return if(IsDisabled($hash->{NAME})); # CD 0091 + my $qi=AttrVal($hash->{NAME}, "trackPositionQueryInterval", 5); # CD 0064 if(!defined($hash->{helper}{lastTimeQuery})||($hash->{helper}{lastTimeQuery}{NAME}, "trackPositionQueryInterval", 5); # CD 0064 SB_PLAYER_QueryElapsedTime($hash); @@ -820,13 +880,15 @@ sub SB_PLAYER_tcb_TTSRestore( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + # CD 0033 start if(defined($hash->{helper}{ttsqueue})) { SB_PLAYER_SetTTSState($hash,TTS_LOADPLAYLIST,0,0); SB_PLAYER_LoadTalk($hash); } else { # CD 0033 end - if(!defined($hash->{helper}{ttsOptions}{nosaverestore}) && !defined($hash->{helper}{sgTalkActive})) { # CD 0063 sgTalkActive hinzugefügt + if(!defined($hash->{helper}{ttsActiveOptions}{nosaverestore}) && !defined($hash->{helper}{sgTalkActive})) { # CD 0063 sgTalkActive hinzugefügt SB_PLAYER_SetTTSState($hash,TTS_RESTORE,0,0); SB_PLAYER_Recall( $hash, "xxTTSxx del" ); } else { @@ -837,6 +899,43 @@ sub SB_PLAYER_tcb_TTSRestore( $ ) { } # CD 0028 end +# CD 0091 start +# ---------------------------------------------------------------------------- +# Player ist nicht (mehr) vorhanden, aufräumen +# ---------------------------------------------------------------------------- +sub SB_PLAYER_SetPlayerAbsent( $ ) { + my ($hash) = @_; + my $name = $hash->{NAME}; + + Log3( $hash, 4, "SB_PLAYER_SetPlayerAbsent($name) called" ); + + readingsBulkUpdate( $hash, 'connected', '0' ); # CD 0091 + readingsBulkUpdate( $hash, 'presence', 'absent' ); + readingsBulkUpdate( $hash, 'state', 'off' ); + readingsBulkUpdate( $hash, 'power', 'off' ); + # CD 0074 bei disconnect playStatus und Timer zurücksetzen + readingsBulkUpdate( $hash, 'playStatus', 'stopped' ); + RemoveInternalTimer( $hash ); + RemoveInternalTimer( "QueryElapsedTime:$name"); + $hash->{WILLSLEEPIN} = '?'; # CD 0089 + delete($hash->{helper}{recallPause}) if (defined($hash->{helper}{recallPause})); # CD 0095 + delete($hash->{helper}{pauseAfterPlay}) if (defined($hash->{helper}{pauseAfterPlay})); # CD 0095 + # CD 0074 end + SB_PLAYER_Amplifier( $hash ); + # CD 0031 wenn Player während TTS verschwindet Zustand zurücksetzen + if(($hash->{helper}{ttsstate}>TTS_IDLE)&&($hash->{helper}{ttsstate}{helper}{savedPlayerState}{power}="off" if(defined($hash->{helper}{savedPlayerState})); + SB_PLAYER_SetTTSState($hash,TTS_STOP,1,0); + RemoveInternalTimer( "TTSRestore:$name"); + InternalTimer( gettimeofday() + 0.01, + 'SB_PLAYER_tcb_TTSRestore', + "TTSRestore:$name", + 0 ); + } + # CD 0031 end +} +# CD 0091 start + # ---------------------------------------------------------------------------- # called from the global dispatch if new data is available # ---------------------------------------------------------------------------- @@ -884,16 +983,26 @@ sub SB_PLAYER_Parse( $$ ) { # this line supports autocreate return( "UNDEFINED SB_PLAYER_$id SB_PLAYER $idbuf" ); } else { - # the MAC adress is not valid - Log3( undef, 3, "SB_PLAYER_Parse: the unknown ID $id is NOT " . - "a valid MAC Adress" ); - return( undef ); + # CD 0089 auf IP-Adresse prüfen + if( SB_PLAYER_IsValidIPV4( $id ) == 1 ) { + $hash->{PLAYERMAC} = $id; + Log3( undef, 3, "SB_PLAYER_Parse: the unknown ID $id is a valid " . + "IPv4 Adress" ); + # this line supports autocreate + return( "UNDEFINED SB_PLAYER_$id SB_PLAYER $id" ); + } else { + # the MAC adress is not valid + Log3( undef, 3, "SB_PLAYER_Parse: the unknown ID $id is NOT " . + "a valid MAC Adress" ); + return( undef ); + } } } # so the data is for us my $name = $hash->{NAME}; - #return "" if(IsIgnored($name)); + + return if(IsDisabled($name)); # CD 0091 Log3( $hash, 5, "SB_PLAYER_Parse: $name CMD:$cmd ARGS:@args..." ); @@ -937,7 +1046,7 @@ sub SB_PLAYER_Parse( $$ ) { } elsif( $cmd eq "play" ) { - if(!defined($hash->{helper}{recallPause})) { # CD 0014 + if(!defined($hash->{helper}{recallPause}) && !defined($hash->{helper}{pauseAfterPlay})) { # CD 0014 CD 0095 readingsBulkUpdate( $hash, "playStatus", "playing" ); SB_PLAYER_Amplifier( $hash ); } # CD 0014 @@ -960,8 +1069,24 @@ sub SB_PLAYER_Parse( $$ ) { Log3( $hash, 5, "SB_PLAYER_Parse($name): mode:$cmd args:$args[0]" ); if( $args[ 0 ] eq "play" ) { # CD 0014 start - if(defined($hash->{helper}{recallPause})) { + # CD 0095 pause muss an alle Player der Gruppe geschickt werden + if(defined($hash->{helper}{recallPause}) || defined($hash->{helper}{pauseAfterPlay})) { # CD 0095 IOWrite( $hash, "$hash->{PLAYERMAC} pause 1\n" ); + if (defined($hash->{SYNCGROUP}) && ($hash->{SYNCGROUP} ne '?') && ($hash->{SYNCMASTER} ne 'none')) { + my @pl=split(",",$hash->{SYNCGROUP}); + foreach (@pl) { + if ($hash->{PLAYERMAC} ne $_) { + IOWrite( $hash, "$_ pause 1\n" ); + } + } + } + # CD 0095 start + RemoveInternalTimer( "recallPause:$name"); + InternalTimer( gettimeofday() + 2.0, # CD 0095 Zeit eventuell nicht ausreichend bei vielen oder langsamen Playern + "SB_PLAYER_tcb_DeleteRecallPause", + "recallPause:$name", + 0 ); + # CD 0095 end } else { # CD 0014 end readingsBulkUpdate( $hash, "playStatus", "playing" ); @@ -996,6 +1121,7 @@ sub SB_PLAYER_Parse( $$ ) { } elsif( $args[ 0 ] eq "stop" ) { # CD 0028 start if($hash->{helper}{ttsstate}==TTS_PLAYING) { + RemoveInternalTimer( "TTSStopped:$name"); # CD 0091 SB_PLAYER_TTSStopped($hash); } @@ -1102,7 +1228,7 @@ sub SB_PLAYER_Parse( $$ ) { # CD 0000 end # CD 0014 start - if(defined($hash->{helper}{recallPause})) { + if(defined($hash->{helper}{recallPause}) || defined($hash->{helper}{pauseAfterPlay})) { # CD 0095 IOWrite( $hash, "$hash->{PLAYERMAC} pause 1\n" ); RemoveInternalTimer( "recallPause:$name"); InternalTimer( gettimeofday() + 0.5, @@ -1193,7 +1319,7 @@ sub SB_PLAYER_Parse( $$ ) { readingsBulkUpdate( $hash, "playlists", $pn); # CD 0021 $pn verwenden wegen Dropdown # join( "_", @args ) ); # CD 0021 deaktiviert # CD 0007 start - check if playlist == fav, 0014 removed debug info - if( defined($hash->{helper}{SB_PLAYER_Favs}{$pn}) && defined($hash->{helper}{SB_PLAYER_Favs}{$pn}{ID})) { # CD 0011 check if defined($hash->{helper}{SB_PLAYER_Favs}{$pn}) + if( defined($pn) && defined($hash->{helper}{SB_PLAYER_Favs}{$pn}) && defined($hash->{helper}{SB_PLAYER_Favs}{$pn}{ID})) { # CD 0011 check if defined($hash->{helper}{SB_PLAYER_Favs}{$pn}) # CD 0091 check if $pn is defined $hash->{FAVSELECT} = $pn; readingsBulkUpdate( $hash, "$hash->{FAVSET}", "$pn" ); } else { @@ -1240,9 +1366,13 @@ sub SB_PLAYER_Parse( $$ ) { SB_PLAYER_GetStatus( $hash ); # CD 0014 } elsif( $args[ 0 ] eq "url" ) { shift( @args ); - readingsBulkUpdate( $hash, "currentPlaylistUrl", - join( " ", @args ) ); - + # CD 0091 überprüfen ob HASH vom LMS kommt, ignorieren + my $plurl=join( " ", @args ); + if($plurl=~/HASH/) { + readingsBulkUpdate( $hash, "currentPlaylistUrl", ''); + } else { + readingsBulkUpdate( $hash, "currentPlaylistUrl", $plurl); + } } elsif( $args[ 0 ] eq "stop" ) { readingsBulkUpdate( $hash, "playStatus", "stopped" ); # CD 0012 'power off' durch 'playStatus stopped' ersetzt SB_PLAYER_Amplifier( $hash ); @@ -1305,14 +1435,16 @@ sub SB_PLAYER_Parse( $$ ) { if(defined($hash->{helper}{recallPending})) { delete($hash->{helper}{recallPending}); SB_PLAYER_SetTTSState($hash,TTS_IDLE,1,1); + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - play" ); # CD 0097 IOWrite( $hash, "$hash->{PLAYERMAC} play 300\n" ); - IOWrite( $hash, "$hash->{PLAYERMAC} time $hash->{helper}{recallPendingElapsedTime}\n" ); # CD 0047, Position setzen korrigiert + IOWrite( $hash, "$hash->{PLAYERMAC} time $hash->{helper}{recallPendingElapsedTime}\n" ) if defined($hash->{helper}{recallPendingElapsedTime}); # CD 0047, Position setzen korrigiert delete($hash->{helper}{recallPendingElapsedTime}); # CD 0047 } } elsif( $args[ 0 ] eq "loadtracks" ) { if(defined($hash->{helper}{recallPending})) { delete($hash->{helper}{recallPending}); SB_PLAYER_SetTTSState($hash,TTS_IDLE,1,1); + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - play" ); # CD 0097 IOWrite( $hash, "$hash->{PLAYERMAC} play 300\n" ); IOWrite( $hash, "$hash->{PLAYERMAC} time $hash->{helper}{recallPendingElapsedTime}\n" ); # CD 0047, Position setzen korrigiert delete($hash->{helper}{recallPendingElapsedTime}); # CD 0047 @@ -1338,8 +1470,11 @@ sub SB_PLAYER_Parse( $$ ) { } elsif( $cmd eq "connected" ) { readingsBulkUpdate( $hash, "connected", $args[ 0 ] ); - readingsBulkUpdate( $hash, "presence", "present" ); - + if($args[0] eq '1') { # CD 0092 nur bei 1 auf present setzen + readingsBulkUpdate( $hash, "presence", "present" ); + } else { + SB_PLAYER_SetPlayerAbsent($hash); # CD 0092 + } } elsif( $cmd eq "name" ) { $hash->{PLAYERNAME} = join( " ", @args ); @@ -1396,13 +1531,21 @@ sub SB_PLAYER_Parse( $$ ) { } elsif( $args[ 0 ] eq "1" ) { readingsBulkUpdate( $hash, "state", "on" ); readingsBulkUpdate( $hash, "power", "on" ); - + # CD 0091 start + if(defined($hash->{helper}{playAfterPowerOn})) { + IOWrite( $hash, "$hash->{PLAYERMAC} play ".$hash->{helper}{playAfterPowerOn}."\n" ); + delete($hash->{helper}{playAfterPowerOn}); + } + # CD 0091 end SB_PLAYER_Amplifier( $hash ); } elsif( $args[ 0 ] eq "0" ) { #readingsBulkUpdate( $hash, "presence", "absent" ); # CD 0013 deaktiviert, power sagt nichts über presence readingsBulkUpdate( $hash, "state", "off" ); readingsBulkUpdate( $hash, "power", "off" ); SB_PLAYER_Amplifier( $hash ); + $hash->{WILLSLEEPIN} = '?'; # CD 0089 + delete($hash->{helper}{recallPause}) if (defined($hash->{helper}{recallPause})); # CD 0095 + delete($hash->{helper}{pauseAfterPlay}) if (defined($hash->{helper}{pauseAfterPlay})); # CD 0095 } else { # should be "?" normally } @@ -1492,26 +1635,7 @@ sub SB_PLAYER_Parse( $$ ) { if( $args[ 0 ] eq "new" ) { # not to be handled here, should lead to a new FHEM Player } elsif( $args[ 0 ] eq "disconnect" ) { - readingsBulkUpdate( $hash, "presence", "absent" ); - readingsBulkUpdate( $hash, "state", "off" ); - readingsBulkUpdate( $hash, "power", "off" ); - # CD 0074 bei disconnect playStatus und Timer zurücksetzen - readingsBulkUpdate( $hash, "playStatus", "stopped" ); - RemoveInternalTimer( $hash ); - RemoveInternalTimer( "QueryElapsedTime:$name"); - # CD 0074 end - SB_PLAYER_Amplifier( $hash ); - # CD 0031 wenn Player während TTS verschwindet Zustand zurücksetzen - if(($hash->{helper}{ttsstate}>TTS_IDLE)&&($hash->{helper}{ttsstate}{helper}{savedPlayerState}{power}="off" if(defined($hash->{helper}{savedPlayerState})); - SB_PLAYER_SetTTSState($hash,TTS_STOP,1,0); - RemoveInternalTimer( "TTSRestore:$name"); - InternalTimer( gettimeofday() + 0.01, - "SB_PLAYER_tcb_TTSRestore", - "TTSRestore:$name", - 0 ); - } - # CD 0031 end + SB_PLAYER_SetPlayerAbsent($hash); } elsif( $args[ 0 ] eq "reconnect" ) { IOWrite( $hash, "$hash->{PLAYERMAC} status 0 500 tags:Kcu\n" ); # CD 0030 u added to tags # CD 0079 nach reconnect Status abfragen @@ -1557,8 +1681,11 @@ sub SB_PLAYER_Parse( $$ ) { #readingsBulkUpdate( $hash, "presence", "absent" ); # CD 0013 deaktiviert, power sagt nichts über presence readingsBulkUpdate( $hash, "state", "off" ); readingsBulkUpdate( $hash, "power", "off" ); + $hash->{WILLSLEEPIN} = '?'; # CD 0089 SB_PLAYER_Amplifier( $hash ); delete($hash->{helper}{playAfterPowerOn}) if(defined($hash->{helper}{playAfterPowerOn})); # CD 0030 + delete($hash->{helper}{recallPause}) if (defined($hash->{helper}{recallPause})); # CD 0095 + delete($hash->{helper}{pauseAfterPlay}) if (defined($hash->{helper}{pauseAfterPlay})); # CD 0095 # CD 0031 wenn Player während TTS ausgeschaltet wird nicht wieder einschalten if(($hash->{helper}{ttsstate}>TTS_IDLE)&&($hash->{helper}{ttsstate}{helper}{savedPlayerState}{power}="off" if(defined($hash->{helper}{savedPlayerState})); @@ -1701,6 +1828,35 @@ sub SB_PLAYER_Parse( $$ ) { $hash->{helper}{elapsedTime}{TS}=gettimeofday(); readingsBulkUpdate( $hash, "currentTrackPosition",int($args[ 0 ]+0.5)); # CD 0047 delete($hash->{helper}{saveLocked}) if (($hash->{helper}{ttsstate}==TTS_IDLE) && defined($hash->{helper}{saveLocked})); + # CD 0091 Hänger erkennen + # CD 0093 nur wenn abgespielt wird + if(ReadingsVal($name,'playStatus','x') eq 'playing') { + $hash->{helper}{elapsedTime}{last}=$args[ 0 ] unless defined($hash->{helper}{elapsedTime}{last}); + if($hash->{helper}{elapsedTime}{last} eq $args[ 0 ]) { + $hash->{helper}{elapsedTime}{count}=0 unless defined($hash->{helper}{elapsedTime}{count}); + $hash->{helper}{elapsedTime}{count}++; + if($hash->{helper}{elapsedTime}{count}>10) { + # Player noch vorhanden, Status abfragen + if(ReadingsVal($name,"presence","x") eq "present") { + Log3( $hash, 2, "SB_PLAYER_Parse($name): currentTrackPosition frozen, player present, sending status request"); + delete($hash->{helper}{disableGetStatus}) if defined($hash->{helper}{disableGetStatus}); + SB_PLAYER_GetStatus( $hash ); + $hash->{helper}{elapsedTime}{count}=0; + } + if(ReadingsVal($name,"presence","x") eq "absent") { + Log3( $hash, 2, "SB_PLAYER_Parse($name): currentTrackPosition frozen, player absent, trying to stop..."); + IOWrite( $hash, "$hash->{PLAYERMAC} stop\n" ); + $hash->{helper}{elapsedTime}{count}=0; + } + } + } else { + $hash->{helper}{elapsedTime}{count}=0; + $hash->{helper}{elapsedTime}{last}=$args[ 0 ]; + } + } else { + $hash->{helper}{elapsedTime}{count}=0; + $hash->{helper}{elapsedTime}{last}=$args[ 0 ]; + } } elsif( $cmd eq "playlist_tracks" ) { readingsBulkUpdate( $hash, "playlistTracks", $args[ 0 ] ); # CD 0014 end @@ -1752,7 +1908,7 @@ sub SB_PLAYER_Parse( $$ ) { RemoveInternalTimer( "TTSStopped:$name"); InternalTimer( gettimeofday() + 0.01, "SB_PLAYER_tcb_TTSStopped", - "TTSRestore:$name", + "TTSStopped:$name", # CD 0991 Name korrigiert 0 ); } } @@ -1768,12 +1924,14 @@ sub SB_PLAYER_Parse( $$ ) { SB_PLAYER_SetTTSState($hash,TTS_IDLE,1,0); # CD 0030 start if(defined($hash->{helper}{ttspoweroffafterstop})) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - power off" ); # CD 0097 IOWrite( $hash, "$hash->{PLAYERMAC} power 0\n" ); delete($hash->{helper}{ttspoweroffafterstop}); } # CD 0030 end # CD 0031 Lautstärke zurücksetzen if(defined($hash->{helper}{ttsRestoreVolumeAfterStop})) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - restore volume after stop" ); # CD 0097 IOWrite( $hash, "$hash->{PLAYERMAC} mixer volume ".SB_PLAYER_FHEM2LMSVolume($hash, $hash->{helper}{ttsRestoreVolumeAfterStop})."\n" ); # CD 0065 SB_PLAYER_FHEM2LMSVolume delete($hash->{helper}{ttsRestoreVolumeAfterStop}); } @@ -1851,8 +2009,24 @@ sub SB_PLAYER_Parse( $$ ) { } elsif( $_ =~ /^(url:)(.*)/ ) { $hash->{helper}{playlistInfo}{$trackid}{url}=$2; $flush=7; - } elsif( $_ =~ /^(artwork_url:)(http.*)/ ) { - $hash->{helper}{playlistInfo}{$trackid}{artwork_url}=$2; +# } elsif( $_ =~ /^(artwork_url:)(http.*)/ ) { + } elsif( $_ =~ /^(artwork_url:)(.*)/ ) { # CD 0097 urls beginnen nicht immmer mit http:// + my $url=$2; + # url beginnt mit http -> direkt übernehmen + if($url =~ /^http.*/) { + $hash->{helper}{playlistInfo}{$trackid}{artwork_url}=$url; + } elsif ($url =~ /^\/imageproxy.*/) { + # url beginnt mit /imageproxy -> Adresse vom Server hinzufügen + $hash->{helper}{playlistInfo}{$trackid}{artwork_url}="http://" . $hash->{SBSERVER} . $url; + } else { + # ... + # CD 0098 / einfügen wenn URL nicht mit / beginnt + if ($url =~ /^\//) { + $hash->{helper}{playlistInfo}{$trackid}{artwork_url}="http://" . $hash->{SBSERVER} . $url; + } else { + $hash->{helper}{playlistInfo}{$trackid}{artwork_url}="http://" . $hash->{SBSERVER} . '/' . $url; + } + } $flush=7; } elsif( $_ =~ /^(.*:)(.*)/ ) { $flush=7; @@ -1889,6 +2063,10 @@ sub SB_PLAYER_Parse( $$ ) { "ftuiMedialist:$name", 0 ); # CD 0065 end + # CD 0089 start + } elsif( $cmd eq "sleep" ) { + $hash->{WILLSLEEPIN} = int($args[0])." secs" if defined($args[ 0 ]); + # CD 0089 end } elsif( $cmd eq "NONE" ) { # we shall never end up here, as cmd=NONE is used by the server for # autocreate @@ -1921,6 +2099,8 @@ sub SB_PLAYER_tcb_ftuiMedialist( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + if(defined($hash->{helper}{ftuiSupport}{medialist})) { my $t31=time; readingsBeginUpdate( $hash ); @@ -1952,6 +2132,8 @@ sub SB_PLAYER_ftuiMedialist($) { my ($hash) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + my $wait=1; my $trackcounter=1; # CD 0082 my $coverbase="http://" . $hash->{SBSERVER} . "/music/"; @@ -2009,7 +2191,7 @@ sub SB_PLAYER_ftuiMedialist($) { } } else { $ftuimedialist.="\"Title\":\"no data\","; # CD 0076 - Log3( $hash, 3, "SB_PLAYER_Parse: $name: no songinfo for id $_" ); # CD 0072 + Log3( $hash, 4, "SB_PLAYER_Parse: $name: no songinfo for id $_" ); # CD 0072 } $ftuimedialist.="\"Album\":\"-\","; $ftuimedialist.="\"Time\":\"0\","; @@ -2051,6 +2233,8 @@ sub SB_PLAYER_tcb_TTSDelay( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + SB_PLAYER_SetTTSState($hash,TTS_WAITFORPLAY,0,0); IOWrite( $hash, "$hash->{PLAYERMAC} play\n" ); # CD 0038 Timeout hinzugefügt @@ -2072,7 +2256,10 @@ sub SB_PLAYER_tcb_TimeoutTTSWaitForPlay( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + if($hash->{helper}{ttsstate}==TTS_WAITFORPLAY) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - timeout waiting for play" ); # CD 0097 readingsBeginUpdate( $hash ); SB_PLAYER_TTSStopped($hash); if( AttrVal( $name, "donotnotify", "false" ) eq "true" ) { @@ -2091,7 +2278,10 @@ sub SB_PLAYER_tcb_TimeoutTTSWaitForPowerOn( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + if($hash->{helper}{ttsstate}==TTS_WAITFORPOWERON) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - timeout waiting for power on" ); # CD 0097 SB_PLAYER_SetTTSState($hash,TTS_IDLE,0,0); } } @@ -2106,6 +2296,8 @@ sub SB_PLAYER_tcb_TTSStopped( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + readingsBeginUpdate( $hash ); SB_PLAYER_TTSStopped($hash); @@ -2127,6 +2319,8 @@ sub SB_PLAYER_tcb_TTSStartAfterPowerOn( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + if(($hash->{helper}{playerStatusOK}==1)||($hash->{helper}{playerStatusOKCounter}>10)) { SB_PLAYER_PrepareTalk($hash); SB_PLAYER_LoadTalk($hash); @@ -2148,6 +2342,8 @@ sub SB_PLAYER_TTSStopped($) { my ($hash) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + if(defined($hash->{helper}{ttsqueue})) { SB_PLAYER_SetTTSState($hash,TTS_LOADPLAYLIST,1,0); SB_PLAYER_LoadTalk($hash); # CD 0033 @@ -2203,6 +2399,8 @@ sub SB_PLAYER_Get( $@ ) { my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + Log3( $hash, 4, "SB_PLAYER_Get: called with @a" ); if( @a < 2 ) { @@ -2286,6 +2484,8 @@ sub SB_PLAYER_tcb_StartT2STalk( $ ) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + if($hash->{helper}{ttsstate}==TTS_TEXT2SPEECH_ACTIVE) { # talk ist nicht aktiv SB_PLAYER_PrepareTalk($hash); @@ -2301,7 +2501,9 @@ sub SB_PLAYER_Notify( $$ ) { my ( $hash, $dev_hash ) = @_; my $name = $hash->{NAME}; # own name / hash my $devName = $dev_hash->{NAME}; # Device that created the events - + + return "" if(IsDisabled($name)); # CD 0091 Return without any further action if the module is disabled + if ($dev_hash->{NAME} eq "global" && grep (m/^INITIALIZED$|^REREADCFG$/,@{$dev_hash->{CHANGED}})){ # CD 0077 unbenutzte Attribute entfernen $modules{$hash->{TYPE}}{AttrList} =~ s/serverautoon.//; @@ -2369,8 +2571,6 @@ sub SB_PLAYER_Notify( $$ ) { sub SB_PLAYER_Set( $@ ) { my ( $hash, $name, $cmd, @arg ) = @_; - #my $name = $hash->{NAME}; - Log3( $hash, 5, "SB_PLAYER_Set: called with $cmd"); # check if we have received a command @@ -2433,6 +2633,8 @@ sub SB_PLAYER_Set( $@ ) { return( $res ); } + return if(IsDisabled($name)); # CD 0091 + # CD 0038 Befehle ignorieren wenn Player nicht vorhanden ist # CD 0040 wieder deaktiviert # if(ReadingsVal($name,"presence","x") ne "present") { @@ -2724,6 +2926,7 @@ sub SB_PLAYER_Set( $@ ) { my $filename; # CD 0038 if (length($ttstext)>0) { + $ttstext=~s/\|\|/\| \|/g; # CD 0091 my @words=split(' ',$ttstext); for my $w (@words) { # CD 0033 Datei ?, teilweise aus 00_SONOS übernommen @@ -2732,8 +2935,13 @@ sub SB_PLAYER_Set( $@ ) { $tl=''; $filename = $1; - $filename = $targetSpeakMP3FileDir.'/'.$filename if ($filename !~ m/^(\/|[a-z]:)/i); - $filename = $filename.'.mp3' if ($filename !~ m/\.mp3$/i); + # CD 0089 kein Dateiname sondern Optionen/Befehle + if($filename=~/^opt:(.*)/) { + + } else { + $filename = $targetSpeakMP3FileDir.'/'.$filename if ($filename !~ m/^(\/|[a-z]:)/i); + $filename = $filename.'.mp3' if ($filename !~ m/\.mp3$/i); + } push(@textlines, '|'.$filename.'|'); $filename=undef; # CD 0038 Leerzeichen in Dateinamen zulassen @@ -2745,8 +2953,13 @@ sub SB_PLAYER_Set( $@ ) { push(@textlines,$tl) if($tl ne ''); $tl=''; - $filename = $targetSpeakMP3FileDir.'/'.$filename if ($filename !~ m/^(\/|[a-z]:)/i); - $filename = $filename.'.mp3' if ($filename !~ m/\.mp3$/i); + # CD 0089 kein Dateiname sondern Optionen/Befehle + if($filename=~/^opt:(.*)/) { + + } else { + $filename = $targetSpeakMP3FileDir.'/'.$filename if ($filename !~ m/^(\/|[a-z]:)/i); + $filename = $filename.'.mp3' if ($filename !~ m/\.mp3$/i); + } push(@textlines, '|'.$filename.'|'); $filename=undef; # CD 0038 @@ -2770,6 +2983,44 @@ sub SB_PLAYER_Set( $@ ) { push(@textlines,$tl) if($tl ne ''); if($hash->{helper}{ttsstate}==TTS_IDLE) { + # CD 0091 start + delete($hash->{helper}{ttsActiveOptions}) if defined($hash->{helper}{ttsActiveOptions}); + $hash->{helper}{ttsActiveOptions}{nosaverestore}=$hash->{helper}{ttsOptions}{nosaverestore} if defined($hash->{helper}{ttsOptions}{nosaverestore}); + $hash->{helper}{ttsActiveOptions}{forcegroupon}=$hash->{helper}{ttsOptions}{forcegroupon} if defined($hash->{helper}{ttsOptions}{forcegroupon}); + $hash->{helper}{ttsActiveOptions}{ignorevolumelimit}=$hash->{helper}{ttsOptions}{ignorevolumelimit} if defined($hash->{helper}{ttsOptions}{ignorevolumelimit}); + $hash->{helper}{ttsActiveOptions}{eventondone}=$hash->{helper}{ttsOptions}{eventondone} if defined($hash->{helper}{ttsOptions}{eventondone}); + $hash->{helper}{ttsActiveOptions}{ttslanguage}=AttrVal( $name, "ttslanguage", "de" ); + $hash->{helper}{ttsActiveOptions}{volume}=ReadingsVal($name,'volume',50); + for my $outstr (@textlines) { + if (($outstr eq '|opt:nosaverestore|')||($outstr eq '|opt:nosaverestore=1|')) { + $hash->{helper}{ttsActiveOptions}{nosaverestore}=1; + } + if (($outstr eq '|opt:forcegroupon|')||($outstr eq '|opt:forcegroupon=1|')) { + $hash->{helper}{ttsActiveOptions}{forcegroupon}=1; + } + if (($outstr eq '|opt:ignorevolumelimit|')||($outstr eq '|opt:ignorevolumelimit=1|')) { + $hash->{helper}{ttsActiveOptions}{ignorevolumelimit}=1; + } + if (($outstr eq '|opt:eventondone|')||($outstr eq '|opt:eventondone=1|')) { + $hash->{helper}{ttsActiveOptions}{eventondone}=1; + } + if ($outstr eq '|opt:nosaverestore=0|') { + delete($hash->{helper}{ttsActiveOptions}{nosaverestore}) if defined($hash->{helper}{ttsActiveOptions}{nosaverestore}); + } + if ($outstr eq '|opt:forcegroupon=0|') { + delete($hash->{helper}{ttsActiveOptions}{forcegroupon}) if defined($hash->{helper}{ttsActiveOptions}{forcegroupon}); + } + if ($outstr eq '|opt:ignorevolumelimit=0|') { + delete($hash->{helper}{ttsActiveOptions}{ignorevolumelimit}) if defined($hash->{helper}{ttsActiveOptions}{ignorevolumelimit}); + } + if ($outstr eq '|opt:eventondone=0|') { + delete($hash->{helper}{ttsActiveOptions}{eventondone}) if defined($hash->{helper}{ttsActiveOptions}{eventondone}); + } + } + # CD 0091 end + + SB_PLAYER_TTSLogPlayerState($hash, 'not active, starting...'); # CD 0097 Zustand aller Player ausgeben + # talk ist nicht aktiv # CD 0038 Player zuerst einschalten if(ReadingsVal($name,"power","x") ne "on") { @@ -2797,10 +3048,25 @@ sub SB_PLAYER_Set( $@ ) { } else { } + my $lang=$hash->{helper}{ttsActiveOptions}{ttslanguage}; for my $outstr (@textlines) { if ($outstr =~ m/\|(.*)\|/) { # CD 0033 - Log3($hash, defined($hash->{helper}{ttsOptions}{debug})?0:6,"SB_PLAYER_Set: $name: add to ttsqueue: $1"); # CD 0036 - push(@{$hash->{helper}{ttsqueue}},uri_escape(decode('utf-8',$1))); # CD 0033 # CD 0038 uri_escape(decode... hinzugefügt + if($1=~m/opt:l=(.*)/) { + Log3($hash, defined($hash->{helper}{ttsOptions}{debug})?0:6,"SB_PLAYER_Set: $name: changing tts language to $1"); + $lang=$1; + $hash->{helper}{ttsActiveOptions}{ttslanguage}=$1; + } elsif($1 eq 'opt:replace') { + # CD 0091 wenn tts abgespielt wird, Playlist löschen, SB_PLAYER_LoadTalk kümmert sich um den Rest + if((($hash->{helper}{ttsstate}>=TTS_DELAY) && ($hash->{helper}{ttsstate}<=TTS_PLAYING))||($hash->{helper}{ttsstate}==TTS_SYNCGROUPACTIVE)) { + Log3($hash, defined($hash->{helper}{ttsOptions}{debug})?0:6,"SB_PLAYER_Set: $name: replacing active tts"); + IOWrite( $hash, "$hash->{PLAYERMAC} playlist clear\n" ); + } + # Queue löschen + delete($hash->{helper}{ttsqueue}) if defined($hash->{helper}{ttsqueue}); + } else { + Log3($hash, defined($hash->{helper}{ttsOptions}{debug})?0:6,"SB_PLAYER_Set: $name: add to ttsqueue: $1"); # CD 0036 + push(@{$hash->{helper}{ttsqueue}},uri_escape(decode('utf-8',$1))); # CD 0033 # CD 0038 uri_escape(decode... hinzugefügt + } } else { $outstr =~ s/\s/+/g; @@ -2817,7 +3083,6 @@ sub SB_PLAYER_Set( $@ ) { my $ttslink=AttrVal( $name, "ttslink", "" ); if(defined($ttslink)) { # Profile - my $lang=AttrVal( $name, "ttslanguage", "de" ); if ($ttslink =~ m/voicerss/i) { # CD 0047 Sprache auch bei voicerss innerhalb der URL anpassen $lang="de-de" if($lang eq "de"); $lang="en-us" if($lang eq "en"); @@ -2851,7 +3116,7 @@ sub SB_PLAYER_Set( $@ ) { } } - SB_PLAYER_LoadTalk($hash) if($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST); # CD 0033 # CD 0038 auf TTS_LOADPLAYLIST prüfen + SB_PLAYER_LoadTalk($hash) if(($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST)||($hash->{helper}{ttsstate}==TTS_SYNCGROUPACTIVE)); # CD 0033 # CD 0038 auf TTS_LOADPLAYLIST prüfen # CD 0091 auf TTS_SYNCGROUPACTIVE prüfen # CD 0028 end } elsif( ( $cmd eq "playlist" ) || @@ -2867,7 +3132,7 @@ sub SB_PLAYER_Set( $@ ) { if (@arg>1) { my $outstr = uri_escape(decode('utf-8',join( " ", @arg[1..$#arg]))); # CD 0017 - Log3( $hash, 5, "SB_PLAYER_Set($name): playlists command = $arg[ 0 ] param = $outstr" ); + Log3( $hash, 5, "SB_PLAYER_Set($name): playlist command = $arg[ 0 ] param = $outstr" ); if( $arg[ 0 ] eq "track" ) { IOWrite( $hash, "$hash->{PLAYERMAC} playlist loadtracks " . @@ -3046,6 +3311,7 @@ sub SB_PLAYER_Set( $@ ) { IOWrite( $hash, "$hash->{PLAYERMAC} sync -\n" ); # CD 0028 start if($hash->{helper}{ttsstate}==TTS_SYNCGROUPACTIVE) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - cancel tts, sync group changed" ); # CD 0097 SB_PLAYER_SetTTSState($hash,TTS_IDLE,0,0); # CD 0066 single statt bulk update } # CD 0028 end @@ -3062,7 +3328,7 @@ sub SB_PLAYER_Set( $@ ) { my $dev=$_; my $mac; # CD 0018 end - if( defined( $hash->{helper}{SB_PLAYER_SyncMasters}{$dev}{MAC} ) ) { + if( defined( $hash->{helper}{SB_PLAYER_SyncMasters}{$dev} && defined( $hash->{helper}{SB_PLAYER_SyncMasters}{$dev}{MAC} ) )) { # CD 0094 zuerst auf {$dev} prüfen $mac=$hash->{helper}{SB_PLAYER_SyncMasters}{$dev}{MAC}; } else { # CD 0038 Player nicht gefunden, testen ob Name zu einem FHEM-Gerät passt @@ -3080,10 +3346,14 @@ sub SB_PLAYER_Set( $@ ) { if((@arg == 2) && ($arg[1] eq "asSlave")) { IOWrite( $hash, "$mac sync " . "$hash->{PLAYERMAC}\n" ); + # CD 0094 nur zum Test + Log3( $hash, 2, "SB_PLAYER_Set($name): sync $dev ($mac) <- $name ($hash->{PLAYERMAC})"); } else { # CD 0038 end IOWrite( $hash, "$hash->{PLAYERMAC} sync " . "$mac\n" ); + # CD 0094 nur zum Test + Log3( $hash, 2, "SB_PLAYER_Set($name): sync $dev ($mac) -> $name ($hash->{PLAYERMAC})"); } $doGetStatus=1; } @@ -3096,11 +3366,12 @@ sub SB_PLAYER_Set( $@ ) { SB_PLAYER_GetStatus( $hash ); # CD 0028 start if($hash->{helper}{ttsstate}==TTS_SYNCGROUPACTIVE) { + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - cancel tts, sync group changed" ); # CD 0097 SB_PLAYER_SetTTSState($hash,TTS_IDLE,0,0); # CD 0066 single statt bulk update } # CD 0028 end } elsif( $cmd eq "playlists" ) { - if( @arg == 1 ) { + if(( @arg == 1 )||( @arg == 2 )) { my $msg; if( defined( $hash->{helper}{SB_PLAYER_Playlists}{$arg[0]}{ID} ) ) { if($hash->{helper}{SB_PLAYER_Playlists}{$arg[0]}{SOURCE} eq 'LMS') { # CD 0070 @@ -3113,6 +3384,11 @@ sub SB_PLAYER_Set( $@ ) { Log3( $hash, 5, "SB_PLAYER_Set($name): playlists command = " . $msg . " ........ with $arg[0]" ); IOWrite( $hash, $msg . "\n" ); + # CD 0095 Player auf stop oder pause setzen + if(defined($arg[1])) { + $hash->{helper}{pauseAfterPlay}=1 if($arg[1] eq 'paused'); + IOWrite( $hash, $hash->{PLAYERMAC} . " stop\n" ) if($arg[1] eq 'stopped'); + } readingsSingleUpdate( $hash, "playlists", "$arg[ 0 ]", 1 ); SB_PLAYER_GetStatus( $hash ); } else { @@ -3128,6 +3404,7 @@ sub SB_PLAYER_Set( $@ ) { } elsif( $cmd eq "resetTTS" ) { delete($hash->{helper}{saveLocked}) if (defined($hash->{helper}{saveLocked})); # CD 0056 delete $hash->{helper}{sgTalkActive} if defined($hash->{helper}{sgTalkActive}); # CD 0063 + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - reset tts" ); # CD 0097 SB_PLAYER_SetTTSState($hash,TTS_IDLE,0,1); # CD 0047 start } elsif( lc($cmd) eq "currenttrackposition" ) { @@ -3190,19 +3467,41 @@ sub SB_PLAYER_LoadTalk($) { my ( $hash ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + if(defined($hash->{helper}{ttsqueue})) { if(($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST)||($hash->{helper}{ttsstate}==TTS_SYNCGROUPACTIVE)) { IOWrite( $hash, "$hash->{PLAYERMAC} playlist clear\n" ) if($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST); - for (@{$hash->{helper}{ttsqueue}}) { - if($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST) { - # ich bin Master und talk ist nicht aktiv - IOWrite( $hash, "$hash->{PLAYERMAC} playlist add " . $_ . "\n" ); - } else { - # talk ist aktiv und ein anderer Player ist Master - IOWrite( $hash, $hash->{helper}{ttsMaster}." fhemrelay ttsadd ".$_."\n" ); + my $arr = $hash->{helper}{ttsqueue}; + my $playlistadd=0; + if(defined($arr)) { + # CD 0089 Optionen hinzugefügt + while(@{$arr} > 0) { + my $qe=$arr->[0]; + #Log 0,$qe; + if($hash->{helper}{ttsstate}==TTS_LOADPLAYLIST) { + if($qe=~/^opt%3A(.*)/) { + my @opts=split '=',uri_unescape($1); + if(($opts[0] eq 'v') && (@opts==2)) { + last if($playlistadd==1); # wenn bereits Elemente in die Playlist eingefügt wurden warten bis diese abgespielt wurden + $opts[1]=AttrVal( $name, "ttsVolume", 100 ) if($opts[1] eq 'tts'); # CD 0091 + $opts[1]=$hash->{helper}{ttsActiveOptions}{volume} if($opts[1] eq 'music'); # CD 0091 + SB_PLAYER_SetTTSVolume($hash,$opts[1],0); + } + } else { + # ich steuere talk + IOWrite( $hash, "$hash->{PLAYERMAC} playlist add " . $qe . "\n" ); + $playlistadd=1; + } + } else { + # ein anderer Player steuert talk + IOWrite( $hash, $hash->{helper}{ttsMaster}." fhemrelay ttsadd ". $qe ."\n" ); + $playlistadd=1; + } + shift(@{$arr}); } + delete($hash->{helper}{ttsqueue}) if(@{$arr} == 0); } - delete($hash->{helper}{ttsqueue}); if($hash->{helper}{ttsstate}!=TTS_SYNCGROUPACTIVE) { # andere Player in Gruppe informieren @@ -3211,13 +3510,13 @@ sub SB_PLAYER_LoadTalk($) { foreach (@pl) { if ($hash->{PLAYERMAC} ne $_) { IOWrite( $hash, "$_ fhemrelay ttsactive ".$hash->{PLAYERMAC}."\n" ); - IOWrite( $hash, "$_ fhemrelay ttsforcegroupon\n" ) if(defined($hash->{helper}{ttsOptions}{forcegroupon})); # CD 0030 + IOWrite( $hash, "$_ fhemrelay ttsforcegroupon\n" ) if(defined($hash->{helper}{ttsActiveOptions}{forcegroupon})); # CD 0030 } } } } } else { - # talk ist aktiv und ich bin Master + # talk ist aktiv # warten bis stop } } @@ -3234,8 +3533,10 @@ sub SB_PLAYER_PrepareTalk($) { my ( $hash ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + # talk ist nicht aktiv - if(!defined($hash->{helper}{ttsOptions}{nosaverestore}) && !defined($hash->{helper}{sgTalkActive})) { # CD 0063 sgTalkActive hinzugefügt + if(!defined($hash->{helper}{ttsActiveOptions}{nosaverestore}) && !defined($hash->{helper}{sgTalkActive})) { # CD 0063 sgTalkActive hinzugefügt SB_PLAYER_SetTTSState($hash,TTS_SAVE,0,0); SB_PLAYER_Save( $hash, "xxTTSxx" ) if(!defined($hash->{helper}{saveLocked})); } @@ -3243,15 +3544,27 @@ sub SB_PLAYER_PrepareTalk($) { IOWrite( $hash, "$hash->{PLAYERMAC} playlist repeat 0\n" ); IOWrite( $hash, "$hash->{PLAYERMAC} playlist clear\n" ); if(defined($hash->{helper}{ttsVolume})) { - SB_PLAYER_SetTTSState($hash,TTS_SETVOLUME,0,0); - my $vol=$hash->{helper}{ttsVolume}; - $vol=AttrVal( $name, "volumeLimit", 100 ) if(( $hash->{helper}{ttsVolume} > AttrVal( $name, "volumeLimit", 100 ) )&&!defined($hash->{helper}{ttsOptions}{ignorevolumelimit})); # CD 0031 - IOWrite( $hash, "$hash->{PLAYERMAC} mixer volume ".SB_PLAYER_FHEM2LMSVolume($hash, $vol)."\n" ); # CD 0065 SB_PLAYER_FHEM2LMSVolume - SB_PLAYER_SetSyncedVolume($hash,$hash->{helper}{ttsVolume},1); + SB_PLAYER_SetTTSVolume($hash,$hash->{helper}{ttsVolume},1); } SB_PLAYER_SetTTSState($hash,TTS_LOADPLAYLIST,0,0); } +# CD 0089 start +sub SB_PLAYER_SetTTSVolume($$$) { + my ( $hash, $ttsvolume, $changestate ) = @_; + my $name = $hash->{NAME}; + + return unless defined($ttsvolume); + return if(IsDisabled($name)); # CD 0091 + + SB_PLAYER_SetTTSState($hash,TTS_SETVOLUME,0,0) if($changestate==1); + my $vol=$ttsvolume; + $vol=AttrVal( $name, "volumeLimit", 100 ) if(( $ttsvolume > AttrVal( $name, "volumeLimit", 100 ) )&&!defined($hash->{helper}{ttsActiveOptions}{ignorevolumelimit})); # CD 0031 + IOWrite( $hash, "$hash->{PLAYERMAC} mixer volume ".SB_PLAYER_FHEM2LMSVolume($hash, $vol)."\n" ); # CD 0065 SB_PLAYER_FHEM2LMSVolume + SB_PLAYER_SetSyncedVolume($hash,$ttsvolume,1); +} +# CD 0089 end + # CD 0014 start # ---------------------------------------------------------------------------- # recall player state @@ -3262,6 +3575,8 @@ sub SB_PLAYER_Recall($$) { my ( $hash, $arg ) = @_; # CD 0036 my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + # CD 0036 start my $del=0; my $delonly=0; @@ -3352,6 +3667,8 @@ sub SB_PLAYER_Recall($$) { } # CD 0028 start if ((($hash->{helper}{savedPlayerState}{$statename}{power} eq "off") && ($forceon!=1))||($forceoff==1)) { # CD 0036 added $forceon and $forceoff + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - stop and power off" ); # CD 0097 + IOWrite( $hash, "$hash->{PLAYERMAC} stop\n" ); # CD 0091 IOWrite( $hash, "$hash->{PLAYERMAC} power 0\n" ); if($hash->{helper}{ttsstate}==TTS_RESTORE) { SB_PLAYER_SetTTSState($hash,TTS_IDLE,0,1); @@ -3360,6 +3677,7 @@ sub SB_PLAYER_Recall($$) { } else { # CD 0028 end if ((($hash->{helper}{savedPlayerState}{$statename}{playStatus} eq "stopped" ) && ($forceplay!=1))||($forcestop==1)) { # CD 0036 added $forceplay and $forcestop + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - stop" ); # CD 0097 IOWrite( $hash, "$hash->{PLAYERMAC} stop\n" ); # CD 0028 start if($hash->{helper}{ttsstate}==TTS_RESTORE) { @@ -3368,6 +3686,7 @@ sub SB_PLAYER_Recall($$) { } # CD 0028 end } elsif(( $hash->{helper}{savedPlayerState}{$statename}{playStatus} eq "playing" )||($forceplay==1)) { # CD 0036 added $forceplay + Log3( $hash, defined($hash->{helper}{ttsOptions}{debug})?0:6, "$name: ttsdebug - play" ); # CD 0097 my @secbuf = split(',',AttrVal( $name, "fadeinsecs", '10,10' )); # CD 0050 split hinzugefügt IOWrite( $hash, "$hash->{PLAYERMAC} play ".$secbuf[0]."\n" ); IOWrite( $hash, "$hash->{PLAYERMAC} time $hash->{helper}{savedPlayerState}{$statename}{elapsedTime}\n" ) if(defined($hash->{helper}{savedPlayerState}{$statename}{elapsedTime})); @@ -3414,6 +3733,8 @@ sub SB_PLAYER_tcb_TriggerPlaylistStop($) { my(undef,$name) = split(':',$in); my $hash = $defs{$name}; + return if(IsDisabled($name)); # CD 0091 + $hash->{helper}{noStopEventUntil}=0 unless defined($hash->{helper}{noStopEventUntil}); if ((ReadingsVal($name,"playStatus","x") eq "stopped")&&(time()>$hash->{helper}{noStopEventUntil})&&($hash->{helper}{ttsstate}==TTS_IDLE)) { @@ -3427,6 +3748,7 @@ sub SB_PLAYER_SetTTSState($$$$) { my $name = $hash->{NAME}; return if($state eq $hash->{helper}{ttsstate}); + return if(IsDisabled($name)); # CD 0091 my $oldstate=$hash->{helper}{ttsstate}; # CD 0062 @@ -3455,7 +3777,7 @@ sub SB_PLAYER_SetTTSState($$$$) { # CD 0062 start if(($state==TTS_IDLE)&&($oldstate!=TTS_IDLE)) { - if(defined($hash->{helper}{ttsOptions}{eventondone})) { + if(defined($hash->{helper}{ttsActiveOptions}{eventondone})) { RemoveInternalTimer( "TriggerTTSDone:$name"); InternalTimer( gettimeofday() + 0.5, "SB_PLAYER_tcb_TriggerTTSDone", @@ -3463,10 +3785,50 @@ sub SB_PLAYER_SetTTSState($$$$) { 0 ); } IOWrite( $hash, "$name fhemrelay ttsdone" ); + + SB_PLAYER_TTSLogPlayerState($hash, 'idle'); # CD 0097 Zustand aller Player ausgeben } # CD 0062 end + + # CD 0091 Timer aufräumen + RemoveInternalTimer( "TimeoutTTSWaitForPlay:$name") if ($state!=TTS_WAITFORPLAY); + RemoveInternalTimer( "TimeoutTTSWaitForPowerOn:$name") if($state!=TTS_WAITFORPOWERON); + RemoveInternalTimer( "TTSDelay:$name") if($state==TTS_IDLE); + RemoveInternalTimer( "TTSRestore:$name") if($state==TTS_IDLE); + RemoveInternalTimer( "TTSStartAfterPowerOn:$name") if($state==TTS_IDLE); } +# CD 0097 start +# ---------------------------------------------------------------------------- +# log player state for tts +# ---------------------------------------------------------------------------- +sub SB_PLAYER_TTSLogPlayerState($$) { + my ( $hash, $msg ) = @_; + my $name = $hash->{NAME}; + + if(defined($hash->{helper}{ttsOptions}{debug})) { + Log3($hash, 0,"$name: ttsdebug - $msg"); + if (defined($hash->{SYNCGROUP}) && ($hash->{SYNCGROUP} ne '?') && ($hash->{SYNCMASTER} ne 'none')) { + my @pl=split(",",$hash->{SYNCGROUP}.",".$hash->{SYNCMASTER}); + Log3($hash, 0,"$name: ttsdebug - SM: " . SB_PLAYER_MACToFHEMPlayername($hash,$hash->{SYNCMASTER})); + + foreach (@pl) { + my $pn=SB_PLAYER_MACToFHEMPlayername($hash,$_); + Log3($hash, 0,"$name: ttsdebug - $pn power: " . ReadingsVal($pn,'power','x')); + Log3($hash, 0,"$name: ttsdebug - $pn presence: " . ReadingsVal($pn,'presence','x')); + Log3($hash, 0,"$name: ttsdebug - $pn playStatus: " . ReadingsVal($pn,'playStatus','x')); + Log3($hash, 0,"$name: ttsdebug - $pn volume: " . ReadingsVal($pn,'volume','x')); + } + } else { + Log3($hash, 0,"$name: ttsdebug - power: " . ReadingsVal($name,'power','x')); + Log3($hash, 0,"$name: ttsdebug - presence: " . ReadingsVal($name,'presence','x')); + Log3($hash, 0,"$name: ttsdebug - playStatus: " . ReadingsVal($name,'playStatus','x')); + Log3($hash, 0,"$name: ttsdebug - volume: " . ReadingsVal($name,'volume','x')); + } + } +} +# CD 0097 end + # ---------------------------------------------------------------------------- # save player state # @@ -3476,6 +3838,8 @@ sub SB_PLAYER_Save($$) { my ( $hash, $statename ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + $statename='default' unless defined($statename); delete($hash->{helper}{savedPlayerState}{$statename}) if(defined($hash->{helper}{savedPlayerState}) && defined($hash->{helper}{savedPlayerState}{$statename})); @@ -3572,6 +3936,8 @@ sub SB_PLAYER_Alarm( $$@ ) { my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + # CD 0015 deaktiviert #if( ( $n != 1 ) && ( $n != 2 ) ) { # Log3( $hash, 1, "SB_PLAYER_Alarm: $name: wrong ID given. Must be 1|2" ); @@ -3844,6 +4210,7 @@ sub SB_PLAYER_GetStatus( $ ) { Log3( $hash, 5, "SB_PLAYER_GetStatus: called" ); return if(defined($hash->{helper}{disableGetStatus})); + return if(IsDisabled($name)); # CD 0091 # CD 0014 start - Anzahl Anfragen begrenzen if(!defined($hash->{helper}{lastGetStatus})||($hash->{helper}{lastGetStatus}{NAME}; + return if(IsDisabled($name)); # CD 0091 + Log3( $hash, 5, "SB_PLAYER_Broadcast($name): called with $msg" ); # let's see what we got. Split the data at the space @@ -3967,6 +4336,7 @@ sub SB_PLAYER_RecBroadcast( $$@ ) { } } elsif( $cmd eq "FAVORITES" ) { + RemoveInternalTimer( "ServerStatusRequest:$name"); # CD 0091 if( $args[ 0 ] eq "ADD" ) { # format: ADD IODEVname ID shortentry $hash->{helper}{SB_PLAYER_Favs}{$args[3]}{ID} = $args[ 2 ]; @@ -4056,15 +4426,35 @@ sub SB_PLAYER_RecBroadcast( $$@ ) { } else { $hash->{SYNCMASTERS} .= "," . $args[ 1 ]; } + } else { + $hash->{helper}{foundMyself}='1'; # CD 0091 } } elsif( $args[ 0 ] eq "FLUSH" ) { undef( %{$hash->{helper}{SB_PLAYER_SyncMasters}} ); $hash->{SYNCMASTERS} = ""; - + $hash->{helper}{foundMyself}='0'; # CD 0091 + # CD 0091 start + } elsif( $args[ 0 ] eq 'DONE' ) { + # überprüfen ob Player in der Liste enthalten war, falls nicht 'absent' setzen + if($hash->{helper}{foundMyself} eq '0') { + readingsBeginUpdate( $hash ); + SB_PLAYER_SetPlayerAbsent($hash); + if( AttrVal( $name, "donotnotify", "false" ) eq "true" ) { + readingsEndUpdate( $hash, 0 ); + } else { + readingsEndUpdate( $hash, 1 ); + } + } else { + if (ReadingsVal($name,'presence','x') ne 'present') { + readingsSingleUpdate( $hash, 'presence', 'present', 1 ); + } + } + # CD 0091 end } else { } } elsif( $cmd eq "PLAYLISTS" ) { + RemoveInternalTimer( "ServerStatusRequest:$name"); # CD 0091 if( $args[ 0 ] eq "ADD" ) { # CD 0014 Playlists mit fhem_* ignorieren if($args[3]=~/^fhem_.*/) { @@ -4168,6 +4558,7 @@ sub SB_PLAYER_RecBroadcast( $$@ ) { # CD 0026 start } elsif( $cmd eq "ALARMPLAYLISTS" ) { + RemoveInternalTimer( "ServerStatusRequest:$name"); # CD 0091 if( $args[ 0 ] eq "ADD" ) { $hash->{helper}{alarmPlaylists}{$args[ 1 ]}{$args[ 2 ]}=join( " ", @args[3..$#args]); } elsif( $args[ 0 ] eq "FLUSH" ) { @@ -4188,6 +4579,8 @@ sub SB_PLAYER_ParseAlarms( $@ ) { my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + # CD 0016 start {ALARMSCOUNT} verschieben nach reload if (defined($hash->{ALARMSCOUNT})) { $hash->{helper}{ALARMSCOUNT}=$hash->{ALARMSCOUNT}; @@ -4204,7 +4597,7 @@ sub SB_PLAYER_ParseAlarms( $@ ) { shift( @data ); } - fhem( "deletereading $name alarmid.*" ); # CD 0015 alte readings entfernen + fhem( "deletereading $name alarmid.*" ) if(ReadingsVal($name,'alarmid1','__xxx__') ne '__xxx__'); # CD 0015 alte readings entfernen # CD 0096 aber nur wenn es die Readings noch gibt, führt zu Hänger (83228) my $alarmcounter=0; # CD 0015 @@ -4358,6 +4751,31 @@ sub SB_PLAYER_IsValidMAC( $ ) { } } +# CD 0089 start +# ---------------------------------------------------------------------------- +# used for checking, if the string contains a valid IP v4 (decimal) address +# ---------------------------------------------------------------------------- +sub SB_PLAYER_IsValidIPV4( $ ) { + my $instr = shift( @_ ); + + if( $instr =~ m/^(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)$/ ) + { + if($1 <= 255 && $2 <= 255 && $3 <= 255 && $4 <= 255) + { + return( 1 ); + } + else + { + return( 0 ); + } + } + else + { + return( 0 ); + } +} +# CD 0089 end + # ---------------------------------------------------------------------------- # used to turn on our server # ---------------------------------------------------------------------------- @@ -4394,6 +4812,10 @@ sub SB_PLAYER_Amplifier( $ ) { my ( $hash ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + + Log3( $hash, 4, "SB_PLAYER_Amplifier($name): called" ); + if( ( $hash->{AMPLIFIER} eq "none" ) || ( !defined( $defs{$hash->{AMPLIFIER}} ) ) ) { # amplifier not specified @@ -4401,15 +4823,25 @@ sub SB_PLAYER_Amplifier( $ ) { return; } + # CD 0088 start + my $amplifierShared=(AttrVal($name,'amplifierMode','exclusive') eq 'shared'); + + if (defined($hash->{IODev}) && defined($hash->{IODev}->{NAME}) && $amplifierShared) { + if(ReadingsVal($hash->{IODev}->{NAME},'state','x') ne 'opened') { + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): SB Server not connected, ignoring" ); + return; + } + } + # CD 0088 end + my $setvalue = "off"; my $delayAmp=0.01; # CD 0043 - Log3( $hash, 4, "SB_PLAYER_Amplifier($name): called" ); - + my $thestatus = ''; # CD 0087 if( AttrVal( $name, "amplifier", "play" ) eq "play" ) { - my $thestatus = ReadingsVal( $name, "playStatus", "pause" ); + $thestatus = ReadingsVal( $name, "playStatus", "pause" ); - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): with mode play " . + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): with mode play " . "and status:$thestatus" ); if( ( $thestatus eq "playing" ) || (( $thestatus eq "paused" ) && ($hash->{helper}{amplifierDelayOffPause}==0)) ) { # CD 0043 DelayOffPause abfragen @@ -4426,9 +4858,9 @@ sub SB_PLAYER_Amplifier( $ ) { $setvalue = "off"; } } elsif( AttrVal( $name, "amplifier", "on" ) eq "on" ) { - my $thestatus = ReadingsVal( $name, "power", "off" ); + $thestatus = ReadingsVal( $name, "power", "off" ); - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): with mode on " . + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): with mode on " . "and status:$thestatus" ); if( $thestatus eq "on" ) { @@ -4445,7 +4877,14 @@ sub SB_PLAYER_Amplifier( $ ) { my $actualState = ReadingsVal( "$hash->{AMPLIFIER}", "state", "off" ); - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): actual:$actualState " . + # CD 0088 start + if (($thestatus eq "?") && $amplifierShared) { + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): player state unknown, ignoring"); + return; + } + # CD 0088 end + + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): actual:$actualState " . "and set:$setvalue" ); if ( $actualState ne $setvalue) { @@ -4455,25 +4894,31 @@ sub SB_PLAYER_Amplifier( $ ) { if (!defined($hash->{helper}{AMPLIFIERDELAYOFF})) { # CD 0043 Timer nicht neu starten wenn Zustand sich nicht geändert hat if ((!defined($hash->{helper}{AMPLIFIERACTIVETIMER})) || ($hash->{helper}{AMPLIFIERACTIVETIMER} ne ($actualState.$setvalue))) { - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): delaying amplifier on/off by $delayAmp" ); - RemoveInternalTimer( "DelayAmplifier:$name"); - InternalTimer( gettimeofday() + $delayAmp, - "SB_PLAYER_tcb_DelayAmplifier", # CD 0014 Name geändert - "DelayAmplifier:$name", - 0 ); - $hash->{helper}{AMPLIFIERACTIVETIMER}=$actualState.$setvalue; # CD 0043 + if(($hash->{helper}{amplifierLastStatus} ne $thestatus) || !$amplifierShared) { # CD 0088 + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): delaying amplifier on/off by $delayAmp" ); + RemoveInternalTimer( "DelayAmplifier:$name"); + InternalTimer( gettimeofday() + $delayAmp, + "SB_PLAYER_tcb_DelayAmplifier", # CD 0014 Name geändert + "DelayAmplifier:$name", + 0 ); + $hash->{helper}{AMPLIFIERACTIVETIMER}=$actualState.$setvalue; # CD 0043 + } else { + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): player state didn't change, ignoring" ); + } } else { - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): delay already active" ); + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): delay already active" ); } return; } # CD 0012 end - fhem( "set $hash->{AMPLIFIER} $setvalue" ); - - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): amplifier changed to " . - $setvalue ); + if(($hash->{helper}{amplifierLastStatus} ne $thestatus) || !$amplifierShared) { # CD 0087 + fhem( "set $hash->{AMPLIFIER} $setvalue" ); + $hash->{helper}{amplifierLastStatus}=$thestatus; # CD 0087 + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): amplifier changed to " . + $setvalue ); + } } else { - Log3( $hash, 5, "SB_PLAYER_Amplifier($name): no amplifier " . + Log3( $hash, 3, "SB_PLAYER_Amplifier($name): no amplifier " . "state change" ); } delete($hash->{helper}{AMPLIFIERDELAYOFF}) if (defined($hash->{helper}{AMPLIFIERDELAYOFF})); @@ -4490,6 +4935,8 @@ sub SB_PLAYER_CoverArt( $ ) { my ( $hash ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + # return if (defined($hash->{helper}{CoverOk}) && ($hash->{helper}{CoverOk} == 1) && ( $hash->{ISREMOTESTREAM} eq "0" )); # CD 0026 added # CD 0027 removed # CD 0003 fix missing server @@ -4560,6 +5007,9 @@ sub SB_PLAYER_ParsePlayerStatus( $$ ) { my( $hash, $dataptr ) = @_; my $name = $hash->{NAME}; + + return if(IsDisabled($name)); # CD 0091 + my $leftover = ""; my $cur = ""; my $playlistIds = ""; # CD 0014 @@ -4654,17 +5104,25 @@ sub SB_PLAYER_ParsePlayerStatus( $$ ) { # CD 0003 end my $lastId=0; # CD 0030 + my $willsleepinfound=0; # CD 0089 + my $playerpresent=0; + my $querymode=0; + # loop through the results foreach( @data2 ) { my $cur=$_; if( $cur =~ /^(player_connected:)([0-9]*)/ ) { - if( $2 == "1" ) { + if( $2 eq "1" ) { readingsBulkUpdate( $hash, "connected", $2 ); readingsBulkUpdate( $hash, "presence", "present" ); + # CD 0091 start + delete($hash->{helper}{disableGetStatus}) if defined($hash->{helper}{disableGetStatus}); + $playerpresent=1; + $querymode=1; + # CD 0091 end } else { - readingsBulkUpdate( $hash, "connected", $3 ); - readingsBulkUpdate( $hash, "presence", "absent" ); + SB_PLAYER_SetPlayerAbsent($hash); } next; @@ -4681,8 +5139,9 @@ sub SB_PLAYER_ParsePlayerStatus( $$ ) { next; } elsif( $cur =~ /^(power:)([0-9\.]*)/ ) { + $querymode=0; if( $2 eq "1" ) { - if(ReadingsVal($name,'presence','absent') eq 'present') { # CD 0079 power nur auf 1 setzen wenn Player verbunden ist + if($playerpresent==1) { # CD 0079 power nur auf 1 setzen wenn Player verbunden ist # CD 0091 nicht ReadingsVal verwenden da Wert noch nicht gesetzt ist readingsBulkUpdate( $hash, "state", "on" ); # CD 0041 hinzugefügt readingsBulkUpdate( $hash, "power", "on" ); SB_PLAYER_Amplifier( $hash ); @@ -4795,12 +5254,25 @@ sub SB_PLAYER_ParsePlayerStatus( $$ ) { readingsBulkUpdate( $hash, "synced", $syncgroup ); } else { # CD 0055 end - readingsBulkUpdate( $hash, "synced", "$hash->{SYNCMASTERPN},$hash->{SYNCGROUPPN}" ); # Matthew 0019 hinzugefügt + if(defined($hash->{SYNCMASTERPN})) { + if(defined($hash->{SYNCGROUPPN})) { + readingsBulkUpdate( $hash, "synced", "$hash->{SYNCMASTERPN},$hash->{SYNCGROUPPN}" ); # Matthew 0019 hinzugefügt + } else { + readingsBulkUpdate( $hash, "synced", "$hash->{SYNCMASTERPN}" ); + } + } else { + if(defined($hash->{SYNCGROUPPN})) { + readingsBulkUpdate( $hash, "synced", "$hash->{SYNCGROUPPN}" ); + } else { + readingsBulkUpdate( $hash, "synced", '' ); + } + } } next; } elsif( $cur =~ /^(will_sleep_in:)([0-9\.]*)/ ) { - $hash->{WILLSLEEPIN} = "$2 secs"; + $hash->{WILLSLEEPIN} = int($2)." secs"; + $willsleepinfound=1; next; } elsif( $cur =~ /^(mixervolume:)(.*)/ ) { @@ -4902,8 +5374,12 @@ sub SB_PLAYER_ParsePlayerStatus( $$ ) { } } + $hash->{WILLSLEEPIN} = '?' unless $willsleepinfound==1; # CD 0089 $hash->{helper}{playerStatusOK}=1; # CD 0042 + # CD 0091 mode abfragen wenn presence sich geändert hat aber keine Info über power vorhanden war + IOWrite( $hash, "$hash->{PLAYERMAC} power ?\n" ) if($querymode==1); + # CD 0065 start if(defined($hash->{helper}{ftuiSupport}{medialist})) { delete($hash->{SONGINFOQUEUE}) if(defined($hash->{SONGINFOQUEUE})); # CD 0072 @@ -4960,6 +5436,29 @@ sub SB_PLAYER_MACToLMSPlayername( $$ ) { } # CD 0018 end +# CD 0097 start +# ---------------------------------------------------------------------------- +# search FHEM device for given MAC +# ---------------------------------------------------------------------------- +sub SB_PLAYER_MACToFHEMPlayername( $$ ) { + my( $hash, $mac ) = @_; + my $name = $hash->{NAME}; + + return $name if($hash->{PLAYERMAC} eq $mac); + + my @players=devspec2array("TYPE=SB_PLAYER"); + + foreach (@players) { + my $phash=$defs{$_}; + if($phash->{PLAYERMAC} eq $mac) { + return $_; + } + } + + return undef; +} +# CD 0097 end + # CD 0014 start # ---------------------------------------------------------------------------- # estimate elapsed time @@ -4968,6 +5467,8 @@ sub SB_PLAYER_EstimateElapsedTime( $ ) { my( $hash ) = @_; my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + my $d=ReadingsVal($name,"duration",0); # nur wenn duration>0 if(($d ne '?')&&($d>0)) { # CD 0033 check for '?' @@ -5062,6 +5563,8 @@ sub SB_PLAYER_SetSyncedVolume( $$$ ) { my $name = $hash->{NAME}; + return if(IsDisabled($name)); # CD 0091 + return if (!defined($hash->{SYNCED}) || ($hash->{SYNCED} ne "yes")); my $sva=AttrVal($name, "syncVolume", undef); @@ -5287,6 +5790,7 @@ sub SB_PLAYER_RemoveInternalTimers($) { RemoveInternalTimer( "TriggerPlaylistStop:$name"); RemoveInternalTimer( "TriggerTTSDone:$name"); RemoveInternalTimer( "recallPause:$name"); + RemoveInternalTimer( "ServerStatusRequest:$name"); RemoveInternalTimer( "ftuiMedialist:$name"); # CD 0085 RemoveInternalTimer( $hash ); }