From 0b383df03235ad434a0c33aed57df1bbc92751bb Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Wed, 22 Feb 2017 10:19:23 +0100 Subject: [PATCH] diverse Bugfixes und Anpassungen am Groupmodul --- 21_HEOSGroup.pm | 195 +++++++++++++++++++++++++++++++++++++++-------- 21_HEOSMaster.pm | 53 ++++++++----- 21_HEOSPlayer.pm | 22 ++++-- 3 files changed, 211 insertions(+), 59 deletions(-) diff --git a/21_HEOSGroup.pm b/21_HEOSGroup.pm index 68f7906..bbee6fd 100644 --- a/21_HEOSGroup.pm +++ b/21_HEOSGroup.pm @@ -38,7 +38,7 @@ use JSON qw(decode_json); use Encode qw(encode_utf8); -my $version = "0.1.56"; +my $version = "0.1.57"; @@ -218,11 +218,12 @@ sub HEOSGroup_Set($$@) { my ($hash, $name, @aa) = @_; my ($cmd, @args) = @aa; - my $gid = $hash->{GID}; + my $gid = $hash->{GID}; my $action; my $heosCmd; my $rvalue; - my $string = "gid=$gid"; + my $favcount = 1; + my $string = "gid=$gid"; if( $cmd eq 'getGroupInfo' ) { @@ -233,7 +234,7 @@ sub HEOSGroup_Set($$@) { } elsif( $cmd eq 'mute' ) { return "usage: mute on/off" if( @args != 1 ); - $heosCmd = 'setMute'; + $heosCmd = 'setGroupMute'; $action = "state=$args[0]"; } elsif( $cmd eq 'volume' ) { @@ -254,16 +255,116 @@ sub HEOSGroup_Set($$@) { $heosCmd = 'groupVolumeDown'; $action = "step=$args[0]"; + } elsif( $cmd eq 'clearGroup' ) { + return "usage: clearGroup" if( @args != 0 ); + + $heosCmd = 'createGroup'; + $string = "pid=$gid"; + + #ab hier Playerbefehle emuliert + } elsif( $cmd eq 'play' ) { + return "usage: play" if( @args != 0 ); + + $heosCmd = 'setPlayState'; + $action = "state=$cmd"; + + } elsif( $cmd eq 'stop' ) { + return "usage: stop" if( @args != 0 ); + + $heosCmd = 'setPlayState'; + $action = "state=$cmd"; + $string = "pid=$gid"; + + } elsif( $cmd eq 'pause' ) { + return "usage: pause" if( @args != 0 ); + + $heosCmd = 'setPlayState'; + $action = "state=$cmd"; + $string = "pid=$gid"; + + } elsif( $cmd eq 'next' ) { + + return "usage: next" if( @args != 0 ); + $heosCmd = 'playNext'; + $string = "pid=$gid"; + + } elsif( $cmd eq 'prev' ) { + return "usage: prev" if( @args != 0 ); + + $heosCmd = 'playPrev'; + $string = "pid=$gid"; + + } elsif ( $cmd eq 'channel' ) { + + $favcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); + return "usage: channel 1-$favcount" if( @args != 1 ); + + $heosCmd = 'playPresetStation'; + $action = "preset=$args[0]"; + $string = "pid=$gid"; + + } elsif( $cmd eq 'channelUp' ) { + + return "usage: channelUp" if( @args != 0 ); + $favcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); + + $heosCmd = 'playPresetStation'; + my $fav = ReadingsVal($name,"channel", 0) + 1; + $fav = $favcount if ( $fav > $favcount); + $action = "preset=".$fav; + $string = "pid=$gid"; + + } elsif( $cmd eq 'channelDown' ) { + + return "usage: channelDown" if( @args != 0 ); + + $heosCmd = 'playPresetStation'; + my $fav = ReadingsVal($name,"channel", 0) - 1; + $fav = 1 if ($fav <= 0); + $action = "preset=".$fav; + $string = "pid=$gid"; + + } elsif ( $cmd eq 'playlist' ) { + + my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} }); + + if ( scalar @args == 1 && scalar @cids == 1 ) { + + $heosCmd = 'playPlaylist'; + $action = "sid=1025&cid=$cids[0]&aid=4"; + $string = "pid=$gid"; + + } else { + + my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}}); + return "usage: playlist ".join(",",@playlists); + + } + } else { - my $list = "getGroupInfo:noArg mute:on,off volume:slider,0,5,100 volumeUp:slider,0,1,10 volumeDown:slider,0,1,10"; + + my @playlists; + my $list = "getGroupInfo:noArg mute:on,off volume:slider,0,5,100 volumeUp:slider,0,1,10 volumeDown:slider,0,1,10 clearGroup:noArg play:noArg stop:noArg pause:noArg next:noArg prev:noArg channelUp:noArg channelDown:noArg "; + + $list .= " channel:slider,1,1,".scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); + + if ( defined $hash->{IODev}{helper}{playlists} ) { + + @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}}); + $list .= " playlist:".join(",",@playlists) if( scalar @playlists > 0 ); + } + return "Unknown argument $cmd, choose one of $list"; } - - - $string .= "&$action" if( defined($action)); - - IOWrite($hash,"$heosCmd","$string"); - Log3 $name, 4, "HEOSGroup ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}"; + + + #senden von Befehlen unterdrücken solange state nicht on ist + if ( ReadingsVal($name, "state", "off") eq "on" ) { + $string .= "&$action" if( defined($action)); + + IOWrite($hash,"$heosCmd","$string"); + Log3 $name, 4, "HEOSGroup ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}"; + } return undef; } @@ -290,10 +391,14 @@ sub HEOSGroup_Parse($$) { $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) ); + #print "code #######################################################################\n".Dumper($code); + if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) { my $name = $hash->{NAME}; + #print "hash #######################################################################\n".Dumper($hash); + IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}"); Log3 $name, 4, "HEOSGroup ($name) - find logical device: $hash->{NAME}"; Log3 $name, 4, "HEOSGroup ($name) - find GID in root from decode_json"; @@ -315,8 +420,9 @@ sub HEOSGroup_Parse($$) { if( defined($decode_json->{payload}{gid}) ) { $gid = $decode_json->{payload}{gid}; - } elsif ( $decode_json->{heos}{message} =~ /^gid=/ ) { + } elsif ( $decode_json->{heos}{message} =~ /^gid=/ or $decode_json->{heos}{message} =~ /^pid=/ ) { # das mit dem PID wird nicht klappen, da solche Telegramme erst gar nicht an das Groupmodul gesendet werden + #pid wird bei leerer gruppe zurück gegeben my @gid = split('&', $decode_json->{heos}{message}); $gid = substr($gid[0],4); Log3 $name, 4, "HEOSGroup ($name) - gid[0]: $gid[0] and gid: $gid"; @@ -347,6 +453,9 @@ sub HEOSGroup_WriteReadings($$) { my ($hash,$decode_json) = @_; my $name = $hash->{NAME}; + my $leaderchannel; + my $leaderStation; + my $leaderStatus; Log3 $name, 3, "HEOSGroup ($name) - processing data to write readings"; @@ -359,6 +468,21 @@ sub HEOSGroup_WriteReadings($$) { my $readingsHash = HEOSGroup_PreProcessingReadings($hash,$decode_json) if( $decode_json->{heos}{message} =~ /^gid=/ ); + my $code = abs($hash->{GID}); + $code = $hash->{IODev}{NAME} ."-". $code if( defined($hash->{IODev}{NAME}) ); + #print "code #######################################################################\n".Dumper($code); + + if( my $leaderhash = $modules{HEOSPlayer}{defptr}{$code} ) { + + my $leadername = $leaderhash->{NAME}; + #print "hash #######################################################################\n".Dumper($leaderhash); + $leaderchannel = ReadingsVal($leadername, 'channel', ''); + $leaderStation = ReadingsVal($leadername, 'currentStation', ''); + $leaderStatus = ReadingsVal($leadername, 'playStatus', 'stop'); + + Log3 $name, 4, "HEOSGroup ($name) - read readings from $leadername"; + } + ############################ #### schreiben der Readings @@ -385,31 +509,42 @@ sub HEOSGroup_WriteReadings($$) { readingsBulkUpdate( $hash, 'name', $decode_json->{payload}{name} ); readingsBulkUpdate( $hash, 'gid', $decode_json->{payload}{gid} ); + readingsBulkUpdate( $hash, 'state', 'on' ); - my @members; + readingsBulkUpdate( $hash, 'channel', $leaderchannel ); + readingsBulkUpdate( $hash, 'currentStation', $leaderStation ); + readingsBulkUpdate( $hash, 'playStatus', $leaderStatus ); + + #gruppe wurde geleert + if ( $decode_json->{heos}{message} =~ /^pid=/ ) { + + readingsBulkUpdate( $hash, 'member', "" ); + readingsBulkUpdate( $hash, 'name', "" ); + readingsBulkUpdate( $hash, 'state', "off" ); + + } elsif ( ref($decode_json->{payload}{players}) eq "ARRAY" ) { + + my @members; - if( ref($decode_json->{payload}{players}) eq "ARRAY" ) { foreach my $player (@{ $decode_json->{payload}{players} }) { - + readingsBulkUpdate( $hash, 'leader', $player->{name} ) if ( $player->{role} eq "leader" ); push( @members, $player->{name}) if ( $player->{role} eq "member" ); - print"Player ###################################\n".Dumper($player); + } + + if ( scalar @members > 1 ) { + + readingsBulkUpdate( $hash, 'member', join(",",@members) ); + + } else { + + readingsBulkUpdate( $hash, 'member', $members[0] ); + + } + } - - if( scalar @members > 1 ) { - - readingsBulkUpdate( $hash, 'member', join(",",@members) ); - - } else { - - readingsBulkUpdate( $hash, 'member', $members[0] ); - } - - print"Member ##################################\n".Dumper(@members); - - - readingsBulkUpdate( $hash, 'state', 'on' ); + readingsEndUpdate( $hash, 1 ); Log3 $name, 5, "HEOSGroup ($name) - readings set for $name"; diff --git a/21_HEOSMaster.pm b/21_HEOSMaster.pm index e715195..f56ecc2 100644 --- a/21_HEOSMaster.pm +++ b/21_HEOSMaster.pm @@ -50,7 +50,7 @@ use Encode qw(encode_utf8); use Net::Telnet; -my $version = "0.1.56"; +my $version = "0.1.57"; my %heosCmds = ( @@ -60,17 +60,17 @@ my %heosCmds = ( 'signAccountOut' => 'system/sign_out', 'reboot' => 'system/reboot', 'getMusicSources' => 'browse/get_music_sources', - 'browseSource' => 'browse/browse?', + 'browseSource' => 'browse/browse?', 'getPlayers' => 'player/get_players', 'getGroups' => 'group/get_groups', 'getPlayerInfo' => 'player/get_player_info?', 'getGroupInfo' => 'group/get_group_info?', 'getPlayState' => 'player/get_play_state?', 'getPlayMode' => 'player/get_play_mode?', - 'getMute' => 'player/get_mute?' + 'getMute' => 'player/get_mute?', 'getGroupMute' => 'group/get_mute?', 'clearQueue' => 'player/clear_queue?', - 'saveQueue' => 'player/save_queue?', + 'saveQueue' => 'player/save_queue?', 'getVolume' => 'player/get_volume?', 'getGroupVolume' => 'group/get_volume?', 'setPlayState' => 'player/set_play_state?', @@ -352,7 +352,7 @@ sub HEOSMaster_Open($) { my $host = $hash->{HOST}; my $port = 1255; my $timeout = 0.1; - my $user = AttrVal($name,'heosUsername',0); + my $user = AttrVal($name,'heosUsername',undef); my $password = HEOSMaster_ReadPassword($hash); @@ -549,6 +549,11 @@ sub HEOSMaster_ResponseProcessing($$) { unless(ref($decode_json) eq "HASH"); + #wenn noch in Bearbeitung dann message ignorieren + return Log3 $name, 3, "HEOSMaster ($name) - heos worked" # Konnte nicht genau erkennen ob Du es so haben wolltest. Anders macht es aber auch keinen Sinn + if( defined($decode_json->{heos}{message}) && $decode_json->{heos}{message} =~ /command\sunder\sprocess/ ); + + if( (defined($decode_json->{heos}{result}) and defined($decode_json->{heos}{command})) or ($decode_json->{heos}{command} =~ /^system/) ) { HEOSMaster_WriteReadings($hash,$decode_json); @@ -615,12 +620,10 @@ sub HEOSMaster_ResponseProcessing($$) { #Favoriten einlesen $hash->{helper}{favorites} = $decode_json->{payload}; - my @keys = (keys %defs); - my @pids = map { $_->{PID} } grep { $_->{TYPE} =~ /HEOSPlayer/i } @defs{@keys}; #Nachricht an die Player das die Favoriten sich geändert haben - foreach my $pid (@pids) { - + foreach my $dev ( devspec2array("TYPE=HEOSPlayer") ) { + my $pid = $defs{$dev}->{PID}; $json = '{"heos": {"command": "event/favorites_changed", "message": "pid='.$pid.'"}}'; Dispatch($hash,$json,undef); Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Favorites Changed"; @@ -701,13 +704,11 @@ sub HEOSMaster_ResponseProcessing($$) { if( $decode_json->{heos}{command} =~ /^player/ or $decode_json->{heos}{command} =~ /^event\/player/ or $decode_json->{heos}{command} =~ /^group/ or $decode_json->{heos}{command} =~ /^event\/group/ or $decode_json->{heos}{command} =~ /^event\/repeat_mode_changed/ or $decode_json->{heos}{command} =~ /^event\/shuffle_mode_changed/ ) { if( ref($decode_json->{payload}) eq "ARRAY" ) { - - return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received" - unless(scalar(@{$decode_json->{payload}}) > 0); - if( $decode_json->{heos}{command} =~ /^player/ ) { - + return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received" + unless(scalar(@{$decode_json->{payload}}) > 0); + foreach my $payload (@{$decode_json->{payload}}) { $json = '{"pid": "'; @@ -723,14 +724,24 @@ sub HEOSMaster_ResponseProcessing($$) { } elsif( $decode_json->{heos}{command} =~ /^group/ ) { - foreach my $payload (@{$decode_json->{payload}}) { - - $json = '{"gid": "'; - $json .= "$payload->{gid}"; - $json .= '","heos": {"command": "group/get_groups"}}'; + unless ( scalar(@{$decode_json->{payload}}) > 0 ) { + #alle gruppen ausschalten da leer + foreach my $dev ( devspec2array("TYPE=HEOSGroup") ) { + + my $ghash = $defs{$dev}; + readingsSingleUpdate( $ghash, "state", "off", 1 ); + } + } else { - Dispatch($hash,$json,undef); - Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Groups"; + foreach my $payload (@{$decode_json->{payload}}) { + + $json = '{"gid": "'; + $json .= "$payload->{gid}"; + $json .= '","heos": {"command": "group/get_groups"}}'; + + Dispatch($hash,$json,undef); + Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Groups"; + } } return; diff --git a/21_HEOSPlayer.pm b/21_HEOSPlayer.pm index fa98820..55626b0 100644 --- a/21_HEOSPlayer.pm +++ b/21_HEOSPlayer.pm @@ -38,7 +38,7 @@ use JSON qw(decode_json); use Encode qw(encode_utf8); -my $version = "0.1.56"; +my $version = "0.1.57"; @@ -72,6 +72,7 @@ sub HEOSPlayer_Initialize($) { # Provider $hash->{SetFn} = "HEOSPlayer_Set"; + $hash->{GetFn} = "HEOSPlayer_Get"; $hash->{DefFn} = "HEOSPlayer_Define"; $hash->{UndefFn} = "HEOSPlayer_Undef"; $hash->{AttrFn} = "HEOSPlayer_Attr"; @@ -410,17 +411,17 @@ sub HEOSPlayer_Set($$@) { $heosCmd = 'getMusicSources'; } elsif ( $cmd eq 'channel' ) { - - return "usage: channel 1-$favcount" if( @args != 1 ); + $favcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); + return "usage: channel 1-$favcount" if( @args != 1 ); $heosCmd = 'playPresetStation'; $action = "preset=$args[0]"; - } elsif( $cmd eq 'channelUp' ) { - + } elsif( $cmd eq 'channelUp' ) { + return "usage: channelUp" if( @args != 0 ); - $favcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); + #$favcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); $heosCmd = 'playPresetStation'; my $fav = ReadingsVal($name,"channel", 0) + 1; @@ -559,7 +560,7 @@ sub HEOSPlayer_Set($$@) { return "usage: savequeue" if( @args != 1 ); $heosCmd = 'saveQueue name'; - $action = "name=$args[0]"; + $action = "name=$args[0]"; #} elsif( $cmd eq 'sayText' ) { # return "usage: sayText Text" if( @args != 1 ); @@ -570,7 +571,7 @@ sub HEOSPlayer_Set($$@) { my @inputs; my @media; - my $list = "getPlayerInfo:noArg getPlayState:noArg getNowPlayingMedia:noArg getPlayMode:noArg play:noArg stop:noArg pause:noArg mute:on,off volume:slider,0,5,100 volumeUp:slider,0,1,10 volumeDown:slider,0,1,10 repeat:one,all,off shuffle:on,off clearqueue:noArg savequeue channelUp:noArg channelDown:noArg "; + my $list = "getPlayerInfo:noArg getPlayState:noArg getNowPlayingMedia:noArg getPlayMode:noArg play:noArg stop:noArg pause:noArg mute:on,off volume:slider,0,5,100 volumeUp:slider,0,1,10 volumeDown:slider,0,1,10 repeat:one,all,off shuffle:on,off clearqueue:noArg savequeue channelUp:noArg channelDown:noArg next:noArg prev:noArg "; $list .= "groupWithMember:" . join( ",", devspec2array("TYPE=HEOSPlayer:FILTER=NAME!=$name") ); @@ -852,6 +853,11 @@ sub HEOSPlayer_PreProcessingReadings($$) { my @value = split('&', $decode_json->{heos}{message}); $buffer{'input'} = substr($value[1],6); + } elsif ( $decode_json->{heos}{command} =~ /playback_error/ ) { + + my @value = split('&', $decode_json->{heos}{message}); + $buffer{'error'} = substr($value[1],6); + } else { Log3 $name, 3, "HEOSPlayer ($name) - no match found";