Formatierung, diverse Bugfixes
This commit is contained in:
parent
bc9eb8ec8e
commit
80a84377e2
142
21_HEOSGroup.pm
142
21_HEOSGroup.pm
@ -36,7 +36,7 @@ use warnings;
|
||||
use JSON qw(decode_json);
|
||||
use Encode qw(encode_utf8);
|
||||
|
||||
my $version = "0.1.58";
|
||||
my $version = "0.1.60";
|
||||
|
||||
# Declare functions
|
||||
sub HEOSGroup_Initialize($);
|
||||
@ -53,10 +53,12 @@ sub HEOSGroup_GetGroupVolume($);
|
||||
sub HEOSGroup_GetGroupMute($);
|
||||
|
||||
sub HEOSGroup_Initialize($) {
|
||||
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = '.*{"command":."group.*|.*{"command":."event\/group.*';
|
||||
|
||||
|
||||
# Provider
|
||||
$hash->{SetFn} = "HEOSGroup_Set";
|
||||
$hash->{DefFn} = "HEOSGroup_Define";
|
||||
@ -69,26 +71,32 @@ sub HEOSGroup_Initialize($) {
|
||||
$readingFnAttributes;
|
||||
|
||||
foreach my $d(sort keys %{$modules{HEOSGroup}{defptr}}) {
|
||||
|
||||
my $hash = $modules{HEOSGroup}{defptr}{$d};
|
||||
$hash->{VERSION} = $version;
|
||||
}
|
||||
}
|
||||
|
||||
sub HEOSGroup_Define($$) {
|
||||
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t]+", $def );
|
||||
splice( @a, 1, 1 );
|
||||
my $iodev;
|
||||
my $i = 0;
|
||||
|
||||
|
||||
foreach my $param ( @a ) {
|
||||
if( $param =~ m/IODev=([^\s]*)/ ) {
|
||||
|
||||
$iodev = $1;
|
||||
splice( @a, $i, 3 );
|
||||
last;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return "too few parameters: define <name> HEOSGroup <gid>" if( @a < 2 );
|
||||
|
||||
my ($name,$gid) = @a;
|
||||
@ -97,73 +105,96 @@ sub HEOSGroup_Define($$) {
|
||||
$hash->{VERSION} = $version;
|
||||
$hash->{NOTIFYDEV} = "HEOSPlayer".abs($gid);
|
||||
AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
|
||||
|
||||
if(defined($hash->{IODev}->{NAME})) {
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - I/O device is " . $hash->{IODev}->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 1, "HEOSGroup ($name) - no I/O device";
|
||||
}
|
||||
|
||||
$iodev = $hash->{IODev}->{NAME};
|
||||
my $code = abs($gid);
|
||||
|
||||
$code = $iodev."-".$code if( defined($iodev) );
|
||||
my $d = $modules{HEOSGroup}{defptr}{$code};
|
||||
|
||||
return "HEOSGroup device $hash->{GID} on HEOSMaster $iodev already defined as $d->{NAME}."
|
||||
if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - defined with Code: $code";
|
||||
|
||||
$attr{$name}{room} = "HEOS" if( !defined( $attr{$name}{room} ) );
|
||||
$attr{$name}{devStateIcon} = "on:10px-kreis-gruen off:10px-kreis-rot" if( !defined( $attr{$name}{devStateIcon} ) );
|
||||
|
||||
if( $init_done ) {
|
||||
|
||||
InternalTimer( gettimeofday()+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
InternalTimer( gettimeofday()+15+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+15+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
|
||||
}
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, 'state','Initialized');
|
||||
readingsBulkUpdate($hash, 'volumeUp', 5);
|
||||
readingsBulkUpdate($hash, 'volumeDown', 5);
|
||||
readingsEndUpdate($hash, 1);
|
||||
|
||||
$modules{HEOSGroup}{defptr}{$code} = $hash;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSGroup_Undef($$) {
|
||||
|
||||
my ( $hash, $arg ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
my $code = abs($hash->{GID});
|
||||
$code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) );
|
||||
delete($modules{HEOSGroup}{defptr}{$code});
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - device $name deleted with Code: $code";
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSGroup_Attr(@) {
|
||||
|
||||
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
||||
my $hash = $defs{$name};
|
||||
my $token = $hash->{IODev}->{TOKEN};
|
||||
|
||||
|
||||
if( $attrName eq "disable" ) {
|
||||
if( $cmd eq "set" and $attrVal eq "1" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "disabled", 1 );
|
||||
Log3 $name, 3, "HEOSGroup ($name) - disabled";
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSGroup ($name) - enabled";
|
||||
}
|
||||
}
|
||||
|
||||
if( $attrName eq "disabledForIntervals" ) {
|
||||
if( $cmd eq "set" ) {
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - enable disabledForIntervals";
|
||||
readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSGroup ($name) - delete disabledForIntervals";
|
||||
}
|
||||
@ -171,27 +202,33 @@ sub HEOSGroup_Attr(@) {
|
||||
}
|
||||
|
||||
sub HEOSGroup_Notify($$) {
|
||||
|
||||
my ($hash,$dev) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
return undef if(IsDisabled($name));
|
||||
|
||||
my $events = deviceEvents($dev,1);
|
||||
|
||||
#print "notify ####################################################\n".Dumper($events);
|
||||
|
||||
return if( !$events );
|
||||
readingsBeginUpdate($hash);
|
||||
#my %playerEevents = map { my ( $key, $value ) = split ":"; $value =~ s/^\s+//; ( $key, $value ) } @$events;
|
||||
|
||||
my %playerEevents = map { my ( $key, $value ) = split /:\s/; $value =~ s/^\s+//; ( $key, $value ) } @$events;
|
||||
|
||||
foreach my $key ( keys %playerEevents ) {
|
||||
|
||||
#### playing Infos
|
||||
readingsBulkUpdate( $hash, $key, $playerEevents{$key} ) if( grep { $_ =~ /$key/ } ("channel", "currentAlbum", "currentArtist", "currentImageUrl", "currentMedia", "currentMid", "currentQid", "currentSid", "currentStation", "currentTitle", "error", "playStatus", "repeat", "shuffle" ) );
|
||||
}
|
||||
|
||||
readingsEndUpdate( $hash, 1 );
|
||||
}
|
||||
|
||||
sub HEOSGroup_Set($$@) {
|
||||
|
||||
my ($hash, $name, @aa) = @_;
|
||||
my ($cmd, @args) = @aa;
|
||||
my $gid = $hash->{GID};
|
||||
@ -202,110 +239,156 @@ sub HEOSGroup_Set($$@) {
|
||||
my $favoritcount = 1;
|
||||
my $string = "gid=$gid";
|
||||
|
||||
|
||||
#senden von Befehlen unterdrücken solange state nicht on ist
|
||||
return undef unless ( ReadingsVal($name, "state", "off") eq "on" );
|
||||
|
||||
if( $cmd eq 'getGroupInfo' ) {
|
||||
return "usage: getGroupInfo" if( @args != 0 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
|
||||
} elsif( $cmd eq 'mute' ) {
|
||||
return "usage: mute on/off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setGroupMute';
|
||||
$action = "state=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volume' ) {
|
||||
return "usage: volume 0-100" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setGroupVolume';
|
||||
$action = "level=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volumeUp' ) {
|
||||
return "usage: volumeUp 0-10" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'GroupVolumeUp';
|
||||
$action = "step=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volumeDown' ) {
|
||||
return "usage: volumeDown 0-10" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'groupVolumeDown';
|
||||
$action = "step=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'clearGroup' ) {
|
||||
return "usage: clearGroup" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'createGroup';
|
||||
$string = "pid=$gid";
|
||||
|
||||
} elsif( grep { $_ =~ /\Q$cmd\E/ } ("play", "stop", "pause", "next", "prev", "channel", "channelUp", "channelDown", "playlist" ) ) {
|
||||
|
||||
#ab hier Playerbefehle emuliert
|
||||
$string = "pid=$gid";
|
||||
|
||||
if( $cmd eq 'repeat' ) {
|
||||
return "usage: repeat one,all,off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setPlayMode';
|
||||
$rvalue = 'on_'.$args[0];
|
||||
$rvalue = 'off' if($rvalue eq 'on_off');
|
||||
$action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off');
|
||||
|
||||
} elsif( $cmd eq 'shuffle' ) {
|
||||
return "usage: shuffle on,off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setPlayMode';
|
||||
$rvalue = 'on_'.ReadingsVal($name,'repeat','off');
|
||||
$rvalue = 'off' if($rvalue eq 'on_off');
|
||||
$action = "repeat=$rvalue&shuffle=$args[0]";
|
||||
|
||||
} 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";
|
||||
|
||||
} elsif( $cmd eq 'pause' ) {
|
||||
return "usage: pause" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'setPlayState';
|
||||
$action = "state=$cmd";
|
||||
} elsif( $cmd eq 'next' ) {
|
||||
return "usage: next" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'playNext';
|
||||
|
||||
} elsif( $cmd eq 'prev' ) {
|
||||
return "usage: prev" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'playPrev';
|
||||
|
||||
} elsif ( $cmd eq 'channel' ) {
|
||||
|
||||
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
|
||||
return "usage: channel 1-$favoritcount" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'playPresetStation';
|
||||
$action = "preset=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'channelUp' ) {
|
||||
return "usage: channelUp" if( @args != 0 );
|
||||
|
||||
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
|
||||
$heosCmd = 'playPresetStation';
|
||||
$favorit = ReadingsVal($name,"channel", 0) + 1;
|
||||
$favorit = $favoritcount if ( $favorit > $favoritcount);
|
||||
$action = "preset=".$favorit;
|
||||
|
||||
} elsif( $cmd eq 'channelDown' ) {
|
||||
return "usage: channelDown" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'playPresetStation';
|
||||
$favorit = ReadingsVal($name,"channel", 0) - 1;
|
||||
$favorit = 1 if ($favorit <= 0);
|
||||
$action = "preset=".$favorit;
|
||||
|
||||
} elsif ( $cmd =~ /Playlist/ ) {
|
||||
|
||||
my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} });
|
||||
|
||||
if ( scalar @args == 1 && scalar @cids > 0 ) {
|
||||
if ( $cmd eq 'playPlaylist' ) {
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "sid=1025&cid=$cids[0]&aid=4";
|
||||
|
||||
} elsif ( $cmd eq 'deletePlaylist' ) {
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "cid=$cids[0]";
|
||||
$string = "sid=1025";
|
||||
}
|
||||
} else {
|
||||
|
||||
IOWrite($hash,'browseSource','sid=1025');
|
||||
my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}});
|
||||
return "usage: $cmd ".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 clearGroup:noArg repeat:one,all,off shuffle:on,off 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} ) {
|
||||
|
||||
my @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}";
|
||||
@ -313,42 +396,58 @@ sub HEOSGroup_Set($$@) {
|
||||
}
|
||||
|
||||
sub HEOSGroup_Parse($$) {
|
||||
|
||||
my ($io_hash,$json) = @_;
|
||||
my $name = $io_hash->{NAME};
|
||||
my $gid;
|
||||
my $decode_json;
|
||||
my $code;
|
||||
|
||||
|
||||
$decode_json = decode_json(encode_utf8($json));
|
||||
Log3 $name, 4, "HEOSGroup ($name) - ParseFn wurde aufgerufen";
|
||||
|
||||
if( defined($decode_json->{gid}) ) {
|
||||
|
||||
$gid = $decode_json->{gid};
|
||||
$code = abs($gid);
|
||||
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
|
||||
|
||||
|
||||
if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
|
||||
|
||||
IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}");
|
||||
Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}";
|
||||
Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find GID in root from decode_json";
|
||||
return $hash->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
my $devname = "HEOSGroup".abs($gid);
|
||||
return "UNDEFINED $devname HEOSGroup $gid IODev=$name";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
|
||||
|
||||
$gid = $message{pid} if( defined($message{pid}) );
|
||||
$gid = $message{gid} if( defined($message{gid}) );
|
||||
$gid = $decode_json->{payload}{gid} if( defined($decode_json->{payload}{gid}) );
|
||||
|
||||
Log3 $name, 4, "HEOSGroup ($name) - GID: $gid";
|
||||
|
||||
$code = abs($gid);
|
||||
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
|
||||
|
||||
if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
|
||||
|
||||
HEOSGroup_WriteReadings($hash,$decode_json);
|
||||
Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}";
|
||||
return $hash->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
my $devname = "HEOSGroup".abs($gid);
|
||||
return "UNDEFINED $devname HEOSGroup $gid IODev=$name";
|
||||
}
|
||||
@ -356,9 +455,11 @@ sub HEOSGroup_Parse($$) {
|
||||
}
|
||||
|
||||
sub HEOSGroup_WriteReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - processing data to write readings";
|
||||
############################
|
||||
#### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel)
|
||||
@ -370,31 +471,44 @@ sub HEOSGroup_WriteReadings($$) {
|
||||
readingsBeginUpdate($hash);
|
||||
### Event Readings
|
||||
if( ref($readingsHash) eq "HASH" ) {
|
||||
|
||||
Log3 $name, 4, "HEOSGroup ($name) - response json Hash back from HEOSGroup_PreProcessingReadings";
|
||||
my $t;
|
||||
my $v;
|
||||
|
||||
while( ( $t, $v ) = each (%{$readingsHash}) ) {
|
||||
|
||||
readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) );
|
||||
}
|
||||
}
|
||||
|
||||
readingsBulkUpdate( $hash, 'state', 'on' );
|
||||
### GroupInfos
|
||||
readingsBulkUpdate( $hash, 'name', $decode_json->{payload}{name} );
|
||||
readingsBulkUpdate( $hash, 'gid', $decode_json->{payload}{gid} );
|
||||
|
||||
if ( ref($decode_json->{payload}{players}) eq "ARRAY" ) {
|
||||
|
||||
my @members;
|
||||
|
||||
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" );
|
||||
}
|
||||
|
||||
if ( scalar @members > 1 ) {
|
||||
|
||||
readingsBulkUpdate( $hash, 'member', join(",",@members) );
|
||||
|
||||
} else {
|
||||
|
||||
readingsBulkUpdate( $hash, 'member', $members[0] );
|
||||
}
|
||||
}
|
||||
|
||||
readingsEndUpdate( $hash, 1 );
|
||||
|
||||
Log3 $name, 5, "HEOSGroup ($name) - readings set for $name";
|
||||
return undef;
|
||||
}
|
||||
@ -403,52 +517,68 @@ sub HEOSGroup_WriteReadings($$) {
|
||||
### my little Helpers
|
||||
|
||||
sub HEOSGroup_PreProcessingReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $reading;
|
||||
my %buffer;
|
||||
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSGroup ($name) - preprocessing readings";
|
||||
if ( $decode_json->{heos}{command} =~ /volume_changed/ or $decode_json->{heos}{command} =~ /set_volume/ or $decode_json->{heos}{command} =~ /get_volume/ ) {
|
||||
|
||||
my @value = split('&', $decode_json->{heos}{message});
|
||||
|
||||
$buffer{'volume'} = substr($value[1],6);
|
||||
$buffer{'mute'} = substr($value[2],5) if( $decode_json->{heos}{command} =~ /volume_changed/ );
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /volume_up/ or $decode_json->{heos}{command} =~ /volume_down/ ) {
|
||||
|
||||
my @value = split('&', $decode_json->{heos}{message});
|
||||
|
||||
$buffer{'volumeUp'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_up/ );
|
||||
$buffer{'volumeDown'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_down/ );
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) {
|
||||
|
||||
my @value = split('&', $decode_json->{heos}{message});
|
||||
|
||||
$buffer{'mute'} = substr($value[1],6);
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 3, "HEOSGroup ($name) - no match found";
|
||||
return undef;
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSGroup ($name) - Match found for decode_json";
|
||||
return \%buffer;
|
||||
}
|
||||
|
||||
sub HEOSGroup_GetGroupInfo($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSGroup_GetGroupInfo');
|
||||
IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}");
|
||||
}
|
||||
|
||||
sub HEOSGroup_GetGroupVolume($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSGroup_GetGroupVolume');
|
||||
IOWrite($hash,'getGroupVolume',"gid=$hash->{GID}");
|
||||
}
|
||||
|
||||
sub HEOSGroup_GetGroupMute($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSGroup_GetGroupMute');
|
||||
IOWrite($hash,'getGroupMute',"gid=$hash->{GID}");
|
||||
}
|
||||
|
248
21_HEOSMaster.pm
248
21_HEOSMaster.pm
@ -47,7 +47,7 @@ use Encode qw(encode_utf8);
|
||||
use Net::Telnet;
|
||||
use Data::Dumper;
|
||||
|
||||
my $version = "0.1.58";
|
||||
my $version = "0.1.60";
|
||||
|
||||
my %heosCmds = (
|
||||
'enableChangeEvents' => 'system/register_for_change_events?enable=',
|
||||
@ -126,8 +126,10 @@ sub HEOSMaster_GetPlaylists($);
|
||||
sub HEOSMaster_GetServers($);
|
||||
|
||||
sub HEOSMaster_Initialize($) {
|
||||
|
||||
my ($hash) = @_;
|
||||
|
||||
|
||||
# Provider
|
||||
$hash->{ReadFn} = "HEOSMaster_Read";
|
||||
$hash->{WriteFn} = "HEOSMaster_Write";
|
||||
@ -147,15 +149,18 @@ sub HEOSMaster_Initialize($) {
|
||||
$readingFnAttributes;
|
||||
|
||||
foreach my $d(sort keys %{$modules{HEOSMaster}{defptr}}) {
|
||||
|
||||
my $hash = $modules{HEOSMaster}{defptr}{$d};
|
||||
$hash->{VERSION} = $version;
|
||||
}
|
||||
}
|
||||
|
||||
sub HEOSMaster_Define($$) {
|
||||
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
|
||||
|
||||
return "too few parameters: define <name> HEOSMaster <HOST>" if( @a != 3 );
|
||||
|
||||
my $name = $a[0];
|
||||
@ -173,118 +178,159 @@ sub HEOSMaster_Define($$) {
|
||||
readingsEndUpdate($hash,1);
|
||||
|
||||
if( $init_done ) {
|
||||
|
||||
HEOSMaster_firstRun($hash);
|
||||
|
||||
} else {
|
||||
|
||||
InternalTimer( gettimeofday()+15, 'HEOSMaster_firstRun', $hash, 0 ) if( ($hash->{HOST}) );
|
||||
}
|
||||
|
||||
$modules{HEOSPlayer}{defptr}{$host} = $hash;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSMaster_Undef($$) {
|
||||
|
||||
my ( $hash, $arg ) = @_;
|
||||
my $host = $hash->{HOST};
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
HEOSMaster_Close($hash);
|
||||
delete $modules{HEOSMaster}{defptr}{$hash->{HOST}};
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted";
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSMaster_Attr(@) {
|
||||
|
||||
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
||||
my $hash = $defs{$name};
|
||||
my $orig = $attrVal;
|
||||
|
||||
|
||||
if( $attrName eq "disable" ) {
|
||||
if( $cmd eq "set" and $attrVal eq "1" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "disabled", 1 );
|
||||
Log3 $name, 3, "HEOSMaster ($name) - disabled";
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSMaster ($name) - enabled";
|
||||
}
|
||||
}
|
||||
|
||||
if( $attrName eq "disabledForIntervals" ) {
|
||||
if( $cmd eq "set" ) {
|
||||
|
||||
Log3 $name, 3, "HEOSMaster ($name) - enable disabledForIntervals";
|
||||
readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSMaster ($name) - delete disabledForIntervals";
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSMaster_Get($$@) {
|
||||
|
||||
my ($hash, $name, @aa) = @_;
|
||||
my ($cmd, @args) = @aa;
|
||||
my $pid = $hash->{PID};
|
||||
|
||||
|
||||
if( $cmd eq 'showAccount' ) {
|
||||
|
||||
return AttrVal($name,'heosUsername',0) . ":" .HEOSMaster_ReadPassword($hash);
|
||||
}
|
||||
|
||||
my $list = 'showAccount:noArg';
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
|
||||
sub HEOSMaster_Set($@) {
|
||||
|
||||
my ($hash, $name, $cmd, @args) = @_;
|
||||
my ($arg, @params) = @args;
|
||||
my $action;
|
||||
my $heosCmd;
|
||||
|
||||
|
||||
if($cmd eq 'reopen') {
|
||||
|
||||
return "usage: reopen" if( @args != 0 );
|
||||
HEOSMaster_ReOpen($hash);
|
||||
return undef;
|
||||
|
||||
} elsif($cmd eq 'getPlayers') {
|
||||
|
||||
return "usage: getPlayers" if( @args != 0 );
|
||||
$heosCmd = 'getPlayers';
|
||||
$action = undef;
|
||||
|
||||
} elsif($cmd eq 'getGroups') {
|
||||
|
||||
return "usage: getGroups" if( @args != 0 );
|
||||
$heosCmd = 'getGroups';
|
||||
$action = undef;
|
||||
|
||||
} elsif($cmd eq 'enableChangeEvents') {
|
||||
|
||||
return "usage: enableChangeEvents" if( @args != 1 );
|
||||
$heosCmd = $cmd;
|
||||
$action = $args[0];
|
||||
|
||||
} elsif($cmd eq 'checkAccount') {
|
||||
|
||||
return "usage: checkAccount" if( @args != 0 );
|
||||
$heosCmd = $cmd;
|
||||
$action = undef;
|
||||
|
||||
} elsif($cmd eq 'signAccount') {
|
||||
|
||||
return "usage: signAccountIn" if( @args != 1 );
|
||||
return "please set account informattion first" if(AttrVal($name,'heosUsername','none') eq 'none');
|
||||
$heosCmd = $cmd . $args[0];
|
||||
$action = 'un='. AttrVal($name,'heosUsername','none') . '&pw=' . HEOSMaster_ReadPassword($hash) if($args[0] eq 'In');
|
||||
|
||||
} elsif($cmd eq 'password') {
|
||||
|
||||
return "usage: password" if( @args != 1 );
|
||||
return HEOSMaster_StorePassword( $hash, $args[0] );
|
||||
|
||||
} elsif($cmd eq 'reboot') {
|
||||
|
||||
return "usage: reboot" if( @args != 0 );
|
||||
return HEOSMaster_StorePassword( $hash, $args[0] );
|
||||
###################################################
|
||||
### Dieser Menüpunkt ist nur zum testen
|
||||
|
||||
} elsif($cmd eq 'eventSend') {
|
||||
return "usage: eventSend" if( @args != 0 );
|
||||
HEOSMaster_send($hash);
|
||||
return undef;
|
||||
###################################################
|
||||
|
||||
} else {
|
||||
|
||||
my $list = "";
|
||||
$list .= "reopen:noArg getPlayers:noArg getGroups:noArg enableChangeEvents:on,off checkAccount:noArg signAccount:In,Out password reboot";
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
|
||||
HEOSMaster_Write($hash,$heosCmd,$action);
|
||||
}
|
||||
|
||||
sub HEOSMaster_Open($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
my $host = $hash->{HOST};
|
||||
@ -293,6 +339,7 @@ sub HEOSMaster_Open($) {
|
||||
my $user = AttrVal($name,'heosUsername',undef);
|
||||
my $password = HEOSMaster_ReadPassword($hash);
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - Baue Socket Verbindung auf";
|
||||
|
||||
my $socket = new Net::Telnet ( Host=>$host,
|
||||
@ -314,9 +361,11 @@ sub HEOSMaster_Open($) {
|
||||
|
||||
#hinzugefügt laut Protokoll 2.1.1 Initsequenz
|
||||
if( defined($user) and defined($password) ) {
|
||||
|
||||
HEOSMaster_Write($hash,'signAccountIn',"un=$user&pw=$password");
|
||||
Log3 $name, 4, "HEOSMaster ($name) - sign in";
|
||||
}
|
||||
|
||||
HEOSMaster_GetPlayers($hash);
|
||||
InternalTimer( gettimeofday()+1, 'HEOSMaster_EnableChangeEvents', $hash, 0 );
|
||||
InternalTimer( gettimeofday()+2, 'HEOSMaster_GetMusicSources', $hash, 0 );
|
||||
@ -324,93 +373,131 @@ sub HEOSMaster_Open($) {
|
||||
}
|
||||
|
||||
sub HEOSMaster_Close($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
return if( !$hash->{CD} );
|
||||
|
||||
close($hash->{CD}) if($hash->{CD});
|
||||
delete($hash->{FD});
|
||||
delete($hash->{CD});
|
||||
delete($selectlist{$name});
|
||||
|
||||
readingsSingleUpdate($hash, 'state', 'not connected', 1 );
|
||||
}
|
||||
|
||||
sub HEOSMaster_ReOpen($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
HEOSMaster_Close($hash);
|
||||
HEOSMaster_Open($hash) if( !$hash->{CD} or !defined($hash->{CD}) );
|
||||
}
|
||||
|
||||
sub HEOSMaster_Write($@) {
|
||||
|
||||
my ($hash,$heosCmd,$value) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $string = "heos://$heosCmds{$heosCmd}";
|
||||
|
||||
|
||||
if( defined($value) ) {
|
||||
|
||||
$string .= "${value}" if( $value ne '&' );
|
||||
}
|
||||
|
||||
$string .= "\r\n";
|
||||
Log3 $name, 4, "HEOSMaster ($name) - WriteFn called";
|
||||
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - socket not connected"
|
||||
unless($hash->{CD});
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - $string";
|
||||
syswrite($hash->{CD}, $string);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSMaster_Read($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
my $len;
|
||||
my $buf;
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - ReadFn gestartet";
|
||||
$len = sysread($hash->{CD},$buf,1024); # die genaue Puffergröße wird noch ermittelt
|
||||
|
||||
if( !defined($len) || !$len ) {
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - connection closed by remote Host";
|
||||
HEOSMaster_Close($hash);
|
||||
return;
|
||||
}
|
||||
|
||||
unless( defined $buf) {
|
||||
|
||||
Log3 $name, 3, "HEOSMaster ($name) - Keine Daten empfangen";
|
||||
return;
|
||||
}
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - received buffer data, start HEOSMaster_ProcessRead: $buf";
|
||||
HEOSMaster_ProcessRead($hash,$buf);
|
||||
}
|
||||
|
||||
sub HEOSMaster_ProcessRead($$) {
|
||||
|
||||
my ($hash, $data) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $buffer = '';
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - process read";
|
||||
#include previous partial message
|
||||
|
||||
if(defined($hash->{PARTIAL}) && $hash->{PARTIAL}) {
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL};
|
||||
$buffer = $hash->{PARTIAL};
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - No PARTIAL buffer";
|
||||
}
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - Incoming data: " . $data;
|
||||
|
||||
$buffer = $buffer . $data;
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - Current processing buffer (PARTIAL + incoming data): " . $buffer;
|
||||
|
||||
my ($json,$tail) = HEOSMaster_ParseMsg($hash, $buffer);
|
||||
#processes all complete messages
|
||||
|
||||
while($json) {
|
||||
|
||||
$hash->{LAST_RECV} = time();
|
||||
Log3 $name, 5, "HEOSMaster ($name) - Decoding JSON message. Length: " . length($json) . " Content: " . $json;
|
||||
my $obj = JSON->new->utf8(0)->decode($json);
|
||||
|
||||
if(defined($obj->{heos})) {
|
||||
|
||||
HEOSMaster_ResponseProcessing($hash,$json);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - starte HEOSMaster_ResponseProcessing";
|
||||
|
||||
} elsif(defined($obj->{error})) {
|
||||
|
||||
Log3 $name, 3, "HEOSMaster ($name) - Received error message: " . $json;
|
||||
}
|
||||
|
||||
($json,$tail) = HEOSMaster_ParseMsg($hash, $tail);
|
||||
}
|
||||
|
||||
$hash->{PARTIAL} = $tail;
|
||||
Log3 $name, 5, "HEOSMaster ($name) - Tail: " . $tail;
|
||||
Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL};
|
||||
@ -418,10 +505,12 @@ sub HEOSMaster_ProcessRead($$) {
|
||||
}
|
||||
|
||||
sub HEOSMaster_ResponseProcessing($$) {
|
||||
|
||||
my ($hash,$json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $decode_json;
|
||||
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - JSON String: $json";
|
||||
return Log3 $name, 3, "HEOSMaster ($name) - empty answer received"
|
||||
unless( defined($json));
|
||||
@ -436,6 +525,7 @@ sub HEOSMaster_ResponseProcessing($$) {
|
||||
if( $decode_json->{heos}{message} =~ /command\sunder\sprocess/ );
|
||||
|
||||
if( defined($decode_json->{heos}{result}) or $decode_json->{heos}{command} =~ /^system/ ) {
|
||||
|
||||
HEOSMaster_WriteReadings($hash,$decode_json);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Sub HEOSMaster_WriteReadings";
|
||||
}
|
||||
@ -447,24 +537,28 @@ sub HEOSMaster_ResponseProcessing($$) {
|
||||
|
||||
#Quellen neu einlesen
|
||||
if( $decode_json->{heos}{command} =~ /^event\/sources_changed/ ) {
|
||||
|
||||
HEOSMaster_Write($hash,'getMusicSources',undef);
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - source changed";
|
||||
}
|
||||
|
||||
#Player neu einlesen
|
||||
if( $decode_json->{heos}{command} =~ /^event\/players_changed/ ) {
|
||||
|
||||
HEOSMaster_Write($hash,'getPlayers',undef);
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - player changed";
|
||||
}
|
||||
|
||||
#User neu einlesen
|
||||
if( $decode_json->{heos}{command} =~ /^event\/user_changed/ ) {
|
||||
|
||||
HEOSMaster_Write($hash,'checkAccount',undef);
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - user changed";
|
||||
}
|
||||
|
||||
#Gruppen neu einlesen
|
||||
if( $decode_json->{heos}{command} =~ /^event\/groups_changed/ ) {
|
||||
|
||||
#InternalTimer( gettimeofday()+5, 'HEOSMaster_GetGroups', $hash, 0 );
|
||||
HEOSMaster_Write($hash,'getGroups',undef);
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - groups changed";
|
||||
@ -478,78 +572,113 @@ sub HEOSMaster_ResponseProcessing($$) {
|
||||
|
||||
foreach my $payload ( @{$decode_json->{payload}} ) {
|
||||
if( $payload->{sid} eq "1024" ) {
|
||||
|
||||
$i += 2;
|
||||
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetServers', $hash, 0 );
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetServers in $i seconds";
|
||||
|
||||
} elsif( $payload->{sid} eq "1025" ) {
|
||||
|
||||
$i += 2;
|
||||
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetPlaylists', $hash, 0 );
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetPlaylists in $i seconds";
|
||||
|
||||
} elsif( $payload->{sid} eq "1026" ) {
|
||||
|
||||
$i += 2;
|
||||
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetHistory', $hash, 0 );
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetHistory in $i seconds";
|
||||
|
||||
} elsif( $payload->{sid} eq "1027" ) {
|
||||
|
||||
$i += 2;
|
||||
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetInputs', $hash, 0 );
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetInputs in $i seconds";
|
||||
|
||||
} elsif( $payload->{sid} eq "1028" ) {
|
||||
|
||||
$i += 2;
|
||||
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetFavorites', $hash, 0 );
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetFavorites in $i seconds";
|
||||
|
||||
} else {
|
||||
|
||||
#Onlinedienste
|
||||
push( @{$hash->{helper}{sources}},$payload);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - GetRadioSource {$payload->{name} with sid $payload->{sid}";
|
||||
}
|
||||
}
|
||||
|
||||
return Log3 $name, 3, "HEOSMaster ($name) - call Sourcebrowser";
|
||||
}
|
||||
|
||||
if( $decode_json->{heos}{command} =~ /^browse\/browse/ and ref($decode_json->{payload}) eq "ARRAY" and scalar(@{$decode_json->{payload}}) > 0) {
|
||||
if ( defined $message{sid} ) {
|
||||
#my @range = ( 0 );
|
||||
#@range = split(',', $message{range}) if ( defined $message{range} );
|
||||
if ( defined $message{range} ) { $message{range} =~ s/(\d+)\,\d+/$1/; }
|
||||
else { $message{range} = 0; }
|
||||
if ( defined $message{range} ) {
|
||||
|
||||
$message{range} =~ s/(\d+)\,\d+/$1/;
|
||||
|
||||
} else {
|
||||
|
||||
$message{range} = 0;
|
||||
}
|
||||
|
||||
my $start = $message{range} + $message{returned};
|
||||
|
||||
if( $message{sid} eq '1028' ) {
|
||||
|
||||
#Favoriten einlesen
|
||||
$hash->{helper}{favorites} = [] if ( $message{range} == 0 );
|
||||
push( @{$hash->{helper}{favorites}}, (@{$decode_json->{payload}}) );
|
||||
|
||||
if ( $start >= $message{count} ) {
|
||||
|
||||
#Nachricht an die Player das sich die Favoriten geändert haben
|
||||
foreach my $dev ( devspec2array("TYPE=HEOSPlayer") ) {
|
||||
|
||||
$json = '{"heos": {"command": "event/favorites_changed", "message": "pid='.$defs{$dev}->{PID}.'"}}';
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Favorites Changed";
|
||||
}
|
||||
}
|
||||
|
||||
} elsif( $message{sid} eq '1026' ) {
|
||||
|
||||
#History einlesen
|
||||
$hash->{helper}{history} = [] if ( $message{range} == 0 );
|
||||
push( @{$hash->{helper}{history}}, (@{$decode_json->{payload}}) );
|
||||
|
||||
} elsif( $message{sid} eq '1025' ) {
|
||||
|
||||
#Playlisten einlesen
|
||||
$hash->{helper}{playlists} = [] if ( $message{range} == 0 );
|
||||
push( @{$hash->{helper}{playlists}}, (@{$decode_json->{payload}}) );
|
||||
|
||||
} elsif( $message{sid} eq '1027' ) {
|
||||
|
||||
#Inputs einlesen
|
||||
push( @{$hash->{helper}{sources}}, map { $_->{name} .= " AUX"; $_ } (@{$decode_json->{payload}}) );
|
||||
|
||||
} elsif( $message{sid} eq '1024' ) {
|
||||
|
||||
#Lokal einlesen
|
||||
push( @{$hash->{helper}{sources}}, map { $_->{name} .= " USB" if ( $_->{sid} < 0 ); $_ } (@{$decode_json->{payload}}) );
|
||||
|
||||
} else {
|
||||
|
||||
#aktuellen Input/Media einlesen
|
||||
$hash->{helper}{media} = [] if ( $message{range} == 0 );
|
||||
push( @{$hash->{helper}{media}}, (@{$decode_json->{payload}}) );
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Browser with sid $message{sid} and $message{returned} items from $message{count} items";
|
||||
|
||||
if ( $start < $message{count} ) {
|
||||
|
||||
HEOSMaster_Write($hash,'browseSource',"sid=$message{sid}&range=$start,".($start + 100) );
|
||||
Log3 $name, 3, "HEOSMaster ($name) - call Browser with sid $message{sid} next Range from $message{returned}";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -557,22 +686,29 @@ 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( $decode_json->{heos}{command} =~ /player\/get_players/ ) {
|
||||
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received"
|
||||
unless(scalar(@{$decode_json->{payload}}) > 0);
|
||||
|
||||
foreach my $payload (@{$decode_json->{payload}}) {
|
||||
|
||||
$json = '{"pid": "';
|
||||
$json .= "$payload->{pid}";
|
||||
$json .= '","heos": {"command": "player/get_player_info"}}';
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Players";
|
||||
}
|
||||
|
||||
} elsif( $decode_json->{heos}{command} =~ /group\/get_groups/ ) {
|
||||
|
||||
my $filter = "TYPE=HEOSGroup";
|
||||
|
||||
if ( scalar(@{$decode_json->{payload}}) > 0 ) {
|
||||
|
||||
$filter .= ":FILTER=GID!=";
|
||||
|
||||
foreach my $payload (@{$decode_json->{payload}}) {
|
||||
|
||||
$json = '{"gid": "';
|
||||
$json .= "$payload->{gid}";
|
||||
$json .= '","heos": {"command": "group/get_group_info"}}';
|
||||
@ -580,40 +716,52 @@ sub HEOSMaster_ResponseProcessing($$) {
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Groups";
|
||||
$filter .= $payload->{gid}."|";
|
||||
}
|
||||
|
||||
chop($filter); #letztes | wieder abschneiden
|
||||
}
|
||||
|
||||
#alle Gruppe ausschalten die nicht mehr im HEOS System existieren
|
||||
foreach my $dev ( devspec2array($filter) ) {
|
||||
|
||||
my $ghash = $defs{$dev};
|
||||
readingsSingleUpdate( $ghash, "state", "off", 1 );
|
||||
}
|
||||
|
||||
} elsif( $decode_json->{heos}{command} =~ /player\/get_queue/ ) {
|
||||
return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received"
|
||||
unless(scalar(@{$decode_json->{payload}}) > 0);
|
||||
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for QueueInfo";
|
||||
#} elsif( defined($decode_json->{payload}{pid}) ) {
|
||||
|
||||
} elsif( $decode_json->{heos}{command} =~ /player\/get_player_info/ ) { # ist vielleicht verständlicher?
|
||||
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for PlayerInfo";
|
||||
#} elsif( defined($decode_json->{payload}{gid}) and defined($decode_json->{payload}{players}) ) {
|
||||
|
||||
} elsif( $decode_json->{heos}{command} =~ /group\/get_group_info/ ) { # ist vielleicht verständlicher?
|
||||
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for GroupInfo";
|
||||
|
||||
} elsif( defined($message{pid}) or defined($message{gid}) ) {
|
||||
|
||||
Dispatch($hash,$json,undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - no Match for processing data";
|
||||
}
|
||||
|
||||
sub HEOSMaster_WriteReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
############################
|
||||
#### Aufbereiten der Daten soweit nötig
|
||||
my $readingsHash = HEOSMaster_PreProcessingReadings($hash,$decode_json)
|
||||
@ -629,20 +777,26 @@ sub HEOSMaster_WriteReadings($$) {
|
||||
|
||||
### Event Readings
|
||||
if( ref($readingsHash) eq "HASH" ) {
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - response json Hash back from HEOSMaster_PreProcessingReadings";
|
||||
my $t;
|
||||
my $v;
|
||||
|
||||
while( ( $t, $v ) = each (%{$readingsHash}) ) {
|
||||
|
||||
readingsBulkUpdate( $hash, $t, $v ) if( defined($v) );
|
||||
}
|
||||
}
|
||||
|
||||
readingsBulkUpdate( $hash, "lastCommand", $decode_json->{heos}{command} );
|
||||
readingsBulkUpdate( $hash, "lastResult", $decode_json->{heos}{result} );
|
||||
|
||||
if( ref($decode_json->{payload}) ne "ARRAY" ) {
|
||||
|
||||
readingsBulkUpdate( $hash, "lastPlayerId", $decode_json->{payload}{pid} );
|
||||
readingsBulkUpdate( $hash, "lastPlayerName", $decode_json->{payload}{name} );
|
||||
}
|
||||
|
||||
readingsEndUpdate( $hash, 1 );
|
||||
return undef;
|
||||
}
|
||||
@ -651,6 +805,7 @@ sub HEOSMaster_WriteReadings($$) {
|
||||
### my little Helpers
|
||||
|
||||
sub HEOSMaster_ParseMsg($$) {
|
||||
|
||||
my ($hash, $buffer) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $open = 0;
|
||||
@ -658,169 +813,220 @@ sub HEOSMaster_ParseMsg($$) {
|
||||
my $msg = '';
|
||||
my $tail = '';
|
||||
|
||||
|
||||
if($buffer) {
|
||||
foreach my $c (split //, $buffer) {
|
||||
if($open == $close && $open > 0) {
|
||||
$tail .= $c;
|
||||
#Log3 $name, 5, "HEOSMaster ($name) - $open == $close && $open > 0";
|
||||
|
||||
} elsif(($open == $close) && ($c ne '{')) {
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - Garbage character before message: " . $c;
|
||||
|
||||
} else {
|
||||
|
||||
if($c eq '{') {
|
||||
|
||||
$open++;
|
||||
|
||||
} elsif($c eq '}') {
|
||||
|
||||
$close++;
|
||||
}
|
||||
|
||||
$msg .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
if($open != $close) {
|
||||
|
||||
$tail = $msg;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
|
||||
Log3 $name, 5, "HEOSMaster ($name) - return msg: $msg and tail: $tail";
|
||||
return ($msg,$tail);
|
||||
}
|
||||
|
||||
sub HEOSMaster_PreProcessingReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $reading;
|
||||
my %buffer;
|
||||
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - preprocessing readings";
|
||||
|
||||
if ( $decode_json->{heos}{command} eq 'system/register_for_change_events' ) {
|
||||
|
||||
$buffer{'enableChangeEvents'} = $message{enable};
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} eq 'system/check_account' or $decode_json->{heos}{command} eq 'system/sign_in' ) {
|
||||
if ( exists $message{signed_out} ) {
|
||||
|
||||
$buffer{'heosAccount'} = "signed_out";
|
||||
|
||||
} else {
|
||||
|
||||
$buffer{'heosAccount'} = "signed_in as $message{un}";
|
||||
HEOSMaster_GetFavorites($hash) if( ReadingsVal($name,"enableChangeEvents", "off") eq "on" );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 3, "HEOSMaster ($name) - no match found";
|
||||
return undef;
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - Match found for decode_json";
|
||||
return \%buffer;
|
||||
}
|
||||
|
||||
sub HEOSMaster_firstRun($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSMaster_firstRun');
|
||||
HEOSMaster_Open($hash) if( !IsDisabled($name) );
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetPlayers($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSMaster_GetPlayers');
|
||||
HEOSMaster_Write($hash,'getPlayers',undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getPlayers";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetGroups($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSMaster_GetGroups');
|
||||
HEOSMaster_Write($hash,'getGroups',undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getGroups";
|
||||
}
|
||||
|
||||
sub HEOSMaster_EnableChangeEvents($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSMaster_EnableChangeEvents');
|
||||
HEOSMaster_Write($hash,'enableChangeEvents','on');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - set enableChangeEvents on";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetMusicSources($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetMusicSources');
|
||||
HEOSMaster_Write($hash,'getMusicSources',undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getMusicSources";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetFavorites($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetFavorites');
|
||||
HEOSMaster_Write($hash,'browseSource','sid=1028');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getFavorites";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetInputs($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetInputs');
|
||||
HEOSMaster_Write($hash,'browseSource','sid=1027');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getInputs";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetServers($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetServers');
|
||||
HEOSMaster_Write($hash,'browseSource','sid=1024');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getServers";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetPlaylists($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetPlaylists');
|
||||
HEOSMaster_Write($hash,'browseSource','sid=1025');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getPlaylists";
|
||||
}
|
||||
|
||||
sub HEOSMaster_GetHistory($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_GetHistory');
|
||||
HEOSMaster_Write($hash,'browseSource','sid=1026');
|
||||
Log3 $name, 4, "HEOSMaster ($name) - getHistory";
|
||||
}
|
||||
|
||||
sub HEOSMaster_CheckAccount($) {
|
||||
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash, 'HEOSMaster_CheckAccount');
|
||||
HEOSMaster_Write($hash,'checkAccount',undef);
|
||||
Log3 $name, 4, "HEOSMaster ($name) - checkAccount";
|
||||
}
|
||||
|
||||
sub HEOSMaster_StorePassword($$) {
|
||||
|
||||
my ($hash, $password) = @_;
|
||||
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
|
||||
my $key = getUniqueId().$index;
|
||||
my $enc_pwd = "";
|
||||
|
||||
|
||||
if(eval "use Digest::MD5;1") {
|
||||
|
||||
$key = Digest::MD5::md5_hex(unpack "H*", $key);
|
||||
$key .= Digest::MD5::md5_hex($key);
|
||||
}
|
||||
|
||||
for my $char (split //, $password) {
|
||||
|
||||
my $encode=chop($key);
|
||||
$enc_pwd.=sprintf("%.2x",ord($char)^ord($encode));
|
||||
$key=$encode.$key;
|
||||
}
|
||||
|
||||
my $err = setKeyValue($index, $enc_pwd);
|
||||
return "error while saving the password - $err" if(defined($err));
|
||||
|
||||
@ -828,32 +1034,45 @@ sub HEOSMaster_StorePassword($$) {
|
||||
}
|
||||
|
||||
sub HEOSMaster_ReadPassword($) {
|
||||
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
|
||||
my $key = getUniqueId().$index;
|
||||
my ($password, $err);
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - Read FritzBox password from file";
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - Read password from file";
|
||||
|
||||
($err, $password) = getKeyValue($index);
|
||||
|
||||
if ( defined($err) ) {
|
||||
Log3 $name, 4, "HEOSMaster ($name) - unable to read FritzBox password from file: $err";
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - unable to read password from file: $err";
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
if ( defined($password) ) {
|
||||
if ( eval "use Digest::MD5;1" ) {
|
||||
|
||||
$key = Digest::MD5::md5_hex(unpack "H*", $key);
|
||||
$key .= Digest::MD5::md5_hex($key);
|
||||
}
|
||||
|
||||
my $dec_pwd = '';
|
||||
|
||||
for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) {
|
||||
|
||||
my $decode=chop($key);
|
||||
$dec_pwd.=chr(ord($char)^ord($decode));
|
||||
$key=$decode.$key;
|
||||
}
|
||||
|
||||
return $dec_pwd;
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 4, "HEOSMaster ($name) - No password in file";
|
||||
return undef;
|
||||
}
|
||||
@ -862,7 +1081,10 @@ sub HEOSMaster_ReadPassword($) {
|
||||
################
|
||||
### Nur für mich um dem Emulator ein Event ab zu jagen
|
||||
sub HEOSMaster_send($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
HEOSMaster_Write($hash,'eventChangeVolume',undef);
|
||||
}
|
||||
|
||||
|
243
21_HEOSPlayer.pm
243
21_HEOSPlayer.pm
@ -37,7 +37,7 @@ use JSON qw(decode_json);
|
||||
use Encode qw(encode_utf8);
|
||||
use Data::Dumper;
|
||||
|
||||
my $version = "0.1.58";
|
||||
my $version = "0.1.60";
|
||||
|
||||
# Declare functions
|
||||
sub HEOSPlayer_Initialize($);
|
||||
@ -57,10 +57,12 @@ sub HEOSPlayer_Get($$@);
|
||||
sub HEOSPlayer_GetMute($);
|
||||
|
||||
sub HEOSPlayer_Initialize($) {
|
||||
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = '.*{"command":."player.*|.*{"command":."event/player.*|.*{"command":."event\/repeat_mode_changed.*|.*{"command":."event\/shuffle_mode_changed.*|.*{"command":."event\/favorites_changed.*';
|
||||
|
||||
|
||||
# Provider
|
||||
$hash->{SetFn} = "HEOSPlayer_Set";
|
||||
$hash->{GetFn} = "HEOSPlayer_Get";
|
||||
@ -74,26 +76,32 @@ sub HEOSPlayer_Initialize($) {
|
||||
$readingFnAttributes;
|
||||
|
||||
foreach my $d(sort keys %{$modules{HEOSPlayer}{defptr}}) {
|
||||
|
||||
my $hash = $modules{HEOSPlayer}{defptr}{$d};
|
||||
$hash->{VERSION} = $version;
|
||||
}
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Define($$) {
|
||||
|
||||
my ( $hash, $def ) = @_;
|
||||
my @a = split( "[ \t]+", $def );
|
||||
splice( @a, 1, 1 );
|
||||
my $iodev;
|
||||
my $i = 0;
|
||||
|
||||
|
||||
foreach my $param ( @a ) {
|
||||
if( $param =~ m/IODev=([^\s]*)/ ) {
|
||||
|
||||
$iodev = $1;
|
||||
splice( @a, $i, 3 );
|
||||
last;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return "too few parameters: define <name> HEOSPlayer <pid>" if( @a < 2 );
|
||||
|
||||
my ($name,$pid) = @a;
|
||||
@ -101,30 +109,40 @@ sub HEOSPlayer_Define($$) {
|
||||
$hash->{PID} = $pid;
|
||||
$hash->{VERSION} = $version;
|
||||
AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
|
||||
|
||||
if(defined($hash->{IODev}->{NAME})) {
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - I/O device is " . $hash->{IODev}->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 1, "HEOSPlayer ($name) - no I/O device";
|
||||
}
|
||||
|
||||
$iodev = $hash->{IODev}->{NAME};
|
||||
my $code = abs($pid);
|
||||
|
||||
$code = $iodev."-".$code if( defined($iodev) );
|
||||
my $d = $modules{HEOSPlayer}{defptr}{$code};
|
||||
|
||||
return "HEOSPlayer device $hash->{pid} on HEOSMaster $iodev already defined as $d->{NAME}."
|
||||
if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - defined with Code: $code";
|
||||
$attr{$name}{room} = "HEOS" if( !defined( $attr{$name}{room} ) );
|
||||
$attr{$name}{devStateIcon} = "on:10px-kreis-gruen off:10px-kreis-rot" if( !defined( $attr{$name}{devStateIcon} ) );
|
||||
|
||||
if( $init_done ) {
|
||||
|
||||
InternalTimer( gettimeofday()+int(rand(2)), "HEOSPlayer_GetPlayerInfo", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(4)), "HEOSPlayer_GetPlayState", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(6)), "HEOSPlayer_GetNowPlayingMedia", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(8)), "HEOSPlayer_GetPlayMode", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(10)), "HEOSPlayer_GetVolume", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
InternalTimer( gettimeofday()+15+int(rand(2)), "HEOSPlayer_GetPlayerInfo", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+15+int(rand(4)), "HEOSPlayer_GetPlayState", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSPlayer_GetNowPlayingMedia", $hash, 0 );
|
||||
@ -132,49 +150,61 @@ sub HEOSPlayer_Define($$) {
|
||||
InternalTimer( gettimeofday()+15+int(rand(10)), "HEOSPlayer_GetVolume", $hash, 0 );
|
||||
InternalTimer( gettimeofday()+15+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 );
|
||||
}
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate($hash, 'state','Initialized');
|
||||
readingsBulkUpdate($hash, 'volumeUp', 5);
|
||||
readingsBulkUpdate($hash, 'volumeDown', 5);
|
||||
readingsEndUpdate($hash, 1);
|
||||
|
||||
$modules{HEOSPlayer}{defptr}{$code} = $hash;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Undef($$) {
|
||||
|
||||
my ( $hash, $arg ) = @_;
|
||||
my $pid = $hash->{PID};
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
my $code = abs($pid);
|
||||
$code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) );
|
||||
delete($modules{HEOSPlayer}{defptr}{$code});
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted with Code: $code";
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Attr(@) {
|
||||
|
||||
my ( $cmd, $name, $attrName, $attrVal ) = @_;
|
||||
my $hash = $defs{$name};
|
||||
my $token = $hash->{IODev}->{TOKEN};
|
||||
|
||||
|
||||
if( $attrName eq "disable" ) {
|
||||
if( $cmd eq "set" and $attrVal eq "1" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "disabled", 1 );
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - disabled";
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - enabled";
|
||||
}
|
||||
}
|
||||
|
||||
if( $attrName eq "disabledForIntervals" ) {
|
||||
if( $cmd eq "set" ) {
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - enable disabledForIntervals";
|
||||
readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
|
||||
}
|
||||
elsif( $cmd eq "del" ) {
|
||||
|
||||
} elsif( $cmd eq "del" ) {
|
||||
|
||||
readingsSingleUpdate ( $hash, "state", "active", 1 );
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - delete disabledForIntervals";
|
||||
}
|
||||
@ -182,48 +212,58 @@ sub HEOSPlayer_Attr(@) {
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Get($$@) {
|
||||
|
||||
my ($hash, $name, @aa) = @_;
|
||||
my ($cmd, @args) = @aa;
|
||||
my $pid = $hash->{PID};
|
||||
my $result = "";
|
||||
|
||||
|
||||
#print "CL ###################################################\n".Dumper($hash->{CL});
|
||||
$hash->{helper}{cl} = $hash->{CL} if( ref($hash->{CL}) eq 'HASH' );
|
||||
|
||||
#Leerzeichen müßen für die Rückgabe escaped werden sonst werden sie falsch angezeigt
|
||||
if( $cmd eq 'playlists' ) {
|
||||
|
||||
#gibt die Playlisten durch Komma getrennt zurück
|
||||
my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}});
|
||||
|
||||
$result .= join(",",@playlists) if( scalar @playlists > 0 );
|
||||
return $result;
|
||||
|
||||
} elsif( $cmd eq 'channels' ) {
|
||||
|
||||
#gibt die Favoriten durch Komma getrennt zurück
|
||||
my @channels = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{favorites}});
|
||||
|
||||
$result .= join(",",@channels) if( scalar @channels > 0 );
|
||||
return $result;
|
||||
|
||||
} elsif( $cmd eq 'channelscount' ) {
|
||||
|
||||
#gibt die Favoritenanzahl zurück
|
||||
return scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
|
||||
|
||||
} elsif( $cmd eq 'inputs' ) {
|
||||
|
||||
#gibt die Quellen durch Komma getrennt zurück
|
||||
my @inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{sources}});
|
||||
push(@inputs, "Warteschlange");
|
||||
$result .= join(",",@inputs) if( scalar @inputs > 0 );
|
||||
return $result;
|
||||
|
||||
} elsif( $cmd eq 'search' ) {
|
||||
|
||||
return "usage: search <keywords>" if( @args != 1 );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
my $list = 'playlists:noArg channels:noArg channelscount:noArg inputs:noArg ls search';
|
||||
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Set($$@) {
|
||||
|
||||
my ($hash, $name, @aa) = @_;
|
||||
my ($cmd, @args) = @aa;
|
||||
my $pid = $hash->{PID};
|
||||
@ -232,185 +272,270 @@ sub HEOSPlayer_Set($$@) {
|
||||
my $rvalue;
|
||||
my $favoritcount = 1;
|
||||
my $qcount = 1;
|
||||
my $string = "pid=$pid";
|
||||
my $string = '';
|
||||
|
||||
|
||||
#print "cmd ###################################################\n".Dumper($cmd);
|
||||
|
||||
if( $cmd eq 'getPlayerInfo' ) {
|
||||
return "usage: getPlayerInfo" if( @args != 0 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
|
||||
} elsif( $cmd eq 'getPlayState' ) {
|
||||
return "usage: getPlayState" if( @args != 0 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
|
||||
} elsif( $cmd eq 'getPlayMode' ) {
|
||||
return "usage: getPlayMode" if( @args != 0 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
|
||||
} elsif( $cmd eq 'getNowPlayingMedia' ) {
|
||||
return "usage: getNowPlayingMedia" if( @args != 0 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
|
||||
} elsif( $cmd eq 'repeat' ) {
|
||||
return "usage: repeat one,all,off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setPlayMode';
|
||||
$rvalue = 'on_'.$args[0];
|
||||
$rvalue = 'off' if($rvalue eq 'on_off');
|
||||
$action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off');
|
||||
|
||||
} elsif( $cmd eq 'shuffle' ) {
|
||||
return "usage: shuffle on,off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setPlayMode';
|
||||
$rvalue = 'on_'.ReadingsVal($name,'repeat','off');
|
||||
$rvalue = 'off' if($rvalue eq 'on_off');
|
||||
$action = "repeat=$rvalue&shuffle=$args[0]";
|
||||
|
||||
} 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";
|
||||
|
||||
} elsif( $cmd eq 'pause' ) {
|
||||
return "usage: pause" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'setPlayState';
|
||||
$action = "state=$cmd";
|
||||
|
||||
} elsif( $cmd eq 'mute' ) {
|
||||
return "usage: mute on/off" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setMute';
|
||||
$action = "state=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volume' ) {
|
||||
return "usage: volume 0-100" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'setVolume';
|
||||
$action = "level=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volumeUp' ) {
|
||||
return "usage: volumeUp 0-10" if( @args != 1 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "step=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'volumeDown' ) {
|
||||
return "usage: volumeDown 0-10" if( @args != 1 );
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "step=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'groupWithMember' ) {
|
||||
return "usage: groupWithMember" if( @args != 1 );
|
||||
|
||||
$pid .= ",$defs{$args[0]}->{PID}";
|
||||
$heosCmd = 'createGroup';
|
||||
|
||||
} elsif( $cmd eq 'clearGroup' ) {
|
||||
return "usage: clearGroup" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'createGroup';
|
||||
|
||||
} elsif( $cmd eq 'next' ) {
|
||||
return "usage: next" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'playNext';
|
||||
|
||||
} elsif( $cmd eq 'prev' ) {
|
||||
return "usage: prev" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'playPrev';
|
||||
#} elsif( $cmd eq 'reReadSources' ) {
|
||||
# return "usage: reReadSources" if( @args != 0 );
|
||||
# $heosCmd = 'getMusicSources';
|
||||
|
||||
} elsif ( $cmd =~ /channel/ ) {
|
||||
|
||||
my $favorit = ReadingsVal($name,"channel", 0);
|
||||
|
||||
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
|
||||
$heosCmd = 'playPresetStation';
|
||||
|
||||
if ( $cmd eq 'channel' ) {
|
||||
return "usage: channel 1-$favoritcount" if( @args != 1 );
|
||||
|
||||
$action = "preset=$args[0]";
|
||||
|
||||
} elsif( $cmd eq 'channelUp' ) {
|
||||
return "usage: channelUp" if( @args != 0 );
|
||||
|
||||
$favorit = $favoritcount if ( ++$favorit > $favoritcount );
|
||||
$action = "preset=".$favorit;
|
||||
|
||||
} elsif( $cmd eq 'channelDown' ) {
|
||||
|
||||
$favorit = 1 if ( --$favorit <= 0 );
|
||||
$action = "preset=".$favorit;
|
||||
}
|
||||
|
||||
} elsif ( $cmd =~ /Playlist/ ) {
|
||||
|
||||
my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} });
|
||||
|
||||
if ( scalar @args == 1 && scalar @cids > 0 ) {
|
||||
if ( $cmd eq 'playPlaylist' ) {
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "sid=1025&cid=$cids[0]&aid=4";
|
||||
|
||||
} elsif ( $cmd eq 'deletePlaylist' ) {
|
||||
|
||||
$heosCmd = $cmd;
|
||||
$action = "cid=$cids[0]";
|
||||
$string = "sid=1025";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
IOWrite($hash,'browseSource','sid=1025');
|
||||
my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}});
|
||||
return "usage: $cmd ".join(",",@playlists);
|
||||
}
|
||||
|
||||
} elsif( $cmd eq 'input' ) {
|
||||
|
||||
my @sids;
|
||||
my $search = $args[0];
|
||||
|
||||
$search =~ s/\xC2\xA0/ /g;
|
||||
#$search =~ s/\s+/\ /g;
|
||||
|
||||
if ( $search =~ /Warteschlange/ ) {
|
||||
|
||||
push(@sids, "9999");
|
||||
|
||||
} else {
|
||||
|
||||
@sids = map { $_->{sid} } grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{sources} });
|
||||
}
|
||||
|
||||
if ( scalar @args == 1 && scalar @sids > 0 ) {
|
||||
|
||||
readingsSingleUpdate($hash, "input", $args[0], 1);
|
||||
#sid des Input für Container merken
|
||||
readingsSingleUpdate($hash, ".input", $sids[0], 1);
|
||||
#alten Container löschen bei Inputwechsel
|
||||
readingsSingleUpdate($hash, ".cid", 0, 1);
|
||||
|
||||
if ( $sids[0] eq "9999" ) {
|
||||
|
||||
$heosCmd = 'getQueue';
|
||||
|
||||
} else {
|
||||
|
||||
$heosCmd = 'browseSource';
|
||||
$action = "sid=$sids[0]";
|
||||
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - set input with sid $sids[0] and name $args[0]";
|
||||
|
||||
} else {
|
||||
|
||||
my @inputs = map { $_->{name} } (@{ $hash->{IODev}{helper}{sources}});
|
||||
push(@inputs, "Warteschlange");
|
||||
return "usage: input ".join(",",@inputs);
|
||||
}
|
||||
|
||||
} elsif( $cmd eq 'media' ) {
|
||||
|
||||
my @ids;
|
||||
my $search = $args[0];
|
||||
my $sid = ReadingsVal($name,".input", "9999");
|
||||
|
||||
return "usage: set input first" unless( defined($sid) );
|
||||
|
||||
if ( scalar @args == 1 ) {
|
||||
|
||||
$search =~ s/\xC2\xA0/ /g;
|
||||
|
||||
if ( $sid eq "9999" ) {
|
||||
|
||||
@ids = grep { $_->{song} =~ /\Q$search\E/i } (@{ $hash->{helper}{queue} });
|
||||
|
||||
} else {
|
||||
|
||||
@ids = grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{media} });
|
||||
}
|
||||
|
||||
if ( scalar @ids > 0 ) {
|
||||
if ( exists $ids[0]{cid} ) {
|
||||
#hier Container verarbeiten
|
||||
if ( $ids[0]{playable} eq "yes" ) {
|
||||
|
||||
#alles abspielen
|
||||
$heosCmd = 'playPlaylist';
|
||||
$action = "sid=$sid&cid=$ids[0]{cid}&aid=4";
|
||||
#Container merken
|
||||
readingsSingleUpdate($hash, ".cid", 0, 1);
|
||||
|
||||
} else {
|
||||
|
||||
#mehr einlesen
|
||||
readingsSingleUpdate($hash, ".cid", $ids[0]{cid}, 1);
|
||||
$heosCmd = 'browseSource';
|
||||
$action = "sid=$sid&cid=$ids[0]{cid}";
|
||||
}
|
||||
|
||||
} elsif ( exists $ids[0]{qid} ) {
|
||||
|
||||
$heosCmd = 'playQueue';
|
||||
$action = "qid=$ids[0]{qid}";
|
||||
|
||||
} elsif ( exists $ids[0]{mid} ) {
|
||||
#hier Medien verarbeiten
|
||||
if ( $ids[0]{mid} =~ /inputs\// ) {
|
||||
|
||||
#Input abspielen
|
||||
$heosCmd = 'playInput';
|
||||
$action = "input=$ids[0]{mid}";
|
||||
|
||||
} else {
|
||||
|
||||
#aktuellen Container holen
|
||||
my $cid = ReadingsVal($name,".cid", undef);
|
||||
|
||||
if ( defined $cid ) {
|
||||
if ( $ids[0]{type} eq "station" ) {
|
||||
|
||||
#Radio abspielen
|
||||
$heosCmd = 'playStream';
|
||||
$action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}";
|
||||
|
||||
} else {
|
||||
|
||||
#Song abspielen
|
||||
$heosCmd = 'playPlaylist';
|
||||
$action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}&aid=4";
|
||||
@ -419,32 +544,46 @@ sub HEOSPlayer_Set($$@) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
my @media;
|
||||
|
||||
if ( $sid eq "9999" ) {
|
||||
|
||||
@media = map { $_->{song} } (@{ $hash->{helper}{queue}});
|
||||
|
||||
} else {
|
||||
|
||||
@media = map { $_->{name} } (@{ $hash->{IODev}{helper}{media}});
|
||||
}
|
||||
|
||||
return "usage: media ".join(",",@media);
|
||||
}
|
||||
|
||||
} elsif ( $cmd eq 'clearQueue' ) {
|
||||
#löscht die Warteschlange
|
||||
return "usage: clearQueue" if( @args != 0 );
|
||||
|
||||
$heosCmd = 'clearQueue';
|
||||
delete $hash->{helper}{queue};
|
||||
|
||||
} elsif ( $cmd eq 'saveQueue' ) {
|
||||
#speichert die aktuelle Warteschlange als Playlist ab
|
||||
return "usage: saveQueue" if( @args != 1 );
|
||||
|
||||
$heosCmd = 'saveQueue';
|
||||
$action = "name=$args[0]";
|
||||
|
||||
} elsif ( $cmd eq 'history' ) {
|
||||
return "usage: history track,channel" if( @args != 1 );
|
||||
|
||||
$heosCmd = "browseSource";
|
||||
$action = "sid=1026&cid=TRACKS" if ( $args[0] eq "track" );
|
||||
$action = "sid=1026&cid=STATIONS" if ( $args[0] eq "channel" );
|
||||
|
||||
} else {
|
||||
|
||||
my @playlists;
|
||||
my @inputs;
|
||||
my @media;
|
||||
@ -456,26 +595,36 @@ sub HEOSPlayer_Set($$@) {
|
||||
#Parameterlisten für FHEMWeb zusammen bauen
|
||||
$list .= " channel:slider,1,1,".scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
|
||||
#$list .= " playQueue:slider,1,1,".scalar(@{$hash->{helper}{queue}}) if ( defined $hash->{helper}{queue} );
|
||||
|
||||
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 .= " playPlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
|
||||
$list .= " deletePlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
|
||||
#$list .= " renamePlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
|
||||
}
|
||||
|
||||
if ( defined $hash->{IODev}{helper}{sources}) {
|
||||
@inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{sources}});
|
||||
push(@inputs, "Warteschlange");
|
||||
$list .= " input:".join(",",@inputs) if( scalar @inputs > 0 );
|
||||
}
|
||||
|
||||
if ( $sid eq "9999" ) {
|
||||
@media = map { my %n; $n{name} = $_->{song}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{helper}{queue}});
|
||||
$list .= " clearQueue:noArg saveQueue";
|
||||
|
||||
} else {
|
||||
|
||||
@media = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\ /g; $n{name} } (@{ $hash->{IODev}{helper}{media}}) if ( defined $hash->{IODev}{helper}{media});
|
||||
}
|
||||
|
||||
$list .= " media:".join(",",@media) if( scalar @media > 0 );
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
|
||||
|
||||
$string .= "pid=$pid";
|
||||
$string .= "&$action" if( defined($action));
|
||||
IOWrite($hash,"$heosCmd","$string");
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}";
|
||||
@ -483,28 +632,37 @@ sub HEOSPlayer_Set($$@) {
|
||||
}
|
||||
|
||||
sub HEOSPlayer_Parse($$) {
|
||||
|
||||
my ($io_hash,$json) = @_;
|
||||
my $name = $io_hash->{NAME};
|
||||
my $pid;
|
||||
my $decode_json;
|
||||
my $code;
|
||||
|
||||
|
||||
$decode_json = decode_json(encode_utf8($json));
|
||||
Log3 $name, 4, "HEOSPlayer - ParseFn wurde aufgerufen";
|
||||
if( defined($decode_json->{pid}) ) {
|
||||
|
||||
$pid = $decode_json->{pid};
|
||||
$code = abs($pid);
|
||||
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
|
||||
|
||||
if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) {
|
||||
|
||||
IOWrite($hash,'getPlayerInfo',"pid=$hash->{PID}");
|
||||
Log3 $hash->{NAME}, 4, "HEOSPlayer ($hash->{NAME}) - find logical device: $hash->{NAME}";
|
||||
Log3 $hash->{NAME}, 4, "HEOSPlayer ($hash->{NAME}) - find PID in root from decode_json";
|
||||
return $hash->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
my $devname = "HEOSPlayer".abs($pid);
|
||||
return "UNDEFINED $devname HEOSPlayer $pid IODev=$name";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
|
||||
|
||||
$pid = $message{pid} if( defined($message{pid}) );
|
||||
@ -512,27 +670,44 @@ sub HEOSPlayer_Parse($$) {
|
||||
Log3 $name, 4, "HEOSPlayer ($name) PID: $pid";
|
||||
$code = abs($pid);
|
||||
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
|
||||
|
||||
if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) {
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if ( $decode_json->{heos}{command} =~ /get_queue/ ) {
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - call getQueue for $message{pid}";
|
||||
if ( defined $message{range} ) { $message{range} =~ s/(\d+)\,\d+/$1/; }
|
||||
else { $message{range} = 0;
|
||||
|
||||
if ( defined $message{range} ) {
|
||||
|
||||
$message{range} =~ s/(\d+)\,\d+/$1/;
|
||||
|
||||
} else {
|
||||
|
||||
$message{range} = 0;
|
||||
$hash->{helper}{queue} = [];
|
||||
}
|
||||
|
||||
my $start = $message{range} + $message{returned};
|
||||
push( @{$hash->{helper}{queue}}, (@{$decode_json->{payload}}) );
|
||||
|
||||
if ( $start < $message{count} ) {
|
||||
|
||||
IOWrite($hash,'getQueue',"pid=$message{pid}&range=$start,".($start + 100));
|
||||
Log3 $name, 3, "HEOSMaster ($name) - call getQueue with pid $message{pid} next Range from $message{returned}";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
HEOSPlayer_WriteReadings($hash,$decode_json);
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - find logical device: $hash->{NAME}";
|
||||
}
|
||||
|
||||
return $hash->{NAME};
|
||||
|
||||
} else {
|
||||
|
||||
my $devname = "HEOSPlayer".abs($pid);
|
||||
return "UNDEFINED $devname HEOSPlayer $pid IODev=$name";
|
||||
}
|
||||
@ -540,9 +715,11 @@ sub HEOSPlayer_Parse($$) {
|
||||
}
|
||||
|
||||
sub HEOSPlayer_WriteReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - processing data to write readings";
|
||||
############################
|
||||
#### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel)
|
||||
@ -554,9 +731,11 @@ sub HEOSPlayer_WriteReadings($$) {
|
||||
readingsBeginUpdate($hash);
|
||||
### Event Readings
|
||||
if( ref($readingsHash) eq "HASH" ) {
|
||||
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - response json Hash back from HEOSPlayer_PreProcessingReadings";
|
||||
my $t;
|
||||
my $v;
|
||||
|
||||
while( ( $t, $v ) = each (%{$readingsHash}) ) {
|
||||
readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) );
|
||||
}
|
||||
@ -587,6 +766,7 @@ sub HEOSPlayer_WriteReadings($$) {
|
||||
my @presets = map { $_->{name} } (@{ $hash->{IODev}{helper}{favorites} });
|
||||
my $search = ReadingsVal($name,"currentStation" ,undef);
|
||||
my( @index )= grep { $presets[$_] eq $search } 0..$#presets if ( defined $search );
|
||||
|
||||
readingsBulkUpdate( $hash, 'channel', $index[0]+1 ) if ( scalar @index > 0 );
|
||||
readingsBulkUpdate( $hash, 'state', 'on' );
|
||||
readingsEndUpdate( $hash, 1 );
|
||||
@ -599,15 +779,20 @@ sub HEOSPlayer_WriteReadings($$) {
|
||||
### my little Helpers
|
||||
|
||||
sub HEOSPlayer_PreProcessingReadings($$) {
|
||||
|
||||
my ($hash,$decode_json) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $reading;
|
||||
my %buffer;
|
||||
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
|
||||
|
||||
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - preprocessing readings";
|
||||
|
||||
if ( $decode_json->{heos}{command} =~ /play_state/ or $decode_json->{heos}{command} =~ /player_state_changed/ ) {
|
||||
|
||||
$buffer{'playStatus'} = $message{state};
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /volume_changed/ or $decode_json->{heos}{command} =~ /set_volume/ or $decode_json->{heos}{command} =~ /get_volume/ ) {
|
||||
|
||||
my @value = split('&', $decode_json->{heos}{message});
|
||||
@ -617,76 +802,106 @@ sub HEOSPlayer_PreProcessingReadings($$) {
|
||||
IOWrite($hash,'setPlayState',"pid=$hash->{PID}&state=play") if $buffer{'mute'} eq "off";
|
||||
IOWrite($hash,'setPlayState',"pid=$hash->{PID}&state=stop") if $buffer{'mute'} eq "on";
|
||||
}
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /play_mode/ or $decode_json->{heos}{command} =~ /repeat_mode_changed/ or $decode_json->{heos}{command} =~ /shuffle_mode_changed/ ) {
|
||||
|
||||
$buffer{'shuffle'} = $message{shuffle};
|
||||
$buffer{'repeat'} = $message{repeat};
|
||||
$buffer{'repeat'} ==~ s/.*\_(.*)/$1/g;
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) {
|
||||
|
||||
$buffer{'mute'} = $message{state};
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /volume_up/ or $decode_json->{heos}{command} =~ /volume_down/ ) {
|
||||
|
||||
$buffer{'volumeUp'} = $message{step} if( $decode_json->{heos}{command} =~ /volume_up/ );
|
||||
$buffer{'volumeDown'} = $message{step} if( $decode_json->{heos}{command} =~ /volume_down/ );
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /player_now_playing_changed/ or $decode_json->{heos}{command} =~ /favorites_changed/ ) {
|
||||
IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}");
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /play_preset/ ) {
|
||||
|
||||
$buffer{'channel'} = $message{preset}
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /play_input/ ) {
|
||||
|
||||
$buffer{'input'} = $message{input};
|
||||
|
||||
} elsif ( $decode_json->{heos}{command} =~ /playback_error/ ) {
|
||||
|
||||
$buffer{'error'} = $message{error};
|
||||
|
||||
} else {
|
||||
|
||||
Log3 $name, 3, "HEOSPlayer ($name) - no match found";
|
||||
return undef;
|
||||
}
|
||||
|
||||
Log3 $name, 4, "HEOSPlayer ($name) - Match found for decode_json";
|
||||
return \%buffer;
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetPlayerInfo($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayerInfo');
|
||||
IOWrite($hash,'getPlayerInfo',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetPlayState($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayState');
|
||||
IOWrite($hash,'getPlayState',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetPlayMode($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayMode');
|
||||
IOWrite($hash,'getPlayMode',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetNowPlayingMedia($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetNowPlayingMedia');
|
||||
IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetVolume($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetVolume');
|
||||
IOWrite($hash,'getVolume',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetMute($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetMute');
|
||||
IOWrite($hash,'getMute',"pid=$hash->{PID}");
|
||||
}
|
||||
|
||||
sub HEOSPlayer_GetQueue($) {
|
||||
|
||||
my $hash = shift;
|
||||
|
||||
|
||||
RemoveInternalTimer($hash,'HEOSPlayer_GetQueue');
|
||||
IOWrite($hash,'getQueue',"pid=$hash->{PID}");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user