############################################################################## # # $Id$ # # 71_PHILIPS_AUDIO.pm # # An FHEM Perl module for controlling Philips Audio Equipment connected to local network # such as MCi, Streamium and Fidelio devices. # The module provides basic functionality accessible through the port 8889 of the device: # (http://:8889/index). # e.g. NP3500, NP3700, NP3900. # # Copyright by Radoslaw Watroba # (e-mail: ra666ack at g**glemail d*t c*m) # # This file is part of fhem. # # Fhem is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # Fhem is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with fhem. If not, see . # ############################################################################## package main; use strict; use warnings; use Time::HiRes qw(gettimeofday sleep); use Time::Piece; use POSIX qw{strftime}; use HttpUtils; ################################### sub PHILIPS_AUDIO_Initialize { my ($hash) = @_; $hash->{DefFn} = "PHILIPS_AUDIO_Define"; $hash->{GetFn} = "PHILIPS_AUDIO_Get"; $hash->{SetFn} = "PHILIPS_AUDIO_Set"; $hash->{AttrFn} = "PHILIPS_AUDIO_Attr"; $hash->{UndefFn} = "PHILIPS_AUDIO_Undefine"; $hash->{AttrList} = "do_not_notify:0,1 disable:0,1 model max-device-presets max-device-favorites request-timeout:1,2,3,4,5 ".$readingFnAttributes; return; } ################################### sub PHILIPS_AUDIO_GetStatus { my ($hash, $local) = @_; my $name = $hash->{NAME}; my $power; $local = 0 unless(defined($local)); return "" if((!defined($hash->{IP_ADDRESS})) or (!defined($hash->{helper}{OFF_INTERVAL})) or (!defined($hash->{helper}{ON_INTERVAL}))); my $device = $hash->{IP_ADDRESS}; # Check for Presets availability if(not defined($hash->{READINGS}{"totalInetRadioPresets"})) { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; PHILIPS_AUDIO_SendCommand($hash, "/index", "", "getInetRadioPresets", "noArg"); # Wait 10 seconds for next http request due to slow command processing of the streamium devices. PHILIPS_AUDIO_ResetTimer($hash, 10); return; } # Check for Favorites availability if(not defined($hash->{READINGS}{"totalInetRadioFavorites"})) { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; PHILIPS_AUDIO_SendCommand($hash, "/index", "", "getInetRadioFavorites", "noArg"); # Wait 10 seconds for next http request due to slow command processing of the streamium devices. PHILIPS_AUDIO_ResetTimer($hash, 10); return; } PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg"); PHILIPS_AUDIO_ResetTimer($hash) unless($local == 1); return; } ################################### sub PHILIPS_AUDIO_Get { my ($hash, @a) = @_; my $what; my $return; my $name = $hash->{NAME}; my $address = $hash->{IP_ADDRESS}; $hash->{IP_ADDRESS} = $address; return "argument is missing" if(int(@a) != 2); if(not defined($hash->{MODEL})) { return "Please provide the model information as argument."; } $what = $a[1]; if(exists($hash->{READINGS}{$what})) { if(defined($hash->{READINGS}{$what})) { return $hash->{READINGS}{$what}{VAL}; } else { return "no such reading: $what"; } } else { $return = "unknown argument $what, choose one of"; foreach my $reading (keys %{$hash->{READINGS}}) { $return .= " $reading:noArg"; } return $return; } } ################################### sub PHILIPS_AUDIO_Set { my ($hash, @a) = @_; my $name = $hash->{NAME}; my $port = $hash->{PORT}; if(not defined($hash->{MODEL})) { return "Please provide the model information as argument."; } return "No Argument given" if(!defined($a[1])); my $what = $a[1]; my $index; # Provide number of selectable presets according to the given attribute my $inetRadioPreset = "inetRadioPreset:"; for ($index = 1; $index < AttrVal($name, "max-device-presets", "24"); $index++) { $inetRadioPreset .= $index . ","; } $inetRadioPreset .= $index . " "; # Provide number of selectable favorites according to the given attribute my $inetRadioFavorite = "inetRadioFavorite:"; for ($index = 1; $index < AttrVal($name, "max-device-favorites", "24"); $index++) { $inetRadioFavorite .= $index . ","; } $inetRadioFavorite .= $index . " "; my $usage; $usage = "Unknown argument $what, choose one of ". "volumeStraight:slider,0,1,64 ". "volume:slider,0,1,100 ". #"volumeUp:noArg ". #"volumeDown:noArg ". "standbyButton:noArg ". "unmute:noArg ". "next:noArg ". "previous:noArg ". "play_pause:noArg ". "stop:noArg ". "shuffle:on,off ". "aux:noArg ". #"input:aux,internetRadio,mediaLibrary,onlineServices ". $inetRadioPreset. $inetRadioFavorite. "statusRequest:noArg ". "getInetRadioPresets:noArg ". "getInetRadioFavorites:noArg ". ((exists($hash->{helper}{PRESETS}))? "inetRadioPresetByName:".($hash->{helper}{PRESETS})." ":""). ((exists($hash->{helper}{FAVORITES}))? "inetRadioFavoriteByName:".($hash->{helper}{FAVORITES})." ":""). #"addToFavourites:noArg ". #"removeFromFavourites:noArg ". "repeat:single,all,off ". #"home:noArg ". "mute:noArg "; Log3 $name, 5, "PHILIPS_AUDIO ($name) - set ".join(" ", @a); if($what eq "standbyButton") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$STANDBY", "",$what, "noArg"); } elsif($what eq "aux") { PHILIPS_AUDIO_SendCommand($hash, "/aux", "",$what, $a[2]); } elsif($what eq "home") { PHILIPS_AUDIO_SendCommand($hash, "/index", "",$what, $a[2]); } elsif($what eq "mediaLibrary") { PHILIPS_AUDIO_SendCommand($hash, "/nav\$02\$01\$001\$0", "",$what, $a[2]); } elsif($what eq "internetRadio") { PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "",$what, $a[2]); } elsif($what eq "onlineServices") { PHILIPS_AUDIO_SendCommand($hash, "/nav\$09\$01\$001\$0", "",$what, $a[2]); } elsif($what eq "shuffle") { if($a[2] eq "on") { PHILIPS_AUDIO_SendCommand($hash, "/MODE\$SHUFFLE_ON", "",$what, $a[2]); } elsif($a[2] eq "off") { PHILIPS_AUDIO_SendCommand($hash, "/MODE\$SHUFFLE_OFF", "",$what, $a[2]); } else { return $usage; } } elsif($what eq "repeat") { if($a[2] eq "single") { PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_SINGLE", "",$what, $a[2]); } elsif($a[2] eq "all") { PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_ALL", "",$what, $a[2]); } elsif($a[2] eq "off") { PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_OFF", "",$what, $a[2]); } else { return $usage; } } elsif($what eq "statusRequest") { PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg"); } elsif($what eq "addToFavourites") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$ADD2FAV", "",$what, "noArg"); } elsif($what eq "removeFromFavourites") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$REMFAV", "",$what, "noArg"); } elsif($what eq "mute") { PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$MUTE", "",$what, "noArg"); } elsif($what eq "unmute") { PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$UNMUTE", "",$what, "noArg"); } elsif($what eq "next") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$NEXT", "",$what, "noArg"); } elsif($what eq "previous") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$PREV", "",$what, "noArg"); } elsif($what eq "play_pause") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$PLAY_PAUSE", "",$what, "noArg"); } elsif($what eq "stop") { PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$STOP", "",$what, "noArg"); } elsif($what eq "inetRadioPreset") { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; $hash->{helper}{inetRadioPreset} = $a[2]; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]); } elsif($what eq "inetRadioPresetByName") { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; my ($presetNumber, $presetName) = split(/:/, $a[2], 2); $hash->{helper}{inetRadioPresetNumber} = $presetNumber; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]); } elsif($what eq "inetRadioFavorite") { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; $hash->{helper}{inetRadioFavorite} = $a[2]; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]); } elsif($what eq "inetRadioFavoriteByName") { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; my ($favoriteNumber, $favoriteName) = split(/:/, $a[2], 2); $hash->{helper}{inetRadioFavoriteNumber} = $favoriteNumber; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]); } elsif($what eq "volumeStraight") { if($a[2] >= 0 and $a[2] <= 64) { $hash->{helper}{targetVolume} = $a[2]; PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$".$a[2], "",$what, $a[2]); } else { return "volumeStraight must be in the range 0...64."; } } elsif($what eq "volume") { if($a[2] >= 0 and $a[2] <= 100) { $hash->{helper}{targetVolume} = PHILIPS_AUDIO_volume_rel2abs($hash, $a[2]); PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$".$a[2], "",$what, $a[2]); } else { return "volumeStraight must be in the range 0...100."; } } elsif($what eq "nowplay") { PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "",$what, "noArg"); } elsif($what eq "getInetRadioPresets") { delete($hash->{helper}{PRESETS}); # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, "noArg"); } elsif($what eq "getInetRadioFavorites") { # Hierarchichal navigation through the contents mandatory $hash->{helper}{cmdStep} = 1; PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, "noArg"); } else { return $usage; } PHILIPS_AUDIO_ResetTimer($hash); return; } ############################# sub PHILIPS_AUDIO_Define { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $name = $hash->{NAME}; if(! @a >= 4) { my $msg = "Wrong syntax: define PHILIPS_AUDIO [] [] "; Log3 $name, 2, $msg; return $msg; } if(defined($a[2])) { $hash->{MODEL} = $a[2]; # Used by 'fheminfo' command for statistics $attr{$name}{"model"} = $hash->{MODEL}; } $hash->{IP_ADDRESS} = $a[3]; $hash->{PORT} = 8889; # if an update interval was given which is greater than zero, use it. if(defined($a[4]) and $a[4] > 0) { $hash->{helper}{OFF_INTERVAL} = $a[4]; # Minimum interval 3 sec if($hash->{helper}{OFF_INTERVAL} < 3) { $hash->{helper}{OFF_INTERVAL} = 3; } } else { $hash->{helper}{OFF_INTERVAL} = 30; } if(defined($a[5]) and $a[5] > 0) { $hash->{helper}{ON_INTERVAL} = $a[5]; # Minimum interval 3 sec if($hash->{helper}{ON_INTERVAL} < 3) { $hash->{helper}{ON_INTERVAL} = 3; } } else { $hash->{helper}{ON_INTERVAL} = $hash->{helper}{OFF_INTERVAL}; } unless(exists($hash->{helper}{AVAILABLE}) and ($hash->{helper}{AVAILABLE} == 0)) { $hash->{helper}{AVAILABLE} = 1; readingsSingleUpdate($hash, "presence", "present", 1); } # start the status update timer $hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED})); PHILIPS_AUDIO_ResetTimer($hash,0); return; } ########################## sub PHILIPS_AUDIO_Attr { my @a = @_; my $hash = $defs{$a[1]}; if($a[0] eq "set" && $a[2] eq "disable") { if($a[3] eq "0") { $hash->{helper}{DISABLED} = 0; PHILIPS_AUDIO_GetStatus($hash, 1); } elsif($a[3] eq "1") { $hash->{helper}{DISABLED} = 1; } } elsif($a[0] eq "del" && $a[2] eq "disable") { $hash->{helper}{DISABLED} = 0; PHILIPS_AUDIO_GetStatus($hash, 1); } # Start/Stop Timer according to new disabled-Value PHILIPS_AUDIO_ResetTimer($hash); return; } ############################# sub PHILIPS_AUDIO_Undefine { my($hash, $name) = @_; # Stop the internal GetStatus-Loop and exit RemoveInternalTimer($hash); return; } ############################################################################################################ # # Begin of helper functions # ############################################################################################################ ############################# # sends a command to the receiver via HTTP sub PHILIPS_AUDIO_SendCommand { my ($hash,$url,$data,$cmd,$arg) = @_; my $name = $hash->{NAME}; my $address = $hash->{IP_ADDRESS}; my $port = $hash->{PORT}; Log3 $name, 5, "PHILIPS_AUDIO ($name) - execute nonblocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data"; HttpUtils_NonblockingGet ({ url => "http://".$address.":".$port."".$url, timeout => AttrVal($name, "request-timeout", 30), noshutdown => 1, data => $data, loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5), hash => $hash, cmd => $cmd, arg => $arg, callback => \&PHILIPS_AUDIO_ParseResponse }); return; } ############################# # parses the receiver response sub PHILIPS_AUDIO_ParseResponse { my ($param, $err, $data ) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; my $cmd = $param->{cmd}; my $arg = $param->{arg}; if(exists($param->{code})) { Log3 $name, 5, "PHILIPS_AUDIO ($name) - received HTTP code ".$param->{code}." for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\""; } #Log3 $name, 5, "Error = $err"; #Log3 $name, 5, "Data = $data"; if($err ne "") { Log3 $name, 5, "PHILIPS_AUDIO ($name) - could not execute command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $err"; if((not exists($hash->{helper}{AVAILABLE})) or (exists($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} == 1)) { Log3 $name, 3, "PHILIPS_AUDIO ($name) - could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress."; readingsSingleUpdate($hash, "presence", "absent", 1); readingsSingleUpdate($hash, "state", "absent", 1); $hash->{STATE} = "absent"; } $hash->{helper}{AVAILABLE} = 0; } elsif($data ne "") { Log3 $name, 5, "PHILIPS_AUDIO ($name) - got response for \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $data"; if (defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 0) { Log3 $name, 3, "PHILIPS_AUDIO ($name) - device $name reappeared"; readingsSingleUpdate($hash, "presence", "present", 1); } $hash->{helper}{AVAILABLE} = 1; readingsBeginUpdate($hash); readingsBulkUpdate($hash, "power", "on"); readingsBulkUpdate($hash, "state","on"); $hash->{STATE} = "on"; if($cmd eq "standbyButton") { if($data =~ /SUCCESS/) { #readingsBulkUpdate($hash, "power", "on"); #readingsBulkUpdate($hash, "state","on"); } } elsif($cmd eq "mute") { if($data =~ /SUCCESS/) { readingsBulkUpdate($hash, "mute", "on"); } } elsif($cmd eq "unmute") { if($data =~ /SUCCESS/) { readingsBulkUpdate($hash, "mute", "off"); } } elsif($cmd eq "removeFromFavourites") { # evtl. for future use } elsif($cmd eq "addToFavourites") { # evtl. for future use } elsif($cmd eq "inetRadioPreset") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "inetRadioPreset", $hash->{helper}{inetRadioPreset}); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Presets PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$001\$0", "","inetRadioPreset", $hash->{helper}{inetRadioPreset}); } elsif($hash->{helper}{cmdStep} == 3) { $hash->{helper}{cmdStep} = 4; # Preset select PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$".sprintf("%03d", $hash->{helper}{inetRadioPreset})."\$1", "","inetRadioPreset", $hash->{helper}{inetRadioPreset}); } } elsif($cmd eq "inetRadioPresetByName") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "inetRadioPresetByName", $hash->{helper}{inetRadioPresetNumber}); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Presets PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$001\$0", "","inetRadioPresetByName", $hash->{helper}{inetRadioPresetNumber}); } elsif($hash->{helper}{cmdStep} == 3) { $hash->{helper}{cmdStep} = 4; # Preset select PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$". sprintf("%03d", $hash->{helper}{inetRadioPresetNumber}) . "\$1", "", "inetRadioPresetByName", $hash->{helper}{inetRadioPresetNumber}); } } elsif($cmd eq "inetRadioFavorite") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio favorite PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "inetRadioFavorite", $hash->{helper}{inetRadioFavorite}); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Favorite Presets PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$002\$0", "","inetRadioFavorite", $hash->{helper}{inetRadioFavorite}); } elsif($hash->{helper}{cmdStep} == 3) { $hash->{helper}{cmdStep} = 4; # Favorite Preset select PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$".sprintf("%03d", $hash->{helper}{inetRadioFavorite})."\$1", "","inetRadioFavorite", $hash->{helper}{inetRadioFavorite}); } } elsif($cmd eq "inetRadioFavoriteByName") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "inetRadioFavoriteByName", $hash->{helper}{inetRadioFavoriteNumber}); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Favorites PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$002\$0", "","inetRadioFavoriteByName", $hash->{helper}{inetRadioFavoriteNumber}); } elsif($hash->{helper}{cmdStep} == 3) { $hash->{helper}{cmdStep} = 4; PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$". sprintf("%03d", $hash->{helper}{inetRadioFavoriteNumber}) . "\$1", "", "inetRadioFavoriteByName", $hash->{helper}{inetRadioFavoriteNumber}); } } elsif($cmd eq "play_pause") { if($data =~ /SUCCESS/) { #readingsBulkUpdate($hash, "play_pause", "on"); #readingsBulkUpdate($hash, "stop", "off"); } } elsif($cmd eq "stop") { if($data =~ /STOP/) { readingsBulkUpdate($hash, "playing", "no"); } } elsif($cmd eq "volume" or $cmd eq "volumeStraight") { if($data =~ /SUCCESS/) { readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume}); my $targetVolume = $hash->{helper}{targetVolume}; readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $targetVolume)); } } elsif($cmd eq "nowplay") { if($data =~ /'title':'\\'(.+)\\''/) { readingsBulkUpdate($hash, "title", PHILIPS_AUDIO_STREAMIUMNP2txt($1)); } else { readingsBulkUpdate($hash, "title", ""); } if($data =~ /'title':'(.+)'/) { readingsBulkUpdate($hash, "title", PHILIPS_AUDIO_STREAMIUMNP2txt($1)); } else { readingsBulkUpdate($hash, "title", ""); } if($data =~ /'subTitle':'(.+)'/) { readingsBulkUpdate($hash, "subtitle", $1); } else { readingsBulkUpdate($hash, "subtitle", ""); } if($data =~ /'albumArt':'(.+)'/) { readingsBulkUpdate($hash, "albumArt", $1); } else { readingsBulkUpdate($hash, "albumArt", ""); } if($data =~ /'volume':(.+),/) { readingsBulkUpdate($hash, "volumeStraight", $1); readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $1)); } else { readingsBulkUpdate($hash, "volumeStraight", "0"); readingsBulkUpdate($hash, "volume", "0"); } if($data =~ /'elapsetime':(.+),/) { readingsBulkUpdate($hash, "elapseTime", strftime("\%H:\%M:\%S", gmtime($1))); } else { readingsBulkUpdate($hash, "elapseTime", ""); } if($data =~ /'totaltime':(.+),/) { # Playing radio delivers that total time if($1 eq "65535") { readingsBulkUpdate($hash, "totalTime", "infinite"); } else { readingsBulkUpdate($hash, "totalTime", strftime("\%H:\%M:\%S", gmtime($1))); } } else { readingsBulkUpdate($hash, "totalTime", ""); } if($data =~ /'muteStatus':(.+),/) { if($1 == 1) { readingsBulkUpdate($hash, "mute", "on"); } else { readingsBulkUpdate($hash, "mute", "off"); } } # typo in the (buggy) Streamium firmware... if($data =~ /'playStaus':(.+),/) { if($1 == 1) { readingsBulkUpdate($hash, "playing", "yes"); } else { readingsBulkUpdate($hash, "playing", "no"); } } else { readingsBulkUpdate($hash, "playing", "no"); } } # Eventual future UPNP implementation. Requests IO::Socket::Multicast non-standard module. elsif ($cmd eq "getModel") { if($data =~ /(.+)<\/friendlyName>/) { $hash->{FRIENDLY_NAME} = $1; } if($data =~ /(.+)<\/UDN>/) { $hash->{UNIQUE_DEVICE_NAME} = uc($1); } my $modelName = ""; my $modelNumber = ""; if($data =~ /(.+)<\/modelName>/) { $modelName = $1; } if($data =~ /(.+)<\/modelNumber>/) { $modelNumber = $1; } # Combine both strings if(($modelName ne "") and ($modelNumber ne "")) { $hash->{MODEL} = $modelName . $modelNumber; } if($data =~ /(.+)<\/serialNumber>/) { $hash->{SERIAL_NUMBER} = uc($1); } if($data =~ /(.+)<\/modelDescription>/) { $hash->{MODEL_DESCRIPTION} = $1; } # Replace \n, \r, \t from the string for XML parsing # replace \n by "" $data =~ s/\n//g; # replace \t by "" $data =~ s/\t//g; # replace \r by "" $data =~ s/\r//g; if($data =~ /(.+?)<\/iconList>/) { my $address = $hash->{IP_ADDRESS}; my $i = 1; while ($data =~ /(.+?)<\/url>/g) { $hash->{"NP_ICON_$i"} = "http://".$address.":".$arg."/".$1; $i++; } } } elsif ($cmd eq "getInetRadioPresets") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "","getInetRadioPresets", "noArg"); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Presets PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$001\$0", "","getInetRadioPresets", "noArg"); } elsif($hash->{helper}{cmdStep} == 3) { my $listedItems; # Visible Items in the display. Max 8 my $nextreqURL; my $i; my $presetID = 0; my $presetName; # Parse first 8 Presets if($data =~ /Error<\/title>/) { # In case on presets defined the player returns an Error # Do nothing $hash->{helper}{TOTALINETRADIOPRESETS} = 0; readingsBulkUpdate($hash, "totalInetRadioPresets", "0"); } else { if ($data =~ /'nextrequrl':'(.+?)',/) { $nextreqURL = $1; #Log3 $name, 5, "NextreqURL: $nextreqURL"; } if ($data =~ /'totalListCount':(.+),/) { $hash->{helper}{TOTALINETRADIOPRESETS} = $1; readingsBulkUpdate($hash, "totalInetRadioPresets", $1); #Log3 $name, 5, "ListedItems: $listedItems"; } #if ($data =~ /'totalitems':(.+),/) #{ # $listedItems = $1; #} $data =~ s/\R//g; # Remove new lines for(;;) { if($data =~ /{'title':'(.+?)',/g) { $presetName = $1; #Log3 $name, 5, "PresetName: $presetName"; if($data =~ /'id':(.+?),/g) { $presetID = $1; #Log3 $name, 5, "PresetIDLoop: $presetID"; } if ($presetID ne "" and $presetName ne "") { readingsBulkUpdate($hash, sprintf("inetRadioPreset%02d", $presetID), $presetName); } } else { last; } } #Log3 $name, 5, "PresetIDNachLoop: $presetID"; if($presetID < ($hash->{helper}{TOTALINETRADIOPRESETS})) # Maximum listed items = 8. Get the next items by sending the nextreqURL { PHILIPS_AUDIO_SendCommand($hash, $nextreqURL, "","getInetRadioPresets", "noArg"); } else { $hash->{helper}{cmdStep} = 4; if (exists($hash->{helper}{PRESETS})) { $hash->{helper}{PRESETS} = ""; # Reset the pull-down menue } PHILIPS_AUDIO_updatePresets($hash); #my $debug = $hash->{helper}{PRESETS}; #Log3 $name, 5, "Presets: $debug"; } } } } elsif ($cmd eq "getInetRadioFavorites") { # This command must be processed hierarchicaly through the navigation path if($hash->{helper}{cmdStep} == 1) { $hash->{helper}{cmdStep} = 2; # Internet radio PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "","getInetRadioFavorites", "noArg"); } elsif($hash->{helper}{cmdStep} == 2) { $hash->{helper}{cmdStep} = 3; # Favorites PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$002\$0", "","getInetRadioFavorites", "noArg"); } elsif($hash->{helper}{cmdStep} == 3) { if($data =~ /<title>Error<\/title>/) { # In case on presets defined the player returns an Error # Do nothing $hash->{helper}{TOTALINETRADIOFAVORITES} = 0; readingsBulkUpdate($hash, "totalInetRadioFavorites", "0"); } else { my $listedItems; # Visible Items in the display. Max 8 my $nextreqURL; my $i; my $favoriteID = 0; my $favoriteName; # Parse first 8 Presets if ($data =~ /'nextrequrl':'(.+?)',/) { $nextreqURL = $1; #Log3 $name, 5, "NextreqURL: $nextreqURL"; } if ($data =~ /'totalListCount':(.+),/) { $hash->{helper}{TOTALINETRADIOFAVORITES} = $1; readingsBulkUpdate($hash, "totalInetRadioFavorites", $1); #Log3 $name, 5, "ListedItems: $listedItems"; } #if ($data =~ /'totalitems':(.+),/) #{ # $listedItems = $1; #} $data =~ s/\R//g; # Remove new lines for(;;) { if($data =~ /{'title':'(.+?)',/g) { $favoriteName = $1; #Log3 $name, 5, "FavoriteName: $favoriteName"; if($data =~ /'id':(.+?),/g) { $favoriteID = $1; #Log3 $name, 5, "FavoriteIDLoop: $favoriteID"; } if ($favoriteID ne "" and $favoriteName ne "") { readingsBulkUpdate($hash, sprintf("inetRadioFavorite%02d", $favoriteID), $favoriteName); } } else { last; } } #Log3 $name, 5, "FavoriteIDNachLoop: $favoriteID"; if($favoriteID < ($hash->{helper}{TOTALINETRADIOFAVORITES})) # Maximum listed items = 8. Get the next items by sending the nextreqURL { PHILIPS_AUDIO_SendCommand($hash, $nextreqURL, "","getInetRadioFavorites", "noArg"); } else { $hash->{helper}{cmdStep} = 4; if (exists($hash->{helper}{FAVORITES})) { $hash->{helper}{FAVORITES} = ""; # Reset the pull-down menue } PHILIPS_AUDIO_updateFavorites($hash); #my $debug = $hash->{helper}{FAVORITES}; #Log3 $name, 5, "Favorites: $debug"; } } } } readingsEndUpdate($hash, 1); return; } } ############################# # converts straight volume in percentage volume (volumestraightmin .. volumestraightmax => 0 .. 100%) sub PHILIPS_AUDIO_volume_rel2abs { my ($hash, $percentage) = @_; return int(($percentage * 64 / 100 )); } ############################# # converts relative volume to "straight" volume (0 .. 100% => volumestraightmin .. volumestraightmax) sub PHILIPS_AUDIO_volume_abs2rel { my ($hash, $absolute) = @_; return int(int($absolute * 100) / int(64)); } ############################# # Restarts the internal status request timer according to the given interval or current receiver state sub PHILIPS_AUDIO_ResetTimer { my ($hash, $interval) = @_; RemoveInternalTimer($hash); if($hash->{helper}{DISABLED} == 0) { if(defined($interval)) { InternalTimer(gettimeofday()+$interval, "PHILIPS_AUDIO_GetStatus", $hash, 0); } elsif((exists($hash->{READINGS}{presence}{VAL}) and $hash->{READINGS}{presence}{VAL} eq "present") and (exists($hash->{READINGS}{power}{VAL}) and $hash->{READINGS}{power}{VAL} eq "on")) { InternalTimer(gettimeofday() + $hash->{helper}{ON_INTERVAL}, "PHILIPS_AUDIO_GetStatus", $hash, 0); } else { InternalTimer(gettimeofday() + $hash->{helper}{OFF_INTERVAL}, "PHILIPS_AUDIO_GetStatus", $hash, 0); } } return; } ############################# # convert all HTML entities into UTF-8 equivalent sub PHILIPS_AUDIO_STREAMIUMNP2txt { my ($string) = @_; $string =~ s/\\'//g; return $string; } ############################# # Updates the pull-down menue sub PHILIPS_AUDIO_updatePresets { my ($hash) = @_; my $name = $hash->{NAME}; if((not defined($hash->{helper}{PRESETS}) or length($hash->{helper}{PRESETS}) == 0)) { my $presetName; for(my $i = 1; $i < (AttrVal($name, "max-device-presets", "24") + 1); $i++) { if(exists($hash->{READINGS}{sprintf("inetRadioPreset%02d", $i)})) { if($i != 1) { $presetName = ","; } $presetName .= sprintf("%02d", $i) . ":"; $presetName .= $hash->{READINGS}{sprintf("inetRadioPreset%02d", $i)}{VAL}; $presetName =~ s/ /_/g; # Replace blank by underscore $hash->{helper}{PRESETS} .= $presetName; } else { last; } } } else { $hash->{helper}{PRESETS} = ""; } return; } ############################# # Updates the pull-down menue sub PHILIPS_AUDIO_updateFavorites { my ($hash) = @_; my $name = $hash->{NAME}; if((not defined($hash->{helper}{FAVORITES}) or length($hash->{helper}{FAVORITES}) == 0)) { my $favoriteName; for(my $i = 1; $i < (AttrVal($name, "max-device-favorites", "24") + 1); $i++) { if(exists($hash->{READINGS}{sprintf("inetRadioFavorite%02d", $i)})) { if($i != 1) { $favoriteName = ","; } $favoriteName .= sprintf("%02d", $i) . ":"; $favoriteName .= $hash->{READINGS}{sprintf("inetRadioFavorite%02d" , $i)}{VAL}; $favoriteName =~ s/ /_/g; # Replace blank by underscore $hash->{helper}{FAVORITES} .= $favoriteName; } else { last; } } } } 1; =pod =begin html <a name="PHILIPS_AUDIO"></a> <h3>PHILIPS_AUDIO</h3> <ul> <a name="PHILIPS_AUDIOdefine"></a> <b>Define</b> <br><br> <ul> <code> define <name> PHILIPS_AUDIO <device model> <ip-address> [<status_interval>]<br><br> define <name> PHILIPS_AUDIO <device model> [<off_status_interval>] [<on_status_interval>] </code> <br><br> This module controls a Philips Audio Player e.g. MCi, Streamium or Fidelio and (potentially) any other device including a navigation server.<br> To check, open the following URL in the browser: http://[ip # of your device]:8889/index <br><br> Currently implemented features: <br><br> <ul> <li>Power on/off</li> <li>Internet Radio Preset Selection</li> <li>Input selection</li> <li>Volume +/-</li> <li>Mute on/off</li> <li>...</li> </ul> <br> Defining a PHILIPS_AUDIO device will schedule an internal task (interval can be set with optional parameters <off_status_interval> and <on_status_interval> in seconds.<br> <off_status_interval> is a parameter used in case the device is powered off or not available.<br> <on_status_interval> is a parameter used in case the device is powered on.<br> If both parameters are unset, a default value 30 (seconds) for both is used.<br> If <off_status_interval> is set only the same value is used for both parameters.<br> Due to a relatively low-performance of the devices the minimum interval is set to 3 seconds. <br> The internal task periodically reads the status of the Network Player (power state, volume and mute status etc.) and triggers notify/filelog commands. <br><br> Example:<br><br> <ul><br> Add the following code into the <b>fhem.cfg</b> configuration file and restart fhem:<br><br> <code> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15<br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset<br><br> # With custom status interval of 60 seconds<br> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60</b><br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset<br><br> # With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60 10</b><br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset<br><br> </code> </ul> </ul> <br><br> <a name="PHILIPS_AUDIOset"></a> <b>Set</b> <ul> <code> set <name> <command> [<parameter>] </code><br><br> Currently, the following commands are defined.<br> <i>Note: Commands and parameters are case sensitive.</i><br> <ul><br><br> <u>Available commands:</u><br><br> <li><b>aux</b>  -   Switches to the AUX input (MP3 Link or similar).</li> <li><b>getInetRadioFavorites</b>   -   Reads the favorites. (May take some seconds...).</li> <li><b>getInetRadioPresets</b>   -   Reads the presets. (May take some seconds...).</li> <li><b>inetRadioFavorite</b> [1..24]   -   Selects an internet radio favorite (May take some seconds...).</li> <li><b>inetRadioPreset</b> [1..24]   -   Selects an internet radio preset (May take some seconds...).</li> <li><b>inetRadioFavoriteByName</b> [name]   -   Selects an internet radio favorite by name. (getInetRadioFavorites must be run previously for the command to become available.) (May take some seconds...).</li> <li><b>inetRadioPresetByName</b> [name]   -   Selects an internet radio preset by name. (getInetRadioPresets must be run previously for the command to become available.) (May take some seconds...).</li> <li><b>mute</b>  -   Mutes the device.</li> <li><b>unmute</b>  -   Unmutes the device.</li> <li><b>next</b>   -   Selects the next song, preset etc.</li> <li><b>play_pause</b>   -   Toggles PLAY/PAUSE.</li> <li><b>previous</b>   -   Selects the previous song, preset etc.</li> <li><b>repeat [single|all|off]</b>   -   Sets the repeat mode.</li> <li><b>shuffle [on|off]</b>   -   Sets the shuffle mode.</li> <li><b>standbyButton</b>   -   Toggles between standby and power on.</li> <li><b>statusRequest</b>   -   Updates the readings.</li> <li><b>stop</b>   -   Stops the player.</li> <li><b>volume</b>   -   Sets the relative volume 0...100%.</li> <li><b>volumeStraight</b>   -   Sets the absolute volume 0...64.</li> </ul><br><br> A typical example is powering the device remotely and tuning the favourite radio station:<br><br> Add the following code into the <b>fhem.cfg</b> configuration file:<br><br><br> <ul> <code> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 30 5<br> attr PHAUDIO_player webCmd volume:mute:inetRadioPreset </code> </ul><br><br> Add the following code into the <b>99_MyUtils.pm</b> file:<br><br> <ul> <code> sub startMyFavouriteRadioStation()<br> {<br>   fhem "set PHAUDIO_player inetRadioPreset 1";<br>   sleep 1;<br>   fhem "set PHAUDIO_player volume 30";<br> } </code> </ul> <br><br> It's a good idea to insert a 'sleep' instruction between each fhem commands due to internal processing time of the player. Be patient when executing the commands...<br><br> Now the function can be called by typing the following line in the FHEM command line or by the notify-definitions:<br><br> <ul> <code> {startMyFavouriteRadioStation()}<br><br> </code> </ul> </ul> <a name="PHILIPS_AUDIOget"></a> <b>Get</b> <ul> <code> get <name> <reading> </code> <br><br> Currently, the 'get' command returns reading values only. For a specific list of possible values, see section <b>"Generated Readings"</b>.<br><br> </ul> <a name="PHILIPS_AUDIOattr"></a> <b>Attributes</b><br><br> <ul> <ul> <li><b><a href="#do_not_notify">do_not_notify</a></b></li> <li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li> <li><b><a name="request-timeout">request-timeout</a></b></li> <br>Optional attribute change the response timeout in seconds for all queries to the receiver. <br>Possible values: 1...5 seconds. Default value is 4 seconds.<br><br> <li><b><a name="max-device-presets">max-device-presets</a></b></li> <br>Optional attribute defining maximum number of available preset slots in device's memory. Default value 24.<br><br> <li><b><a name="max-device-favorites">max-device-favorites</a></b></li> <br>Optional attribute defining maximum number of favorite slots in device's memory. Default value 24.<br><br> <li><b><a name="disable">disable</a></b></li> <br>Optional attribute to disable the internal cyclic status update of the receiver. Manual status updates via statusRequest command is still possible. <br>Possible values: 0 → perform cyclic status update, 1 → don't perform cyclic status updates.<br><br><br> </ul> </ul> <b>Readings</b><br><br> <ul> <ul> <li><b>albumArt</b> - Link to current album art or radio station.</li> <li><b>elapseTime</b> - Elapse time of the played audio.</li> <li><b>inetRadioFavorite[value]</b> - Name of the stored favorite.</li> <li><b>inetRadioPreset[value]</b> - Name of the stored preset.</li> <li><b>mute</b> - Reports the mute status (on|off).</li> <li><b>playing</b> - Reports the current playier status (yes|no).</li> <li><b>power</b> - Reports the current power status (on|absent).</li> <li><b>presence</b> - Reports the current presence (present|absent).</li> <li><b>state</b> - Reports the current state status (on|absent).</li> <li><b>subtitle</b> - Reports the current subtitle of played audio.</li> <li><b>totalInetRadioFavorites</b> - Number of stored favorites.</li> <li><b>totalInetRadioPresets</b> - Number of stored presets.</li> <li><b>title</b> - Reports the current title of played audio.</li> <li><b>totalTime</b> - Reports the total time of the played audio.</li> <li><b>volume</b> - Reports current relative volume (0..100).</li> <li><b>volumeStraight</b> - Reports current absolute volume (0..64).</li> </ul> </ul><br> <b>Implementer's note</b><br><br> <ul> Trivial: In order to use that module the network player must be connected to the Ethernet.<br> There's no possibility to read back the current power on/standby status from the device. This fuctionality is missing in the server application.<br> </ul><br> </ul> =end html =begin html_DE <a name="PHILIPS_AUDIO"></a> <h3>PHILIPS_AUDIO</h3> <ul> <a name="PHILIPS_AUDIOdefine"></a> <b>Define</b><br><br> <ul> <code> define <name> PHILIPS_AUDIO <device model> <ip-address> [<status_interval>]<br><br> define <name> PHILIPS_AUDIO <device model> [<off_status_interval>] [<on_status_interval>] </code> <br><br> Mit Hilfe dieses Moduls lassen sich Philips Audio Netzwerk Player wie z.B. MCi, Streamium oder Fidelio via Ethernet steuern.<br> Theoretisch sollten alle Geräte, die über einer implementierten HTTP Server am Port 8889 haben (http://[ip Nummer des Gerätes]:8889/index), bedient werden können.<br> <br> Die aktuelle Implementierung ermöglicht u.a. den folgenden Funktionsumfang:<br><br> <ul> <li>Power on/off</li> <li>Internet Radio Preset Auswahl</li> <li>Input Auswahl</li> <li>Volume +/-</li> <li>Mute on/off</li> <li>...</li> </ul> <br> Eine PHILIPS_AUDIO Definition initiiert einen internen Task, der von FHEM zyklisch abgearbeitet wird.<br> Das Intervall (in Sekunden) kann für die Zustände <on_status_interval> und <off_status_interval> optional gesetzt werden.<br> <off_status_interval> steht für das Intervall, wenn das Gerät ausgeschaltet/abwesend ist.<br> <on_status_interval> steht für das Intervall, wenn das Gerät eingeschaltet/verfügbar ist.<br> Wenn keine Parameter angegeben wurden, wird ein Default-Wert von 30 Sekunden für beide gesetzt.<br> Wenn nur <off_status_interval> gesetzt wird, gilt dieser Wert für beide Zustände (eingeschaltet/ausgeschaltet).<br> Der Task liest zyklisch grundlegende Parameter vom Player und triggert notify/filelog Befehle.<br> Aufgrund der recht schwachen Rechenleistung der Player wurde das minimale Intervall auf 3 Sekunden beschränkt.<br><br> Beispiel:<br><br> <ul><br> Definition in der <b>fhem.cfg</b> Konfigurationsdatei:<br><br> <code> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15<br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset<br><br> # 60 Sekunden Intervall<br> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60</b><br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset<br><br> # 60 Sekunden Intervall für "off" und 10 Sekunden für "on"<br> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60 10</b><br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset </code> </ul> </ul><br><br> <a name="PHILIPS_AUDIOset"></a> <b>Set</b> <ul> <code> set <name> <command> [<parameter>] </code> <br><br> Aktuell sind folgende Befehle implementiert:<br> <i>Bemerkung: Bitte bei den Befehlen und Parametern die Groß- und Kleinschreibung beachten.</i><br> <ul><br><br> <li><b>aux</b>  -   Schaltet auf den AUX Eingang um (MP3 Link oder ähnlich.).</li> <li><b>getInetRadioFavorites</b>   -   Liest die Favoriten. (Kann einige Sekunden dauern...).</li> <li><b>getInetRadioPresets</b>   -   Liest die Presets. (Kann einige Sekunden dauern...).</li> <li><b>inetRadioFavorite</b> [1..24]   -   Wählt den Internetradio-Lieblingssender (Das Umschalten kann einige Sekunden dauern...).</li> <li><b>inetRadioPreset</b> [1..24]   -   Wählt die Internetradio Voreinstellung (Das Umschalten kann einige Sekunden dauern...).</li> <li><b>inetRadioFavoriteByName</b> [name]   -   Wählt einen Internetradio Favoriten mit Hilfe seines Names. (getInetRadioFavorites muss zuvor ausgeführt werden, damit der Befehl verfügbar wird. (Kann einige Sekunden dauern...).</li> <li><b>inetRadioPresetByName</b> [name]   -   Wählt eine Internetradio Voreinstellung mit Hilfe ihres Names. (getInetRadioPresets muss zuvor ausgeführt werden, damit der Befehl verfügbar wird. (Kann einige Sekunden dauern...).</li> <li><b>mute</b>  -   Stummschaltung des Players.</li> <li><b>unmute</b>  -   Deaktivierung der Stummschaltung.</li> <li><b>next</b>   -   Wählt den nächten Titel, Voreinstellung etc.</li> <li><b>play_pause</b>   -   Schaltet um zwischen PLAY um PAUSE.</li> <li><b>previous</b>   -   Wählt den vorherigen Titel, Voreinstellung etc.</li> <li><b>repeat [single|all|off]</b>   -   Bestimmt den Wiederholungsmodus.</li> <li><b>shuffle [on|off]</b>   -   Bestimmt den Zufallswiedergabemodus.</li> <li><b>standbyButton</b>   -   Schaltet um zwischen Standby und Power on.</li> <li><b>statusRequest</b>   -   Readings Update.</li> <li><b>stop</b>   -   Stoppt den Player.</li> <li><b>volume</b>   -   Setzt die relative Lautstärke 0...100%.</li> <li><b>volumeStraight</b>   -   Setzt die absolute Lautstärke 0...64.</li> </ul><br><br> Ein typisches Beispiel ist das Einschalten des Gerätes und das Umschalten auf den Lieblingsradiosender:<br><br> Beispieldefinition in der <b>fhem.cfg</b> Konfigurationsdatei:<br><br><br> <ul> <code> define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 30 5<br> attr PHAUDIO_player webCmd input:volume:mute:inetRadioPreset </code> </ul><br><br> Folgender Code kann anschließend in die Datei <b>99_MyUtils.pm</b> eingebunden werden:<br><br> <ul> <code> sub startMyFavouriteRadioStation()<br> {<br>   fhem "set PHAUDIO_player inetRadioPreset 1";<br>   sleep 1;<br>   fhem "set PHAUDIO_player volume 30";<br>} </code> </ul><br><br> <i>Bemerkung: Aufgrund der relativ langsamen Befehlsverarbeitung im Player im Vergleich zur asynchronen Ethernet-Kommunikation, kann es vorkommen, dass veraltete Statusinformationen zurückgesendet werden.<br> Aus diesem Grund wird empfohlen, während der Automatisierung zwischen den 'set' und 'get' Befehlen ein Delay einzubauen.</i><br><br> Die Funktion kann jetzt in der FHEM Befehlszeile eingegeben oder in die Notify-Definitionen eingebunden werden.<br><br> <ul> <code> {startMyFavouriteRadioStation()}<br><br> </code> </ul> </ul> <a name="PHILIPS_AUDIOget"></a> <b>Get</b> <code> get <name> <reading> </code><br><br> Aktuell liefert der Befehl 'get' ausschließlich Reading-Werte (s. Abschnitt <b>"Readings"</b>).<br><br> </ul> <a name="PHILIPS_AUDIOattr"></a> <ul> <b>Attribute</b><br><br> <ul> <ul> <li><b><a href="#do_not_notify">do_not_notify</a></b></li> <li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li><br> <li><b><a name="request-timeout">request-timeout</a></b></li><br> Optionales Attribut, um das HTTP response timeout zu beeinflußen.<br> Mögliche Werte: 1...5 Sekunden. Default Wert ist 4 Sekunden.<br><br> <li><b><a name="max-device-presets">max-device-presets</a></b></li> <br>Optionales Attribut zur Bestimmung der max. Anzahl von verfügbaren Preset-Speicherplätzen des Players. Default-Wert 24.<br><br> <li><b><a name="max-device-favorites">max-device-favorites</a></b></li> <br>Optionales Attribut zur Bestimmung der max. Anzahl von verfügbaren Favorite-Speicherplätzen des Players. Default-Wert 24.<br><br> <li><b><a name="disable">disable</a></b></li><br> Optionales Attribut zum Deaktivieren des internen zyklischen Timers zum Aktualisieren des NP-Status. Manuelles Update ist nach wie vor möglich.<br> Mögliche Werte: 0 → Zyklisches Update aktiv., 1 → Zyklisches Update inaktiv.<br><br><br> </ul> </ul> <b>Readings</b><br><br> <ul> <ul> <li><b>albumArt</b> - Link zum aktuellen Album art oder Radiostation.</li> <li><b>elapseTime</b> - Aktuelle Zeit des abgespielten Audiostückes.</li> <li><b>inetRadioFavorite[Wert]</b> - Name des/der gespeicherten Favoriten.</li> <li><b>inetRadioPreset[Wert]</b> - Name des/der gespeicherten Presets.</li> <li><b>mute</b> - Abfrage des Stummschaltungstatus (on|off).</li> <li><b>playing</b> - Abfrage des aktuelle Playierstatus (yes|no).</li> <li><b>power</b> - Abfrage des aktuellen Gerätezustands (on|absent).</li> <li><b>presence</b> - Abfrage der Geräteanwesenheit (present|absent).</li> <li><b>state</b> - Abfrage des aktuellen 'state'-Status (on|absent).</li> <li><b>subtitle</b> - Untertiltel des abgespielten Audiostückes.</li> <li><b>title</b> - Titel des abgespielten Audiostückes.</li> <li><b>totalInetRadioFavorites</b> - Anzahl der gespeicherten Favoriten.</li> <li><b>totalInetRadioPresets</b> - Anzahl der gespeicherten Presets.</li> <li><b>totalTime</b> Gesamtspieldauer des Audiostückes.</li> <li><b>volume</b> - Aktuelle relative Lautstärke (0..100).</li> <li><b>volumeStraight</b> - Aktuelle absolute Lautstärke (0..64).</li> </ul> </ul><br> <b>Bemerkung des Entwicklers</b><br><br> <ul> Trivial: Um das Gerät fernbedienen zu können, muss es an das Ethernet-Netzwerk angeschlossen und erreichbar sein.<br> Es gibt keine Möglichkeit, den Zustand Power-on/Standby des Gerätes abzufragen. Diese Limitierung liegt auf Seiten des Gerätes.<br> </ul><br> </ul> =end html_DE =cut