# $Id$ ############################################################################## # # 71_YAMAHA_BD.pm # An FHEM Perl module for controlling Yamaha Blu-Ray players # via network connection. As the interface is standardized # within all Yamaha Blue-Ray players, this module should work # with any player which has an ethernet or wlan connection. # # Copyright by Markus Bloch # e-mail: Notausstieg0309@googlemail.com # # 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); use HttpUtils; sub YAMAHA_BD_Get($@); sub YAMAHA_BD_Define($$); sub YAMAHA_BD_GetStatus($;$); sub YAMAHA_BD_Attr(@); sub YAMAHA_BD_ResetTimer($;$); sub YAMAHA_BD_Undefine($$); ################################### sub YAMAHA_BD_Initialize($) { my ($hash) = @_; $hash->{GetFn} = "YAMAHA_BD_Get"; $hash->{SetFn} = "YAMAHA_BD_Set"; $hash->{DefFn} = "YAMAHA_BD_Define"; $hash->{AttrFn} = "YAMAHA_BD_Attr"; $hash->{UndefFn} = "YAMAHA_BD_Undefine"; $hash->{AttrList} = "do_not_notify:0,1 disable:0,1 request-timeout:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 model ". $readingFnAttributes; $data{RC_layout}{YAMAHA_BluRay} = "YAMAHA_BD_RClayout"; $data{RC_makenotify}{YAMAHA_BD} = "YAMAHA_BD_RCmakenotify"; } ################################### sub YAMAHA_BD_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $name = $hash->{NAME}; if(! @a >= 3) { my $msg = "wrong syntax: define YAMAHA_BD [] []"; Log 2, $msg; return $msg; } my $address = $a[2]; $hash->{helper}{ADDRESS} = $address; # if an update interval was given which is greater than zero, use it. if(defined($a[3]) and $a[3] > 0) { $hash->{helper}{OFF_INTERVAL}=$a[3]; } else { $hash->{helper}{OFF_INTERVAL}=30; } # if a second update interval is given, use this as ON_INTERVAL, otherwise use OFF_INTERVAL instead. if(defined($a[4]) and $a[4] > 0) { $hash->{helper}{ON_INTERVAL}=$a[4]; } else { $hash->{helper}{ON_INTERVAL}=$hash->{helper}{OFF_INTERVAL}; } $hash->{helper}{CMD_QUEUE} = (); delete($hash->{helper}{HTTP_CONNECTION}) if(exists($hash->{helper}{HTTP_CONNECTION})); # start the status update timer $hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED})); YAMAHA_BD_ResetTimer($hash, 2); return undef; } ################################### sub YAMAHA_BD_Get($@) { my ($hash, @a) = @_; my $what; my $return; return "argument is missing" if(int(@a) != 2); $what = $a[1]; if(exists($hash->{READINGS}{$what})) { YAMAHA_BD_GetStatus($hash, 1); 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 YAMAHA_BD_Set($@) { my ($hash, @a) = @_; my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; my $result = ""; return "No Argument given" if(!defined($a[1])); my $what = $a[1]; my $usage = "Unknown argument $what, choose one of on:noArg ". "off:noArg ". "statusRequest:noArg ". "tray:open,close ". "remoteControl:power,eject,up,down,left,right,return,enter,OSDonScreen,OSDstatus,topMenu,popupMenu,red,green,blue,yellow,0,1,2,3,4,5,6,7,8,9,setup,home,clear,program,search,repeat,repeat-AB,subtitle,angle,audio,pictureInPicture,secondVideo,secondAudio".(exists($hash->{MODEL}) && $hash->{MODEL} eq "BD-S673" ? ",netflix" : "")." ". "fast:forward,reverse ". "slow:forward,reverse ". "skip:forward,reverse ". "play:noArg pause:noArg ". "stop:noArg ". "trickPlay:normal,repeatChapter,repeatTitle,repeatFolder,repeat-AB,randomChapter,randomTitle,randomAll,shuffleChapter,shuffleTitle,shuffleAll,setApoint"; if($what eq "on") { YAMAHA_BD_SendCommand($hash, "On","on",undef); } elsif($what eq "off") { YAMAHA_BD_SendCommand($hash, "Network Standby","off",undef); } elsif($what eq "remoteControl") { if($a[2] eq "up") { YAMAHA_BD_SendCommand($hash, "Up","remoteControl","up"); } elsif($a[2] eq "down") { YAMAHA_BD_SendCommand($hash, "Down","remoteControl","down"); } elsif($a[2] eq "left") { YAMAHA_BD_SendCommand($hash, "Left","remoteControl","left"); } elsif($a[2] eq "right") { YAMAHA_BD_SendCommand($hash, "Right","remoteControl","right"); } elsif($a[2] eq "enter") { YAMAHA_BD_SendCommand($hash, "Enter","remoteControl","enter"); } elsif($a[2] eq "return") { YAMAHA_BD_SendCommand($hash, "Return","remoteControl","return"); } elsif($a[2] eq "OSDonScreen") { YAMAHA_BD_SendCommand($hash,"OnScreen","remoteControl","OSDonScreen"); } elsif($a[2] eq "OSDstatus") { YAMAHA_BD_SendCommand($hash,"Status","remoteControl","OSDstatus"); } elsif($a[2] eq "topMenu") { YAMAHA_BD_SendCommand($hash,"TOP MENU","remoteControl","topMenu"); } elsif($a[2] eq "popupMenu") { YAMAHA_BD_SendCommand($hash,"POPUP MENU","remoteControl","popupMenu"); } elsif($a[2] eq "red") { YAMAHA_BD_SendCommand($hash,"RED","remoteControl","red"); } elsif($a[2] eq "green") { YAMAHA_BD_SendCommand($hash,"GREEN","remoteControl","green"); } elsif($a[2] eq "blue") { YAMAHA_BD_SendCommand($hash,"BLUE","remoteControl","blue"); } elsif($a[2] eq "yellow") { YAMAHA_BD_SendCommand($hash,"YELLOW","remoteControl","yellow"); } elsif($a[2] eq "0") { YAMAHA_BD_SendCommand($hash,"0","remoteControl","0"); } elsif($a[2] eq "1") { YAMAHA_BD_SendCommand($hash,"1","remoteControl","1"); } elsif($a[2] eq "2") { YAMAHA_BD_SendCommand($hash,"2","remoteControl","2"); } elsif($a[2] eq "3") { YAMAHA_BD_SendCommand($hash,"3","remoteControl","3"); } elsif($a[2] eq "4") { YAMAHA_BD_SendCommand($hash,"4","remoteControl","4"); } elsif($a[2] eq "5") { YAMAHA_BD_SendCommand($hash,"5","remoteControl","5"); } elsif($a[2] eq "6") { YAMAHA_BD_SendCommand($hash,"6","remoteControl","6"); } elsif($a[2] eq "7") { YAMAHA_BD_SendCommand($hash,"7","remoteControl","7"); } elsif($a[2] eq "8") { YAMAHA_BD_SendCommand($hash,"8","remoteControl","8"); } elsif($a[2] eq "9") { YAMAHA_BD_SendCommand($hash,"9","remoteControl","9"); } elsif($a[2] eq "setup") { YAMAHA_BD_SendCommand($hash,"SETUP","remoteControl","setup"); } elsif($a[2] eq "home") { YAMAHA_BD_SendCommand($hash,"HOME","remoteControl","home"); } elsif($a[2] eq "clear") { YAMAHA_BD_SendCommand($hash,"CLEAR","remoteControl","clear"); } elsif($a[2] eq "program") { YAMAHA_BD_SendCommand($hash,"PROGRAM","remoteControl","program"); } elsif($a[2] eq "search") { YAMAHA_BD_SendCommand($hash,"7C9E","remoteControl","search"); } elsif($a[2] eq "repeat") { YAMAHA_BD_SendCommand($hash,"7CA3","remoteControl","repeat"); } elsif($a[2] eq "repeat-AB") { YAMAHA_BD_SendCommand($hash,"7CA4","remoteControl","repeat-AB"); } elsif($a[2] eq "subtitle") { YAMAHA_BD_SendCommand($hash,"SUBTITLE","remoteControl","subtitle"); } elsif($a[2] eq "angle") { YAMAHA_BD_SendCommand($hash,"ANGLE","remoteControl","angle"); } elsif($a[2] eq "audio") { YAMAHA_BD_SendCommand($hash,"AUDIO","remoteControl","audio"); } elsif($a[2] eq "pictureInPicture") { YAMAHA_BD_SendCommand($hash,"PinP","remoteControl","pictureInPicture"); } elsif($a[2] eq "secondVideo") { YAMAHA_BD_SendCommand($hash,"2nd Video","remoteControl","secondVideo"); } elsif($a[2] eq "secondAudio") { YAMAHA_BD_SendCommand($hash,"2nd Audio","remoteControl","secondAudio"); } elsif($a[2] eq "power") { YAMAHA_BD_SendCommand($hash,"7C80","remoteControl","power"); } elsif($a[2] eq "eject") { YAMAHA_BD_SendCommand($hash,"7C81","remoteControl","eject"); } elsif($a[2] eq "netflix") { YAMAHA_BD_SendCommand($hash,"7CFA","remoteControl","netflix"); } else { return $usage; } } elsif($what eq "trickPlay") { if($a[2] eq "normal") { YAMAHA_BD_SendCommand($hash,"Normal","trickPlay","normal"); } elsif($a[2] eq "repeatChapter") { YAMAHA_BD_SendCommand($hash,"Repeat Chapter/Track/File","trickPlay","repeatChapter"); } elsif($a[2] eq "repeatTitle") { YAMAHA_BD_SendCommand($hash,"Repeat Title","trickPlay","repeatTitle"); } elsif($a[2] eq "repeatFolder") { YAMAHA_BD_SendCommand($hash,"Repeat Folder","trickPlay","repeatFolder"); } elsif($a[2] eq "randomChapter") { YAMAHA_BD_SendCommand($hash,"Random Chapter/Track/File","trickPlay","randomChapter"); } elsif($a[2] eq "randomTitle") { YAMAHA_BD_SendCommand($hash,"Random title","trickPlay","randomTitle"); } elsif($a[2] eq "randomAll") { YAMAHA_BD_SendCommand($hash,"Random All","trickPlay","randomAll"); } elsif($a[2] eq "shuffleChapter") { YAMAHA_BD_SendCommand($hash,"Shuffle Chapter/Track/File","trickPlay","shuffleChapter"); } elsif($a[2] eq "shuffleTitle") { YAMAHA_BD_SendCommand($hash,"Shuffle title","trickPlay","shuffleTitle"); } elsif($a[2] eq "shuffleAll") { YAMAHA_BD_SendCommand($hash,"Shuffle All","trickPlay","shuffleAll"); } elsif($a[2] eq "setApoint") { YAMAHA_BD_SendCommand($hash,"SetA point","trickPlay","setApoint"); } elsif($a[2] eq "repeat-AB") { YAMAHA_BD_SendCommand($hash,"A-B Repeat","trickPlay","ABrepeat"); } else { return $usage; } } elsif($what eq "tray") { if($a[2] eq "open") { YAMAHA_BD_SendCommand($hash, "Open","tray","open"); } elsif($a[2] eq "close") { YAMAHA_BD_SendCommand($hash, "Close","tray","close"); } } elsif($what eq "skip") { if($a[2] eq "forward") { YAMAHA_BD_SendCommand($hash, "Fwd","skip","forward"); } elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","skip","reverse"); } } elsif($what eq "fast") { if($a[2] eq "forward") { YAMAHA_BD_SendCommand($hash, "Fwd","fast","forward"); } elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","fast","reverse"); } } elsif($what eq "slow") { if($a[2] eq "forward") { YAMAHA_BD_SendCommand($hash, "Fwd","slow","forward"); } elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","slow","reverse"); } } elsif($what eq "play") { YAMAHA_BD_SendCommand($hash, "Play","play", undef); } elsif($what eq "pause") { YAMAHA_BD_SendCommand($hash, "Pause","pause", undef); } elsif($what eq "stop") { YAMAHA_BD_SendCommand($hash, "Stop", "play",undef); } elsif($what eq "statusRequest") { YAMAHA_BD_GetStatus($hash, 1); } else { return $usage; } return undef; } ################################### sub YAMAHA_BD_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; YAMAHA_BD_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; YAMAHA_BD_GetStatus($hash, 1); } # Start/Stop Timer according to new disabled-Value YAMAHA_BD_ResetTimer($hash); return undef; } ################################### sub YAMAHA_BD_Undefine($$) { my($hash, $name) = @_; # Stop the internal GetStatus-Loop and exit RemoveInternalTimer($hash); return undef; } ############################################################################################################# # # Begin of helper functions # ############################################################################################################ ################################### # get status of player sub YAMAHA_BD_GetStatus($;$) { my ($hash, $local) = @_; my $name = $hash->{NAME}; my $power; my $return; $local = 0 unless(defined($local)); return "" if(!defined($hash->{helper}{ADDRESS}) or !defined($hash->{helper}{ON_INTERVAL}) or !defined($hash->{helper}{OFF_INTERVAL})); # get the model informations if no informations are available if((not defined($hash->{MODEL})) or (not defined($hash->{FIRMWARE}))) { YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","systemConfig"); } Log3 $name, 4, "YAMAHA_BD ($name) - Requesting system status"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","systemStatus"); Log3 $name, 4, "YAMAHA_BD ($name) - Requesting input info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","inputInfo"); Log3 $name, 4, "YAMAHA_BD ($name) - Requesting power state"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","powerStatus"); Log3 $name, 4, "YAMAHA_BD ($name) - Requesting playing info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","playInfo"); Log3 $name, 4, "YAMAHA_BD ($name) - Requesting trickPlay info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","trickPlayInfo"); # Reset timer if this is not a local run YAMAHA_BD_ResetTimer($hash) unless($local == 1); } ############################# # pushes new command to cmd queue sub YAMAHA_BD_SendCommand($$$$) { my ($hash, $data,$cmd,$arg) = @_; my $name = $hash->{NAME}; my $response; Log3 $name, 4, "YAMAHA_BD ($name) - append to queue \"$cmd".(defined($arg) ? " ".$arg : "")."\": $data"; # In case any URL changes must be made, this part is separated in this function". my $param = { data => "".$data, cmd => $cmd, arg => $arg, }; push @{$hash->{helper}{CMD_QUEUE}}, $param; YAMAHA_BD_HandleCmdQueue($hash); } ############################# # starts http requests from cmd queue sub YAMAHA_BD_HandleCmdQueue($) { my ($hash) = @_; my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; if(not($hash->{helper}{RUNNING_REQUEST}) and @{$hash->{helper}{CMD_QUEUE}}) { my $params = { url => "http://".$address.":50100/YamahaRemoteControl/ctrl", timeout => AttrVal($name, "request-timeout", 4), noshutdown => 1, keepalive => 0, httpversion => "1.0", loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5), hash => $hash, callback => \&YAMAHA_BD_ParseResponse }; my $request = pop @{$hash->{helper}{CMD_QUEUE}}; map {$hash->{helper}{HTTP_CONNECTION}{$_} = $params->{$_}} keys %{$params}; map {$hash->{helper}{HTTP_CONNECTION}{$_} = $request->{$_}} keys %{$request}; $hash->{helper}{RUNNING_REQUEST} = 1; Log3 $name, 4, "YAMAHA_BD ($name) - send command \"$request->{cmd}".(defined($request->{arg}) ? " ".$request->{arg} : "")."\": $request->{data}"; HttpUtils_NonblockingGet($hash->{helper}{HTTP_CONNECTION}); } } ############################# # parses all HTTP response and creates events/readings sub YAMAHA_BD_ParseResponse($$$) { my ( $param, $err, $data ) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; my $cmd = $param->{cmd}; my $arg = $param->{arg}; $data = "" unless(defined($data)); $err = "" unless(defined($err)); $hash->{helper}{RUNNING_REQUEST} = 0; delete($hash->{helper}{HTTP_CONNECTION}) unless($param->{keepalive}); if($err ne "") { Log3 $name, 4, "YAMAHA_BD ($name) - error while executing \"$cmd".(defined($arg) ? " ".$arg : "")."\": $err"; if((not exists($hash->{helper}{AVAILABLE})) or (exists($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 1)) { Log3 $name, 3, "YAMAHA_BD ($name) - could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress: $err"; readingsSingleUpdate($hash, "presence", "absent", 1); readingsSingleUpdate($hash, "state", "absent", 1); } } elsif($data ne "") { Log3 $name, 5, "YAMAHA_BD ($name) - got HTTP response for \"$cmd".(defined($arg) ? " ".$arg : "")."\": $data"; if (defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} == 0) { Log3 $name, 3, "YAMAHA_BD: device $name reappeared"; readingsSingleUpdate($hash, "presence", "present", 1); } readingsBeginUpdate($hash); if(not $data =~ /RC="0"/) { # if the returncode isn't 0, than the command was not successful Log3 $name, 3, "YAMAHA_BD ($name) - Could not execute \"$cmd".(defined($arg) ? " ".$arg : "")."\""; } if($cmd eq "statusRequest" and $arg eq "systemStatus") { if($data =~ /(.+?)<\/Error_Info>/) { readingsBulkUpdate($hash, "error", lc($1)); } } elsif($cmd eq "statusRequest" and $arg eq "systemConfig") { if($data =~ /(.+?)<\/Model_Name>.*(.+?)<\/Version>/) { $hash->{MODEL} = $1; $hash->{FIRMWARE} = $2; $hash->{MODEL} =~ s/\s*YAMAHA\s*//g; $attr{$name}{"model"} = $hash->{MODEL}; } } elsif($cmd eq "statusRequest" and $arg eq "powerStatus") { if($data =~ /(.+?)<\/Power>/) { my $power = $1; if($power eq "Standby" or $power eq "Network Standby") { $power = "off"; } readingsBulkUpdate($hash, "power", lc($power)); readingsBulkUpdate($hash, "state", lc($power)); } } elsif($cmd eq "on") { if($data =~ /RC="0"/ and $data =~ /<\/Power>/) { # As the player startup takes about 5 seconds, the status will be already set, if the return code of the command is 0. readingsBulkUpdate($hash, "power", "on"); readingsBulkUpdate($hash, "state","on"); } else { Log3 $name, 3, "YAMAHA_BD ($name) - Could not set power to on"; } } elsif($cmd eq "statusRequest" and $arg eq "trickPlayInfo") { if($data =~ /(.+?)<\/Trick_Play>/) { readingsBulkUpdate($hash, "trickPlay", $1); } } elsif($cmd eq "statusRequest" and $arg eq "inputInfo") { if($data =~ /(.+?)<\/Status><\/Input_Info/) { readingsBulkUpdate($hash, "input", $1); } elsif($data =~ /(.+?)<\/Input_Info/) { readingsBulkUpdate($hash, "input", $1); } } elsif($cmd eq "statusRequest" and $arg eq "playInfo") { if($data =~ /(.+?)<\/Status>/) { readingsBulkUpdate($hash, "playStatus", lc($1)); } if($data =~ /.*?(.+?)<\/Chapter>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentChapter", $1); } if($data =~ /.*?(.+?)<\/Track>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentTrack", $1); } if($data =~ /.*?(.+?)<\/Title>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentTitle", $1); } if($data =~ /<Disc_Info>.*?<Track_Num>(.+?)<\/Track_Num>.*?<\/Disc_Info>/) { readingsBulkUpdate($hash, "totalTracks", $1); } if($data =~ /<Contents>.*?<Type>(.+?)<\/Type>.*?<\/Contents>/) { readingsBulkUpdate($hash, "contentType", lc($1)); } if($data =~ /<File_Name>(.+?)<\/File_Name>/) { readingsBulkUpdate($hash, "currentMedia", $1); } if($data =~ /<Disc_Type>(.+?)<\/Disc_Type>/) { readingsBulkUpdate($hash, "discType", $1); } if($data =~ /<Tray>(.+?)<\/Tray>/) { readingsBulkUpdate($hash, "trayStatus", lc($1)); } if($data =~ /<Current_PlayTime>(.+?)<\/Current_PlayTime>/) { readingsBulkUpdate($hash, "playTimeCurrent", YAMAHA_BD_formatTimestamp($1)); } if($data =~ /<Total_Time>(.+?)<\/Total_Time>/) { readingsBulkUpdate($hash, "playTimeTotal", YAMAHA_BD_formatTimestamp($1)); } } readingsEndUpdate($hash, 1); YAMAHA_BD_GetStatus($hash, 1) if($cmd ne "statusRequest" and $cmd ne "on"); YAMAHA_BD_ResetTimer($hash, 10) if($cmd eq "on"); } $hash->{helper}{AVAILABLE} = ($err ne "" ? 0 : 1); YAMAHA_BD_HandleCmdQueue($hash); } ############################# # resets the StatusUpdate Timer according to the device state and respective interval sub YAMAHA_BD_ResetTimer($;$) { my ($hash, $interval) = @_; RemoveInternalTimer($hash); if($hash->{helper}{DISABLED} == 0) { if(defined($interval)) { InternalTimer(gettimeofday()+$interval, "YAMAHA_BD_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}, "YAMAHA_BD_GetStatus", $hash, 0); } else { InternalTimer(gettimeofday()+$hash->{helper}{OFF_INTERVAL}, "YAMAHA_BD_GetStatus", $hash, 0); } } } ############################# # define the layout for module 95_remotecontrol.pm sub YAMAHA_BD_RClayout() { my @row; $row[0] = "remoteControl eject:EJECT,:blank,:blank,remoteControl power:POWEROFF3"; $row[1] = "remoteControl red:RED,remoteControl green:GREEN,remoteControl yellow:YELLOW,remoteControl blue:BLUE"; $row[2] = "remoteControl 1:1,remoteControl 2:2,remoteControl 3:3,remoteControl repeat-AB:REPEAT_AB"; $row[3] = "remoteControl 4:4,remoteControl 5:5,remoteControl 6:6,remoteControl subtitle:SUBTITLE"; $row[4] = "remoteControl 7:7,remoteControl 8:8,remoteControl 9:9,remoteControl angle:ANGLE"; $row[5] = "remoteControl clear:CLEAR,remoteControl 0:0,remoteControl search:SEARCH,remoteControl audio:AUDIO2"; $row[6] = ":blank,:blank,:blank,:blank"; $row[7] = "remoteControl pictureInPicture:PIP,:blank,:blank,:blank"; $row[8] = "remoteControl secondAudio:2ND_AUDIO,remoteControl home:HOMEtxt,remoteControl setup:SETUP,:blank"; $row[9] = ":blank,:blank,:blank,:blank"; $row[10] = "remoteControl topMenu:TOPMENU,remoteControl up:UP,remoteControl popupMenu:POPUP_MENU,:blank"; $row[11] = "remoteControl left:LEFT,remoteControl enter:ENTER3,remoteControl right:RIGHT,:blank"; $row[12] = "remoteControl return:RETURN,remoteControl down:DOWN,remoteControl OSDonScreen:ONSCREEN,:blank"; $row[13] = ":blank,:blank,:blank,:blank"; $row[14] = "stop:STOP,pause:PAUSE,play:PLAY,:blank"; $row[15] = "slow reverse:SLOW_REWIND,slow forward:SLOW_FORWARD,fast reverse:REWIND,fast forward:FF"; $row[16] = ":blank,remoteControl OSDstatus:STATUS,skip reverse:SKIP_REVERSE,skip forward:SKIP_FORWARD"; $row[17] = "attr rc_iconpath icons/remotecontrol"; $row[18] = "attr rc_iconprefix black_btn_"; return @row; } ##################################### # Callback from 95_remotecontrol for command makenotify. sub YAMAHA_BD_RCmakenotify($$) { my ($name, $dev) = @_; my $new_name="notify_$name"; fhem("define $new_name notify $name set $dev ".'$EVENT',1); Log3 undef, 2, "[remotecontrol:YAMAHA_BD] Notify created: $new_name"; return "Notify created by YAMAHA_BD: $new_name"; } ############################# # formats a 3 byte Hex Value into human readable time duration sub YAMAHA_BD_formatTimestamp($) { my ($hex) = @_; my ($hour) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 0, 2)))); my ($min) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 2, 2)))); my ($sec) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 4, 2)))); return "$hour:$min:$sec"; } 1; =pod =item device =begin html <a name="YAMAHA_BD"></a> <h3>YAMAHA_BD</h3> <ul> <a name="YAMAHA_BDdefine"></a> <b>Define</b> <ul> <code> define <name> YAMAHA_BD <ip-address> [<status_interval>] <br><br> define <name> YAMAHA_BD <ip-address> [<off_status_interval>] [<on_status_interval>] </code> <br><br> This module controls Blu-Ray players from Yamaha via network connection. You are able to switch your player on and off, query it's power state, control the playback, open and close the tray and send all remote control commands.<br><br> Defining a YAMAHA_BD device will schedule an internal task (interval can be set with optional parameter <status_interval> in seconds, if not set, the value is 30 seconds), which periodically reads the status of the player (power state, current disc, tray status,...) and triggers notify/filelog commands. <br><br> Different status update intervals depending on the power state can be given also. If two intervals are given to the define statement, the first interval statement represents the status update interval in seconds in case the device is off, absent or any other non-normal state. The second interval statement is used when the device is on. Example:<br><br> <ul><code> define BD_Player YAMAHA_BD 192.168.0.10 <br><br> # With custom status interval of 60 seconds<br> define BD_Player YAMAHA_BD 192.168.0.10 60 <br><br> # With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br> define BD_Player YAMAHA_BD 192.168.0.10 60 10 </code></ul> </ul> <br><br> <a name="YAMAHA_BDset"></a> <b>Set </b> <ul> <code>set <name> <command> [<parameter>]</code> <br><br> Currently, the following commands are defined. <br><br> <ul> <li><b>on</b>   -   powers on the device</li> <li><b>off</b>   -   shuts down the device </li> <li><b>tray</b> open,close   -   open or close the disc tray</li> <li><b>statusRequest</b>   -   requests the current status of the device</li> <li><b>remoteControl</b> up,down,...   -   sends remote control commands as listed in the following chapter</li> </ul><br> <u>Playback control commands</u> <ul> <li><b>play</b>   -   start playing the current media</li> <li><b>pause</b>   -   pause the current media playback</li> <li><b>stop</b>   -   stop the current media playback</li> <li><b>skip</b> forward,reverse   -   skip the current track or chapter</li> <li><b>fast</b> forward,reverse   -   fast forward or reverse playback</li> <li><b>slow</b> forward,reverse   -   slow forward or reverse playback</li> <li><b>trickPlay</b> normal,repeatChapter,repeatTitle,...   -   controls the Trick-Play features</li> </ul> </ul><br><br> <u>Remote control</u><br><br> <ul> The following commands are available:<br><br> <u>Number Buttons (0-9):</u><br><br> <ul><code> remoteControl 0<br> remoteControl 1<br> remoteControl 2<br> ...<br> remoteControl 9<br> </code></ul><br><br> <u>Cursor Selection:</u><br><br> <ul><code> remoteControl up<br> remoteControl down<br> remoteControl left<br> remoteControl right<br> remoteControl enter<br> remoteControl return<br> </code></ul><br><br> <u>Menu Selection:</u><br><br> <ul><code> remoteControl OSDonScreen<br> remoteControl OSDstatus<br> remoteControl popupMenu<br> remoteControl topMenu<br> remoteControl setup<br> remoteControl home<br> remoteControl clear<br> </code></ul><br><br> <u>Color Buttons:</u><br><br> <ul><code> remoteControl red<br> remoteControl green<br> remoteControl yellow<br> remoteControl blue<br> </code></ul><br><br> <u>Play Control Buttons:</u><br><br> <ul><code> remoteControl program<br> remoteControl search<br> remoteControl repeat<br> remoteControl repeat-AB<br> remoteControl subtitle<br> remoteControl audio<br> remoteControl angle<br> remoteControl pictureInPicture<br> remoteControl secondAudio<br> remoteControl secondVideo<br> </code></ul><br><br> The button names are the same as on your remote control.<br><br> </ul> <a name="YAMAHA_BDget"></a> <b>Get</b> <ul> <code>get <name> <reading></code> <br><br> Currently, the get command only returns the reading values. For a specific list of possible values, see section "Generated Readings/Events". <br><br> </ul> <a name="YAMAHA_BDattr"></a> <b>Attributes</b> <ul> <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a name="disable">disable</a></li> Optional attribute to disable the internal cyclic status update of the player. Manual status updates via statusRequest command is still possible. <br><br> Possible values: 0 => perform cyclic status update, 1 => don't perform cyclic status updates.<br><br> <li><a name="request-timeout">request-timeout</a></li> Optional attribute change the response timeout in seconds for all queries to the player. <br><br> Possible values: 1-5 seconds. Default value is 4 seconds.<br><br> </ul> <b>Generated Readings/Events:</b><br> <ul> <li><b>input</b> - The current playback source (e.g. "DISC", "USB", "Network", "YouTube", ...)</li> <li><b>discType</b> - The current type of disc, which is inserted (e.g. "No Disc", "CD", "DVD", "BD", ...)</li> <li><b>contentType</b> - The current type of content, which is played (e.g. "audio", "video", "photo" or "no contents")</li> <li><b>error</b> - indicates an hardware error of the player (can be "none", "fan error" or "usb overcurrent")</li> <li><b>power</b> - Reports the power status of the player or zone (can be "on" or "off")</li> <li><b>presence</b> - Reports the presence status of the player or zone (can be "absent" or "present"). In case of an absent device, it cannot be controlled via FHEM anymore.</li> <li><b>trayStatus</b> - The disc tray status (can be "open" or "close")</li> <li><b>trickPlay</b> - The current trickPlay mode</li> <li><b>state</b> - Reports the current power state and an absence of the device (can be "on", "off" or "absent")</li> <br><br><u>Input dependent Readings/Events:</u><br> <li><b>currentChapter</b> - Number of the current DVD/BD Chapter (only at DVD/BD's)</li> <li><b>currentMedia</b> - Name of the current file (only at USB)</li> <li><b>currentTrack</b> - Number of the current CD-Audio title (only at CD-Audio)</li> <li><b>currentTitle</b> - Number of the current title (only at DVD/BD's)</li> <li><b>playTimeCurrent</b> - current timecode of played media</li> <li><b>playTimeTotal</b> - the total time of the current movie (only at DVD/BD's)</li> <li><b>playStatus</b> - indicates if the player plays media or not (can be "play", "pause", "stop", "fast fwd", "fast rev", "slow fwd", "slow rev")</li> <li><b>totalTracks</b> - The number of total tracks on inserted CD-Audio</li> </ul> <br> <b>Implementator's note</b><br> <ul> <li>Some older models (e.g. BD-S671) cannot be controlled over networked by delivery. A <u><b>firmware update is neccessary</b></u> to control these models via FHEM. In general it is always recommended to use the latest firmware.</li> <li>The module is only usable if you activate "Network Control" on your player. Otherwise it is not possible to communicate with the player.</li> </ul> <br> </ul> =end html =begin html_DE <a name="YAMAHA_BD"></a> <h3>YAMAHA_BD</h3> <ul> <a name="YAMAHA_BDdefine"></a> <b>Definition</b> <ul> <code>define <name> YAMAHA_BD <IP-Addresse> [<Status_Interval>] <br><br> define <name> YAMAHA_BD <IP-Addresse> [<Off_Interval>] [<On_Interval>] </code> <br><br> Dieses Modul steuert Blu-Ray Player des Herstellers Yamaha über die Netzwerkschnittstelle. Es bietet die Möglichkeit den Player an-/auszuschalten, die Schublade zu öffnen und schließen, die Wiedergabe beeinflussen, sämtliche Fernbedieungs-Befehle zu senden, sowie den aktuellen Status abzufragen. <br><br> Bei der Definition eines YAMAHA_BD-Moduls wird eine interne Routine in Gang gesetzt, welche regelmäßig (einstellbar durch den optionalen Parameter <code><Status_Interval></code>; falls nicht gesetzt ist der Standardwert 30 Sekunden) den Status des Players abfragt und entsprechende Notify-/FileLog-Definitionen triggert. <br><br> Sofern 2 Interval-Argumente übergeben werden, wird der erste Parameter <code><Off_Interval></code> genutzt sofern der Player ausgeschaltet oder nicht erreichbar ist. Der zweiter Parameter <code><On_Interval></code> wird verwendet, sofern der Player eingeschaltet ist. <br><br> Beispiel:<br><br> <ul><code> define BD_Player YAMAHA_BD 192.168.0.10 <br><br> # Mit modifiziertem Status Interval (60 Sekunden)<br> define BD_Player YAMAHA_BD 192.168.0.10 60 <br><br> # Mit gesetztem "Off"-Interval (60 Sekunden) und "On"-Interval (10 Sekunden)<br> define BD_Player YAMAHA_BD 192.168.0.10 60 10 </code></ul><br><br> </ul> <a name="YAMAHA_BDset"></a> <b>Set-Kommandos </b> <ul> <code>set <Name> <Kommando> [<Parameter>]</code> <br><br> Aktuell werden folgende Kommandos unterstützt. <br><br> <ul> <li><b>on</b>   -   schaltet den Player ein</li> <li><b>off</b>   -   schaltet den Player aus </li> <li><b>tray</b> open,close   -   öffnet oder schließt die Schublade</li> <li><b>statusRequest</b>   -   fragt den aktuellen Status ab</li> <li><b>remoteControl</b> up,down,...   -   sendet Fernbedienungsbefehle wie im folgenden Kapitel beschrieben.</li> </ul><br> <u>Wiedergabespezifische Kommandos</u> <ul> <li><b>play</b>   -   startet die Wiedergabe des aktuellen Mediums</li> <li><b>pause</b>   -   pausiert die Wiedergabe</li> <li><b>stop</b>   -   stoppt die Wiedergabe</li> <li><b>skip</b> forward,reverse   -   überspringt das aktuelle Kapitel oder den aktuellen Titel</li> <li><b>fast</b> forward,reverse   -   schneller Vor- oder Rücklauf</li> <li><b>slow</b> forward,reverse   -   langsamer Vor- oder Rücklauf</li> <li><b>trickPlay</b> normal,repeatChapter,repeatTitle,...   -   aktiviert Trick-Play Funktionen (Wiederholung, Zufallswiedergabe, ...)</li> </ul> <br><br> </ul> <u>Fernbedienung</u><br><br> <ul> Es stehen folgende Befehle zur Verfügung:<br><br> <u>Zahlen Tasten (0-9):</u><br><br> <ul><code> remoteControl 0<br> remoteControl 1<br> remoteControl 2<br> ...<br> remoteControl 9<br> </code></ul><br><br> <u>Cursor Steuerung:</u><br><br> <ul><code> remoteControl up<br> remoteControl down<br> remoteControl left<br> remoteControl right<br> remoteControl enter<br> remoteControl return<br> </code></ul><br><br> <u>Menü Auswahl:</u><br><br> <ul><code> remoteControl OSDonScreen<br> remoteControl OSDstatus<br> remoteControl popupMenu<br> remoteControl topMenu<br> remoteControl setup<br> remoteControl home<br> remoteControl clear<br> </code></ul><br><br> <u>Farbtasten:</u><br><br> <ul><code> remoteControl red<br> remoteControl green<br> remoteControl yellow<br> remoteControl blue<br> </code></ul><br><br> <u>Wiedergabetasten:</u><br><br> <ul><code> remoteControl program<br> remoteControl search<br> remoteControl repeat<br> remoteControl repeat-AB<br> remoteControl subtitle<br> remoteControl audio<br> remoteControl angle<br> remoteControl pictureInPicture<br> remoteControl secondAudio<br> remoteControl secondVideo<br> </code></ul><br><br> Die Befehlsnamen entsprechen den Tasten auf der Fernbedienung.<br><br> </ul> <a name="YAMAHA_BDget"></a> <b>Get-Kommandos</b> <ul> <code>get <Name> <Readingname></code> <br><br> Aktuell stehen via GET lediglich die Werte der Readings zur Verfügung. Eine genaue Auflistung aller möglichen Readings folgen unter "Generierte Readings/Events". </ul> <br><br> <a name="YAMAHA_BDattr"></a> <b>Attribute</b> <ul> <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a name="disable">disable</a></li> Optionales Attribut zur Deaktivierung des zyklischen Status-Updates. Ein manuelles Update via statusRequest-Befehl ist dennoch möglich. <br><br> Mögliche Werte: 0 => zyklische Status-Updates, 1 => keine zyklischen Status-Updates.<br><br> <li><a name="request-timeout">request-timeout</a></li> Optionales Attribut. Maximale Dauer einer Anfrage in Sekunden zum Player. <br><br> Mögliche Werte: 1-5 Sekunden. Standartwert ist 4 Sekunden<br><br> </ul> <b>Generierte Readings/Events:</b><br> <ul> <li><b>input</b> - Die aktuelle Wiedergabequelle (z.B. "DISC", "USB", "Network", "YouTube", ...)</li> <li><b>discType</b> - Die Art der eingelegten Disc (z.B "No Disc" => keine Disc eingelegt, "CD", "DVD", "BD", ...)</li> <li><b>contentType</b> - Die Art des Inhaltes, der gerade abgespielt wird ("audio", "video", "photo" oder "no contents")</li> <li><b>error</b> - zeigt an, ob ein interner Fehler im Player vorliegt ("none" => kein Fehler, "fan error" => Lüfterdefekt, "usb overcurrent" => USB Spannungsschutz)</li> <li><b>power</b> - Der aktuelle Betriebsstatus ("on" => an, "off" => aus)</li> <li><b>presence</b> - Die aktuelle Empfangsbereitschaft ("present" => empfangsbereit, "absent" => nicht empfangsbereit, z.B. Stromausfall)</li> <li><b>trayStatus</b> - Der Status der Schublade("open" => geöffnet, "close" => geschlossen)</li> <li><b>trickPlay</b> - Der aktuell aktive Trick-Play Modus</li> <li><b>state</b> - Der aktuelle Schaltzustand (power-Reading) oder die Abwesenheit des Gerätes (mögliche Werte: "on", "off" oder "absent")</li> <br><br><u>Quellenabhängige Readings/Events:</u><br> <li><b>currentChapter</b> - Das aktuelle Kapitel eines DVD- oder Blu-Ray-Films</li> <li><b>currentTitle</b> - Die Titel-Nummer des aktuellen DVD- oder Blu-Ray-Films</li> <li><b>currentTrack</b> - Die aktuelle Track-Nummer der wiedergebenden Audio-CD</li> <li><b>currentMedia</b> - Der Name der aktuell wiedergebenden Datei (Nur bei der Wiedergabe über USB)</li> <li><b>playTimeCurrent</b> - Der aktuelle Timecode an dem sich die Wiedergabe momentan befindet.</li> <li><b>playTimeTotal</b> - Die komplette Spieldauer des aktuellen Films (Nur bei der Wiedergabe von DVD/BD's)</li> <li><b>playStatus</b> - Wiedergabestatus des aktuellen Mediums</li> <li><b>totalTracks</b> - Gesamtanzahl aller Titel einer Audio-CD</li> </ul> <br> <b>Hinweise des Autors</b> <ul> <li>Einige ältere Player-Modelle (z.B. BD-S671) können im Auslieferungszustand nicht via Netzwerk gesteuert werden. Um eine Steuerung via FHEM zu ermöglichen ist ein <u><b>Firmware-Update notwending</b></u>!</li> <li>Dieses Modul ist nur nutzbar, wenn die Option "Netzwerksteuerung" am Player aktiviert ist. Ansonsten ist die Steuerung nicht möglich.</li> </ul> <br> </ul> =end html_DE =cut