2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

new module YAMAHA_AVR added

git-svn-id: https://svn.fhem.de/fhem/trunk@2053 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
markusbloch 2012-11-02 09:17:36 +00:00
parent fcbb32c8d4
commit e597893258
2 changed files with 431 additions and 1 deletions

344
fhem/FHEM/71_YAMAHA_AVR.pm Executable file
View File

@ -0,0 +1,344 @@
#
# Module: YAMAHA_AVR
#
# An FHEM Perl module for controlling Yamaha AV-Receivers
# via network connection. As the interface is standardized
# within all Yamaha AV-Receivers, this module should work
# with any receiver which has an ethernet or wlan connection.
#
# Currently supported are: power (on|off)
# input (hdmi1|hdmi2|...)
# volume (-50 ... 10)
# mute (on|off)
#
# Of course there are more possibilities than these 4 commands.
# But in my oppinion these are the most relevant usecases within FHEM.
#
# For more commands, please email me.
#
# Written by Notausstieg (Notausstieg0309[at]googlemail[dot]com)
#
# 29.10.2012
#
###################################
package main;
use strict;
use warnings;
#use Time::HiRes qw(gettimeofday);
sub YAMAHA_AVR_Get($@);
sub YAMAHA_AVR_Define($$);
sub YAMAHA_AVR_GetStatus($);
###################################
sub
YAMAHA_AVR_Initialize($)
{
my ($hash) = @_;
$hash->{GetFn} = "YAMAHA_AVR_Get";
$hash->{SetFn} = "YAMAHA_AVR_Set";
$hash->{DefFn} = "YAMAHA_AVR_Define";
$hash->{UndefFn} = "YAMAHA_AVR_Undefine";
$hash->{AttrList} = "loglevel:0,1,2,3,4,5 subType event-on-update-reading event-on-change-reading";
}
###################################
sub
YAMAHA_AVR_GetStatus($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $power;
return "" if(!defined($hash->{ADDRESS}) or !defined($hash->{INTERVAL}));
my $device = $hash->{ADDRESS};
my $return = SendCommand($device,"<YAMAHA_AV cmd=\"GET\"><Main_Zone><Basic_Status>GetParam</Basic_Status></Main_Zone></YAMAHA_AV>");
return "Can't submit command. please see fhem logfile for further information" if(not defined($return) or length($return) == 0);
readingsBeginUpdate($hash);
if($return =~ /<Power>(.+)<\/Power>/)
{
$power = $1;
readingsUpdate($hash, "power", lc($power));
if($power eq "Standby")
{
$power = "Off";
}
$hash->{STATE} = lc($power);
}
if($return =~ /<Volume><Lvl><Val>(.+)<\/Val><Exp>(.+)<\/Exp><Unit>.+<\/Unit><\/Lvl><Mute>(.+)<\/Mute><\/Volume>/)
{
readingsUpdate($hash, "volume_level", ($1 / 10 ** $2));
readingsUpdate($hash, "mute", lc($3));
}
if($return =~ /<Input_Sel>(.+)<\/Input_Sel>/)
{
readingsUpdate($hash, "input", lc($1));
}
readingsEndUpdate($hash, 1);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "YAMAHA_AVR_GetStatus", $hash, 1);
Log GetLogLevel($name,4), "YAMAHA_AVR $name: $hash->{STATE}";
return $hash->{STATE};
}
###################################
sub
YAMAHA_AVR_Get($@)
{
my ($hash, @a) = @_;
my $what;
return "argument is missing" if(int(@a) != 2);
$what = $a[1];
if($what =~ /^(power|input|volume|mute)$/)
{
YAMAHA_AVR_GetStatus($hash);
if(defined($hash->{READINGS}{$what}))
{
return $a[0]." ".$what." => ".$hash->{READINGS}{$what}{VAL};
}
else
{
return "no such reading: $what";
}
}
else
{
return "Unknown argument $what, choose one of param power input volume mute get";
}
}
###################################
sub
YAMAHA_AVR_Set($@)
{
my ($hash, @a) = @_;
my $name = $hash->{NAME};
my $address = $hash->{ADDRESS};
my $result = "";
my $inputs_piped = $hash->{INPUTS};
return "No Argument given" if(!defined($a[1]));
my $what = $a[1];
my $usage = "Unknown argument $what, choose one of on off volume:slider,-80,1,16 input:".$hash->{INPUTS}." mute:on,off statusRequest";
readingsBeginUpdate($hash);
if($what eq "on")
{
$result = SendCommand($address, "<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Power_Control><Power>On</Power></Power_Control></Main_Zone></YAMAHA_AV>");
if($result =~ /RC="0"/ and $result =~ /<Power><\/Power>/)
{
# As the receiver startup takes about 5 seconds, the status will be already set, if the return code of the command is 0.
readingsUpdate($hash, "power", "on");
$hash->{STATE} = "on";
return undef;
}
}
elsif($what eq "off")
{
SendCommand($address, "<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Power_Control><Power>Standby</Power></Power_Control></Main_Zone></YAMAHA_AV>");
}
elsif($what eq "input")
{
if(defined($a[2]))
{
if($hash->{STATE} eq "on")
{
$inputs_piped =~ s/,/|/g;
if($a[2] =~ /^($inputs_piped)$/)
{
if($a[2] eq "netradio")
{
$result = SendCommand($address,"<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Input><Input_Sel>NET RADIO</Input_Sel></Input></Main_Zone></YAMAHA_AV>");
}
elsif($a[2] eq "airplay")
{
$result = SendCommand($address,"<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Input><Input_Sel>AirPlay</Input_Sel></Input></Main_Zone></YAMAHA_AV>");
}
else
{
$result = SendCommand($address,"<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Input><Input_Sel>".uc($a[2])."</Input_Sel></Input></Main_Zone></YAMAHA_AV>");
}
if(not $result =~ /RC="0"/)
{
# if the returncode isn't 0, than the command was not successful
return "Could not set input to ".$a[2].". Please use only available inputs on your specific receiver";
}
}
else
{
return $usage;
}
}
else
{
return "input can only be used when device is powered on";
}
}
}
elsif($what eq "mute")
{
if(defined($a[2]))
{
if($hash->{STATE} eq "on")
{
if( $a[2] eq "on")
{
SendCommand($address, "<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Volume><Mute>On</Mute></Volume></Main_Zone></YAMAHA_AV>");
}
elsif($a[2] eq "off")
{
SendCommand($address, "<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Volume><Mute>Off</Mute></Volume></Main_Zone></YAMAHA_AV>");
}
else
{
return $usage;
}
}
else
{
return "mute can only used when device is powered on";
}
}
}
elsif($what eq "volume")
{
if(defined($a[2]) && $a[2] >= -80 && $a[2] < 16)
{
if($hash->{STATE} eq "on")
{
SendCommand($address,"<YAMAHA_AV cmd=\"PUT\"><Main_Zone><Volume><Lvl><Val>".($a[2]*10)."</Val><Exp>1</Exp><Unit>dB</Unit></Lvl></Volume></Main_Zone></YAMAHA_AV>");
}
else
{
return "volume can only be used when device is powered on";
}
}
}
elsif($what eq "statusRequest")
{
# Will be executed on the end of this function anyway, so no need to call it specificly
}
else
{
return $usage;
}
readingsEndUpdate($hash, 1);
YAMAHA_AVR_GetStatus($hash);
return undef;
}
#############################
sub
YAMAHA_AVR_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $name = $hash->{NAME};
my @inputs;
if(! @a >= 3)
{
my $msg = "wrong syntax: define <name> YAMAHA_AVR <ip-or-hostname> [<statusinterval>]";
Log 2, $msg;
return $msg;
}
my $address = $a[2];
my $response = GetFileFromURL("http://".$address."/YamahaRemoteControl/desc.xml");
if($response =~ /<Unit_Description.* Unit_Name="(.+?)">/)
{
$hash->{MODEL} = $1;
}
$hash->{ADDRESS} = $address;
$response = SendCommand($address, "<YAMAHA_AV cmd=\"GET\"><Main_Zone><Input><Input_Sel_Item>GetParam</Input_Sel_Item></Input></Main_Zone></YAMAHA_AV>");
$response =~ s/></>\n</g;
@inputs = split("\n", $response);
foreach (sort @inputs)
{
if($_ =~ /<Param>(.+?)<\/Param>/ and not $1 =~ /iPod/)
{
if(defined($hash->{INPUTS}) and length($hash->{INPUTS}) > 0)
{
$hash->{INPUTS} .= ",";
}
if($1 eq "NET RADIO")
{
$hash->{INPUTS} .= "netradio";
}
else
{
$hash->{INPUTS} .= lc($1);
}
}
}
if(defined($a[3]) and $a[3] > 0)
{
$hash->{INTERVAL}=$a[3];
}
else
{
$hash->{INTERVAL}=30;
}
InternalTimer(gettimeofday()+2, "YAMAHA_AVR_GetStatus", $hash, 0);
return undef;
}
#############################
sub
SendCommand($$)
{
my($address, $command) = @_;
# In case any URL changes must be made, this part is separated in this function".
return GetFileFromURL("http://".$address."/YamahaRemoteControl/ctrl", 10, "<?xml version=\"1.0\" encoding=\"utf-8\"?>".$command);
}
#############################
sub
YAMAHA_AVR_Undefine($$)
{
my($hash, $name) = @_;
RemoveInternalTimer($hash);
return undef;
}
1;

