Formatierung, diverse Bugfixes

This commit is contained in:
Marko Oldenburg 2017-02-27 09:39:48 +01:00
parent bc9eb8ec8e
commit 80a84377e2
3 changed files with 700 additions and 133 deletions

View File

@ -36,7 +36,7 @@ use warnings;
use JSON qw(decode_json); use JSON qw(decode_json);
use Encode qw(encode_utf8); use Encode qw(encode_utf8);
my $version = "0.1.58"; my $version = "0.1.60";
# Declare functions # Declare functions
sub HEOSGroup_Initialize($); sub HEOSGroup_Initialize($);
@ -53,10 +53,12 @@ sub HEOSGroup_GetGroupVolume($);
sub HEOSGroup_GetGroupMute($); sub HEOSGroup_GetGroupMute($);
sub HEOSGroup_Initialize($) { sub HEOSGroup_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
$hash->{Match} = '.*{"command":."group.*|.*{"command":."event\/group.*'; $hash->{Match} = '.*{"command":."group.*|.*{"command":."event\/group.*';
# Provider # Provider
$hash->{SetFn} = "HEOSGroup_Set"; $hash->{SetFn} = "HEOSGroup_Set";
$hash->{DefFn} = "HEOSGroup_Define"; $hash->{DefFn} = "HEOSGroup_Define";
@ -69,26 +71,32 @@ sub HEOSGroup_Initialize($) {
$readingFnAttributes; $readingFnAttributes;
foreach my $d(sort keys %{$modules{HEOSGroup}{defptr}}) { foreach my $d(sort keys %{$modules{HEOSGroup}{defptr}}) {
my $hash = $modules{HEOSGroup}{defptr}{$d}; my $hash = $modules{HEOSGroup}{defptr}{$d};
$hash->{VERSION} = $version; $hash->{VERSION} = $version;
} }
} }
sub HEOSGroup_Define($$) { sub HEOSGroup_Define($$) {
my ( $hash, $def ) = @_; my ( $hash, $def ) = @_;
my @a = split( "[ \t]+", $def ); my @a = split( "[ \t]+", $def );
splice( @a, 1, 1 ); splice( @a, 1, 1 );
my $iodev; my $iodev;
my $i = 0; my $i = 0;
foreach my $param ( @a ) { foreach my $param ( @a ) {
if( $param =~ m/IODev=([^\s]*)/ ) { if( $param =~ m/IODev=([^\s]*)/ ) {
$iodev = $1; $iodev = $1;
splice( @a, $i, 3 ); splice( @a, $i, 3 );
last; last;
} }
$i++; $i++;
} }
return "too few parameters: define <name> HEOSGroup <gid>" if( @a < 2 ); return "too few parameters: define <name> HEOSGroup <gid>" if( @a < 2 );
my ($name,$gid) = @a; my ($name,$gid) = @a;
@ -97,73 +105,96 @@ sub HEOSGroup_Define($$) {
$hash->{VERSION} = $version; $hash->{VERSION} = $version;
$hash->{NOTIFYDEV} = "HEOSPlayer".abs($gid); $hash->{NOTIFYDEV} = "HEOSPlayer".abs($gid);
AssignIoPort($hash,$iodev) if( !$hash->{IODev} ); AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
if(defined($hash->{IODev}->{NAME})) { if(defined($hash->{IODev}->{NAME})) {
Log3 $name, 3, "HEOSGroup ($name) - I/O device is " . $hash->{IODev}->{NAME}; Log3 $name, 3, "HEOSGroup ($name) - I/O device is " . $hash->{IODev}->{NAME};
} else { } else {
Log3 $name, 1, "HEOSGroup ($name) - no I/O device"; Log3 $name, 1, "HEOSGroup ($name) - no I/O device";
} }
$iodev = $hash->{IODev}->{NAME}; $iodev = $hash->{IODev}->{NAME};
my $code = abs($gid); my $code = abs($gid);
$code = $iodev."-".$code if( defined($iodev) ); $code = $iodev."-".$code if( defined($iodev) );
my $d = $modules{HEOSGroup}{defptr}{$code}; my $d = $modules{HEOSGroup}{defptr}{$code};
return "HEOSGroup device $hash->{GID} on HEOSMaster $iodev already defined as $d->{NAME}." return "HEOSGroup device $hash->{GID} on HEOSMaster $iodev already defined as $d->{NAME}."
if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name ); if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
Log3 $name, 3, "HEOSGroup ($name) - defined with Code: $code"; Log3 $name, 3, "HEOSGroup ($name) - defined with Code: $code";
$attr{$name}{room} = "HEOS" if( !defined( $attr{$name}{room} ) ); $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} ) ); $attr{$name}{devStateIcon} = "on:10px-kreis-gruen off:10px-kreis-rot" if( !defined( $attr{$name}{devStateIcon} ) );
if( $init_done ) { if( $init_done ) {
InternalTimer( gettimeofday()+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
} else { } else {
InternalTimer( gettimeofday()+15+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 ); 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(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 ); InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
} }
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'state','Initialized'); readingsBulkUpdate($hash, 'state','Initialized');
readingsBulkUpdate($hash, 'volumeUp', 5); readingsBulkUpdate($hash, 'volumeUp', 5);
readingsBulkUpdate($hash, 'volumeDown', 5); readingsBulkUpdate($hash, 'volumeDown', 5);
readingsEndUpdate($hash, 1); readingsEndUpdate($hash, 1);
$modules{HEOSGroup}{defptr}{$code} = $hash; $modules{HEOSGroup}{defptr}{$code} = $hash;
return undef; return undef;
} }
sub HEOSGroup_Undef($$) { sub HEOSGroup_Undef($$) {
my ( $hash, $arg ) = @_; my ( $hash, $arg ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
my $code = abs($hash->{GID}); my $code = abs($hash->{GID});
$code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) ); $code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) );
delete($modules{HEOSGroup}{defptr}{$code}); delete($modules{HEOSGroup}{defptr}{$code});
Log3 $name, 3, "HEOSGroup ($name) - device $name deleted with Code: $code"; Log3 $name, 3, "HEOSGroup ($name) - device $name deleted with Code: $code";
return undef; return undef;
} }
sub HEOSGroup_Attr(@) { sub HEOSGroup_Attr(@) {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
my $token = $hash->{IODev}->{TOKEN}; my $token = $hash->{IODev}->{TOKEN};
if( $attrName eq "disable" ) { if( $attrName eq "disable" ) {
if( $cmd eq "set" and $attrVal eq "1" ) { if( $cmd eq "set" and $attrVal eq "1" ) {
readingsSingleUpdate ( $hash, "state", "disabled", 1 ); readingsSingleUpdate ( $hash, "state", "disabled", 1 );
Log3 $name, 3, "HEOSGroup ($name) - disabled"; Log3 $name, 3, "HEOSGroup ($name) - disabled";
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSGroup ($name) - enabled"; Log3 $name, 3, "HEOSGroup ($name) - enabled";
} }
} }
if( $attrName eq "disabledForIntervals" ) { if( $attrName eq "disabledForIntervals" ) {
if( $cmd eq "set" ) { if( $cmd eq "set" ) {
Log3 $name, 3, "HEOSGroup ($name) - enable disabledForIntervals"; Log3 $name, 3, "HEOSGroup ($name) - enable disabledForIntervals";
readingsSingleUpdate ( $hash, "state", "Unknown", 1 ); readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSGroup ($name) - delete disabledForIntervals"; Log3 $name, 3, "HEOSGroup ($name) - delete disabledForIntervals";
} }
@ -171,27 +202,33 @@ sub HEOSGroup_Attr(@) {
} }
sub HEOSGroup_Notify($$) { sub HEOSGroup_Notify($$) {
my ($hash,$dev) = @_; my ($hash,$dev) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
return undef if(IsDisabled($name)); return undef if(IsDisabled($name));
my $events = deviceEvents($dev,1); my $events = deviceEvents($dev,1);
#print "notify ####################################################\n".Dumper($events); #print "notify ####################################################\n".Dumper($events);
return if( !$events ); return if( !$events );
readingsBeginUpdate($hash); 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; my %playerEevents = map { my ( $key, $value ) = split /:\s/; $value =~ s/^\s+//; ( $key, $value ) } @$events;
foreach my $key ( keys %playerEevents ) { foreach my $key ( keys %playerEevents ) {
#### playing Infos #### playing Infos
readingsBulkUpdate( $hash, $key, $playerEevents{$key} ) if( grep { $_ =~ /$key/ } ("channel", "currentAlbum", "currentArtist", "currentImageUrl", "currentMedia", "currentMid", "currentQid", "currentSid", "currentStation", "currentTitle", "error", "playStatus", "repeat", "shuffle" ) ); 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 ); readingsEndUpdate( $hash, 1 );
} }
sub HEOSGroup_Set($$@) { sub HEOSGroup_Set($$@) {
my ($hash, $name, @aa) = @_; my ($hash, $name, @aa) = @_;
my ($cmd, @args) = @aa; my ($cmd, @args) = @aa;
my $gid = $hash->{GID}; my $gid = $hash->{GID};
@ -202,110 +239,156 @@ sub HEOSGroup_Set($$@) {
my $favoritcount = 1; my $favoritcount = 1;
my $string = "gid=$gid"; my $string = "gid=$gid";
#senden von Befehlen unterdrücken solange state nicht on ist #senden von Befehlen unterdrücken solange state nicht on ist
return undef unless ( ReadingsVal($name, "state", "off") eq "on" ); return undef unless ( ReadingsVal($name, "state", "off") eq "on" );
if( $cmd eq 'getGroupInfo' ) { if( $cmd eq 'getGroupInfo' ) {
return "usage: getGroupInfo" if( @args != 0 ); return "usage: getGroupInfo" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
} elsif( $cmd eq 'mute' ) { } elsif( $cmd eq 'mute' ) {
return "usage: mute on/off" if( @args != 1 ); return "usage: mute on/off" if( @args != 1 );
$heosCmd = 'setGroupMute'; $heosCmd = 'setGroupMute';
$action = "state=$args[0]"; $action = "state=$args[0]";
} elsif( $cmd eq 'volume' ) { } elsif( $cmd eq 'volume' ) {
return "usage: volume 0-100" if( @args != 1 ); return "usage: volume 0-100" if( @args != 1 );
$heosCmd = 'setGroupVolume'; $heosCmd = 'setGroupVolume';
$action = "level=$args[0]"; $action = "level=$args[0]";
} elsif( $cmd eq 'volumeUp' ) { } elsif( $cmd eq 'volumeUp' ) {
return "usage: volumeUp 0-10" if( @args != 1 ); return "usage: volumeUp 0-10" if( @args != 1 );
$heosCmd = 'GroupVolumeUp'; $heosCmd = 'GroupVolumeUp';
$action = "step=$args[0]"; $action = "step=$args[0]";
} elsif( $cmd eq 'volumeDown' ) { } elsif( $cmd eq 'volumeDown' ) {
return "usage: volumeDown 0-10" if( @args != 1 ); return "usage: volumeDown 0-10" if( @args != 1 );
$heosCmd = 'groupVolumeDown'; $heosCmd = 'groupVolumeDown';
$action = "step=$args[0]"; $action = "step=$args[0]";
} elsif( $cmd eq 'clearGroup' ) { } elsif( $cmd eq 'clearGroup' ) {
return "usage: clearGroup" if( @args != 0 ); return "usage: clearGroup" if( @args != 0 );
$heosCmd = 'createGroup'; $heosCmd = 'createGroup';
$string = "pid=$gid"; $string = "pid=$gid";
} elsif( grep { $_ =~ /\Q$cmd\E/ } ("play", "stop", "pause", "next", "prev", "channel", "channelUp", "channelDown", "playlist" ) ) { } elsif( grep { $_ =~ /\Q$cmd\E/ } ("play", "stop", "pause", "next", "prev", "channel", "channelUp", "channelDown", "playlist" ) ) {
#ab hier Playerbefehle emuliert #ab hier Playerbefehle emuliert
$string = "pid=$gid"; $string = "pid=$gid";
if( $cmd eq 'repeat' ) { if( $cmd eq 'repeat' ) {
return "usage: repeat one,all,off" if( @args != 1 ); return "usage: repeat one,all,off" if( @args != 1 );
$heosCmd = 'setPlayMode';
$rvalue = 'on_'.$args[0]; $heosCmd = 'setPlayMode';
$rvalue = 'off' if($rvalue eq 'on_off'); $rvalue = 'on_'.$args[0];
$action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off'); $rvalue = 'off' if($rvalue eq 'on_off');
} elsif( $cmd eq 'shuffle' ) { $action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off');
return "usage: shuffle on,off" if( @args != 1 );
$heosCmd = 'setPlayMode'; } elsif( $cmd eq 'shuffle' ) {
$rvalue = 'on_'.ReadingsVal($name,'repeat','off'); return "usage: shuffle on,off" if( @args != 1 );
$rvalue = 'off' if($rvalue eq 'on_off');
$action = "repeat=$rvalue&shuffle=$args[0]"; $heosCmd = 'setPlayMode';
} elsif( $cmd eq 'play' ) { $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 ); return "usage: play" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'stop' ) { } elsif( $cmd eq 'stop' ) {
return "usage: stop" if( @args != 0 ); return "usage: stop" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'pause' ) { } elsif( $cmd eq 'pause' ) {
return "usage: pause" if( @args != 0 ); return "usage: pause" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'next' ) { } elsif( $cmd eq 'next' ) {
return "usage: next" if( @args != 0 ); return "usage: next" if( @args != 0 );
$heosCmd = 'playNext'; $heosCmd = 'playNext';
} elsif( $cmd eq 'prev' ) { } elsif( $cmd eq 'prev' ) {
return "usage: prev" if( @args != 0 ); return "usage: prev" if( @args != 0 );
$heosCmd = 'playPrev'; $heosCmd = 'playPrev';
} elsif ( $cmd eq 'channel' ) { } elsif ( $cmd eq 'channel' ) {
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); $favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
return "usage: channel 1-$favoritcount" if( @args != 1 ); return "usage: channel 1-$favoritcount" if( @args != 1 );
$heosCmd = 'playPresetStation'; $heosCmd = 'playPresetStation';
$action = "preset=$args[0]"; $action = "preset=$args[0]";
} elsif( $cmd eq 'channelUp' ) { } elsif( $cmd eq 'channelUp' ) {
return "usage: channelUp" if( @args != 0 ); return "usage: channelUp" if( @args != 0 );
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); $favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
$heosCmd = 'playPresetStation'; $heosCmd = 'playPresetStation';
$favorit = ReadingsVal($name,"channel", 0) + 1; $favorit = ReadingsVal($name,"channel", 0) + 1;
$favorit = $favoritcount if ( $favorit > $favoritcount); $favorit = $favoritcount if ( $favorit > $favoritcount);
$action = "preset=".$favorit; $action = "preset=".$favorit;
} elsif( $cmd eq 'channelDown' ) { } elsif( $cmd eq 'channelDown' ) {
return "usage: channelDown" if( @args != 0 ); return "usage: channelDown" if( @args != 0 );
$heosCmd = 'playPresetStation'; $heosCmd = 'playPresetStation';
$favorit = ReadingsVal($name,"channel", 0) - 1; $favorit = ReadingsVal($name,"channel", 0) - 1;
$favorit = 1 if ($favorit <= 0); $favorit = 1 if ($favorit <= 0);
$action = "preset=".$favorit; $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 ) { } elsif ( $cmd =~ /Playlist/ ) {
if ( $cmd eq 'playPlaylist' ) {
$heosCmd = $cmd; my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} });
$action = "sid=1025&cid=$cids[0]&aid=4";
} elsif ( $cmd eq 'deletePlaylist' ) { if ( scalar @args == 1 && scalar @cids > 0 ) {
$heosCmd = $cmd; if ( $cmd eq 'playPlaylist' ) {
$action = "cid=$cids[0]";
$string = "sid=1025"; $heosCmd = $cmd;
} $action = "sid=1025&cid=$cids[0]&aid=4";
} else {
IOWrite($hash,'browseSource','sid=1025'); } elsif ( $cmd eq 'deletePlaylist' ) {
my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}});
return "usage: $cmd ".join(",",@playlists); $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 { } 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 "; 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} ); $list .= " channel:slider,1,1,".scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
if ( defined $hash->{IODev}{helper}{playlists} ) { if ( defined $hash->{IODev}{helper}{playlists} ) {
my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}}); my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}});
$list .= " playlist:".join(",",@playlists) if( scalar @playlists > 0 ); $list .= " playlist:".join(",",@playlists) if( scalar @playlists > 0 );
} }
return "Unknown argument $cmd, choose one of $list"; return "Unknown argument $cmd, choose one of $list";
} }
$string .= "&$action" if( defined($action)); $string .= "&$action" if( defined($action));
IOWrite($hash,"$heosCmd","$string"); IOWrite($hash,"$heosCmd","$string");
Log3 $name, 4, "HEOSGroup ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}"; Log3 $name, 4, "HEOSGroup ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}";
@ -313,42 +396,58 @@ sub HEOSGroup_Set($$@) {
} }
sub HEOSGroup_Parse($$) { sub HEOSGroup_Parse($$) {
my ($io_hash,$json) = @_; my ($io_hash,$json) = @_;
my $name = $io_hash->{NAME}; my $name = $io_hash->{NAME};
my $gid; my $gid;
my $decode_json; my $decode_json;
my $code; my $code;
$decode_json = decode_json(encode_utf8($json)); $decode_json = decode_json(encode_utf8($json));
Log3 $name, 4, "HEOSGroup ($name) - ParseFn wurde aufgerufen"; Log3 $name, 4, "HEOSGroup ($name) - ParseFn wurde aufgerufen";
if( defined($decode_json->{gid}) ) { if( defined($decode_json->{gid}) ) {
$gid = $decode_json->{gid}; $gid = $decode_json->{gid};
$code = abs($gid); $code = abs($gid);
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) ); $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) { if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}"); 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 logical device: $hash->{NAME}";
Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find GID in root from decode_json"; Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find GID in root from decode_json";
return $hash->{NAME}; return $hash->{NAME};
} else { } else {
my $devname = "HEOSGroup".abs($gid); my $devname = "HEOSGroup".abs($gid);
return "UNDEFINED $devname HEOSGroup $gid IODev=$name"; 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}) ); } else {
$gid = $message{gid} if( defined($message{gid}) );
$gid = $decode_json->{payload}{gid} if( defined($decode_json->{payload}{gid}) ); my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
Log3 $name, 4, "HEOSGroup ($name) - GID: $gid";
$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 = abs($gid);
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) ); $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) { if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
HEOSGroup_WriteReadings($hash,$decode_json); HEOSGroup_WriteReadings($hash,$decode_json);
Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}"; Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}";
return $hash->{NAME}; return $hash->{NAME};
} else { } else {
my $devname = "HEOSGroup".abs($gid); my $devname = "HEOSGroup".abs($gid);
return "UNDEFINED $devname HEOSGroup $gid IODev=$name"; return "UNDEFINED $devname HEOSGroup $gid IODev=$name";
} }
@ -356,9 +455,11 @@ sub HEOSGroup_Parse($$) {
} }
sub HEOSGroup_WriteReadings($$) { sub HEOSGroup_WriteReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
Log3 $name, 3, "HEOSGroup ($name) - processing data to write readings"; Log3 $name, 3, "HEOSGroup ($name) - processing data to write readings";
############################ ############################
#### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel) #### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel)
@ -370,31 +471,44 @@ sub HEOSGroup_WriteReadings($$) {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
### Event Readings ### Event Readings
if( ref($readingsHash) eq "HASH" ) { if( ref($readingsHash) eq "HASH" ) {
Log3 $name, 4, "HEOSGroup ($name) - response json Hash back from HEOSGroup_PreProcessingReadings"; Log3 $name, 4, "HEOSGroup ($name) - response json Hash back from HEOSGroup_PreProcessingReadings";
my $t; my $t;
my $v; my $v;
while( ( $t, $v ) = each (%{$readingsHash}) ) { while( ( $t, $v ) = each (%{$readingsHash}) ) {
readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) ); readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) );
} }
} }
readingsBulkUpdate( $hash, 'state', 'on' ); readingsBulkUpdate( $hash, 'state', 'on' );
### GroupInfos ### GroupInfos
readingsBulkUpdate( $hash, 'name', $decode_json->{payload}{name} ); readingsBulkUpdate( $hash, 'name', $decode_json->{payload}{name} );
readingsBulkUpdate( $hash, 'gid', $decode_json->{payload}{gid} ); readingsBulkUpdate( $hash, 'gid', $decode_json->{payload}{gid} );
if ( ref($decode_json->{payload}{players}) eq "ARRAY" ) { if ( ref($decode_json->{payload}{players}) eq "ARRAY" ) {
my @members; my @members;
foreach my $player (@{ $decode_json->{payload}{players} }) { foreach my $player (@{ $decode_json->{payload}{players} }) {
readingsBulkUpdate( $hash, 'leader', $player->{name} ) if ( $player->{role} eq "leader" ); readingsBulkUpdate( $hash, 'leader', $player->{name} ) if ( $player->{role} eq "leader" );
push( @members, $player->{name}) if ( $player->{role} eq "member" ); push( @members, $player->{name}) if ( $player->{role} eq "member" );
} }
if ( scalar @members > 1 ) { if ( scalar @members > 1 ) {
readingsBulkUpdate( $hash, 'member', join(",",@members) ); readingsBulkUpdate( $hash, 'member', join(",",@members) );
} else { } else {
readingsBulkUpdate( $hash, 'member', $members[0] ); readingsBulkUpdate( $hash, 'member', $members[0] );
} }
} }
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
Log3 $name, 5, "HEOSGroup ($name) - readings set for $name"; Log3 $name, 5, "HEOSGroup ($name) - readings set for $name";
return undef; return undef;
} }
@ -403,52 +517,68 @@ sub HEOSGroup_WriteReadings($$) {
### my little Helpers ### my little Helpers
sub HEOSGroup_PreProcessingReadings($$) { sub HEOSGroup_PreProcessingReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $reading; my $reading;
my %buffer; my %buffer;
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message}); my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
Log3 $name, 4, "HEOSGroup ($name) - preprocessing readings"; 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/ ) { 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}); my @value = split('&', $decode_json->{heos}{message});
$buffer{'volume'} = substr($value[1],6); $buffer{'volume'} = substr($value[1],6);
$buffer{'mute'} = substr($value[2],5) if( $decode_json->{heos}{command} =~ /volume_changed/ ); $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/ ) { } elsif ( $decode_json->{heos}{command} =~ /volume_up/ or $decode_json->{heos}{command} =~ /volume_down/ ) {
my @value = split('&', $decode_json->{heos}{message}); my @value = split('&', $decode_json->{heos}{message});
$buffer{'volumeUp'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_up/ ); $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/ ); $buffer{'volumeDown'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_down/ );
} elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) { } elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) {
my @value = split('&', $decode_json->{heos}{message}); my @value = split('&', $decode_json->{heos}{message});
$buffer{'mute'} = substr($value[1],6); $buffer{'mute'} = substr($value[1],6);
} else { } else {
Log3 $name, 3, "HEOSGroup ($name) - no match found"; Log3 $name, 3, "HEOSGroup ($name) - no match found";
return undef; return undef;
} }
Log3 $name, 4, "HEOSGroup ($name) - Match found for decode_json"; Log3 $name, 4, "HEOSGroup ($name) - Match found for decode_json";
return \%buffer; return \%buffer;
} }
sub HEOSGroup_GetGroupInfo($) { sub HEOSGroup_GetGroupInfo($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSGroup_GetGroupInfo'); RemoveInternalTimer($hash,'HEOSGroup_GetGroupInfo');
IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}"); IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}");
} }
sub HEOSGroup_GetGroupVolume($) { sub HEOSGroup_GetGroupVolume($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSGroup_GetGroupVolume'); RemoveInternalTimer($hash,'HEOSGroup_GetGroupVolume');
IOWrite($hash,'getGroupVolume',"gid=$hash->{GID}"); IOWrite($hash,'getGroupVolume',"gid=$hash->{GID}");
} }
sub HEOSGroup_GetGroupMute($) { sub HEOSGroup_GetGroupMute($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSGroup_GetGroupMute'); RemoveInternalTimer($hash,'HEOSGroup_GetGroupMute');
IOWrite($hash,'getGroupMute',"gid=$hash->{GID}"); IOWrite($hash,'getGroupMute',"gid=$hash->{GID}");
} }

