diff --git a/fhem/CHANGED b/fhem/CHANGED
index 68b98d419..ae7ffdee9 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - bugfix: YAMAHA_AVR: don't let FHEM hang anymore, when the receiver
+ is not reachable
- change: 55_GDS.pm: use Blocking.pm for retrieval of large files
- change: YAMAHA_BD: make YAMAHA_BD more performant by using non-blocking
HTTP request (from HttpUtils.pm)
diff --git a/fhem/FHEM/71_YAMAHA_AVR.pm b/fhem/FHEM/71_YAMAHA_AVR.pm
index bf88ccdd2..daec0d92c 100755
--- a/fhem/FHEM/71_YAMAHA_AVR.pm
+++ b/fhem/FHEM/71_YAMAHA_AVR.pm
@@ -78,21 +78,15 @@ YAMAHA_AVR_GetStatus($;$)
# get the model informations and available zones if no informations are available
if(not defined($hash->{ACTIVE_ZONE}) or not defined($hash->{helper}{ZONES}) or not defined($hash->{MODEL}) or not defined($hash->{FIRMWARE}) or not defined($hash->{helper}{DSP_MODES}))
{
- unless(defined(YAMAHA_AVR_getModel($hash)))
- {
- YAMAHA_AVR_ResetTimer($hash) unless($local == 1);
- return;
- }
+ YAMAHA_AVR_getModel($hash);
+ YAMAHA_AVR_ResetTimer($hash) unless($local == 1);
+ return;
}
- # get all available inputs if nothing is available
- if(not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0)
+ # get all available inputs and scenes if nothing is available
+ if((not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0) or (not defined($hash->{helper}{SCENES}) or length($hash->{helper}{SCENES}) == 0))
{
- unless(defined(YAMAHA_AVR_getInputs($hash)))
- {
- YAMAHA_AVR_ResetTimer($hash) unless($local == 1);
- return;
- }
+ YAMAHA_AVR_getInputs($hash);
}
my $zone = YAMAHA_AVR_getParamName($hash, $hash->{ACTIVE_ZONE}, $hash->{helper}{ZONES});
@@ -103,220 +97,9 @@ YAMAHA_AVR_GetStatus($;$)
return "No Zone available";
}
- my $return = YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ");
-
- #Log3 $name, 4, "YAMAHA_AVR: GetStatus-Request returned: $return" if(defined($return));
-
- if(not defined($return) or $return eq "")
- {
- YAMAHA_AVR_ResetTimer($hash) unless($local == 1);
- return;
- }
-
- readingsBeginUpdate($hash);
-
- if($return =~ /(.+)<\/Power>/)
- {
- $power = $1;
-
- if($power eq "Standby")
- {
- $power = "off";
- }
- readingsBulkUpdate($hash, "power", lc($power));
- readingsBulkUpdate($hash, "state", lc($power));
- }
-
- # current volume and mute status
- if($return =~ /(.+)<\/Val>(.+)<\/Exp>.+<\/Unit><\/Lvl>(.+)<\/Mute>.*<\/Volume>/)
- {
- readingsBulkUpdate($hash, "volumeStraight", ($1 / 10 ** $2));
- readingsBulkUpdate($hash, "volume", YAMAHA_AVR_volume_abs2rel(($1 / 10 ** $2)));
- readingsBulkUpdate($hash, "mute", lc($3));
-
- $hash->{helper}{USE_SHORT_VOL_CMD} = "0";
- }
- elsif($return =~ /(.+)<\/Val>(.+)<\/Exp>.+<\/Unit><\/Lvl>(.+)<\/Mute>.*<\/Vol>/)
- {
- readingsBulkUpdate($hash, "volumeStraight", ($1 / 10 ** $2));
- readingsBulkUpdate($hash, "volume", YAMAHA_AVR_volume_abs2rel(($1 / 10 ** $2)));
- readingsBulkUpdate($hash, "mute", lc($3));
-
- $hash->{helper}{USE_SHORT_VOL_CMD} = "1";
- }
-
-
- # (only available in zones other than mainzone) absolute or relative volume change to the mainzone
- if($return =~ /.*?(.+?)<\/Output>.*?<\/Volume>/)
- {
- readingsBulkUpdate($hash, "output", lc($1));
- }
- elsif($return =~ /.*?(.+?)<\/Output>.*?<\/Vol>/)
- {
- readingsBulkUpdate($hash, "output", lc($1));
- }
- else
- {
- # delete the reading if this information is not available
- delete($hash->{READINGS}{output}) if(defined($hash->{READINGS}{output}));
- }
-
- # current input same as the corresponding set command name
- if($return =~ /(.+)<\/Input_Sel>/)
- {
- readingsBulkUpdate($hash, "input", YAMAHA_AVR_Param2Fhem(lc($1), 0));
-
- if($return =~ /(.+?)<\/Src_Name>/)
- {
- Log3 $name, 4, "YAMAHA_AVR $name: check for extended informations";
-
- my $infos = YAMAHA_AVR_SendCommand($hash, "<$1>GetParam $1> ");
-
- if($infos =~ /.*?(.+?)<\/Artist>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentArtist", YAMAHA_AVR_html2txt($1));
- }
- else
- {
- readingsBulkUpdate($hash, "currentArtist", "", 0);
- }
-
- if($infos =~ /.*?(.+?)<\/Station>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentStation", YAMAHA_AVR_html2txt($1));
- }
- elsif($infos =~ /.*?(.+?)<\/Program_Service>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentStation", YAMAHA_AVR_html2txt($1));
- }
- else
- {
- readingsBulkUpdate($hash, "currentStation", "", 0);
- }
-
-
- if($infos =~ /.*?(.+?)<\/Channel>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentChannel", $1);
- }
- else
- {
- readingsBulkUpdate($hash, "currentChannel", "", 0);
- }
-
- if($infos =~ /.*?(.+?)<\/Album>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentAlbum", YAMAHA_AVR_html2txt($1));
- }
- else
- {
- readingsBulkUpdate($hash, "currentAlbum", "", 0);
- }
-
- if($infos =~ /.*?(.+?)<\/Song>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1));
- }
- elsif($infos =~ /.*?(.+?)<\/Radio_Text_A>.*?<\/Meta_Info>/)
- {
- my $tmp = $1;
-
- if($infos =~ /.*?(.+?)<\/Radio_Text_A>.*?(.+?)<\/Radio_Text_B>.*?<\/Meta_Info>/)
- {
- readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1." ".$2));
- }
- else
- {
- readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($tmp));
- }
- }
- elsif($infos =~ /.*?(.+?)<\/Radio_Text_B>.*?<\/Meta_Info>/)
- {
-
- readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1));
-
- }
- else
- {
- readingsBulkUpdate($hash, "currentTitle", "", 0);
- }
-
- if($infos =~ /(.+?)<\/Playback_Info>/)
- {
- readingsBulkUpdate($hash, "playStatus", lc($1));
- }
-
- }
- else
- {
- readingsBulkUpdate($hash, "currentAlbum", "", 0);
- readingsBulkUpdate($hash, "currentTitle", "", 0);
- readingsBulkUpdate($hash, "currentChannel", "", 0);
- readingsBulkUpdate($hash, "currentStation", "", 0);
- readingsBulkUpdate($hash, "currentArtist", "", 0);
- }
- }
-
- # input name as it is displayed on the receivers front display
- if($return =~ / .*?\s*(.+?)\s*<\/Title>.*<\/Input>/)
- {
- readingsBulkUpdate($hash, "inputName", $1);
- }
-
- if($return =~ /.*?.*?(.+?)<\/Straight>.*?<\/Current>.*?<\/Surround>/)
- {
- readingsBulkUpdate($hash, "straight", lc($1));
- }
-
- if($return =~ /.*?.*?(.+?)<\/Enhancer>.*?<\/Current>.*?<\/Surround>/)
- {
- readingsBulkUpdate($hash, "enhancer", lc($1));
- }
-
- if($return =~ /.*?.*?(.+?)<\/Sound_Program>.*?<\/Current>.*?<\/Surround>/)
- {
- readingsBulkUpdate($hash, "dsp", YAMAHA_AVR_Param2Fhem($1, 0));
- }
-
- if($return =~ /.*?<_3D_Cinema_DSP>(.+?)<\/_3D_Cinema_DSP>*?<\/Surround>/)
- {
- readingsBulkUpdate($hash, "3dCinemaDsp", lc($1));
- }
-
- if($return =~ /.*?(.+?)<\/Adaptive_DRC>.*?<\/Sound_Video>/)
- {
- readingsBulkUpdate($hash, "adaptiveDrc", lc($1));
- }
-
- if($return =~ /.*?(.+?)<\/Sleep>.*?<\/Power_Control>/)
- {
- readingsBulkUpdate($hash, "sleep", YAMAHA_AVR_Param2Fhem($1, 0));
- }
-
- if($return =~ /.*?.*?(.+?)<\/Mode>.*?<\/Direct>.*?<\/Sound_Video>/)
- {
- readingsBulkUpdate($hash, "direct", lc($1));
- $hash->{helper}{DIRECT_TAG} = "Direct";
- }
- elsif($return =~ /.*?.*?(.+?)<\/Mode>.*?<\/Pure_Direct>.*?<\/Sound_Video>/)
- {
- readingsBulkUpdate($hash, "direct", lc($1));
- $hash->{helper}{DIRECT_TAG} = "Pure_Direct";
- }
- else
- {
- delete($hash->{helper}{DIRECT_TAG}) if(exists($hash->{helper}{DIRECT_TAG}));
- }
-
-
-
- readingsEndUpdate($hash, 1);
+ YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ", "statusRequest", "basicStatus");
YAMAHA_AVR_ResetTimer($hash) unless($local == 1);
-
- Log3 $name, 4, "YAMAHA_AVR $name: ".$hash->{STATE};
-
- return $hash->{STATE};
}
###################################
@@ -365,28 +148,25 @@ YAMAHA_AVR_Set($@)
my ($hash, @a) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
- my $result = "";
- my $command;
- my $target_volume;
# get the model informations and available zones if no informations are available
- if(not defined($hash->{ACTIVE_ZONE}) or not defined($hash->{helper}{ZONES}) or not defined($hash->{MODEL}) or not defined($hash->{FIRMWARE}))
+ if(not defined($hash->{ACTIVE_ZONE}) or not defined($hash->{helper}{ZONES}))
{
YAMAHA_AVR_getModel($hash);
+ return "Unable to execute \"".join(" ",@a)."\" - please perform a statusRequest first";
}
# get all available inputs if nothing is available
- if(not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0)
+ if((not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0) or (not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0))
{
YAMAHA_AVR_getInputs($hash);
+ return "Unable to execute \"".join(" ",@a)."\" - please perform a statusRequest first";
}
my $zone = YAMAHA_AVR_getParamName($hash, $hash->{ACTIVE_ZONE}, $hash->{helper}{ZONES});
my $inputs_piped = defined($hash->{helper}{INPUTS}) ? YAMAHA_AVR_Param2Fhem(lc($hash->{helper}{INPUTS}), 0) : "" ;
my $inputs_comma = defined($hash->{helper}{INPUTS}) ? YAMAHA_AVR_Param2Fhem(lc($hash->{helper}{INPUTS}), 1) : "" ;
-
-
my $scenes_piped = defined($hash->{helper}{SCENES}) ? YAMAHA_AVR_Param2Fhem(lc($hash->{helper}{SCENES}), 0) : "" ;
my $scenes_comma = defined($hash->{helper}{SCENES}) ? YAMAHA_AVR_Param2Fhem(lc($hash->{helper}{SCENES}), 1) : "" ;
@@ -400,263 +180,33 @@ YAMAHA_AVR_Set($@)
my $what = $a[1];
my $usage = "Unknown argument $what, choose one of on:noArg off:noArg volumeStraight:slider,-80,1,16 volume:slider,0,1,100 volumeUp volumeDown input:".$inputs_comma." mute:on,off,toggle remoteControl:setup,up,down,left,right,return,option,display,tunerPresetUp,tunerPresetDown,enter ".(defined($hash->{helper}{SCENES})?"scene:".$scenes_comma." ":"").($hash->{helper}{SELECTED_ZONE} eq "mainzone" ? "straight:on,off 3dCinemaDsp:off,auto adaptiveDrc:off,auto ".(exists($hash->{helper}{DIRECT_TAG}) ? "direct:on,off " : "").(exists($hash->{helper}{DSP_MODES}) ? "dsp:".$dsp_modes_comma." " : "")." enhancer:on,off " : "")."sleep:off,30min,60min,90min,120min,last statusRequest:noArg";
- # Depending on the status response, use the short or long Volume command
-
- my $volume_cmd = (exists($hash->{helper}{USE_SHORT_VOL_CMD}) and $hash->{helper}{USE_SHORT_VOL_CMD} eq "1" ? "Vol" : "Volume");
-
-
- if($what eq "on")
- {
-
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> ");
-
- if($result =~ /RC="0"/ and $result =~ /<\/Power>/)
- {
- # As the receiver startup takes about 5 seconds, the status will be already set, if the return code of the command is 0.
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "power", "on");
- readingsBulkUpdate($hash, "state","on");
- readingsEndUpdate($hash, 1);
- return undef;
- }
- else
- {
- return "Could not set power to on";
- }
-
- }
- elsif($what eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Standby $zone> ");
-
- if(not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set power to off";
- }
-
- }
- elsif($what eq "input")
- {
- if(defined($a[2]))
- {
- if($hash->{READINGS}{power}{VAL} eq "on")
- {
- if(not $inputs_piped eq "")
- {
- if($a[2] =~ /^($inputs_piped)$/)
- {
- $command = YAMAHA_AVR_getParamName($hash, $a[2], $hash->{helper}{INPUTS});
- if(defined($command) and length($command) > 0)
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>".$command." $zone> ");
- }
- else
- {
- return "invalid input: ".$a[2];
- }
-
- 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].".";
- }
- }
- else
- {
- return $usage;
- }
- }
- else
- {
- return "No inputs are avaible. Please try an statusUpdate.";
- }
- }
- else
- {
- return "input can only be used when device is powered on";
- }
- }
- else
- {
- return $inputs_piped eq "" ? "No inputs are available. Please try an statusUpdate." : "No input parameter was given";
- }
- }
- elsif($what eq "scene")
- {
- if(defined($a[2]))
- {
-
- if(not $scenes_piped eq "")
- {
- if($a[2] =~ /^($scenes_piped)$/)
- {
- $command = YAMAHA_AVR_getParamName($hash, $a[2], $hash->{helper}{SCENES});
- if(defined($command) and length($command) > 0)
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>".$command." $zone> ");
- }
- else
- {
- return "invalid input: ".$a[2];
- }
-
- if(not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set scene to ".$a[2].".";
- }
- }
- else
- {
- return $usage;
- }
- }
- else
- {
- return "No scenes are avaible. Please try an statusUpdate.";
- }
- }
- else
- {
- return $scenes_piped eq "" ? "No scenes are available. Please try an statusUpdate." : "No scene parameter was given";
- }
- }
-
- elsif($what eq "mute")
- {
- if(defined($a[2]))
- {
- if($hash->{READINGS}{power}{VAL} eq "on")
- {
- if( $a[2] eq "on")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>On $volume_cmd>$zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>Off $volume_cmd>$zone> ");
- }
- elsif($a[2] eq "toggle")
- {
- if(ReadingsVal($hash->{NAME}, "mute", "off") eq "on")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>Off $volume_cmd>$zone> ");
- }
- else
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>On $volume_cmd>$zone> ");
- }
- }
- else
- {
- return $usage;
- }
-
- if(not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set mute to ".$a[2].".";
- }
- }
- else
- {
- return "mute can only used when device is powered on";
- }
- }
- }
- elsif($what =~ /(volumeStraight|volume|volumeUp|volumeDown)/)
- {
-
- if($what eq "volume" and $a[2] >= 0 && $a[2] <= 100)
- {
- $target_volume = YAMAHA_AVR_volume_rel2abs($a[2]);
- }
- elsif($what eq "volumeDown")
- {
- $target_volume = YAMAHA_AVR_volume_rel2abs($hash->{READINGS}{volume}{VAL} - ((defined($a[2]) and $a[2] =~ /^\d+$/) ? $a[2] : AttrVal($hash->{NAME}, "volumeSteps",5)));
- }
- elsif($what eq "volumeUp")
- {
- $target_volume = YAMAHA_AVR_volume_rel2abs($hash->{READINGS}{volume}{VAL} + ((defined($a[2]) and $a[2] =~ /^\d+$/) ? $a[2] : AttrVal($hash->{NAME}, "volumeSteps",5)));
- }
- else
- {
- $target_volume = $a[2];
- }
-
- if(defined($target_volume) && $target_volume >= -80.5 && $target_volume < 16.5)
- {
- if($hash->{READINGS}{power}{VAL} eq "on")
- {
- if(AttrVal($name, "volume-smooth-change", "0") eq "1")
- {
- my $diff = int(($target_volume - $hash->{READINGS}{volumeStraight}{VAL}) / AttrVal($hash->{NAME}, "volume-smooth-steps", 5) / 0.5) * 0.5;
- my $steps = AttrVal($name, "volume-smooth-steps", 5);
- my $current_volume = $hash->{READINGS}{volumeStraight}{VAL};
-
- if($diff > 0)
- {
- Log3 $name, 4, "YAMAHA_AVR: use smooth volume change (with $steps steps of +$diff volume change)";
- }
- else
- {
- Log3 $name, 4, "YAMAHA_AVR: use smooth volume change (with $steps steps of $diff volume change)";
- }
-
- # Only if a volume reading exists and smoohing is really needed (step difference is not zero)
- if(defined($hash->{READINGS}{volumeStraight}{VAL}) and $diff != 0)
- {
- for(my $step = 1; $step <= $steps; $step++)
- {
- Log3 $name, 4, "YAMAHA_AVR: set volume to ".($current_volume + ($diff * $step))." dB";
-
- YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".(($current_volume + ($diff * $step))*10)." 1 dB $volume_cmd>$zone> ");
-
- }
- }
- }
-
- # Set the desired volume
- Log3 $name, 4, "YAMAHA_AVR: set volume to ".$target_volume." dB";
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".($target_volume*10)." 1 dB $volume_cmd>$zone> ");
- if(not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set volume to ".$target_volume.".";
- }
-
- }
- else
- {
- return "volume can only be used when device is powered on";
- }
- }
- }
- elsif($what eq "dsp")
+ if($what eq "on")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> " ,$what,undef);
+ }
+ elsif($what eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Standby $zone> ", $what, undef);
+ }
+ elsif($what eq "input")
+ {
+ if(defined($a[2]))
{
- if(defined($a[2]))
- {
-
- if(not $dsp_modes_piped eq "")
- {
- if($a[2] =~ /^($dsp_modes_piped)$/)
- {
- $command = YAMAHA_AVR_getParamName($hash, $a[2],$hash->{helper}{DSP_MODES});
+ if($hash->{READINGS}{power}{VAL} eq "on")
+ {
+ if(not $inputs_piped eq "")
+ {
+ if($a[2] =~ /^($inputs_piped)$/)
+ {
+ my $command = YAMAHA_AVR_getParamName($hash, $a[2], $hash->{helper}{INPUTS});
if(defined($command) and length($command) > 0)
{
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>$command $zone> ");
+ YAMAHA_AVR_SendCommand($hash, "<$zone>".$command." $zone> ", $what, $a[2]);
}
else
{
- return "invalid dsp mode: ".$a[2];
- }
-
- if(not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set dsp mode to ".$a[2].".";
- }
+ return "invalid input: ".$a[2];
+ }
}
else
{
@@ -665,243 +215,367 @@ YAMAHA_AVR_Set($@)
}
else
{
- return "No DSP presets are avaible. Please try an statusUpdate.";
+ return "No inputs are avaible. Please try an statusUpdate.";
}
}
else
{
- return $dsp_modes_piped eq "" ? "No dsp presets are available. Please try an statusUpdate." : "No dsp preset was given";
+ return "input can only be used when device is powered on";
}
}
- elsif($what eq "straight")
+ else
{
-
- $result = undef;
-
- if($a[2] eq "on")
+ return $inputs_piped eq "" ? "No inputs are available. Please try an statusUpdate." : "No input parameter was given";
+ }
+ }
+ elsif($what eq "scene")
+ {
+ if(defined($a[2]))
+ {
+
+ if(not $scenes_piped eq "")
{
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ");
+ if($a[2] =~ /^($scenes_piped)$/)
+ {
+ my $command = YAMAHA_AVR_getParamName($hash, $a[2], $hash->{helper}{SCENES});
+ if(defined($command) and length($command) > 0)
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>".$command." $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return "invalid input: ".$a[2];
+ }
+ }
+ else
+ {
+ return $usage;
+ }
}
else
{
- return $usage;
- }
-
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set straight to ".$a[2].".";
+ return "No scenes are avaible. Please try an statusUpdate.";
}
}
- elsif($what eq "3dCinemaDsp")
- {
-
- $result = undef;
+ else
+ {
+ return $scenes_piped eq "" ? "No scenes are available. Please try an statusUpdate." : "No scene parameter was given";
+ }
+ }
+ elsif($what eq "mute")
+ {
+ if(defined($a[2]))
+ {
+ if($hash->{READINGS}{power}{VAL} eq "on")
+ {
+ # Depending on the status response, use the short or long Volume command
+ my $volume_cmd = (exists($hash->{helper}{USE_SHORT_VOL_CMD}) and $hash->{helper}{USE_SHORT_VOL_CMD} eq "1" ? "Vol" : "Volume");
- if($a[2] eq "auto")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><_3D_Cinema_DSP>Auto $zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><_3D_Cinema_DSP>Off $zone> ");
+ if( $a[2] eq "on" or ($a[2] eq "toggle" and ReadingsVal($hash->{NAME}, "mute", "off") eq "off"))
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>On $volume_cmd>$zone> ", $what, "on");
+ }
+ elsif($a[2] eq "off" or ($a[2] eq "toggle" and ReadingsVal($hash->{NAME}, "mute", "off") eq "on"))
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>Off $volume_cmd>$zone> ", $what, "off");
+ }
+ else
+ {
+ return $usage;
+ }
}
else
{
- return $usage;
- }
-
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set 3dCinemaDsp to ".$a[2].".";
+ return "mute can only used when device is powered on";
}
}
- elsif($what eq "adaptiveDrc")
- {
+ }
+ elsif($what =~ /(volumeStraight|volume|volumeUp|volumeDown)/)
+ {
+ my $target_volume;
- $result = undef;
-
- if($a[2] eq "auto")
+ if($what eq "volume" and $a[2] >= 0 && $a[2] <= 100)
+ {
+ $target_volume = YAMAHA_AVR_volume_rel2abs($a[2]);
+ }
+ elsif($what eq "volumeDown")
+ {
+ $target_volume = YAMAHA_AVR_volume_rel2abs($hash->{READINGS}{volume}{VAL} - ((defined($a[2]) and $a[2] =~ /^\d+$/) ? $a[2] : AttrVal($hash->{NAME}, "volumeSteps",5)));
+ }
+ elsif($what eq "volumeUp")
+ {
+ $target_volume = YAMAHA_AVR_volume_rel2abs($hash->{READINGS}{volume}{VAL} + ((defined($a[2]) and $a[2] =~ /^\d+$/) ? $a[2] : AttrVal($hash->{NAME}, "volumeSteps",5)));
+ }
+ else
+ {
+ $target_volume = $a[2];
+ }
+
+ # if lower than minimum (-80.5) or higher than max (16.5) set target volume to the corresponding boundary
+ $target_volume = -80.5 if(defined($target_volume) and $target_volume < -80.5);
+ $target_volume = 16.5 if(defined($target_volume) and $target_volume > 16.5);
+
+ Log3 $name, 4, "YAMAHA_AVR ($name) - new target volume: $target_volume";
+
+ if(defined($target_volume) )
+ {
+ if($hash->{READINGS}{power}{VAL} eq "on")
{
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Auto $zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ");
- }
- else
- {
- return $usage;
- }
+ # Depending on the status response, use the short or long Volume command
+ my $volume_cmd = (exists($hash->{helper}{USE_SHORT_VOL_CMD}) and $hash->{helper}{USE_SHORT_VOL_CMD} eq "1" ? "Vol" : "Volume");
+
+ if(AttrVal($name, "volume-smooth-change", "0") eq "1")
+ {
+
+ my $steps = AttrVal($name, "volume-smooth-steps", 5);
+ my $diff = int(($target_volume - $hash->{READINGS}{volumeStraight}{VAL}) / $steps / 0.5) * 0.5;
+ my $current_volume = $hash->{READINGS}{volumeStraight}{VAL};
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set adaptiveDrc to ".$a[2].".";
- }
- }
- elsif($what eq "enhancer")
- {
-
- $result = undef;
+ if($diff > 0)
+ {
+ Log3 $name, 4, "YAMAHA_AVR: use smooth volume change (with $steps steps of +$diff volume change to reach $target_volume)";
+ }
+ else
+ {
+ Log3 $name, 4, "YAMAHA_AVR: use smooth volume change (with $steps steps of $diff volume change to reach $target_volume)";
+ }
- if($a[2] eq "on")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ");
+ # Only if a volume reading exists and smoohing is really needed (step difference is not zero)
+ if(defined($hash->{READINGS}{volumeStraight}{VAL}) and $diff != 0)
+ {
+ Log3 $name, 4, "YAMAHA_AVR: set volume to ".($current_volume + $diff)." dB (target is $target_volume dB)";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".(($current_volume + $diff)*10)." 1 dB $volume_cmd>$zone> ", "volume", ($current_volume + $diff)."|$diff|$target_volume" );
+ }
+ else
+ {
+ # Set the desired volume
+ Log3 $name, 4, "YAMAHA_AVR: set volume to ".$target_volume." dB";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".($target_volume*10)." 1 dB $volume_cmd>$zone> ", "volume", "$target_volume|0|$target_volume");
+ }
+ }
+ else
+ {
+ # Set the desired volume
+ Log3 $name, 4, "YAMAHA_AVR: set volume to ".$target_volume." dB";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".($target_volume*10)." 1 dB $volume_cmd>$zone> ", "volume", "$target_volume|0|$target_volume");
+ }
}
else
{
- return $usage;
- }
-
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set enhancer to ".$a[2].".";
+ return "volume can only be used when device is powered on";
}
}
- elsif($what eq "direct" and exists($hash->{helper}{DIRECT_TAG}))
+ }
+ elsif($what eq "dsp")
+ {
+ if(defined($a[2]))
{
-
- $result = undef;
-
- if($a[2] eq "on")
+ if(not $dsp_modes_piped eq "")
{
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><".$hash->{helper}{DIRECT_TAG}.">On ".$hash->{helper}{DIRECT_TAG}."> $zone> ");
- }
- elsif($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone><".$hash->{helper}{DIRECT_TAG}.">Off ".$hash->{helper}{DIRECT_TAG}."> $zone> ");
+ if($a[2] =~ /^($dsp_modes_piped)$/)
+ {
+ my $command = YAMAHA_AVR_getParamName($hash, $a[2],$hash->{helper}{DSP_MODES});
+ if(defined($command) and length($command) > 0)
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>$command $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return "invalid dsp mode: ".$a[2];
+ }
+ }
+ else
+ {
+ return $usage;
+ }
}
else
{
- return $usage;
- }
-
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set direct to ".$a[2].".";
+ return "No DSP presets are avaible. Please try an statusUpdate.";
}
}
- elsif($what eq "sleep")
- {
- $result = undef;
-
- if($a[2] eq "off")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ");
- }
- elsif($a[2] eq "30min")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>30 min $zone> ");
- }
- elsif($a[2] eq "60min")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>60 min $zone> ");
- }
- elsif($a[2] eq "90min")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>90 min $zone> ");
- }
- elsif($a[2] eq "120min")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>120 min $zone> ");
- }
- elsif($a[2] eq "last")
- {
- $result = YAMAHA_AVR_SendCommand($hash, "<$zone>Last $zone> ");
- }
- else
- {
- return $usage;
- }
-
- if(not defined($result) or not $result =~ /RC="0"/)
- {
- # if the returncode isn't 0, than the command was not successful
- return "Could not set sleep timer to ".$a[2].".";
- }
- }
- elsif($what eq "remoteControl")
+ else
{
-
- # the RX-Vx75 series use a different tag name to access the remoteControl commands
- my $control_tag = ($hash->{MODEL} =~ /RX-V\d75/ ? "Cursor_Control" : "List_Control");
-
- if($a[2] eq "up")
- {
- YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Up $control_tag>$zone> ");
- }
- elsif($a[2] eq "down")
- {
- YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Down $control_tag>$zone> ");
- }
- elsif($a[2] eq "left")
- {
- YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Left $control_tag>$zone> ");
- }
- elsif($a[2] eq "right")
- {
- YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Right $control_tag>$zone> ");
- }
- elsif($a[2] eq "display")
- {
- YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Display $control_tag>$zone> ");
- }
- elsif($a[2] eq "return")
- {
- YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Return $control_tag>$zone> ");
- }
- elsif($a[2] eq "enter")
- {
- YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Sel $control_tag>$zone> ");
- }
- elsif($a[2] eq "setup")
- {
- YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>On Screen $control_tag>$zone> ");
- }
- elsif($a[2] eq "option")
- {
- YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Option $control_tag>$zone> ");
- }
- elsif($a[2] eq "tunerPresetUp")
- {
- YAMAHA_AVR_SendCommand($hash,"Up ");
- }
- elsif($a[2] eq "tunerPresetDown")
- {
- YAMAHA_AVR_SendCommand($hash,"Down ");
- }
- else
- {
- return $usage;
- }
+ return $dsp_modes_piped eq "" ? "No dsp presets are available. Please try an statusUpdate." : "No dsp preset was given";
}
- elsif($what eq "statusRequest")
+ }
+ elsif($what eq "straight")
+ {
+ if($a[2] eq "on")
{
- # Will be executed anyway on the end of the function
+ YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ elsif($what eq "3dCinemaDsp")
+ {
+ if($a[2] eq "auto")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><_3D_Cinema_DSP>Auto $zone> ", "3dCinemaDsp", "auto");
+ }
+ elsif($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><_3D_Cinema_DSP>Off $zone> ", "3dCinemaDsp", "off");
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ elsif($what eq "adaptiveDrc")
+ {
+ if($a[2] eq "auto")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Auto $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ", $what, $a[2]);
}
else
{
return $usage;
}
-
+ }
+ elsif($what eq "enhancer")
+ {
+ if($a[2] eq "on")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>On $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ elsif($what eq "direct" )
+ {
+ if(exists($hash->{helper}{DIRECT_TAG}))
+ {
+ if($a[2] eq "on")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><".$hash->{helper}{DIRECT_TAG}.">On ".$hash->{helper}{DIRECT_TAG}."> $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><".$hash->{helper}{DIRECT_TAG}.">Off ".$hash->{helper}{DIRECT_TAG}."> $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ else
+ {
+ return "Unable to execute \"$what ".$a[2]."\" - please execute a statusUpdate first before you use this command";
+ }
+ }
+ elsif($what eq "sleep")
+ {
+ if($a[2] eq "off")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Off $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "30min")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>30 min $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "60min")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>60 min $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "90min")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>90 min $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "120min")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>120 min $zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "last")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone>Last $zone> ", $what, $a[2]);
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ elsif($what eq "remoteControl")
+ {
+
+ # the RX-Vx75 series use a different tag name to access the remoteControl commands
+ my $control_tag = ($hash->{MODEL} =~ /RX-V\d75/ ? "Cursor_Control" : "List_Control");
+
+ if($a[2] eq "up")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Up $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "down")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Down $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "left")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Left $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "right")
+ {
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$control_tag>Right $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "display")
+ {
+ YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Display $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "return")
+ {
+ YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Return $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "enter")
+ {
+ YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Sel $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "setup")
+ {
+ YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>On Screen $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "option")
+ {
+ YAMAHA_AVR_SendCommand($hash,"<$zone><$control_tag>Option $control_tag>$zone> ", $what, $a[2]);
+ }
+ elsif($a[2] eq "tunerPresetUp")
+ {
+ YAMAHA_AVR_SendCommand($hash,"Up ", $what, $a[2]);
+ }
+ elsif($a[2] eq "tunerPresetDown")
+ {
+ YAMAHA_AVR_SendCommand($hash,"Down ", $what, $a[2]);
+ }
+ else
+ {
+ return $usage;
+ }
+ }
+ elsif($what ne "statusRequest")
+ {
+ return $usage;
+ }
# Call the GetStatus() Function to retrieve the new values after setting something (with local flag, so the internal timer is not getting interupted)
YAMAHA_AVR_GetStatus($hash, 1);
- return undef;
-
+ return undef;
}
@@ -1047,48 +721,419 @@ YAMAHA_AVR_Undefine($$)
#############################
sub
-YAMAHA_AVR_SendCommand($$;$)
+YAMAHA_AVR_SendCommand($@)
{
- my ($hash, $command, $loglevel) = @_;
+ my ($hash, $data,$cmd,$arg) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
- my $response;
- Log3 $name, 5, "YAMAHA_AVR: execute on $name: $command";
+ Log3 $name, 5, "YAMAHA_AVR ($name) - execute \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
# In case any URL changes must be made, this part is separated in this function".
- $response = GetFileFromURL("http://".$address."/YamahaRemoteControl/ctrl", AttrVal($name, "request-timeout", 4) , "".$command, 0, ($hash->{helper}{AVAILABLE} ? undef : 5));
+ HttpUtils_NonblockingGet({
+ url => "http://".$address."/YamahaRemoteControl/ctrl",
+ timeout => AttrVal($name, "request-timeout", 4),
+ noshutdown => 1,
+ data => "".$data,
+ loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
+ hash => $hash,
+ cmd => $cmd,
+ arg => $arg,
+ callback => \&YAMAHA_AVR_ParseResponse
+ }
+ );
- Log3 $name, 5, "YAMAHA_AVR: got response for $name: $response" if(defined($response));
- unless(defined($response))
+
+}
+
+
+sub
+YAMAHA_AVR_ParseResponse ($$$)
+{
+
+ my ( $param, $err, $data ) = @_;
+
+ my $hash = $param->{hash};
+ my $name = $hash->{NAME};
+ my $cmd = $param->{cmd};
+ my $arg = $param->{arg};
+
+ if($err ne "")
{
-
+ Log3 $name, 5, "YAMAHA_AVR ($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} eq 1))
{
- Log3 $name, 3, "YAMAHA_AVR: could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress.";
+ Log3 $name, 3, "YAMAHA_AVR ($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);
- }
- else
- {
- Log3 $name, 5, "YAMAHA_AVR: could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress. (Device is still absent)";
- }
+ }
}
- else
+ elsif($data ne "")
{
+ Log3 $name, 5, "YAMAHA_AVR ($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, "YAMAHA_AVR: device $name reappeared";
+ Log3 $name, 3, "YAMAHA_AVR ($name) - device $name reappeared";
readingsSingleUpdate($hash, "presence", "present", 1);
}
+
+ if(not $data =~ /RC="0"/)
+ {
+ # if the returncode isn't 0, than the command was not successful
+ Log3 $name, 3, "YAMAHA_AVR ($name) - Could not execute \"$cmd".(defined($arg) ? " ".$arg : "")."\"";
+ }
+
+ readingsBeginUpdate($hash);
+
+ if($cmd eq "statusRequest")
+ {
+
+ if($arg eq "unitDescription")
+ {
+ if($data =~ /(.+?)<\/URL>/)
+ {
+ $hash->{helper}{XML} = $1;
+ }
+ else
+ {
+ $hash->{helper}{XML} = "/YamahaRemoteControl/desc.xml";
+ }
+
+ Log3 $name, 5, "YAMAHA_AVR ($name) - requesting unit description XML: http://".$hash->{helper}{ADDRESS}.$hash->{helper}{XML};
+
+ HttpUtils_NonblockingGet({
+ url => "http://".$hash->{helper}{ADDRESS}.$hash->{helper}{XML} ,
+ timeout => AttrVal($name, "request-timeout", 4),
+ noshutdown => 1,
+ loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
+ hash => $hash,
+ callback => \&YAMAHA_AVR_ParseXML
+ }
+ );
+
+ }
+ elsif($arg eq "systemConfig")
+ {
+ if($data =~ /(.+?)<\/Model_Name>.*(.+?)<\/System_ID>.*.*(.+?)<\/Main>.*(.+?)<\/Sub>.*<\/Version>/)
+ {
+ $hash->{MODEL} = $1;
+ $hash->{SYSTEM_ID} = $2;
+ $hash->{FIRMWARE} = $3." ".$4;
+ }
+ elsif($data =~ /(.+?)<\/Model_Name>.*(.+?)<\/System_ID>.*(.+?)<\/Version>/)
+ {
+ $hash->{MODEL} = $1;
+ $hash->{SYSTEM_ID} = $2;
+ $hash->{FIRMWARE} = $3;
+ }
+
+ $attr{$name}{"model"} = $hash->{MODEL};
+ }
+ elsif($arg eq "getInputs")
+ {
+
+ delete($hash->{helper}{INPUTS}) if(exists($hash->{helper}{INPUTS}));
+
+ while($data =~ / (.+?)<\/Param>/gc)
+ {
+ if(defined($hash->{helper}{INPUTS}) and length($hash->{helper}{INPUTS}) > 0)
+ {
+ $hash->{helper}{INPUTS} .= "|";
+ }
+
+ $hash->{helper}{INPUTS} .= $1;
+ }
+
+ $hash->{helper}{INPUTS} = join("|", sort split("\\|", $hash->{helper}{INPUTS}));
+
+ }
+ elsif($arg eq "getScenes")
+ {
+
+ delete($hash->{helper}{SCENES}) if(exists($hash->{helper}{SCENES}));
+
+ # get all available scenes from response
+ while($data =~ /.*? (.+?)<\/Param>.*?(\w+)<\/RW>.*?<\/Item_\d+>/gc)
+ {
+ # check if the RW-value is "W" (means: writeable => can be set through FHEM)
+ if($2 eq "W")
+ {
+ if(defined($hash->{helper}{SCENES}) and length($hash->{helper}{SCENES}) > 0)
+ {
+ $hash->{helper}{SCENES} .= "|";
+ }
+ $hash->{helper}{SCENES} .= $1;
+ }
+ }
+
+ }
+ elsif($arg eq "basicStatus")
+ {
+
+ if($data =~ /(.+)<\/Power>/)
+ {
+ my $power = $1;
+
+ if($power eq "Standby")
+ {
+ $power = "off";
+ }
+ readingsBulkUpdate($hash, "power", lc($power));
+ readingsBulkUpdate($hash, "state", lc($power));
+ }
+
+ # current volume and mute status
+ if($data =~ /(.+)<\/Val>(.+)<\/Exp>.+<\/Unit><\/Lvl>(.+)<\/Mute>.*<\/Volume>/)
+ {
+ readingsBulkUpdate($hash, "volumeStraight", ($1 / 10 ** $2));
+ readingsBulkUpdate($hash, "volume", YAMAHA_AVR_volume_abs2rel(($1 / 10 ** $2)));
+ readingsBulkUpdate($hash, "mute", lc($3));
+
+ $hash->{helper}{USE_SHORT_VOL_CMD} = "0";
+ }
+ elsif($data =~ /(.+)<\/Val>(.+)<\/Exp>.+<\/Unit><\/Lvl>(.+)<\/Mute>.*<\/Vol>/)
+ {
+ readingsBulkUpdate($hash, "volumeStraight", ($1 / 10 ** $2));
+ readingsBulkUpdate($hash, "volume", YAMAHA_AVR_volume_abs2rel(($1 / 10 ** $2)));
+ readingsBulkUpdate($hash, "mute", lc($3));
+
+ $hash->{helper}{USE_SHORT_VOL_CMD} = "1";
+ }
+
+
+ # (only available in zones other than mainzone) absolute or relative volume change to the mainzone
+ if($data =~ /.*?(.+?)<\/Output>.*?<\/Volume>/)
+ {
+ readingsBulkUpdate($hash, "output", lc($1));
+ }
+ elsif($data =~ /.*?(.+?)<\/Output>.*?<\/Vol>/)
+ {
+ readingsBulkUpdate($hash, "output", lc($1));
+ }
+ else
+ {
+ # delete the reading if this information is not available
+ delete($hash->{READINGS}{output}) if(defined($hash->{READINGS}{output}));
+ }
+
+ # current input same as the corresponding set command name
+ if($data =~ /(.+)<\/Input_Sel>/)
+ {
+ readingsBulkUpdate($hash, "input", YAMAHA_AVR_Param2Fhem(lc($1), 0));
+
+ if($data =~ /(.+?)<\/Src_Name>/)
+ {
+ Log3 $name, 4, "YAMAHA_AVR ($name) - check for extended informations";
+
+ YAMAHA_AVR_SendCommand($hash, "<$1>GetParam $1> ", "statusRequest", "playInfo");
+
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentAlbum", "", 0);
+ readingsBulkUpdate($hash, "currentTitle", "", 0);
+ readingsBulkUpdate($hash, "currentChannel", "", 0);
+ readingsBulkUpdate($hash, "currentStation", "", 0);
+ readingsBulkUpdate($hash, "currentArtist", "", 0);
+ }
+ }
+
+ # input name as it is displayed on the receivers front display
+ if($data =~ / .*?\s*(.+?)\s*<\/Title>.*<\/Input>/)
+ {
+ readingsBulkUpdate($hash, "inputName", $1);
+ }
+
+ if($data =~ /.*?.*?(.+?)<\/Straight>.*?<\/Current>.*?<\/Surround>/)
+ {
+ readingsBulkUpdate($hash, "straight", lc($1));
+ }
+
+ if($data =~ /.*?.*?(.+?)<\/Enhancer>.*?<\/Current>.*?<\/Surround>/)
+ {
+ readingsBulkUpdate($hash, "enhancer", lc($1));
+ }
+
+ if($data =~ /.*?.*?(.+?)<\/Sound_Program>.*?<\/Current>.*?<\/Surround>/)
+ {
+ readingsBulkUpdate($hash, "dsp", YAMAHA_AVR_Param2Fhem($1, 0));
+ }
+
+ if($data =~ /.*?<_3D_Cinema_DSP>(.+?)<\/_3D_Cinema_DSP>*?<\/Surround>/)
+ {
+ readingsBulkUpdate($hash, "3dCinemaDsp", lc($1));
+ }
+
+ if($data =~ /.*?(.+?)<\/Adaptive_DRC>.*?<\/Sound_Video>/)
+ {
+ readingsBulkUpdate($hash, "adaptiveDrc", lc($1));
+ }
+
+ if($data =~ /.*?(.+?)<\/Sleep>.*?<\/Power_Control>/)
+ {
+ readingsBulkUpdate($hash, "sleep", YAMAHA_AVR_Param2Fhem($1, 0));
+ }
+
+ if($data =~ /.*?.*?(.+?)<\/Mode>.*?<\/Direct>.*?<\/Sound_Video>/)
+ {
+ readingsBulkUpdate($hash, "direct", lc($1));
+ $hash->{helper}{DIRECT_TAG} = "Direct";
+ }
+ elsif($data =~ /.*?.*?(.+?)<\/Mode>.*?<\/Pure_Direct>.*?<\/Sound_Video>/)
+ {
+ readingsBulkUpdate($hash, "direct", lc($1));
+ $hash->{helper}{DIRECT_TAG} = "Pure_Direct";
+ }
+ else
+ {
+ delete($hash->{helper}{DIRECT_TAG}) if(exists($hash->{helper}{DIRECT_TAG}));
+ }
+
+ }
+ elsif($arg eq "playInfo")
+ {
+
+ if($data =~ /.*?(.+?)<\/Artist>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentArtist", YAMAHA_AVR_html2txt($1));
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentArtist", "", 0);
+ }
+
+ if($data =~ /.*?(.+?)<\/Station>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentStation", YAMAHA_AVR_html2txt($1));
+ }
+ elsif($data =~ /.*?(.+?)<\/Program_Service>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentStation", YAMAHA_AVR_html2txt($1));
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentStation", "", 0);
+ }
+
+
+ if($data =~ /.*?(.+?)<\/Channel>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentChannel", $1);
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentChannel", "", 0);
+ }
+
+ if($data =~ /.*?(.+?)<\/Album>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentAlbum", YAMAHA_AVR_html2txt($1));
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentAlbum", "", 0);
+ }
+
+ if($data =~ /.*?(.+?)<\/Song>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1));
+ }
+ elsif($data =~ /.*?(.+?)<\/Radio_Text_A>.*?<\/Meta_Info>/)
+ {
+ my $tmp = $1;
+
+ if($data =~ /.*?(.+?)<\/Radio_Text_A>.*?(.+?)<\/Radio_Text_B>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1." ".$2));
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($tmp));
+ }
+ }
+ elsif($data =~ /.*?(.+?)<\/Radio_Text_B>.*?<\/Meta_Info>/)
+ {
+ readingsBulkUpdate($hash, "currentTitle", YAMAHA_AVR_html2txt($1));
+ }
+ else
+ {
+ readingsBulkUpdate($hash, "currentTitle", "", 0);
+ }
+
+ if($data =~ /(.+?)<\/Playback_Info>/)
+ {
+ readingsBulkUpdate($hash, "playStatus", lc($1));
+ }
+
+ }
+
+
+
+ }
+ elsif($cmd eq "on")
+ {
+ if($data =~ /RC="0"/ and $data =~ /<\/Power>/)
+ {
+ # As the receiver 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_AVR ($name) - Could not set power to off";
+ }
+
+ }
+ elsif($cmd eq "volume")
+ {
+ my ($current_volume, $diff,$target_volume ) = split("\\|", $arg);
+
+ # Depending on the status response, use the short or long Volume command
+ my $volume_cmd = (exists($hash->{helper}{USE_SHORT_VOL_CMD}) and $hash->{helper}{USE_SHORT_VOL_CMD} eq "1" ? "Vol" : "Volume");
+
+ my $zone = YAMAHA_AVR_getParamName($hash, $hash->{ACTIVE_ZONE}, $hash->{helper}{ZONES});
+
+ if(not $current_volume == $target_volume)
+ {
+
+ if($diff == 0)
+ {
+ Log3 $name, 4, "YAMAHA_AVR ($name) - set volume to ".$target_volume." dB (target is $target_volume dB)";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".($target_volume*10)." 1 dB $volume_cmd>$zone> ", "volume", "$target_volume|0|$target_volume" );
+ return undef;
+ }
+ else
+ {
+
+ if(abs($current_volume - $target_volume) < abs($diff))
+ {
+ Log3 $name, 4, "YAMAHA_AVR ($name) - set volume to ".$target_volume." dB (target is $target_volume dB)";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".($target_volume*10)." 1 dB $volume_cmd>$zone> ", "volume", "$target_volume|0|$target_volume" );
+ return undef;
+ }
+ else
+ {
+ Log3 $name, 4, "YAMAHA_AVR ($name) - set volume to ".($current_volume + $diff)." dB (target is $target_volume dB)";
+ YAMAHA_AVR_SendCommand($hash, "<$zone><$volume_cmd>".(($current_volume + $diff)*10)." 1 dB $volume_cmd>$zone> ", "volume", ($current_volume + $diff)."|$diff|$target_volume" );
+ return undef;
+ }
+ }
+ }
+ }
+
+ readingsEndUpdate($hash, 1);
+
+ YAMAHA_AVR_GetStatus($hash, 1) if($cmd ne "statusRequest");
}
- $hash->{helper}{AVAILABLE} = (defined($response) ? 1 : 0);
-
- return $response;
+ $hash->{helper}{AVAILABLE} = ($err eq "" ? 1 : 0);
}
@@ -1134,7 +1179,6 @@ sub YAMAHA_AVR_getParamName($$$)
}
return undef;
-
}
@@ -1144,63 +1188,28 @@ sub YAMAHA_AVR_getParamName($$$)
sub YAMAHA_AVR_getModel($)
{
my ($hash) = @_;
- my $name = $hash->{NAME};
- my $address = $hash->{helper}{ADDRESS};
- my $response;
- my $desc_url;
-
- $response = YAMAHA_AVR_SendCommand($hash, "GetParam ");
-
- if (not defined($response))
- {
- return undef;
- }
-
- if(defined($response) and $response =~ /(.+?)<\/URL>/)
- {
- $desc_url = $1;
- }
- else
- {
- $desc_url = "/YamahaRemoteControl/desc.xml";
- }
-
- $response = YAMAHA_AVR_SendCommand($hash, "GetParam ");
-
- if(not defined($response))
- {
- return undef;
- }
-
- if(defined($response) and $response =~ /(.+?)<\/Model_Name>.*(.+?)<\/System_ID>.*.*(.+?)<\/Main>.*(.+?)<\/Sub>.*<\/Version>/)
- {
- $hash->{MODEL} = $1;
- $hash->{SYSTEM_ID} = $2;
- $hash->{FIRMWARE} = $3." ".$4;
- }
- elsif(defined($response) and $response =~ /(.+?)<\/Model_Name>.*(.+?)<\/System_ID>.*(.+?)<\/Version>/)
- {
- $hash->{MODEL} = $1;
- $hash->{SYSTEM_ID} = $2;
- $hash->{FIRMWARE} = $3;
- }
- else
- {
- return undef;
- }
-
- $attr{$name}{"model"} = $hash->{MODEL};
+
+ YAMAHA_AVR_SendCommand($hash, "GetParam ", "statusRequest","unitDescription");
+ YAMAHA_AVR_SendCommand($hash, "GetParam ", "statusRequest","systemConfig");
+}
- # query the description url which contains all zones
- $response = GetFileFromURL("http://".$address.$desc_url, AttrVal($name, "request-timeout", 4), undef, 0, ($hash->{helper}{AVAILABLE} ? undef : 5));
+#############################
+# parses the HTTP response for unit description XML file
+sub
+YAMAHA_AVR_ParseXML($$$)
+{
+ my ($param, $err, $data) = @_;
- Log3 $name, 3, "YAMAHA_AVR: could not get unit description from device $name. Please turn on the device or check for correct hostaddress!" if (not defined($response) and defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 1);
+ my $hash = $param->{hash};
+ my $name = $hash->{NAME};
+
+ Log3 $name, 3, "YAMAHA_AVR ($name) - could not get unit description. Please turn on the device or check for correct hostaddress!" if ($err ne "" and defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 1);
- return undef unless(defined($response));
+ return undef if($data eq "");
delete($hash->{helper}{ZONES}) if(exists($hash->{helper}{ZONES}));
- while($response =~ //gc)
+ while($data =~ //gc)
{
if(defined($hash->{helper}{ZONES}) and length($hash->{helper}{ZONES}) > 0)
{
@@ -1213,7 +1222,7 @@ sub YAMAHA_AVR_getModel($)
delete( $hash->{helper}{DSP_MODES}) if(exists($hash->{helper}{DSP_MODES}));
- if($response =~ /.*?(.+?)<\/Get>/)
+ if($data =~ /.*?(.+?)<\/Get>/)
{
my $modes = $1;
@@ -1238,15 +1247,15 @@ sub YAMAHA_AVR_getModel($)
# if explicitly given in the define command, set the desired zone
if(defined(YAMAHA_AVR_getParamName($hash, lc $hash->{helper}{SELECTED_ZONE}, $hash->{helper}{ZONES})))
{
- Log3 $name, 4, "YAMAHA_AVR: using zone ".YAMAHA_AVR_getParamName($hash, lc $hash->{helper}{SELECTED_ZONE}, $hash->{helper}{ZONES});
+ Log3 $name, 4, "YAMAHA_AVR ($name) - using zone ".YAMAHA_AVR_getParamName($hash, lc $hash->{helper}{SELECTED_ZONE}, $hash->{helper}{ZONES});
$hash->{ACTIVE_ZONE} = lc $hash->{helper}{SELECTED_ZONE};
}
else
{
- Log3 $name, 2, "YAMAHA_AVR: selected zone >>".$hash->{helper}{SELECTED_ZONE}."<< is not available on device $name. Using Main Zone instead";
+ Log3 $name, 2, "YAMAHA_AVR ($name) - selected zone >>".$hash->{helper}{SELECTED_ZONE}."<< is not available. Using Main Zone instead";
$hash->{ACTIVE_ZONE} = "mainzone";
}
- return 0;
+
}
sub YAMAHA_AVR_volume_rel2abs($)
@@ -1279,52 +1288,11 @@ sub YAMAHA_AVR_getInputs($)
return undef if (not defined($zone) or $zone eq "");
- my $response = YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ");
-
- if (not defined($response) and defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 1)
- {
- Log3 $name, 3, "YAMAHA_AVR: could not get the available inputs from device $name. Please turn on the device or check for correct hostaddress!!!";
- return undef;
- }
-
- return undef unless (defined($response));
+ # query all inputs
+ YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ", "statusRequest","getInputs");
- delete($hash->{helper}{INPUTS}) if(defined($hash->{helper}{INPUTS}));
-
- while($response =~ / (.+?)<\/Param>/gc)
- {
- if(defined($hash->{helper}{INPUTS}) and length($hash->{helper}{INPUTS}) > 0)
- {
- $hash->{helper}{INPUTS} .= "|";
- }
-
- $hash->{helper}{INPUTS} .= $1;
- }
-
- $hash->{helper}{INPUTS} = join("|", sort split("\\|", $hash->{helper}{INPUTS}));
-
-
# query all available scenes
- $response = YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ", 5);
-
- return undef unless (defined($response));
-
- delete($hash->{helper}{SCENES}) if(defined($hash->{helper}{SCENES}));
-
- # get all available scenes from response
- while($response =~ /.*? (.+?)<\/Param>.*?(\w+)<\/RW>.*?<\/Item_\d+>/gc)
- {
- # check if the RW-value is "W" (means: writeable => can be set through FHEM)
- if($2 eq "W")
- {
- if(defined($hash->{helper}{SCENES}) and length($hash->{helper}{SCENES}) > 0)
- {
- $hash->{helper}{SCENES} .= "|";
- }
- $hash->{helper}{SCENES} .= $1;
- }
- }
-
+ YAMAHA_AVR_SendCommand($hash, "<$zone>GetParam $zone> ", "statusRequest","getScenes");
}
#############################