View File

@ -136,7 +136,7 @@
<a href="#SISPM">SISPM</a> &nbsp;
<a href="#SIS_PMS">SIS_PMS</a> &nbsp;
<a href="#SML">SML</a> &nbsp;
<a href="#STV">STV</a> &nbsp;
<a href="#STV">STV</a> &nbsp;
<a href="#TCM">TCM</a> &nbsp;
<a href="#TellStick">TellStick</a> &nbsp;
<a href="#TRX">TRX</a> &nbsp;
@ -158,6 +158,7 @@
<a href="#WS3600">WS3600</a> &nbsp;
<a href="#X10">X10</a> &nbsp;
<a href="#xxLG7000">xxLG7000</a> &nbsp;
<a href="#YAMAHA_AVR">YAMAHA_AVR</a> &nbsp;
<a href="#ZWDongle">ZWDongle</a> &nbsp;
<a href="#ZWave">ZWave</a> &nbsp;
@ -10100,6 +10101,91 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433
<br>
</ul>
<a name="YAMAHA_AVR"></a>
<h3>YAMAHA_AVR</h3>
<ul>
<a name="YAMAHA_AVRdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; YAMAHA_AVR &lt;ip-address&gt; [&lt;status_interval&gt;]</code>
<br><br>
This module controls AV receiver from Yamaha via network connection. You are able
to power your AV reveiver on and off, query it's power state,
select the input (HDMI, AV, AirPlay, internet radio, Tuner, ...), select the volume
or mute/unmute the volume.<br><br>
Defining a YAMAHA_AVR device will schedule an internal task (interval can be set
with optional parameter &lt;status_interval&gt; in seconds, if not set, the value is 60 seconds), which periodically reads
the status of the AV receiver (power state, selected input, volume and mute status)
and triggers notify/filelog commands.<br><br>
Example:
<ul>
<code>define AV_Receiver YAMAHA_AVR 192.168.0.10</code><br>
</ul>
<a name="YAMAHA_AVRset"></a>
<b>Set </b>
<ul>
<code>set &lt;name&gt; &lt;command&gt; [&lt;parameter&gt;]</code>
<br><br>
Currently, the following commands are defined; the available inputs are depending on the used receiver.
The module only offers the real available inputs. The following input commands are just an example and can differ.
<pre>on
off
input hdmi1
input hdmi2
input hdmi3
input hdmi4
input av1
input av2
input av3
input av3
input av4
input av5
input av6
input usb
input airplay
input tuner
input v-aux
input audio
input server
volume -80..16 (volume between -80 and +16 dB)
mute on
mute off</pre>
</ul>
<a name="YAMAHA_AVRget"></a>
<b>Get</b>
<ul>
<code>get &lt;name&gt; &lt;what&gt;</code>
<br><br>
Currently, the following commands are defined and return the current state of the receiver.
<pre>power
input
mute
volume</pre>
</ul>
<a name="YAMAHA_AVRattr"></a>
<b>Attributes</b>
<ul>
<li><a href="#loglevel">loglevel</a></li>
<li><a href="#event-on-update-reading">event-on-update-reading</a></li>
<li><a href="#event-on-change-reading">event-on-change-reading</a></li>
</ul>
<br>
<b>Implementator's note</b>
<ul>
The module is only usable if you activate "Network Standby" on your receiver.<br><br>
Technically there are many more commands and readings possible, but I think
these are the main usecases within FHEM.
</ul>
<br>
</ul>
<a name="ZWDongle"></a>
<h3>ZWDongle</h3>
<ul>