View File

@ -47,7 +47,7 @@ use Encode qw(encode_utf8);
use Net::Telnet; use Net::Telnet;
use Data::Dumper; use Data::Dumper;
my $version = "0.1.58"; my $version = "0.1.60";
my %heosCmds = ( my %heosCmds = (
'enableChangeEvents' => 'system/register_for_change_events?enable=', 'enableChangeEvents' => 'system/register_for_change_events?enable=',
@ -126,8 +126,10 @@ sub HEOSMaster_GetPlaylists($);
sub HEOSMaster_GetServers($); sub HEOSMaster_GetServers($);
sub HEOSMaster_Initialize($) { sub HEOSMaster_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
# Provider # Provider
$hash->{ReadFn} = "HEOSMaster_Read"; $hash->{ReadFn} = "HEOSMaster_Read";
$hash->{WriteFn} = "HEOSMaster_Write"; $hash->{WriteFn} = "HEOSMaster_Write";
@ -147,15 +149,18 @@ sub HEOSMaster_Initialize($) {
$readingFnAttributes; $readingFnAttributes;
foreach my $d(sort keys %{$modules{HEOSMaster}{defptr}}) { foreach my $d(sort keys %{$modules{HEOSMaster}{defptr}}) {
my $hash = $modules{HEOSMaster}{defptr}{$d}; my $hash = $modules{HEOSMaster}{defptr}{$d};
$hash->{VERSION} = $version; $hash->{VERSION} = $version;
} }
} }
sub HEOSMaster_Define($$) { sub HEOSMaster_Define($$) {
my ( $hash, $def ) = @_; my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def ); my @a = split( "[ \t][ \t]*", $def );
return "too few parameters: define <name> HEOSMaster <HOST>" if( @a != 3 ); return "too few parameters: define <name> HEOSMaster <HOST>" if( @a != 3 );
my $name = $a[0]; my $name = $a[0];
@ -173,118 +178,159 @@ sub HEOSMaster_Define($$) {
readingsEndUpdate($hash,1); readingsEndUpdate($hash,1);
if( $init_done ) { if( $init_done ) {
HEOSMaster_firstRun($hash); HEOSMaster_firstRun($hash);
} else { } else {
InternalTimer( gettimeofday()+15, 'HEOSMaster_firstRun', $hash, 0 ) if( ($hash->{HOST}) ); InternalTimer( gettimeofday()+15, 'HEOSMaster_firstRun', $hash, 0 ) if( ($hash->{HOST}) );
} }
$modules{HEOSPlayer}{defptr}{$host} = $hash; $modules{HEOSPlayer}{defptr}{$host} = $hash;
return undef; return undef;
} }
sub HEOSMaster_Undef($$) { sub HEOSMaster_Undef($$) {
my ( $hash, $arg ) = @_; my ( $hash, $arg ) = @_;
my $host = $hash->{HOST}; my $host = $hash->{HOST};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
HEOSMaster_Close($hash); HEOSMaster_Close($hash);
delete $modules{HEOSMaster}{defptr}{$hash->{HOST}}; delete $modules{HEOSMaster}{defptr}{$hash->{HOST}};
Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted"; Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted";
return undef; return undef;
} }
sub HEOSMaster_Attr(@) { sub HEOSMaster_Attr(@) {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
my $orig = $attrVal; my $orig = $attrVal;
if( $attrName eq "disable" ) { if( $attrName eq "disable" ) {
if( $cmd eq "set" and $attrVal eq "1" ) { if( $cmd eq "set" and $attrVal eq "1" ) {
readingsSingleUpdate ( $hash, "state", "disabled", 1 ); readingsSingleUpdate ( $hash, "state", "disabled", 1 );
Log3 $name, 3, "HEOSMaster ($name) - disabled"; Log3 $name, 3, "HEOSMaster ($name) - disabled";
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSMaster ($name) - enabled"; Log3 $name, 3, "HEOSMaster ($name) - enabled";
} }
} }
if( $attrName eq "disabledForIntervals" ) { if( $attrName eq "disabledForIntervals" ) {
if( $cmd eq "set" ) { if( $cmd eq "set" ) {
Log3 $name, 3, "HEOSMaster ($name) - enable disabledForIntervals"; Log3 $name, 3, "HEOSMaster ($name) - enable disabledForIntervals";
readingsSingleUpdate ( $hash, "state", "Unknown", 1 ); readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSMaster ($name) - delete disabledForIntervals"; Log3 $name, 3, "HEOSMaster ($name) - delete disabledForIntervals";
} }
} }
return undef; return undef;
} }
sub HEOSMaster_Get($$@) { sub HEOSMaster_Get($$@) {
my ($hash, $name, @aa) = @_; my ($hash, $name, @aa) = @_;
my ($cmd, @args) = @aa; my ($cmd, @args) = @aa;
my $pid = $hash->{PID}; my $pid = $hash->{PID};
if( $cmd eq 'showAccount' ) { if( $cmd eq 'showAccount' ) {
return AttrVal($name,'heosUsername',0) . ":" .HEOSMaster_ReadPassword($hash); return AttrVal($name,'heosUsername',0) . ":" .HEOSMaster_ReadPassword($hash);
} }
my $list = 'showAccount:noArg'; my $list = 'showAccount:noArg';
return "Unknown argument $cmd, choose one of $list"; return "Unknown argument $cmd, choose one of $list";
} }
sub HEOSMaster_Set($@) { sub HEOSMaster_Set($@) {
my ($hash, $name, $cmd, @args) = @_; my ($hash, $name, $cmd, @args) = @_;
my ($arg, @params) = @args; my ($arg, @params) = @args;
my $action; my $action;
my $heosCmd; my $heosCmd;
if($cmd eq 'reopen') { if($cmd eq 'reopen') {
return "usage: reopen" if( @args != 0 ); return "usage: reopen" if( @args != 0 );
HEOSMaster_ReOpen($hash); HEOSMaster_ReOpen($hash);
return undef; return undef;
} elsif($cmd eq 'getPlayers') { } elsif($cmd eq 'getPlayers') {
return "usage: getPlayers" if( @args != 0 ); return "usage: getPlayers" if( @args != 0 );
$heosCmd = 'getPlayers'; $heosCmd = 'getPlayers';
$action = undef; $action = undef;
} elsif($cmd eq 'getGroups') { } elsif($cmd eq 'getGroups') {
return "usage: getGroups" if( @args != 0 ); return "usage: getGroups" if( @args != 0 );
$heosCmd = 'getGroups'; $heosCmd = 'getGroups';
$action = undef; $action = undef;
} elsif($cmd eq 'enableChangeEvents') { } elsif($cmd eq 'enableChangeEvents') {
return "usage: enableChangeEvents" if( @args != 1 ); return "usage: enableChangeEvents" if( @args != 1 );
$heosCmd = $cmd; $heosCmd = $cmd;
$action = $args[0]; $action = $args[0];
} elsif($cmd eq 'checkAccount') { } elsif($cmd eq 'checkAccount') {
return "usage: checkAccount" if( @args != 0 ); return "usage: checkAccount" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
$action = undef; $action = undef;
} elsif($cmd eq 'signAccount') { } elsif($cmd eq 'signAccount') {
return "usage: signAccountIn" if( @args != 1 ); return "usage: signAccountIn" if( @args != 1 );
return "please set account informattion first" if(AttrVal($name,'heosUsername','none') eq 'none'); return "please set account informattion first" if(AttrVal($name,'heosUsername','none') eq 'none');
$heosCmd = $cmd . $args[0]; $heosCmd = $cmd . $args[0];
$action = 'un='. AttrVal($name,'heosUsername','none') . '&pw=' . HEOSMaster_ReadPassword($hash) if($args[0] eq 'In'); $action = 'un='. AttrVal($name,'heosUsername','none') . '&pw=' . HEOSMaster_ReadPassword($hash) if($args[0] eq 'In');
} elsif($cmd eq 'password') { } elsif($cmd eq 'password') {
return "usage: password" if( @args != 1 ); return "usage: password" if( @args != 1 );
return HEOSMaster_StorePassword( $hash, $args[0] ); return HEOSMaster_StorePassword( $hash, $args[0] );
} elsif($cmd eq 'reboot') { } elsif($cmd eq 'reboot') {
return "usage: reboot" if( @args != 0 ); return "usage: reboot" if( @args != 0 );
return HEOSMaster_StorePassword( $hash, $args[0] ); return HEOSMaster_StorePassword( $hash, $args[0] );
################################################### ###################################################
### Dieser Menüpunkt ist nur zum testen ### Dieser Menüpunkt ist nur zum testen
} elsif($cmd eq 'eventSend') { } elsif($cmd eq 'eventSend') {
return "usage: eventSend" if( @args != 0 ); return "usage: eventSend" if( @args != 0 );
HEOSMaster_send($hash); HEOSMaster_send($hash);
return undef; return undef;
################################################### ###################################################
} else { } else {
my $list = ""; my $list = "";
$list .= "reopen:noArg getPlayers:noArg getGroups:noArg enableChangeEvents:on,off checkAccount:noArg signAccount:In,Out password reboot"; $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"; return "Unknown argument $cmd, choose one of $list";
} }
HEOSMaster_Write($hash,$heosCmd,$action); HEOSMaster_Write($hash,$heosCmd,$action);
} }
sub HEOSMaster_Open($) { sub HEOSMaster_Open($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $host = $hash->{HOST}; my $host = $hash->{HOST};
@ -293,6 +339,7 @@ sub HEOSMaster_Open($) {
my $user = AttrVal($name,'heosUsername',undef); my $user = AttrVal($name,'heosUsername',undef);
my $password = HEOSMaster_ReadPassword($hash); my $password = HEOSMaster_ReadPassword($hash);
Log3 $name, 4, "HEOSMaster ($name) - Baue Socket Verbindung auf"; Log3 $name, 4, "HEOSMaster ($name) - Baue Socket Verbindung auf";
my $socket = new Net::Telnet ( Host=>$host, my $socket = new Net::Telnet ( Host=>$host,
@ -314,9 +361,11 @@ sub HEOSMaster_Open($) {
#hinzugefügt laut Protokoll 2.1.1 Initsequenz #hinzugefügt laut Protokoll 2.1.1 Initsequenz
if( defined($user) and defined($password) ) { if( defined($user) and defined($password) ) {
HEOSMaster_Write($hash,'signAccountIn',"un=$user&pw=$password"); HEOSMaster_Write($hash,'signAccountIn',"un=$user&pw=$password");
Log3 $name, 4, "HEOSMaster ($name) - sign in"; Log3 $name, 4, "HEOSMaster ($name) - sign in";
} }
HEOSMaster_GetPlayers($hash); HEOSMaster_GetPlayers($hash);
InternalTimer( gettimeofday()+1, 'HEOSMaster_EnableChangeEvents', $hash, 0 ); InternalTimer( gettimeofday()+1, 'HEOSMaster_EnableChangeEvents', $hash, 0 );
InternalTimer( gettimeofday()+2, 'HEOSMaster_GetMusicSources', $hash, 0 ); InternalTimer( gettimeofday()+2, 'HEOSMaster_GetMusicSources', $hash, 0 );
@ -324,93 +373,131 @@ sub HEOSMaster_Open($) {
} }
sub HEOSMaster_Close($) { sub HEOSMaster_Close($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
return if( !$hash->{CD} ); return if( !$hash->{CD} );
close($hash->{CD}) if($hash->{CD}); close($hash->{CD}) if($hash->{CD});
delete($hash->{FD}); delete($hash->{FD});
delete($hash->{CD}); delete($hash->{CD});
delete($selectlist{$name}); delete($selectlist{$name});
readingsSingleUpdate($hash, 'state', 'not connected', 1 ); readingsSingleUpdate($hash, 'state', 'not connected', 1 );
} }
sub HEOSMaster_ReOpen($) { sub HEOSMaster_ReOpen($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
HEOSMaster_Close($hash); HEOSMaster_Close($hash);
HEOSMaster_Open($hash) if( !$hash->{CD} or !defined($hash->{CD}) ); HEOSMaster_Open($hash) if( !$hash->{CD} or !defined($hash->{CD}) );
} }
sub HEOSMaster_Write($@) { sub HEOSMaster_Write($@) {
my ($hash,$heosCmd,$value) = @_; my ($hash,$heosCmd,$value) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $string = "heos://$heosCmds{$heosCmd}"; my $string = "heos://$heosCmds{$heosCmd}";
if( defined($value) ) { if( defined($value) ) {
$string .= "${value}" if( $value ne '&' ); $string .= "${value}" if( $value ne '&' );
} }
$string .= "\r\n"; $string .= "\r\n";
Log3 $name, 4, "HEOSMaster ($name) - WriteFn called"; Log3 $name, 4, "HEOSMaster ($name) - WriteFn called";
return Log3 $name, 4, "HEOSMaster ($name) - socket not connected" return Log3 $name, 4, "HEOSMaster ($name) - socket not connected"
unless($hash->{CD}); unless($hash->{CD});
Log3 $name, 5, "HEOSMaster ($name) - $string"; Log3 $name, 5, "HEOSMaster ($name) - $string";
syswrite($hash->{CD}, $string); syswrite($hash->{CD}, $string);
return undef; return undef;
} }
sub HEOSMaster_Read($) { sub HEOSMaster_Read($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $len; my $len;
my $buf; my $buf;
Log3 $name, 4, "HEOSMaster ($name) - ReadFn gestartet"; Log3 $name, 4, "HEOSMaster ($name) - ReadFn gestartet";
$len = sysread($hash->{CD},$buf,1024); # die genaue Puffergröße wird noch ermittelt $len = sysread($hash->{CD},$buf,1024); # die genaue Puffergröße wird noch ermittelt
if( !defined($len) || !$len ) { if( !defined($len) || !$len ) {
Log3 $name, 5, "HEOSMaster ($name) - connection closed by remote Host"; Log3 $name, 5, "HEOSMaster ($name) - connection closed by remote Host";
HEOSMaster_Close($hash); HEOSMaster_Close($hash);
return; return;
} }
unless( defined $buf) { unless( defined $buf) {
Log3 $name, 3, "HEOSMaster ($name) - Keine Daten empfangen"; Log3 $name, 3, "HEOSMaster ($name) - Keine Daten empfangen";
return; return;
} }
Log3 $name, 5, "HEOSMaster ($name) - received buffer data, start HEOSMaster_ProcessRead: $buf"; Log3 $name, 5, "HEOSMaster ($name) - received buffer data, start HEOSMaster_ProcessRead: $buf";
HEOSMaster_ProcessRead($hash,$buf); HEOSMaster_ProcessRead($hash,$buf);
} }
sub HEOSMaster_ProcessRead($$) { sub HEOSMaster_ProcessRead($$) {
my ($hash, $data) = @_; my ($hash, $data) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $buffer = ''; my $buffer = '';
Log3 $name, 4, "HEOSMaster ($name) - process read"; Log3 $name, 4, "HEOSMaster ($name) - process read";
#include previous partial message #include previous partial message
if(defined($hash->{PARTIAL}) && $hash->{PARTIAL}) { if(defined($hash->{PARTIAL}) && $hash->{PARTIAL}) {
Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL}; Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL};
$buffer = $hash->{PARTIAL}; $buffer = $hash->{PARTIAL};
} else { } else {
Log3 $name, 4, "HEOSMaster ($name) - No PARTIAL buffer"; Log3 $name, 4, "HEOSMaster ($name) - No PARTIAL buffer";
} }
Log3 $name, 5, "HEOSMaster ($name) - Incoming data: " . $data; Log3 $name, 5, "HEOSMaster ($name) - Incoming data: " . $data;
$buffer = $buffer . $data; $buffer = $buffer . $data;
Log3 $name, 5, "HEOSMaster ($name) - Current processing buffer (PARTIAL + incoming data): " . $buffer; Log3 $name, 5, "HEOSMaster ($name) - Current processing buffer (PARTIAL + incoming data): " . $buffer;
my ($json,$tail) = HEOSMaster_ParseMsg($hash, $buffer); my ($json,$tail) = HEOSMaster_ParseMsg($hash, $buffer);
#processes all complete messages #processes all complete messages
while($json) { while($json) {
$hash->{LAST_RECV} = time(); $hash->{LAST_RECV} = time();
Log3 $name, 5, "HEOSMaster ($name) - Decoding JSON message. Length: " . length($json) . " Content: " . $json; Log3 $name, 5, "HEOSMaster ($name) - Decoding JSON message. Length: " . length($json) . " Content: " . $json;
my $obj = JSON->new->utf8(0)->decode($json); my $obj = JSON->new->utf8(0)->decode($json);
if(defined($obj->{heos})) { if(defined($obj->{heos})) {
HEOSMaster_ResponseProcessing($hash,$json); HEOSMaster_ResponseProcessing($hash,$json);
Log3 $name, 4, "HEOSMaster ($name) - starte HEOSMaster_ResponseProcessing"; Log3 $name, 4, "HEOSMaster ($name) - starte HEOSMaster_ResponseProcessing";
} elsif(defined($obj->{error})) { } elsif(defined($obj->{error})) {
Log3 $name, 3, "HEOSMaster ($name) - Received error message: " . $json; Log3 $name, 3, "HEOSMaster ($name) - Received error message: " . $json;
} }
($json,$tail) = HEOSMaster_ParseMsg($hash, $tail); ($json,$tail) = HEOSMaster_ParseMsg($hash, $tail);
} }
$hash->{PARTIAL} = $tail; $hash->{PARTIAL} = $tail;
Log3 $name, 5, "HEOSMaster ($name) - Tail: " . $tail; Log3 $name, 5, "HEOSMaster ($name) - Tail: " . $tail;
Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL}; Log3 $name, 5, "HEOSMaster ($name) - PARTIAL: " . $hash->{PARTIAL};
@ -418,10 +505,12 @@ sub HEOSMaster_ProcessRead($$) {
} }
sub HEOSMaster_ResponseProcessing($$) { sub HEOSMaster_ResponseProcessing($$) {
my ($hash,$json) = @_; my ($hash,$json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $decode_json; my $decode_json;
Log3 $name, 5, "HEOSMaster ($name) - JSON String: $json"; Log3 $name, 5, "HEOSMaster ($name) - JSON String: $json";
return Log3 $name, 3, "HEOSMaster ($name) - empty answer received" return Log3 $name, 3, "HEOSMaster ($name) - empty answer received"
unless( defined($json)); unless( defined($json));
@ -436,6 +525,7 @@ sub HEOSMaster_ResponseProcessing($$) {
if( $decode_json->{heos}{message} =~ /command\sunder\sprocess/ ); if( $decode_json->{heos}{message} =~ /command\sunder\sprocess/ );
if( defined($decode_json->{heos}{result}) or $decode_json->{heos}{command} =~ /^system/ ) { if( defined($decode_json->{heos}{result}) or $decode_json->{heos}{command} =~ /^system/ ) {
HEOSMaster_WriteReadings($hash,$decode_json); HEOSMaster_WriteReadings($hash,$decode_json);
Log3 $name, 4, "HEOSMaster ($name) - call Sub HEOSMaster_WriteReadings"; Log3 $name, 4, "HEOSMaster ($name) - call Sub HEOSMaster_WriteReadings";
} }
@ -447,24 +537,28 @@ sub HEOSMaster_ResponseProcessing($$) {
#Quellen neu einlesen #Quellen neu einlesen
if( $decode_json->{heos}{command} =~ /^event\/sources_changed/ ) { if( $decode_json->{heos}{command} =~ /^event\/sources_changed/ ) {
HEOSMaster_Write($hash,'getMusicSources',undef); HEOSMaster_Write($hash,'getMusicSources',undef);
return Log3 $name, 4, "HEOSMaster ($name) - source changed"; return Log3 $name, 4, "HEOSMaster ($name) - source changed";
} }
#Player neu einlesen #Player neu einlesen
if( $decode_json->{heos}{command} =~ /^event\/players_changed/ ) { if( $decode_json->{heos}{command} =~ /^event\/players_changed/ ) {
HEOSMaster_Write($hash,'getPlayers',undef); HEOSMaster_Write($hash,'getPlayers',undef);
return Log3 $name, 4, "HEOSMaster ($name) - player changed"; return Log3 $name, 4, "HEOSMaster ($name) - player changed";
} }
#User neu einlesen #User neu einlesen
if( $decode_json->{heos}{command} =~ /^event\/user_changed/ ) { if( $decode_json->{heos}{command} =~ /^event\/user_changed/ ) {
HEOSMaster_Write($hash,'checkAccount',undef); HEOSMaster_Write($hash,'checkAccount',undef);
return Log3 $name, 4, "HEOSMaster ($name) - user changed"; return Log3 $name, 4, "HEOSMaster ($name) - user changed";
} }
#Gruppen neu einlesen #Gruppen neu einlesen
if( $decode_json->{heos}{command} =~ /^event\/groups_changed/ ) { if( $decode_json->{heos}{command} =~ /^event\/groups_changed/ ) {
#InternalTimer( gettimeofday()+5, 'HEOSMaster_GetGroups', $hash, 0 ); #InternalTimer( gettimeofday()+5, 'HEOSMaster_GetGroups', $hash, 0 );
HEOSMaster_Write($hash,'getGroups',undef); HEOSMaster_Write($hash,'getGroups',undef);
return Log3 $name, 4, "HEOSMaster ($name) - groups changed"; return Log3 $name, 4, "HEOSMaster ($name) - groups changed";
@ -478,78 +572,113 @@ sub HEOSMaster_ResponseProcessing($$) {
foreach my $payload ( @{$decode_json->{payload}} ) { foreach my $payload ( @{$decode_json->{payload}} ) {
if( $payload->{sid} eq "1024" ) { if( $payload->{sid} eq "1024" ) {
$i += 2; $i += 2;
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetServers', $hash, 0 ); InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetServers', $hash, 0 );
Log3 $name, 4, "HEOSMaster ($name) - GetServers in $i seconds"; Log3 $name, 4, "HEOSMaster ($name) - GetServers in $i seconds";
} elsif( $payload->{sid} eq "1025" ) { } elsif( $payload->{sid} eq "1025" ) {
$i += 2; $i += 2;
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetPlaylists', $hash, 0 ); InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetPlaylists', $hash, 0 );
Log3 $name, 4, "HEOSMaster ($name) - GetPlaylists in $i seconds"; Log3 $name, 4, "HEOSMaster ($name) - GetPlaylists in $i seconds";
} elsif( $payload->{sid} eq "1026" ) { } elsif( $payload->{sid} eq "1026" ) {
$i += 2; $i += 2;
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetHistory', $hash, 0 ); InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetHistory', $hash, 0 );
Log3 $name, 4, "HEOSMaster ($name) - GetHistory in $i seconds"; Log3 $name, 4, "HEOSMaster ($name) - GetHistory in $i seconds";
} elsif( $payload->{sid} eq "1027" ) { } elsif( $payload->{sid} eq "1027" ) {
$i += 2; $i += 2;
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetInputs', $hash, 0 ); InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetInputs', $hash, 0 );
Log3 $name, 4, "HEOSMaster ($name) - GetInputs in $i seconds"; Log3 $name, 4, "HEOSMaster ($name) - GetInputs in $i seconds";
} elsif( $payload->{sid} eq "1028" ) { } elsif( $payload->{sid} eq "1028" ) {
$i += 2; $i += 2;
InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetFavorites', $hash, 0 ); InternalTimer( gettimeofday()+$i, 'HEOSMaster_GetFavorites', $hash, 0 );
Log3 $name, 4, "HEOSMaster ($name) - GetFavorites in $i seconds"; Log3 $name, 4, "HEOSMaster ($name) - GetFavorites in $i seconds";
} else { } else {
#Onlinedienste #Onlinedienste
push( @{$hash->{helper}{sources}},$payload); push( @{$hash->{helper}{sources}},$payload);
Log3 $name, 4, "HEOSMaster ($name) - GetRadioSource {$payload->{name} with sid $payload->{sid}"; Log3 $name, 4, "HEOSMaster ($name) - GetRadioSource {$payload->{name} with sid $payload->{sid}";
} }
} }
return Log3 $name, 3, "HEOSMaster ($name) - call Sourcebrowser"; 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( $decode_json->{heos}{command} =~ /^browse\/browse/ and ref($decode_json->{payload}) eq "ARRAY" and scalar(@{$decode_json->{payload}}) > 0) {
if ( defined $message{sid} ) { if ( defined $message{sid} ) {
#my @range = ( 0 ); if ( defined $message{range} ) {
#@range = split(',', $message{range}) if ( defined $message{range} );
if ( defined $message{range} ) { $message{range} =~ s/(\d+)\,\d+/$1/; } $message{range} =~ s/(\d+)\,\d+/$1/;
else { $message{range} = 0; }
} else {
$message{range} = 0;
}
my $start = $message{range} + $message{returned}; my $start = $message{range} + $message{returned};
if( $message{sid} eq '1028' ) { if( $message{sid} eq '1028' ) {
#Favoriten einlesen #Favoriten einlesen
$hash->{helper}{favorites} = [] if ( $message{range} == 0 ); $hash->{helper}{favorites} = [] if ( $message{range} == 0 );
push( @{$hash->{helper}{favorites}}, (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{favorites}}, (@{$decode_json->{payload}}) );
if ( $start >= $message{count} ) { if ( $start >= $message{count} ) {
#Nachricht an die Player das sich die Favoriten geändert haben #Nachricht an die Player das sich die Favoriten geändert haben
foreach my $dev ( devspec2array("TYPE=HEOSPlayer") ) { foreach my $dev ( devspec2array("TYPE=HEOSPlayer") ) {
$json = '{"heos": {"command": "event/favorites_changed", "message": "pid='.$defs{$dev}->{PID}.'"}}'; $json = '{"heos": {"command": "event/favorites_changed", "message": "pid='.$defs{$dev}->{PID}.'"}}';
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Favorites Changed"; Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Favorites Changed";
} }
} }
} elsif( $message{sid} eq '1026' ) { } elsif( $message{sid} eq '1026' ) {
#History einlesen #History einlesen
$hash->{helper}{history} = [] if ( $message{range} == 0 ); $hash->{helper}{history} = [] if ( $message{range} == 0 );
push( @{$hash->{helper}{history}}, (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{history}}, (@{$decode_json->{payload}}) );
} elsif( $message{sid} eq '1025' ) { } elsif( $message{sid} eq '1025' ) {
#Playlisten einlesen #Playlisten einlesen
$hash->{helper}{playlists} = [] if ( $message{range} == 0 ); $hash->{helper}{playlists} = [] if ( $message{range} == 0 );
push( @{$hash->{helper}{playlists}}, (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{playlists}}, (@{$decode_json->{payload}}) );
} elsif( $message{sid} eq '1027' ) { } elsif( $message{sid} eq '1027' ) {
#Inputs einlesen #Inputs einlesen
push( @{$hash->{helper}{sources}}, map { $_->{name} .= " AUX"; $_ } (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{sources}}, map { $_->{name} .= " AUX"; $_ } (@{$decode_json->{payload}}) );
} elsif( $message{sid} eq '1024' ) { } elsif( $message{sid} eq '1024' ) {
#Lokal einlesen #Lokal einlesen
push( @{$hash->{helper}{sources}}, map { $_->{name} .= " USB" if ( $_->{sid} < 0 ); $_ } (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{sources}}, map { $_->{name} .= " USB" if ( $_->{sid} < 0 ); $_ } (@{$decode_json->{payload}}) );
} else { } else {
#aktuellen Input/Media einlesen #aktuellen Input/Media einlesen
$hash->{helper}{media} = [] if ( $message{range} == 0 ); $hash->{helper}{media} = [] if ( $message{range} == 0 );
push( @{$hash->{helper}{media}}, (@{$decode_json->{payload}}) ); 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"; Log3 $name, 4, "HEOSMaster ($name) - call Browser with sid $message{sid} and $message{returned} items from $message{count} items";
if ( $start < $message{count} ) { if ( $start < $message{count} ) {
HEOSMaster_Write($hash,'browseSource',"sid=$message{sid}&range=$start,".($start + 100) ); 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}"; Log3 $name, 3, "HEOSMaster ($name) - call Browser with sid $message{sid} next Range from $message{returned}";
} }
return; 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/ 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/ ) { if( $decode_json->{heos}{command} =~ /player\/get_players/ ) {
return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received" return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received"
unless(scalar(@{$decode_json->{payload}}) > 0); unless(scalar(@{$decode_json->{payload}}) > 0);
foreach my $payload (@{$decode_json->{payload}}) { foreach my $payload (@{$decode_json->{payload}}) {
$json = '{"pid": "'; $json = '{"pid": "';
$json .= "$payload->{pid}"; $json .= "$payload->{pid}";
$json .= '","heos": {"command": "player/get_player_info"}}'; $json .= '","heos": {"command": "player/get_player_info"}}';
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Players"; Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Players";
} }
} elsif( $decode_json->{heos}{command} =~ /group\/get_groups/ ) { } elsif( $decode_json->{heos}{command} =~ /group\/get_groups/ ) {
my $filter = "TYPE=HEOSGroup"; my $filter = "TYPE=HEOSGroup";
if ( scalar(@{$decode_json->{payload}}) > 0 ) { if ( scalar(@{$decode_json->{payload}}) > 0 ) {
$filter .= ":FILTER=GID!="; $filter .= ":FILTER=GID!=";
foreach my $payload (@{$decode_json->{payload}}) { foreach my $payload (@{$decode_json->{payload}}) {
$json = '{"gid": "'; $json = '{"gid": "';
$json .= "$payload->{gid}"; $json .= "$payload->{gid}";
$json .= '","heos": {"command": "group/get_group_info"}}'; $json .= '","heos": {"command": "group/get_group_info"}}';
@ -580,40 +716,52 @@ sub HEOSMaster_ResponseProcessing($$) {
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Groups"; Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for Groups";
$filter .= $payload->{gid}."|"; $filter .= $payload->{gid}."|";
} }
chop($filter); #letztes | wieder abschneiden chop($filter); #letztes | wieder abschneiden
} }
#alle Gruppe ausschalten die nicht mehr im HEOS System existieren #alle Gruppe ausschalten die nicht mehr im HEOS System existieren
foreach my $dev ( devspec2array($filter) ) { foreach my $dev ( devspec2array($filter) ) {
my $ghash = $defs{$dev}; my $ghash = $defs{$dev};
readingsSingleUpdate( $ghash, "state", "off", 1 ); readingsSingleUpdate( $ghash, "state", "off", 1 );
} }
} elsif( $decode_json->{heos}{command} =~ /player\/get_queue/ ) { } elsif( $decode_json->{heos}{command} =~ /player\/get_queue/ ) {
return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received" return Log3 $name, 4, "HEOSMaster ($name) - empty ARRAY received"
unless(scalar(@{$decode_json->{payload}}) > 0); unless(scalar(@{$decode_json->{payload}}) > 0);
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for QueueInfo"; 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? } elsif( $decode_json->{heos}{command} =~ /player\/get_player_info/ ) { # ist vielleicht verständlicher?
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for PlayerInfo"; 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? } elsif( $decode_json->{heos}{command} =~ /group\/get_group_info/ ) { # ist vielleicht verständlicher?
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for GroupInfo"; Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher for GroupInfo";
} elsif( defined($message{pid}) or defined($message{gid}) ) { } elsif( defined($message{pid}) or defined($message{gid}) ) {
Dispatch($hash,$json,undef); Dispatch($hash,$json,undef);
Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher"; Log3 $name, 4, "HEOSMaster ($name) - call Dispatcher";
} }
return; return;
} }
Log3 $name, 4, "HEOSMaster ($name) - no Match for processing data"; Log3 $name, 4, "HEOSMaster ($name) - no Match for processing data";
} }
sub HEOSMaster_WriteReadings($$) { sub HEOSMaster_WriteReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
############################ ############################
#### Aufbereiten der Daten soweit nötig #### Aufbereiten der Daten soweit nötig
my $readingsHash = HEOSMaster_PreProcessingReadings($hash,$decode_json) my $readingsHash = HEOSMaster_PreProcessingReadings($hash,$decode_json)
@ -629,20 +777,26 @@ sub HEOSMaster_WriteReadings($$) {
### Event Readings ### Event Readings
if( ref($readingsHash) eq "HASH" ) { if( ref($readingsHash) eq "HASH" ) {
Log3 $name, 4, "HEOSMaster ($name) - response json Hash back from HEOSMaster_PreProcessingReadings"; Log3 $name, 4, "HEOSMaster ($name) - response json Hash back from HEOSMaster_PreProcessingReadings";
my $t; my $t;
my $v; my $v;
while( ( $t, $v ) = each (%{$readingsHash}) ) { while( ( $t, $v ) = each (%{$readingsHash}) ) {
readingsBulkUpdate( $hash, $t, $v ) if( defined($v) ); readingsBulkUpdate( $hash, $t, $v ) if( defined($v) );
} }
} }
readingsBulkUpdate( $hash, "lastCommand", $decode_json->{heos}{command} ); readingsBulkUpdate( $hash, "lastCommand", $decode_json->{heos}{command} );
readingsBulkUpdate( $hash, "lastResult", $decode_json->{heos}{result} ); readingsBulkUpdate( $hash, "lastResult", $decode_json->{heos}{result} );
if( ref($decode_json->{payload}) ne "ARRAY" ) { if( ref($decode_json->{payload}) ne "ARRAY" ) {
readingsBulkUpdate( $hash, "lastPlayerId", $decode_json->{payload}{pid} ); readingsBulkUpdate( $hash, "lastPlayerId", $decode_json->{payload}{pid} );
readingsBulkUpdate( $hash, "lastPlayerName", $decode_json->{payload}{name} ); readingsBulkUpdate( $hash, "lastPlayerName", $decode_json->{payload}{name} );
} }
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
return undef; return undef;
} }
@ -651,6 +805,7 @@ sub HEOSMaster_WriteReadings($$) {
### my little Helpers ### my little Helpers
sub HEOSMaster_ParseMsg($$) { sub HEOSMaster_ParseMsg($$) {
my ($hash, $buffer) = @_; my ($hash, $buffer) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $open = 0; my $open = 0;
@ -658,169 +813,220 @@ sub HEOSMaster_ParseMsg($$) {
my $msg = ''; my $msg = '';
my $tail = ''; my $tail = '';
if($buffer) { if($buffer) {
foreach my $c (split //, $buffer) { foreach my $c (split //, $buffer) {
if($open == $close && $open > 0) { if($open == $close && $open > 0) {
$tail .= $c; $tail .= $c;
#Log3 $name, 5, "HEOSMaster ($name) - $open == $close && $open > 0"; #Log3 $name, 5, "HEOSMaster ($name) - $open == $close && $open > 0";
} elsif(($open == $close) && ($c ne '{')) { } elsif(($open == $close) && ($c ne '{')) {
Log3 $name, 5, "HEOSMaster ($name) - Garbage character before message: " . $c; Log3 $name, 5, "HEOSMaster ($name) - Garbage character before message: " . $c;
} else { } else {
if($c eq '{') { if($c eq '{') {
$open++; $open++;
} elsif($c eq '}') { } elsif($c eq '}') {
$close++; $close++;
} }
$msg .= $c; $msg .= $c;
} }
} }
if($open != $close) { if($open != $close) {
$tail = $msg; $tail = $msg;
$msg = ''; $msg = '';
} }
} }
Log3 $name, 5, "HEOSMaster ($name) - return msg: $msg and tail: $tail"; Log3 $name, 5, "HEOSMaster ($name) - return msg: $msg and tail: $tail";
return ($msg,$tail); return ($msg,$tail);
} }
sub HEOSMaster_PreProcessingReadings($$) { sub HEOSMaster_PreProcessingReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $reading; my $reading;
my %buffer; my %buffer;
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message}); my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
Log3 $name, 4, "HEOSMaster ($name) - preprocessing readings"; Log3 $name, 4, "HEOSMaster ($name) - preprocessing readings";
if ( $decode_json->{heos}{command} eq 'system/register_for_change_events' ) { if ( $decode_json->{heos}{command} eq 'system/register_for_change_events' ) {
$buffer{'enableChangeEvents'} = $message{enable}; $buffer{'enableChangeEvents'} = $message{enable};
} elsif ( $decode_json->{heos}{command} eq 'system/check_account' or $decode_json->{heos}{command} eq 'system/sign_in' ) { } elsif ( $decode_json->{heos}{command} eq 'system/check_account' or $decode_json->{heos}{command} eq 'system/sign_in' ) {
if ( exists $message{signed_out} ) { if ( exists $message{signed_out} ) {
$buffer{'heosAccount'} = "signed_out"; $buffer{'heosAccount'} = "signed_out";
} else { } else {
$buffer{'heosAccount'} = "signed_in as $message{un}"; $buffer{'heosAccount'} = "signed_in as $message{un}";
HEOSMaster_GetFavorites($hash) if( ReadingsVal($name,"enableChangeEvents", "off") eq "on" ); HEOSMaster_GetFavorites($hash) if( ReadingsVal($name,"enableChangeEvents", "off") eq "on" );
} }
} else { } else {
Log3 $name, 3, "HEOSMaster ($name) - no match found"; Log3 $name, 3, "HEOSMaster ($name) - no match found";
return undef; return undef;
} }
Log3 $name, 4, "HEOSMaster ($name) - Match found for decode_json"; Log3 $name, 4, "HEOSMaster ($name) - Match found for decode_json";
return \%buffer; return \%buffer;
} }
sub HEOSMaster_firstRun($) { sub HEOSMaster_firstRun($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash,'HEOSMaster_firstRun'); RemoveInternalTimer($hash,'HEOSMaster_firstRun');
HEOSMaster_Open($hash) if( !IsDisabled($name) ); HEOSMaster_Open($hash) if( !IsDisabled($name) );
} }
sub HEOSMaster_GetPlayers($) { sub HEOSMaster_GetPlayers($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash,'HEOSMaster_GetPlayers'); RemoveInternalTimer($hash,'HEOSMaster_GetPlayers');
HEOSMaster_Write($hash,'getPlayers',undef); HEOSMaster_Write($hash,'getPlayers',undef);
Log3 $name, 4, "HEOSMaster ($name) - getPlayers"; Log3 $name, 4, "HEOSMaster ($name) - getPlayers";
} }
sub HEOSMaster_GetGroups($) { sub HEOSMaster_GetGroups($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash,'HEOSMaster_GetGroups'); RemoveInternalTimer($hash,'HEOSMaster_GetGroups');
HEOSMaster_Write($hash,'getGroups',undef); HEOSMaster_Write($hash,'getGroups',undef);
Log3 $name, 4, "HEOSMaster ($name) - getGroups"; Log3 $name, 4, "HEOSMaster ($name) - getGroups";
} }
sub HEOSMaster_EnableChangeEvents($) { sub HEOSMaster_EnableChangeEvents($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash,'HEOSMaster_EnableChangeEvents'); RemoveInternalTimer($hash,'HEOSMaster_EnableChangeEvents');
HEOSMaster_Write($hash,'enableChangeEvents','on'); HEOSMaster_Write($hash,'enableChangeEvents','on');
Log3 $name, 4, "HEOSMaster ($name) - set enableChangeEvents on"; Log3 $name, 4, "HEOSMaster ($name) - set enableChangeEvents on";
} }
sub HEOSMaster_GetMusicSources($) { sub HEOSMaster_GetMusicSources($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetMusicSources'); RemoveInternalTimer($hash, 'HEOSMaster_GetMusicSources');
HEOSMaster_Write($hash,'getMusicSources',undef); HEOSMaster_Write($hash,'getMusicSources',undef);
Log3 $name, 4, "HEOSMaster ($name) - getMusicSources"; Log3 $name, 4, "HEOSMaster ($name) - getMusicSources";
} }
sub HEOSMaster_GetFavorites($) { sub HEOSMaster_GetFavorites($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetFavorites'); RemoveInternalTimer($hash, 'HEOSMaster_GetFavorites');
HEOSMaster_Write($hash,'browseSource','sid=1028'); HEOSMaster_Write($hash,'browseSource','sid=1028');
Log3 $name, 4, "HEOSMaster ($name) - getFavorites"; Log3 $name, 4, "HEOSMaster ($name) - getFavorites";
} }
sub HEOSMaster_GetInputs($) { sub HEOSMaster_GetInputs($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetInputs'); RemoveInternalTimer($hash, 'HEOSMaster_GetInputs');
HEOSMaster_Write($hash,'browseSource','sid=1027'); HEOSMaster_Write($hash,'browseSource','sid=1027');
Log3 $name, 4, "HEOSMaster ($name) - getInputs"; Log3 $name, 4, "HEOSMaster ($name) - getInputs";
} }
sub HEOSMaster_GetServers($) { sub HEOSMaster_GetServers($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetServers'); RemoveInternalTimer($hash, 'HEOSMaster_GetServers');
HEOSMaster_Write($hash,'browseSource','sid=1024'); HEOSMaster_Write($hash,'browseSource','sid=1024');
Log3 $name, 4, "HEOSMaster ($name) - getServers"; Log3 $name, 4, "HEOSMaster ($name) - getServers";
} }
sub HEOSMaster_GetPlaylists($) { sub HEOSMaster_GetPlaylists($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetPlaylists'); RemoveInternalTimer($hash, 'HEOSMaster_GetPlaylists');
HEOSMaster_Write($hash,'browseSource','sid=1025'); HEOSMaster_Write($hash,'browseSource','sid=1025');
Log3 $name, 4, "HEOSMaster ($name) - getPlaylists"; Log3 $name, 4, "HEOSMaster ($name) - getPlaylists";
} }
sub HEOSMaster_GetHistory($) { sub HEOSMaster_GetHistory($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_GetHistory'); RemoveInternalTimer($hash, 'HEOSMaster_GetHistory');
HEOSMaster_Write($hash,'browseSource','sid=1026'); HEOSMaster_Write($hash,'browseSource','sid=1026');
Log3 $name, 4, "HEOSMaster ($name) - getHistory"; Log3 $name, 4, "HEOSMaster ($name) - getHistory";
} }
sub HEOSMaster_CheckAccount($) { sub HEOSMaster_CheckAccount($) {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash, 'HEOSMaster_CheckAccount'); RemoveInternalTimer($hash, 'HEOSMaster_CheckAccount');
HEOSMaster_Write($hash,'checkAccount',undef); HEOSMaster_Write($hash,'checkAccount',undef);
Log3 $name, 4, "HEOSMaster ($name) - checkAccount"; Log3 $name, 4, "HEOSMaster ($name) - checkAccount";
} }
sub HEOSMaster_StorePassword($$) { sub HEOSMaster_StorePassword($$) {
my ($hash, $password) = @_; my ($hash, $password) = @_;
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
my $key = getUniqueId().$index; my $key = getUniqueId().$index;
my $enc_pwd = ""; my $enc_pwd = "";
if(eval "use Digest::MD5;1") { if(eval "use Digest::MD5;1") {
$key = Digest::MD5::md5_hex(unpack "H*", $key); $key = Digest::MD5::md5_hex(unpack "H*", $key);
$key .= Digest::MD5::md5_hex($key); $key .= Digest::MD5::md5_hex($key);
} }
for my $char (split //, $password) { for my $char (split //, $password) {
my $encode=chop($key); my $encode=chop($key);
$enc_pwd.=sprintf("%.2x",ord($char)^ord($encode)); $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode));
$key=$encode.$key; $key=$encode.$key;
} }
my $err = setKeyValue($index, $enc_pwd); my $err = setKeyValue($index, $enc_pwd);
return "error while saving the password - $err" if(defined($err)); return "error while saving the password - $err" if(defined($err));
@ -828,41 +1034,57 @@ sub HEOSMaster_StorePassword($$) {
} }
sub HEOSMaster_ReadPassword($) { sub HEOSMaster_ReadPassword($) {
my ($hash) = @_; my ($hash) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
my $key = getUniqueId().$index; my $key = getUniqueId().$index;
my ($password, $err); 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); ($err, $password) = getKeyValue($index);
if ( defined($err) ) { 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; return undef;
} }
if ( defined($password) ) { if ( defined($password) ) {
if ( eval "use Digest::MD5;1" ) { if ( eval "use Digest::MD5;1" ) {
$key = Digest::MD5::md5_hex(unpack "H*", $key); $key = Digest::MD5::md5_hex(unpack "H*", $key);
$key .= Digest::MD5::md5_hex($key); $key .= Digest::MD5::md5_hex($key);
} }
my $dec_pwd = ''; my $dec_pwd = '';
for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) { for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) {
my $decode=chop($key); my $decode=chop($key);
$dec_pwd.=chr(ord($char)^ord($decode)); $dec_pwd.=chr(ord($char)^ord($decode));
$key=$decode.$key; $key=$decode.$key;
} }
return $dec_pwd; return $dec_pwd;
} else { } else {
Log3 $name, 4, "HEOSMaster ($name) - No password in file";
return undef; Log3 $name, 4, "HEOSMaster ($name) - No password in file";
return undef;
} }
} }
################ ################
### Nur für mich um dem Emulator ein Event ab zu jagen ### Nur für mich um dem Emulator ein Event ab zu jagen
sub HEOSMaster_send($) { sub HEOSMaster_send($) {
my $hash = shift; my $hash = shift;
HEOSMaster_Write($hash,'eventChangeVolume',undef); HEOSMaster_Write($hash,'eventChangeVolume',undef);
} }

