diff --git a/fhem/CHANGED b/fhem/CHANGED index 5c2e594ae..41baa5ad7 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 96_Snapcast: group volume now can be set - feature: 49_SSCam: text field long for some attributes, the body text can contain HTML-Tags when sending snaps/recordings - bugfix: 57_SSCal: fix problem recurring MONTHLY appointment by day diff --git a/fhem/FHEM/96_Snapcast.pm b/fhem/FHEM/96_Snapcast.pm index c2d84ea5e..5e5a83fce 100755 --- a/fhem/FHEM/96_Snapcast.pm +++ b/fhem/FHEM/96_Snapcast.pm @@ -88,6 +88,51 @@ my %_clientmethods = ( latency => 'Client.SetLatency' ); +=pod +https://github.com/badaix/snapcast/blob/develop/doc/json_rpc_api/control.md (v. 0.26.0) +Requests + + Client + Client.GetStatus + Client.SetVolume + Client.SetLatency + Client.SetName + Group + Group.GetStatus + Group.SetMute + Group.SetStream + Group.SetClients + Group.SetName + Server + Server.GetRPCVersion + Server.GetStatus + Server.DeleteClient + Stream + Stream.AddStream + Stream.RemoveStream + Stream.Control + Stream.SetProperty + +Notifications + + Client + Client.OnConnect + Client.OnDisconnect + Client.OnVolumeChanged + Client.OnLatencyChanged + Client.OnNameChanged + Group + Group.OnMute + Group.OnStreamChanged + Group.OnNameChanged + Stream + Stream.OnProperties + Stream.OnUpdate + Server + Server.OnUpdate + +=cut + sub Initialize { my $hash = shift // return; $hash->{DefFn} = \&Define; @@ -222,15 +267,16 @@ sub Set { my @group; for my $sid ( @ids ) { #= devspec2array("TYPE=Snapcast:FILTER=group=$client"); - next if ReadingsVal($name, $_, '') ne $client; + #next if ReadingsVal($name, $_, '') ne $client; #clients_84a93e695051#2_group 207ff3bc-5082-789c-c444-29471f4ce57e if ( $sid =~ m{\Aclients_(.+)_group\z}xms ) { push @group, $1; } } + Log3( $hash, 3, "Snap: groups are @group" ); if ( @group ) { if ( $opt eq 'volume' && looks_like_number($value) && $value !~ m{[+-]}x ) { - Log3($hash,3,"SNAP: Group absolute volume command, volume: $value"); + #Log3($hash,3,"SNAP: Group absolute volume command, volume: $value"); my @paramset; my $grvol; for my $sclient ( @group ) { @@ -251,8 +297,8 @@ sub Set { return if !@paramset; my $payload = q{[}; $payload .= join q{,},@paramset; - $payload .= q{]}; #q{]\r\n}; - Log3($hash,3,"SNAP: send batch $payload"); + $payload .= "]\r\n"; + #Log3($hash,3,"SNAP: send batch $payload"); return DevIo_SimpleWrite( $hash, $payload, 2 ); } for my $sclient ( @group ) { @@ -309,6 +355,7 @@ sub Read { return; } if ( ref $update eq 'ARRAY' ) { + Log3( $name, 4, "Snap JSON array is $line" ); for my $elem ( @{$update} ) { updateClientInGroup($hash,$elem); } @@ -464,10 +511,11 @@ sub onConnect { sub updateClient { my $hash = shift // return; my $c = shift // return; - my $cnumber = shift // return; + my $cnumber = shift // 0; #return; if ( $cnumber == 0 ) { $cnumber++; - while ( defined $hash->{STATUS}->{clients}->{$cnumber} && $c->{host}->{mac} ne $hash->{STATUS}->{clients}->{$cnumber}->{host}->{mac} ) { + #while ( defined $hash->{STATUS}->{clients}->{$cnumber} && $c->{host}->{mac} ne $hash->{STATUS}->{clients}->{$cnumber}->{host}->{mac} ) { + while ( defined $hash->{STATUS}->{clients}->{$cnumber} && $c->{id} ne $hash->{STATUS}->{clients}->{$cnumber}->{id} ) { $cnumber++; } if ( !defined $hash->{STATUS}->{clients}->{$cnumber} ) { @@ -483,38 +531,40 @@ sub updateClient { $hash->{STATUS}->{clients}->{$cnumber}->{id} = $id; $hash->{STATUS}->{clients}->{$cnumber}->{origid} = $orig_id; + my $rvs->{online} = defined $c->{connected} ? + $c->{connected} ? 'true' : 'false' : undef; + $rvs->{name} = $c->{config}->{name} ? $c->{config}->{name} : $c->{host}->{name}; + $rvs->{latency} = $c->{config}->{latency}; + $rvs->{stream_id} = $c->{config}->{stream_id}; + $rvs->{volume} = $c->{config}->{volume}->{percent}; + $rvs->{muted} = defined $c->{config}->{volume}->{muted} ? + $c->{config}->{volume}->{muted} ? 'true' : 'false' : undef; + $rvs->{ip} = $c->{host}->{ip}; + $rvs->{mac} = $c->{host}->{mac}; + $rvs->{id} = $id; + $rvs->{origid} = $orig_id; + $rvs->{nr} = $cnumber; + $rvs->{group} = $c->{config}->{group_id}; + readingsBeginUpdate($hash); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_online", $c->{connected} ? 'true' : 'false' ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_name", $c->{config}->{name} ? $c->{config}->{name} : $c->{host}->{name} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_latency", $c->{config}->{latency} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_stream_id", $c->{config}->{stream_id} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_volume", $c->{config}->{volume}->{percent} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_muted", $c->{config}->{volume}->{muted} ? 'true' : 'false' ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_ip", $c->{host}->{ip} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_mac", $c->{host}->{mac} ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_id", $id ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_origid", $orig_id ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_nr", $cnumber ); - readingsBulkUpdateIfChanged( $hash, "clients_${id}_group", $c->{config}->{group_id} ); + for my $kw ( keys %{$rvs} ) { + next if !defined $rvs->{$kw}; + readingsBulkUpdateIfChanged( $hash, "clients_${id}_${kw}", $rvs->{$kw} ) ; + } readingsEndUpdate( $hash, 1 ); return if !$hash->{$id}; my $clienthash = $defs{ $hash->{$id} } // return; readingsBeginUpdate($clienthash); - readingsBulkUpdateIfChanged( $clienthash, 'online', $c->{connected} ? 'true' : 'false' ); - readingsBulkUpdateIfChanged( $clienthash, 'name', $c->{config}->{name} ? $c->{config}->{name} : $c->{host}->{name} ); - readingsBulkUpdateIfChanged( $clienthash, 'latency', $c->{config}->{latency} ); - readingsBulkUpdateIfChanged( $clienthash, 'stream_id', $c->{config}->{stream_id} ); - readingsBulkUpdateIfChanged( $clienthash, 'volume', $c->{config}->{volume}->{percent} ); - readingsBulkUpdateIfChanged( $clienthash, 'muted', $c->{config}->{volume}->{muted} ? 'true' : 'false' ); - readingsBulkUpdateIfChanged( $clienthash, 'ip', $c->{host}->{ip} ); - readingsBulkUpdateIfChanged( $clienthash, 'mac', $c->{host}->{mac} ); - readingsBulkUpdateIfChanged( $clienthash, 'id', $id ); - readingsBulkUpdateIfChanged( $clienthash, 'origid', $orig_id ); - readingsBulkUpdateIfChanged( $clienthash, 'group', $c->{config}->{group_id} ); + for my $kw ( keys %{$rvs} ) { + next if !defined $rvs->{$kw}; + readingsBulkUpdateIfChanged( $clienthash, $kw, $rvs->{$kw} ); + } readingsEndUpdate( $clienthash, 1 ); + return if !defined $c->{config} || !defined $c->{config}->{volume} || !defined $c->{config}->{volume}->{percent}; + my $maxvol = getVolumeConstraint($clienthash) // 100; _setClient( $hash, $clienthash->{ID}, 'volume', $maxvol ) if $c->{config}->{volume}->{percent} > $maxvol; return; @@ -524,17 +574,21 @@ sub updateClientInGroup { my $hash = shift // return; my $c = shift // return; + delete $hash->{IDLIST}->{ $c->{id} } if defined $hash->{IDLIST} && $c->{id} && defined $hash->{IDLIST}->{ $c->{id} }; + + my $id = $c->{params}->{id} // return Snapcast_getStatus($hash); # recent version uses an ID. + my $cnumber = 1; while ( defined $hash->{STATUS}->{clients}->{$cnumber} && $c->{params}->{id} ne $hash->{STATUS}->{clients}->{$cnumber}->{origid} ) { $cnumber++; } + if ( !defined $hash->{STATUS}->{clients}->{$cnumber} ) { #Snapcast_getStatus($hash); return; } return if !defined $c->{params}; - my $id = $c->{params}->{id} // return; # recent version uses an ID. $id =~ s{:}{}gx; $id =~ s{[#]}{_}gx; @@ -550,6 +604,11 @@ sub updateClientInGroup { readingsBulkUpdateIfChanged( $clienthash, 'volume', $c->{params}->{volume}->{percent} ) if defined $c->{params}->{volume}->{percent}; readingsBulkUpdateIfChanged( $clienthash, 'muted', $c->{params}->{volume}->{muted} ? 'true' : 'false' ) if defined $c->{params}->{volume}->{muted}; readingsEndUpdate( $clienthash, 1 ); + + return if !defined $c->{params} || !defined $c->{params}->{volume} || !defined $c->{params}->{volume}->{percent}; + + my $maxvol = getVolumeConstraint($clienthash) // 100; + _setClient( $hash, $clienthash->{ID}, 'volume', $maxvol ) if $c->{params}->{volume}->{percent} > $maxvol; return; }