View File

@ -37,7 +37,7 @@ use JSON qw(decode_json);
use Encode qw(encode_utf8); use Encode qw(encode_utf8);
use Data::Dumper; use Data::Dumper;
my $version = "0.1.58"; my $version = "0.1.60";
# Declare functions # Declare functions
sub HEOSPlayer_Initialize($); sub HEOSPlayer_Initialize($);
@ -57,10 +57,12 @@ sub HEOSPlayer_Get($$@);
sub HEOSPlayer_GetMute($); sub HEOSPlayer_GetMute($);
sub HEOSPlayer_Initialize($) { sub HEOSPlayer_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
$hash->{Match} = '.*{"command":."player.*|.*{"command":."event/player.*|.*{"command":."event\/repeat_mode_changed.*|.*{"command":."event\/shuffle_mode_changed.*|.*{"command":."event\/favorites_changed.*'; $hash->{Match} = '.*{"command":."player.*|.*{"command":."event/player.*|.*{"command":."event\/repeat_mode_changed.*|.*{"command":."event\/shuffle_mode_changed.*|.*{"command":."event\/favorites_changed.*';
# Provider # Provider
$hash->{SetFn} = "HEOSPlayer_Set"; $hash->{SetFn} = "HEOSPlayer_Set";
$hash->{GetFn} = "HEOSPlayer_Get"; $hash->{GetFn} = "HEOSPlayer_Get";
@ -74,26 +76,32 @@ sub HEOSPlayer_Initialize($) {
$readingFnAttributes; $readingFnAttributes;
foreach my $d(sort keys %{$modules{HEOSPlayer}{defptr}}) { foreach my $d(sort keys %{$modules{HEOSPlayer}{defptr}}) {
my $hash = $modules{HEOSPlayer}{defptr}{$d}; my $hash = $modules{HEOSPlayer}{defptr}{$d};
$hash->{VERSION} = $version; $hash->{VERSION} = $version;
} }
} }
sub HEOSPlayer_Define($$) { sub HEOSPlayer_Define($$) {
my ( $hash, $def ) = @_; my ( $hash, $def ) = @_;
my @a = split( "[ \t]+", $def ); my @a = split( "[ \t]+", $def );
splice( @a, 1, 1 ); splice( @a, 1, 1 );
my $iodev; my $iodev;
my $i = 0; my $i = 0;
foreach my $param ( @a ) { foreach my $param ( @a ) {
if( $param =~ m/IODev=([^\s]*)/ ) { if( $param =~ m/IODev=([^\s]*)/ ) {
$iodev = $1; $iodev = $1;
splice( @a, $i, 3 ); splice( @a, $i, 3 );
last; last;
} }
$i++; $i++;
} }
return "too few parameters: define <name> HEOSPlayer <pid>" if( @a < 2 ); return "too few parameters: define <name> HEOSPlayer <pid>" if( @a < 2 );
my ($name,$pid) = @a; my ($name,$pid) = @a;
@ -101,30 +109,40 @@ sub HEOSPlayer_Define($$) {
$hash->{PID} = $pid; $hash->{PID} = $pid;
$hash->{VERSION} = $version; $hash->{VERSION} = $version;
AssignIoPort($hash,$iodev) if( !$hash->{IODev} ); AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
if(defined($hash->{IODev}->{NAME})) { if(defined($hash->{IODev}->{NAME})) {
Log3 $name, 3, "HEOSPlayer ($name) - I/O device is " . $hash->{IODev}->{NAME}; Log3 $name, 3, "HEOSPlayer ($name) - I/O device is " . $hash->{IODev}->{NAME};
} else { } else {
Log3 $name, 1, "HEOSPlayer ($name) - no I/O device"; Log3 $name, 1, "HEOSPlayer ($name) - no I/O device";
} }
$iodev = $hash->{IODev}->{NAME}; $iodev = $hash->{IODev}->{NAME};
my $code = abs($pid); my $code = abs($pid);
$code = $iodev."-".$code if( defined($iodev) ); $code = $iodev."-".$code if( defined($iodev) );
my $d = $modules{HEOSPlayer}{defptr}{$code}; my $d = $modules{HEOSPlayer}{defptr}{$code};
return "HEOSPlayer device $hash->{pid} on HEOSMaster $iodev already defined as $d->{NAME}." return "HEOSPlayer device $hash->{pid} on HEOSMaster $iodev already defined as $d->{NAME}."
if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name ); if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
Log3 $name, 3, "HEOSPlayer ($name) - defined with Code: $code"; Log3 $name, 3, "HEOSPlayer ($name) - defined with Code: $code";
$attr{$name}{room} = "HEOS" if( !defined( $attr{$name}{room} ) ); $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} ) ); $attr{$name}{devStateIcon} = "on:10px-kreis-gruen off:10px-kreis-rot" if( !defined( $attr{$name}{devStateIcon} ) );
if( $init_done ) { if( $init_done ) {
InternalTimer( gettimeofday()+int(rand(2)), "HEOSPlayer_GetPlayerInfo", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(2)), "HEOSPlayer_GetPlayerInfo", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(4)), "HEOSPlayer_GetPlayState", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(4)), "HEOSPlayer_GetPlayState", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(6)), "HEOSPlayer_GetNowPlayingMedia", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(6)), "HEOSPlayer_GetNowPlayingMedia", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(8)), "HEOSPlayer_GetPlayMode", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(8)), "HEOSPlayer_GetPlayMode", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(10)), "HEOSPlayer_GetVolume", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(10)), "HEOSPlayer_GetVolume", $hash, 0 );
InternalTimer( gettimeofday()+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 ); InternalTimer( gettimeofday()+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 );
} else { } else {
InternalTimer( gettimeofday()+15+int(rand(2)), "HEOSPlayer_GetPlayerInfo", $hash, 0 ); 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(4)), "HEOSPlayer_GetPlayState", $hash, 0 );
InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSPlayer_GetNowPlayingMedia", $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(10)), "HEOSPlayer_GetVolume", $hash, 0 );
InternalTimer( gettimeofday()+15+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 ); InternalTimer( gettimeofday()+15+int(rand(12)), "HEOSPlayer_GetMute", $hash, 0 );
} }
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'state','Initialized'); readingsBulkUpdate($hash, 'state','Initialized');
readingsBulkUpdate($hash, 'volumeUp', 5); readingsBulkUpdate($hash, 'volumeUp', 5);
readingsBulkUpdate($hash, 'volumeDown', 5); readingsBulkUpdate($hash, 'volumeDown', 5);
readingsEndUpdate($hash, 1); readingsEndUpdate($hash, 1);
$modules{HEOSPlayer}{defptr}{$code} = $hash; $modules{HEOSPlayer}{defptr}{$code} = $hash;
return undef; return undef;
} }
sub HEOSPlayer_Undef($$) { sub HEOSPlayer_Undef($$) {
my ( $hash, $arg ) = @_; my ( $hash, $arg ) = @_;
my $pid = $hash->{PID}; my $pid = $hash->{PID};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
my $code = abs($pid); my $code = abs($pid);
$code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) ); $code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) );
delete($modules{HEOSPlayer}{defptr}{$code}); delete($modules{HEOSPlayer}{defptr}{$code});
Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted with Code: $code"; Log3 $name, 3, "HEOSPlayer ($name) - device $name deleted with Code: $code";
return undef; return undef;
} }
sub HEOSPlayer_Attr(@) { sub HEOSPlayer_Attr(@) {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
my $token = $hash->{IODev}->{TOKEN}; my $token = $hash->{IODev}->{TOKEN};
if( $attrName eq "disable" ) { if( $attrName eq "disable" ) {
if( $cmd eq "set" and $attrVal eq "1" ) { if( $cmd eq "set" and $attrVal eq "1" ) {
readingsSingleUpdate ( $hash, "state", "disabled", 1 ); readingsSingleUpdate ( $hash, "state", "disabled", 1 );
Log3 $name, 3, "HEOSPlayer ($name) - disabled"; Log3 $name, 3, "HEOSPlayer ($name) - disabled";
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSPlayer ($name) - enabled"; Log3 $name, 3, "HEOSPlayer ($name) - enabled";
} }
} }
if( $attrName eq "disabledForIntervals" ) { if( $attrName eq "disabledForIntervals" ) {
if( $cmd eq "set" ) { if( $cmd eq "set" ) {
Log3 $name, 3, "HEOSPlayer ($name) - enable disabledForIntervals"; Log3 $name, 3, "HEOSPlayer ($name) - enable disabledForIntervals";
readingsSingleUpdate ( $hash, "state", "Unknown", 1 ); readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
}
elsif( $cmd eq "del" ) { } elsif( $cmd eq "del" ) {
readingsSingleUpdate ( $hash, "state", "active", 1 ); readingsSingleUpdate ( $hash, "state", "active", 1 );
Log3 $name, 3, "HEOSPlayer ($name) - delete disabledForIntervals"; Log3 $name, 3, "HEOSPlayer ($name) - delete disabledForIntervals";
} }
@ -182,48 +212,58 @@ sub HEOSPlayer_Attr(@) {
} }
sub HEOSPlayer_Get($$@) { sub HEOSPlayer_Get($$@) {
my ($hash, $name, @aa) = @_; my ($hash, $name, @aa) = @_;
my ($cmd, @args) = @aa; my ($cmd, @args) = @aa;
my $pid = $hash->{PID}; my $pid = $hash->{PID};
my $result = ""; my $result = "";
#print "CL ###################################################\n".Dumper($hash->{CL});
$hash->{helper}{cl} = $hash->{CL} if( ref($hash->{CL}) eq 'HASH' ); #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 #Leerzeichen müßen für die Rückgabe escaped werden sonst werden sie falsch angezeigt
if( $cmd eq 'playlists' ) { if( $cmd eq 'playlists' ) {
#gibt die Playlisten durch Komma getrennt zurück #gibt die Playlisten durch Komma getrennt zurück
my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}}); my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}});
$result .= join(",",@playlists) if( scalar @playlists > 0 ); $result .= join(",",@playlists) if( scalar @playlists > 0 );
return $result; return $result;
} elsif( $cmd eq 'channels' ) { } elsif( $cmd eq 'channels' ) {
#gibt die Favoriten durch Komma getrennt zurück #gibt die Favoriten durch Komma getrennt zurück
my @channels = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{favorites}}); my @channels = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{favorites}});
$result .= join(",",@channels) if( scalar @channels > 0 ); $result .= join(",",@channels) if( scalar @channels > 0 );
return $result; return $result;
} elsif( $cmd eq 'channelscount' ) { } elsif( $cmd eq 'channelscount' ) {
#gibt die Favoritenanzahl zurück #gibt die Favoritenanzahl zurück
return scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); return scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
} elsif( $cmd eq 'inputs' ) { } elsif( $cmd eq 'inputs' ) {
#gibt die Quellen durch Komma getrennt zurück #gibt die Quellen durch Komma getrennt zurück
my @inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{sources}}); my @inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{sources}});
push(@inputs, "Warteschlange"); push(@inputs, "Warteschlange");
$result .= join(",",@inputs) if( scalar @inputs > 0 ); $result .= join(",",@inputs) if( scalar @inputs > 0 );
return $result; return $result;
} elsif( $cmd eq 'search' ) { } elsif( $cmd eq 'search' ) {
return "usage: search <keywords>" if( @args != 1 );
return "usage: search <keywords>" if( @args != 1 );
}
}
my $list = 'playlists:noArg channels:noArg channelscount:noArg inputs:noArg ls search'; my $list = 'playlists:noArg channels:noArg channelscount:noArg inputs:noArg ls search';
return "Unknown argument $cmd, choose one of $list"; return "Unknown argument $cmd, choose one of $list";
} }
sub HEOSPlayer_Set($$@) { sub HEOSPlayer_Set($$@) {
my ($hash, $name, @aa) = @_; my ($hash, $name, @aa) = @_;
my ($cmd, @args) = @aa; my ($cmd, @args) = @aa;
my $pid = $hash->{PID}; my $pid = $hash->{PID};
@ -232,185 +272,270 @@ sub HEOSPlayer_Set($$@) {
my $rvalue; my $rvalue;
my $favoritcount = 1; my $favoritcount = 1;
my $qcount = 1; my $qcount = 1;
my $string = "pid=$pid"; my $string = '';
#print "cmd ###################################################\n".Dumper($cmd); #print "cmd ###################################################\n".Dumper($cmd);
if( $cmd eq 'getPlayerInfo' ) { if( $cmd eq 'getPlayerInfo' ) {
return "usage: getPlayerInfo" if( @args != 0 ); return "usage: getPlayerInfo" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
} elsif( $cmd eq 'getPlayState' ) { } elsif( $cmd eq 'getPlayState' ) {
return "usage: getPlayState" if( @args != 0 ); return "usage: getPlayState" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
} elsif( $cmd eq 'getPlayMode' ) { } elsif( $cmd eq 'getPlayMode' ) {
return "usage: getPlayMode" if( @args != 0 ); return "usage: getPlayMode" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
} elsif( $cmd eq 'getNowPlayingMedia' ) { } elsif( $cmd eq 'getNowPlayingMedia' ) {
return "usage: getNowPlayingMedia" if( @args != 0 ); return "usage: getNowPlayingMedia" if( @args != 0 );
$heosCmd = $cmd; $heosCmd = $cmd;
} elsif( $cmd eq 'repeat' ) { } elsif( $cmd eq 'repeat' ) {
return "usage: repeat one,all,off" if( @args != 1 ); return "usage: repeat one,all,off" if( @args != 1 );
$heosCmd = 'setPlayMode'; $heosCmd = 'setPlayMode';
$rvalue = 'on_'.$args[0]; $rvalue = 'on_'.$args[0];
$rvalue = 'off' if($rvalue eq 'on_off'); $rvalue = 'off' if($rvalue eq 'on_off');
$action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off'); $action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off');
} elsif( $cmd eq 'shuffle' ) { } elsif( $cmd eq 'shuffle' ) {
return "usage: shuffle on,off" if( @args != 1 ); return "usage: shuffle on,off" if( @args != 1 );
$heosCmd = 'setPlayMode'; $heosCmd = 'setPlayMode';
$rvalue = 'on_'.ReadingsVal($name,'repeat','off'); $rvalue = 'on_'.ReadingsVal($name,'repeat','off');
$rvalue = 'off' if($rvalue eq 'on_off'); $rvalue = 'off' if($rvalue eq 'on_off');
$action = "repeat=$rvalue&shuffle=$args[0]"; $action = "repeat=$rvalue&shuffle=$args[0]";
} elsif( $cmd eq 'play' ) { } elsif( $cmd eq 'play' ) {
return "usage: play" if( @args != 0 ); return "usage: play" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'stop' ) { } elsif( $cmd eq 'stop' ) {
return "usage: stop" if( @args != 0 ); return "usage: stop" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'pause' ) { } elsif( $cmd eq 'pause' ) {
return "usage: pause" if( @args != 0 ); return "usage: pause" if( @args != 0 );
$heosCmd = 'setPlayState'; $heosCmd = 'setPlayState';
$action = "state=$cmd"; $action = "state=$cmd";
} elsif( $cmd eq 'mute' ) { } elsif( $cmd eq 'mute' ) {
return "usage: mute on/off" if( @args != 1 ); return "usage: mute on/off" if( @args != 1 );
$heosCmd = 'setMute'; $heosCmd = 'setMute';
$action = "state=$args[0]"; $action = "state=$args[0]";
} elsif( $cmd eq 'volume' ) { } elsif( $cmd eq 'volume' ) {
return "usage: volume 0-100" if( @args != 1 ); return "usage: volume 0-100" if( @args != 1 );
$heosCmd = 'setVolume'; $heosCmd = 'setVolume';
$action = "level=$args[0]"; $action = "level=$args[0]";
} elsif( $cmd eq 'volumeUp' ) { } elsif( $cmd eq 'volumeUp' ) {
return "usage: volumeUp 0-10" if( @args != 1 ); return "usage: volumeUp 0-10" if( @args != 1 );
$heosCmd = $cmd; $heosCmd = $cmd;
$action = "step=$args[0]"; $action = "step=$args[0]";
} elsif( $cmd eq 'volumeDown' ) { } elsif( $cmd eq 'volumeDown' ) {
return "usage: volumeDown 0-10" if( @args != 1 ); return "usage: volumeDown 0-10" if( @args != 1 );
$heosCmd = $cmd; $heosCmd = $cmd;
$action = "step=$args[0]"; $action = "step=$args[0]";
} elsif( $cmd eq 'groupWithMember' ) { } elsif( $cmd eq 'groupWithMember' ) {
return "usage: groupWithMember" if( @args != 1 ); return "usage: groupWithMember" if( @args != 1 );
$pid .= ",$defs{$args[0]}->{PID}"; $pid .= ",$defs{$args[0]}->{PID}";
$heosCmd = 'createGroup'; $heosCmd = 'createGroup';
} elsif( $cmd eq 'clearGroup' ) { } elsif( $cmd eq 'clearGroup' ) {
return "usage: clearGroup" if( @args != 0 ); return "usage: clearGroup" if( @args != 0 );
$heosCmd = 'createGroup'; $heosCmd = 'createGroup';
} elsif( $cmd eq 'next' ) { } elsif( $cmd eq 'next' ) {
return "usage: next" if( @args != 0 ); return "usage: next" if( @args != 0 );
$heosCmd = 'playNext'; $heosCmd = 'playNext';
} elsif( $cmd eq 'prev' ) { } elsif( $cmd eq 'prev' ) {
return "usage: prev" if( @args != 0 ); return "usage: prev" if( @args != 0 );
$heosCmd = 'playPrev'; $heosCmd = 'playPrev';
#} elsif( $cmd eq 'reReadSources' ) {
# return "usage: reReadSources" if( @args != 0 );
# $heosCmd = 'getMusicSources';
} elsif ( $cmd =~ /channel/ ) { } elsif ( $cmd =~ /channel/ ) {
my $favorit = ReadingsVal($name,"channel", 0); my $favorit = ReadingsVal($name,"channel", 0);
$favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); $favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
$heosCmd = 'playPresetStation'; $heosCmd = 'playPresetStation';
if ( $cmd eq 'channel' ) { if ( $cmd eq 'channel' ) {
return "usage: channel 1-$favoritcount" if( @args != 1 ); return "usage: channel 1-$favoritcount" if( @args != 1 );
$action = "preset=$args[0]"; $action = "preset=$args[0]";
} elsif( $cmd eq 'channelUp' ) { } elsif( $cmd eq 'channelUp' ) {
return "usage: channelUp" if( @args != 0 ); return "usage: channelUp" if( @args != 0 );
$favorit = $favoritcount if ( ++$favorit > $favoritcount ); $favorit = $favoritcount if ( ++$favorit > $favoritcount );
$action = "preset=".$favorit; $action = "preset=".$favorit;
} elsif( $cmd eq 'channelDown' ) { } elsif( $cmd eq 'channelDown' ) {
$favorit = 1 if ( --$favorit <= 0 ); $favorit = 1 if ( --$favorit <= 0 );
$action = "preset=".$favorit; $action = "preset=".$favorit;
} }
} elsif ( $cmd =~ /Playlist/ ) { } elsif ( $cmd =~ /Playlist/ ) {
my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} }); my @cids = map { $_->{cid} } grep { $_->{name} =~ /$args[0]/i } (@{ $hash->{IODev}{helper}{playlists} });
if ( scalar @args == 1 && scalar @cids > 0 ) { if ( scalar @args == 1 && scalar @cids > 0 ) {
if ( $cmd eq 'playPlaylist' ) { if ( $cmd eq 'playPlaylist' ) {
$heosCmd = $cmd; $heosCmd = $cmd;
$action = "sid=1025&cid=$cids[0]&aid=4"; $action = "sid=1025&cid=$cids[0]&aid=4";
} elsif ( $cmd eq 'deletePlaylist' ) { } elsif ( $cmd eq 'deletePlaylist' ) {
$heosCmd = $cmd; $heosCmd = $cmd;
$action = "cid=$cids[0]"; $action = "cid=$cids[0]";
$string = "sid=1025"; $string = "sid=1025";
} }
} else { } else {
IOWrite($hash,'browseSource','sid=1025'); IOWrite($hash,'browseSource','sid=1025');
my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}}); my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}});
return "usage: $cmd ".join(",",@playlists); return "usage: $cmd ".join(",",@playlists);
} }
} elsif( $cmd eq 'input' ) {
my @sids;
my $search = $args[0];
$search =~ s/\xC2\xA0/ /g; } elsif( $cmd eq 'input' ) {
my @sids;
my $search = $args[0];
$search =~ s/\xC2\xA0/ /g;
#$search =~ s/\s+/\&nbsp;/g; #$search =~ s/\s+/\&nbsp;/g;
if ( $search =~ /Warteschlange/ ) { if ( $search =~ /Warteschlange/ ) {
push(@sids, "9999"); push(@sids, "9999");
} else { } else {
@sids = map { $_->{sid} } grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{sources} }); @sids = map { $_->{sid} } grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{sources} });
} }
if ( scalar @args == 1 && scalar @sids > 0 ) { if ( scalar @args == 1 && scalar @sids > 0 ) {
readingsSingleUpdate($hash, "input", $args[0], 1); readingsSingleUpdate($hash, "input", $args[0], 1);
#sid des Input für Container merken #sid des Input für Container merken
readingsSingleUpdate($hash, ".input", $sids[0], 1); readingsSingleUpdate($hash, ".input", $sids[0], 1);
#alten Container löschen bei Inputwechsel #alten Container löschen bei Inputwechsel
readingsSingleUpdate($hash, ".cid", 0, 1); readingsSingleUpdate($hash, ".cid", 0, 1);
if ( $sids[0] eq "9999" ) { if ( $sids[0] eq "9999" ) {
$heosCmd = 'getQueue'; $heosCmd = 'getQueue';
} else {
} else {
$heosCmd = 'browseSource'; $heosCmd = 'browseSource';
$action = "sid=$sids[0]"; $action = "sid=$sids[0]";
} }
Log3 $name, 4, "HEOSPlayer ($name) - set input with sid $sids[0] and name $args[0]"; Log3 $name, 4, "HEOSPlayer ($name) - set input with sid $sids[0] and name $args[0]";
} else { } else {
my @inputs = map { $_->{name} } (@{ $hash->{IODev}{helper}{sources}}); my @inputs = map { $_->{name} } (@{ $hash->{IODev}{helper}{sources}});
push(@inputs, "Warteschlange"); push(@inputs, "Warteschlange");
return "usage: input ".join(",",@inputs); 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) ); } 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 ) { if ( scalar @args == 1 ) {
$search =~ s/\xC2\xA0/ /g; $search =~ s/\xC2\xA0/ /g;
if ( $sid eq "9999" ) { if ( $sid eq "9999" ) {
@ids = grep { $_->{song} =~ /\Q$search\E/i } (@{ $hash->{helper}{queue} }); @ids = grep { $_->{song} =~ /\Q$search\E/i } (@{ $hash->{helper}{queue} });
} else { } else {
@ids = grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{media} }); @ids = grep { $_->{name} =~ /\Q$search\E/i } (@{ $hash->{IODev}{helper}{media} });
} }
if ( scalar @ids > 0 ) { if ( scalar @ids > 0 ) {
if ( exists $ids[0]{cid} ) { if ( exists $ids[0]{cid} ) {
#hier Container verarbeiten #hier Container verarbeiten
if ( $ids[0]{playable} eq "yes" ) { if ( $ids[0]{playable} eq "yes" ) {
#alles abspielen #alles abspielen
$heosCmd = 'playPlaylist'; $heosCmd = 'playPlaylist';
$action = "sid=$sid&cid=$ids[0]{cid}&aid=4"; $action = "sid=$sid&cid=$ids[0]{cid}&aid=4";
#Container merken #Container merken
readingsSingleUpdate($hash, ".cid", 0, 1); readingsSingleUpdate($hash, ".cid", 0, 1);
} else { } else {
#mehr einlesen #mehr einlesen
readingsSingleUpdate($hash, ".cid", $ids[0]{cid}, 1); readingsSingleUpdate($hash, ".cid", $ids[0]{cid}, 1);
$heosCmd = 'browseSource'; $heosCmd = 'browseSource';
$action = "sid=$sid&cid=$ids[0]{cid}"; $action = "sid=$sid&cid=$ids[0]{cid}";
} }
} elsif ( exists $ids[0]{qid} ) { } elsif ( exists $ids[0]{qid} ) {
$heosCmd = 'playQueue'; $heosCmd = 'playQueue';
$action = "qid=$ids[0]{qid}"; $action = "qid=$ids[0]{qid}";
} elsif ( exists $ids[0]{mid} ) { } elsif ( exists $ids[0]{mid} ) {
#hier Medien verarbeiten #hier Medien verarbeiten
if ( $ids[0]{mid} =~ /inputs\// ) { if ( $ids[0]{mid} =~ /inputs\// ) {
#Input abspielen #Input abspielen
$heosCmd = 'playInput'; $heosCmd = 'playInput';
$action = "input=$ids[0]{mid}"; $action = "input=$ids[0]{mid}";
} else { } else {
#aktuellen Container holen #aktuellen Container holen
my $cid = ReadingsVal($name,".cid", undef); my $cid = ReadingsVal($name,".cid", undef);
if ( defined $cid ) { if ( defined $cid ) {
if ( $ids[0]{type} eq "station" ) { if ( $ids[0]{type} eq "station" ) {
#Radio abspielen #Radio abspielen
$heosCmd = 'playStream'; $heosCmd = 'playStream';
$action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}"; $action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}";
} else { } else {
#Song abspielen #Song abspielen
$heosCmd = 'playPlaylist'; $heosCmd = 'playPlaylist';
$action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}&aid=4"; $action = "sid=$sid&cid=$cid&mid=$ids[0]{mid}&aid=4";
@ -419,63 +544,87 @@ sub HEOSPlayer_Set($$@) {
} }
} }
} }
} else { } else {
my @media; my @media;
if ( $sid eq "9999" ) { if ( $sid eq "9999" ) {
@media = map { $_->{song} } (@{ $hash->{helper}{queue}}); @media = map { $_->{song} } (@{ $hash->{helper}{queue}});
} else {
} else {
@media = map { $_->{name} } (@{ $hash->{IODev}{helper}{media}}); @media = map { $_->{name} } (@{ $hash->{IODev}{helper}{media}});
} }
return "usage: media ".join(",",@media); return "usage: media ".join(",",@media);
} }
} elsif ( $cmd eq 'clearQueue' ) { } elsif ( $cmd eq 'clearQueue' ) {
#löscht die Warteschlange #löscht die Warteschlange
return "usage: clearQueue" if( @args != 0 ); return "usage: clearQueue" if( @args != 0 );
$heosCmd = 'clearQueue'; $heosCmd = 'clearQueue';
delete $hash->{helper}{queue}; delete $hash->{helper}{queue};
} elsif ( $cmd eq 'saveQueue' ) { } elsif ( $cmd eq 'saveQueue' ) {
#speichert die aktuelle Warteschlange als Playlist ab #speichert die aktuelle Warteschlange als Playlist ab
return "usage: saveQueue" if( @args != 1 ); return "usage: saveQueue" if( @args != 1 );
$heosCmd = 'saveQueue'; $heosCmd = 'saveQueue';
$action = "name=$args[0]"; $action = "name=$args[0]";
} elsif ( $cmd eq 'history' ) {
} elsif ( $cmd eq 'history' ) {
return "usage: history track,channel" if( @args != 1 ); return "usage: history track,channel" if( @args != 1 );
$heosCmd = "browseSource"; $heosCmd = "browseSource";
$action = "sid=1026&cid=TRACKS" if ( $args[0] eq "track" ); $action = "sid=1026&cid=TRACKS" if ( $args[0] eq "track" );
$action = "sid=1026&cid=STATIONS" if ( $args[0] eq "channel" ); $action = "sid=1026&cid=STATIONS" if ( $args[0] eq "channel" );
} else { } else {
my @playlists; my @playlists;
my @inputs; my @inputs;
my @media; my @media;
my @queue; my @queue;
my $sid = ReadingsVal($name,".input", "9999"); my $sid = ReadingsVal($name,".input", "9999");
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 channelUp:noArg channelDown:noArg next:noArg prev:noArg history:track,channel "; 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 channelUp:noArg channelDown:noArg next:noArg prev:noArg history:track,channel ";
$list .= "groupWithMember:" . join( ",", devspec2array("TYPE=HEOSPlayer:FILTER=NAME!=$name") ); $list .= "groupWithMember:" . join( ",", devspec2array("TYPE=HEOSPlayer:FILTER=NAME!=$name") );
#Parameterlisten für FHEMWeb zusammen bauen #Parameterlisten für FHEMWeb zusammen bauen
$list .= " channel:slider,1,1,".scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} ); $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} ); #$list .= " playQueue:slider,1,1,".scalar(@{$hash->{helper}{queue}}) if ( defined $hash->{helper}{queue} );
if ( defined $hash->{IODev}{helper}{playlists} ) { if ( defined $hash->{IODev}{helper}{playlists} ) {
@playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}}); @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}});
$list .= " playPlaylist:".join(",",@playlists) if( scalar @playlists > 0 ); $list .= " playPlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
$list .= " deletePlaylist:".join(",",@playlists) if( scalar @playlists > 0 ); $list .= " deletePlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
#$list .= " renamePlaylist:".join(",",@playlists) if( scalar @playlists > 0 ); #$list .= " renamePlaylist:".join(",",@playlists) if( scalar @playlists > 0 );
} }
if ( defined $hash->{IODev}{helper}{sources}) { if ( defined $hash->{IODev}{helper}{sources}) {
@inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{sources}}); @inputs = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{sources}});
push(@inputs, "Warteschlange"); push(@inputs, "Warteschlange");
$list .= " input:".join(",",@inputs) if( scalar @inputs > 0 ); $list .= " input:".join(",",@inputs) if( scalar @inputs > 0 );
} }
if ( $sid eq "9999" ) { if ( $sid eq "9999" ) {
@media = map { my %n; $n{name} = $_->{song}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{helper}{queue}}); @media = map { my %n; $n{name} = $_->{song}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{helper}{queue}});
$list .= " clearQueue:noArg saveQueue"; $list .= " clearQueue:noArg saveQueue";
} else { } else {
@media = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{media}}) if ( defined $hash->{IODev}{helper}{media}); @media = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{media}}) if ( defined $hash->{IODev}{helper}{media});
} }
$list .= " media:".join(",",@media) if( scalar @media > 0 ); $list .= " media:".join(",",@media) if( scalar @media > 0 );
return "Unknown argument $cmd, choose one of $list"; return "Unknown argument $cmd, choose one of $list";
} }
$string .= "pid=$pid";
$string .= "&$action" if( defined($action)); $string .= "&$action" if( defined($action));
IOWrite($hash,"$heosCmd","$string"); IOWrite($hash,"$heosCmd","$string");
Log3 $name, 4, "HEOSPlayer ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}"; Log3 $name, 4, "HEOSPlayer ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}";
@ -483,56 +632,82 @@ sub HEOSPlayer_Set($$@) {
} }
sub HEOSPlayer_Parse($$) { sub HEOSPlayer_Parse($$) {
my ($io_hash,$json) = @_; my ($io_hash,$json) = @_;
my $name = $io_hash->{NAME}; my $name = $io_hash->{NAME};
my $pid; my $pid;
my $decode_json; my $decode_json;
my $code; my $code;
$decode_json = decode_json(encode_utf8($json)); $decode_json = decode_json(encode_utf8($json));
Log3 $name, 4, "HEOSPlayer - ParseFn wurde aufgerufen"; Log3 $name, 4, "HEOSPlayer - ParseFn wurde aufgerufen";
if( defined($decode_json->{pid}) ) { if( defined($decode_json->{pid}) ) {
$pid = $decode_json->{pid}; $pid = $decode_json->{pid};
$code = abs($pid); $code = abs($pid);
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) ); $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) { if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) {
IOWrite($hash,'getPlayerInfo',"pid=$hash->{PID}"); 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 logical device: $hash->{NAME}";
Log3 $hash->{NAME}, 4, "HEOSPlayer ($hash->{NAME}) - find PID in root from decode_json"; Log3 $hash->{NAME}, 4, "HEOSPlayer ($hash->{NAME}) - find PID in root from decode_json";
return $hash->{NAME}; return $hash->{NAME};
} else { } else {
my $devname = "HEOSPlayer".abs($pid); my $devname = "HEOSPlayer".abs($pid);
return "UNDEFINED $devname HEOSPlayer $pid IODev=$name"; 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}) ); } else {
$pid = $decode_json->{payload}{pid} if( defined($decode_json->{payload}{pid}) );
Log3 $name, 4, "HEOSPlayer ($name) PID: $pid"; my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
$pid = $message{pid} if( defined($message{pid}) );
$pid = $decode_json->{payload}{pid} if( defined($decode_json->{payload}{pid}) );
Log3 $name, 4, "HEOSPlayer ($name) PID: $pid";
$code = abs($pid); $code = abs($pid);
$code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) ); $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) { if( my $hash = $modules{HEOSPlayer}{defptr}{$code} ) {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
if ( $decode_json->{heos}{command} =~ /get_queue/ ) { if ( $decode_json->{heos}{command} =~ /get_queue/ ) {
Log3 $name, 3, "HEOSPlayer ($name) - call getQueue for $message{pid}"; 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} ) {
$hash->{helper}{queue} = [];
} $message{range} =~ s/(\d+)\,\d+/$1/;
} else {
$message{range} = 0;
$hash->{helper}{queue} = [];
}
my $start = $message{range} + $message{returned}; my $start = $message{range} + $message{returned};
push( @{$hash->{helper}{queue}}, (@{$decode_json->{payload}}) ); push( @{$hash->{helper}{queue}}, (@{$decode_json->{payload}}) );
if ( $start < $message{count} ) { if ( $start < $message{count} ) {
IOWrite($hash,'getQueue',"pid=$message{pid}&range=$start,".($start + 100)); 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}"; Log3 $name, 3, "HEOSMaster ($name) - call getQueue with pid $message{pid} next Range from $message{returned}";
} }
} else { } else {
HEOSPlayer_WriteReadings($hash,$decode_json); HEOSPlayer_WriteReadings($hash,$decode_json);
Log3 $name, 4, "HEOSPlayer ($name) - find logical device: $hash->{NAME}"; Log3 $name, 4, "HEOSPlayer ($name) - find logical device: $hash->{NAME}";
} }
return $hash->{NAME}; return $hash->{NAME};
} else { } else {
my $devname = "HEOSPlayer".abs($pid); my $devname = "HEOSPlayer".abs($pid);
return "UNDEFINED $devname HEOSPlayer $pid IODev=$name"; return "UNDEFINED $devname HEOSPlayer $pid IODev=$name";
} }
@ -540,9 +715,11 @@ sub HEOSPlayer_Parse($$) {
} }
sub HEOSPlayer_WriteReadings($$) { sub HEOSPlayer_WriteReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
Log3 $name, 3, "HEOSPlayer ($name) - processing data to write readings"; Log3 $name, 3, "HEOSPlayer ($name) - processing data to write readings";
############################ ############################
#### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel) #### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel)
@ -554,9 +731,11 @@ sub HEOSPlayer_WriteReadings($$) {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
### Event Readings ### Event Readings
if( ref($readingsHash) eq "HASH" ) { if( ref($readingsHash) eq "HASH" ) {
Log3 $name, 4, "HEOSPlayer ($name) - response json Hash back from HEOSPlayer_PreProcessingReadings"; Log3 $name, 4, "HEOSPlayer ($name) - response json Hash back from HEOSPlayer_PreProcessingReadings";
my $t; my $t;
my $v; my $v;
while( ( $t, $v ) = each (%{$readingsHash}) ) { while( ( $t, $v ) = each (%{$readingsHash}) ) {
readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) ); readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) );
} }
@ -587,6 +766,7 @@ sub HEOSPlayer_WriteReadings($$) {
my @presets = map { $_->{name} } (@{ $hash->{IODev}{helper}{favorites} }); my @presets = map { $_->{name} } (@{ $hash->{IODev}{helper}{favorites} });
my $search = ReadingsVal($name,"currentStation" ,undef); my $search = ReadingsVal($name,"currentStation" ,undef);
my( @index )= grep { $presets[$_] eq $search } 0..$#presets if ( defined $search ); my( @index )= grep { $presets[$_] eq $search } 0..$#presets if ( defined $search );
readingsBulkUpdate( $hash, 'channel', $index[0]+1 ) if ( scalar @index > 0 ); readingsBulkUpdate( $hash, 'channel', $index[0]+1 ) if ( scalar @index > 0 );
readingsBulkUpdate( $hash, 'state', 'on' ); readingsBulkUpdate( $hash, 'state', 'on' );
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
@ -599,15 +779,20 @@ sub HEOSPlayer_WriteReadings($$) {
### my little Helpers ### my little Helpers
sub HEOSPlayer_PreProcessingReadings($$) { sub HEOSPlayer_PreProcessingReadings($$) {
my ($hash,$decode_json) = @_; my ($hash,$decode_json) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $reading; my $reading;
my %buffer; my %buffer;
my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message}); my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
Log3 $name, 4, "HEOSPlayer ($name) - preprocessing readings";
Log3 $name, 4, "HEOSPlayer ($name) - preprocessing readings";
if ( $decode_json->{heos}{command} =~ /play_state/ or $decode_json->{heos}{command} =~ /player_state_changed/ ) { if ( $decode_json->{heos}{command} =~ /play_state/ or $decode_json->{heos}{command} =~ /player_state_changed/ ) {
$buffer{'playStatus'} = $message{state};
$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/ ) { } 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}); 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=play") if $buffer{'mute'} eq "off";
IOWrite($hash,'setPlayState',"pid=$hash->{PID}&state=stop") if $buffer{'mute'} eq "on"; 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/ ) { } 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{'shuffle'} = $message{shuffle};
$buffer{'repeat'} = $message{repeat}; $buffer{'repeat'} = $message{repeat};
$buffer{'repeat'} ==~ s/.*\_(.*)/$1/g; $buffer{'repeat'} ==~ s/.*\_(.*)/$1/g;
} elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) { } elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) {
$buffer{'mute'} = $message{state}; $buffer{'mute'} = $message{state};
} elsif ( $decode_json->{heos}{command} =~ /volume_up/ or $decode_json->{heos}{command} =~ /volume_down/ ) { } 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{'volumeUp'} = $message{step} if( $decode_json->{heos}{command} =~ /volume_up/ );
$buffer{'volumeDown'} = $message{step} if( $decode_json->{heos}{command} =~ /volume_down/ ); $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/ ) { } elsif ( $decode_json->{heos}{command} =~ /player_now_playing_changed/ or $decode_json->{heos}{command} =~ /favorites_changed/ ) {
IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}"); IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}");
} elsif ( $decode_json->{heos}{command} =~ /play_preset/ ) { } elsif ( $decode_json->{heos}{command} =~ /play_preset/ ) {
$buffer{'channel'} = $message{preset}
$buffer{'channel'} = $message{preset}
} elsif ( $decode_json->{heos}{command} =~ /play_input/ ) { } elsif ( $decode_json->{heos}{command} =~ /play_input/ ) {
$buffer{'input'} = $message{input};
$buffer{'input'} = $message{input};
} elsif ( $decode_json->{heos}{command} =~ /playback_error/ ) { } elsif ( $decode_json->{heos}{command} =~ /playback_error/ ) {
$buffer{'error'} = $message{error};
$buffer{'error'} = $message{error};
} else { } else {
Log3 $name, 3, "HEOSPlayer ($name) - no match found"; Log3 $name, 3, "HEOSPlayer ($name) - no match found";
return undef; return undef;
} }
Log3 $name, 4, "HEOSPlayer ($name) - Match found for decode_json"; Log3 $name, 4, "HEOSPlayer ($name) - Match found for decode_json";
return \%buffer; return \%buffer;
} }
sub HEOSPlayer_GetPlayerInfo($) { sub HEOSPlayer_GetPlayerInfo($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayerInfo'); RemoveInternalTimer($hash,'HEOSPlayer_GetPlayerInfo');
IOWrite($hash,'getPlayerInfo',"pid=$hash->{PID}"); IOWrite($hash,'getPlayerInfo',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetPlayState($) { sub HEOSPlayer_GetPlayState($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayState'); RemoveInternalTimer($hash,'HEOSPlayer_GetPlayState');
IOWrite($hash,'getPlayState',"pid=$hash->{PID}"); IOWrite($hash,'getPlayState',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetPlayMode($) { sub HEOSPlayer_GetPlayMode($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetPlayMode'); RemoveInternalTimer($hash,'HEOSPlayer_GetPlayMode');
IOWrite($hash,'getPlayMode',"pid=$hash->{PID}"); IOWrite($hash,'getPlayMode',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetNowPlayingMedia($) { sub HEOSPlayer_GetNowPlayingMedia($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetNowPlayingMedia'); RemoveInternalTimer($hash,'HEOSPlayer_GetNowPlayingMedia');
IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}"); IOWrite($hash,'getNowPlayingMedia',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetVolume($) { sub HEOSPlayer_GetVolume($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetVolume'); RemoveInternalTimer($hash,'HEOSPlayer_GetVolume');
IOWrite($hash,'getVolume',"pid=$hash->{PID}"); IOWrite($hash,'getVolume',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetMute($) { sub HEOSPlayer_GetMute($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetMute'); RemoveInternalTimer($hash,'HEOSPlayer_GetMute');
IOWrite($hash,'getMute',"pid=$hash->{PID}"); IOWrite($hash,'getMute',"pid=$hash->{PID}");
} }
sub HEOSPlayer_GetQueue($) { sub HEOSPlayer_GetQueue($) {
my $hash = shift; my $hash = shift;
RemoveInternalTimer($hash,'HEOSPlayer_GetQueue'); RemoveInternalTimer($hash,'HEOSPlayer_GetQueue');
IOWrite($hash,'getQueue',"pid=$hash->{PID}"); IOWrite($hash,'getQueue',"pid=$hash->{PID}");
} }