2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 23:06:37 +00:00
fhem-mirror/fhem/FHEM/71_YAMAHA_NP.pm
ra666ack fd438d6de1 71_YAMAHA_NP: Minor code correction.
git-svn-id: https://svn.fhem.de/fhem/trunk@11114 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2016-03-23 06:41:10 +00:00

2372 lines
100 KiB
Perl

##############################################################################
#
# $Id$
#
# 71_YAMAHA_NP.pm
#
# Fhem Perl module for controlling the Yamaha PianoCraft(TM) HiFi
# Network Audiosystem MCR-N560(D) over Ethernet.
# The system is also marketed as CRX-N560(D).
#
# The module might also work with other devices such as
# NP-S2000, CD-N500, CD-N301, R-N500, R-N301 or any other device
# implementing the Yamaha Network Player Controller(TM) protocol:
#
# i*S:
# https://itunes.apple.com/us/app/network-player-controller-us/id467502483?mt=8
#
# Andr*id:
# https://play.google.com/store/apps/details?id=com.yamaha.npcontroller
#
# Since the used communication protocol is undisclosed the module bases on
# entirely reverse engineered implementation.
# Some features may be unavailable.
# (Online check for new firmware was excluded intentionally.)
#
# Copyright by Radoslaw Watroba (ra666ack a t 9 m a 1 l d 0 t c 0 m)
#
# This file is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday sleep);
use Time::Piece;
use POSIX qw{strftime};
use HttpUtils;
use List::Util qw(first);
###################################
sub YAMAHA_NP_Initialize
{
my ($hash) = @_;
$hash->{DefFn} = "YAMAHA_NP_Define";
$hash->{GetFn} = "YAMAHA_NP_Get";
$hash->{SetFn} = "YAMAHA_NP_Set";
$hash->{AttrFn} = "YAMAHA_NP_Attr";
$hash->{UndefFn} = "YAMAHA_NP_Undefine";
$hash->{AttrList} = "do_not_notify:0,1 disable:0,1 request-timeout:1,2,3,4,5 model auto-update-player-readings:1,0 auto-update-tuner-readings:1,0 smooth-volume-change:1,0 ".$readingFnAttributes;
return;
}
###################################
sub YAMAHA_NP_GetStatus
{
my ($hash, $local) = @_;
my $name = $hash->{NAME};
my $power;
# Local means a timer reset by the module itself
$local = 0 unless(defined($local));
return "" if((!defined($hash->{helper}{ADDRESS})) or (!defined($hash->{helper}{OFF_INTERVAL})) or (!defined($hash->{helper}{ON_INTERVAL})));
my $device = $hash->{helper}{ADDRESS};
# Get model and firmware information
if(not defined($hash->{MODEL}))
{
YAMAHA_NP_getModel($hash);
# Get network related information from the NP
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", "statusRequest", "networkInfo", 0);
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", "statusRequest", "systemConfig", 0);
YAMAHA_NP_ResetTimer($hash, 1);
return;
}
# Get available inputs if not defined
if((not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0))
{
YAMAHA_NP_getInputs($hash);
YAMAHA_NP_ResetTimer($hash, 1);
return;
}
# Timer readings available?
if(not defined($hash->{READINGS}{timerVolume}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Timer><Mode>GetParam</Mode></Timer></Misc></System></YAMAHA_AV>", "statusRequest", "getTimer", 0);
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Timer><Param>GetParam</Param></Timer></Misc></System></YAMAHA_AV>", "statusRequest", "timerStatus", 0);
}
# Standby mode readings available?
if(not defined($hash->{READINGS}{standbyMode}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Power_Control><Saving>GetParam</Saving></Power_Control></System></YAMAHA_AV>", "statusRequest", "standbyMode", 0);
}
# DAB preset readings available? Only for the DAB model.
if (defined $hash->{MODEL})
{
my $model = $hash->{MODEL};
if ($model eq "CRX-N560D")
{
if(not defined($hash->{READINGS}{tunerPresetDABItem_01}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><DAB><Preset_Sel_Item>GetParam</Preset_Sel_Item></DAB></Preset></Play_Control></Tuner></YAMAHA_AV>", "statusRequest", "tunerPresetDAB", 0);
}
}
}
# FM preset readings available?
if(not defined($hash->{READINGS}{tunerPresetFMItem_01}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><FM><Preset_Sel_Item>GetParam</Preset_Sel_Item></FM></Preset></Play_Control></Tuner></YAMAHA_AV>", "statusRequest", "tunerPresetFM", 0);
}
# Basic status request
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Basic_Status>GetParam</Basic_Status></System></YAMAHA_AV>", "statusRequest", "basicStatus", 0);
if(defined($hash->{READINGS}{input}))
{
# Get dynamic tuner readings
if((AttrVal($name, "auto-update-tuner-readings","1") eq "1") and ($hash->{READINGS}{input}{VAL} eq "tuner") and ($hash->{READINGS}{power}{VAL} eq "on"))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Info>GetParam<\/Play_Info><\/Tuner><\/YAMAHA_AV>", "statusRequest", "tunerStatus", 0);
if($hash->{READINGS}{tunerBand}{VAL} eq "FM")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><FM><Preset_Sel_Item>GetParam</Preset_Sel_Item></FM></Preset></Play_Control></Tuner></YAMAHA_AV>", "statusRequest", "tunerPresetFM", 0);
blankTunerDABReadings($hash);
}
elsif($hash->{READINGS}{tunerBand}{VAL} eq "DAB")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><DAB><Preset_Sel_Item>GetParam</Preset_Sel_Item></DAB></Preset></Play_Control></Tuner></YAMAHA_AV>", "statusRequest", "tunerPresetDAB", 0);
blankTunerFMReadings($hash);
}
# Reset player readings
blankPlayerReadings($hash);
}
elsif(AttrVal($name, "auto-update-player-readings", "1") eq "1" and ($hash->{READINGS}{input}{VAL} ne "tuner") and ($hash->{READINGS}{power}{VAL} eq "on"))
{
# Inputs don't use any player readings. Blank them.
if($hash->{READINGS}{input}{VAL} eq "aux1" or
$hash->{READINGS}{input}{VAL} eq "aux2" or
$hash->{READINGS}{input}{VAL} eq "digital1" or
$hash->{READINGS}{input}{VAL} eq "digital2" or
$hash->{READINGS}{input}{VAL} eq "airplay")
{
blankPlayerReadings($hash);
}
else
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Player><Play_Info>GetParam<\/Play_Info><\/Player><\/YAMAHA_AV>", "statusRequest", "playerStatus", 0);
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Player><List_Info>GetParam</List_Info></Player></YAMAHA_AV>", "playerListGetList", "playerListGetList", 0);
}
# Reset tuner readings
readingsSingleUpdate($hash, "tunerBand", "", 1);
blankTunerDABReadings($hash);
blankTunerFMReadings($hash);
}
}
# Reset Timer for the next loop.
YAMAHA_NP_ResetTimer($hash) unless($local == 1);
return;
}
###################################
sub YAMAHA_NP_Get
{
my ($hash, @a) = @_;
my $what;
my $return;
return "Argument missing." if(int(@a) != 2);
$what = $a[1];
if(exists($hash->{READINGS}{$what}))
{
if(defined($hash->{READINGS}{$what}))
{
return $hash->{READINGS}{$what}{VAL};
}
else
{
return "no such reading: $what";
}
}
else
{
$return = "Unknown argument $what, choose one of";
foreach my $reading (keys %{$hash->{READINGS}})
{
$return .= " $reading:noArg";
}
return $return;
}
}
###################################
sub YAMAHA_NP_Set
{
my ($hash, @a) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
# Get model info in case not defined
if(not defined($hash->{MODEL}) or not defined($hash->{FIRMWARE}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", "statusRequest", "networkInfo",0);
YAMAHA_NP_getModel($hash);
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", "statusRequest", "systemConfig", 0);
}
if(not defined($hash->{helper}{VOLUMESTRAIGHTMIN}) and not defined($hash->{helper}{VOLUMESTRAIGHTMAX}))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", "statusRequest", "systemConfig", 0);
}
# Get available inputs in case of empty list
if(not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0)
{
YAMAHA_NP_getInputs($hash);
}
my $inputs_piped = defined($hash->{helper}{INPUTS}) ? YAMAHA_NP_Param2Fhem(lc($hash->{helper}{INPUTS}), 0) : "" ;
my $inputs_comma = defined($hash->{helper}{INPUTS}) ? YAMAHA_NP_Param2Fhem(lc($hash->{helper}{INPUTS}), 1) : "" ;
# Setting default values. Update from device during existing communication.
my $volumeStraightMin = defined($hash->{helper}{VOLUMESTRAIGHTMIN}) ? $hash->{helper}{VOLUMESTRAIGHTMIN} : "0";
my $volumeStraightMax = defined($hash->{helper}{VOLUMESTRAIGHTMAX}) ? $hash->{helper}{VOLUMESTRAIGHTMAX} : "60";
return "No Argument given" if(!defined($a[1]));
my $what = $a[1];
my $usage = "";
# DAB available? Suffix D stands for DAB. "CRX-N560D"
if (defined($hash->{MODEL}))
{
my $model = $hash->{MODEL};
$usage = "Unknown argument $what, choose one of ".
"on:noArg ".
"off:noArg ".
"timerRepeat:once,every ".
"timerSet:noArg ".
"sleep:off,30min,60min,90min,120min ".
"volumeStraight:slider,".$volumeStraightMin.",1,".$volumeStraightMax." ".
"volume:slider,0,1,100 ".
"volumeUp:noArg ".
"volumeDown:noArg ".
"timerVolume:slider,".$volumeStraightMin.",1,".$volumeStraightMax." ".
"mute:on,off ".
(exists($hash->{helper}{INPUTS})?"input:".$inputs_comma." ":"").
"standbyMode:eco,normal ".
"cdTray:noArg ".
"timer:on,off ".
(($model eq "CRX-N560D") ? "statusRequest:basicStatus,mediaRendererDesc,playerStatus,standbyMode,systemConfig,timerStatus,tunerPresetDAB,tunerPresetFM,tunerStatus ":
"statusRequest:basicStatus,mediaRendererDesc,playerStatus,standbyMode,systemConfig,timerStatus,tunerPresetFM,tunerStatus ").
(($model eq "CRX-N560D") ? "tuner:bandDAB,bandFM,presetUp,presetDown,tuneDown,tuneUp " : "tuner:bandFM,presetUp,presetDown,tuneDown,tuneUp ").
(($model eq "CRX-N560D") ? "tunerPresetDAB:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 " : "").
"player:play,stop,pause,next,prev,shuffleToggle,repeatToggle ".
"clockUpdate:noArg ".
"dimmer:1,2,3 ".
"playerListGetList:noArg ".
"playerListJumpLine ".
"playerListSelectLine ".
"playerListCursorReturn:noArg ".
"playerListCursorDown:noArg ".
"playerListCursorUp:noArg ".
"tunerPresetFM:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 ".
"timerHour:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 ".
"tunerFMFrequency ".
"timerMinute:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 ";
Log3 $name, 5, "Model: $model.";
}
Log3 $name, 5, "YAMAHA_NP ($name) - set ".join(" ", @a);
# Processing of SET commands.
# Device Power ON/OFF
#
if($what eq "on")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Power_Control><Power>On</Power></Power_Control></System></YAMAHA_AV>" ,$what, "On", 0);
}
elsif($what eq "off")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Power_Control><Power>Standby</Power></Power_Control></System></YAMAHA_AV>", $what, "Standby", 0);
}
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)$/)
{
my $command = YAMAHA_NP_getParamName($hash, $a[2], $hash->{helper}{INPUTS});
if(defined($command) and length($command) > 0)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Input><Input_Sel>".$command."</Input_Sel></Input></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "invalid input: ".$a[2];
}
}
else
{
return $usage;
}
}
else
{
return "No inputs avaible. Please try an statusRequest.";
}
}
else
{
return "Switch device on first.";
}
}
else
{
return $inputs_piped eq "" ? "No inputs available. Please try an statusRequest first." : "No input parameter given.";
}
}
#
# MUTE
#
elsif($what eq "mute")
{
if($hash->{READINGS}{power}{VAL} ne "on")
{
return "Power on the device first.";
}
if(defined($a[2]))
{
if($a[2] =~ /^(on|off)$/)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Mute>".ucfirst($a[2])."</Mute></Volume></System></YAMAHA_AV>", $what, ucfirst($a[2]), 0);
}
else
{
return $usage;
}
}
}
#
# DISPLAY DIMMER
#
elsif($what eq "dimmer")
{
if($a[2] >= 1 and $a[2] <= 3)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Display><FL_Dimmer>".$a[2]."</FL_Dimmer></Display></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "Dimmer value must be 1 .. 3";
}
}
#
# VOLUME
#
# VolumeStraight is device specific e.g. 0...60, Volume 0...100, VolumeUp/Down one step
#
elsif($what =~ /^(volumeStraight|volume|volumeUp|volumeDown)$/)
{
my $target_volume;
my $minVolume = $hash->{helper}{VOLUMESTRAIGHTMIN};
my $maxVolume = $hash->{helper}{VOLUMESTRAIGHTMAX};
if($hash->{READINGS}{power}{VAL} ne "on")
{
return "Power on the device first.";
}
if($what eq "volumeDown")
{
$hash->{helper}{volumeChangeDir} = "DOWN";
$target_volume = $hash->{READINGS}{volumeStraight}{VAL} - 1;
$hash->{helper}{targetVolume} = $target_volume;
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".$target_volume."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", $target_volume, 0);
}
elsif($what eq "volumeUp")
{
$hash->{helper}{volumeChangeDir} = "UP";
$target_volume = $hash->{READINGS}{volumeStraight}{VAL} + 1;
$hash->{helper}{targetVolume} = $target_volume;
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".$target_volume."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", $target_volume, 0);
}
else
{
if($what eq "volume")
{
if($a[2] >= 0 and $a[2] <= 100)
{
$target_volume = YAMAHA_NP_volume_rel2abs($hash, $a[2]);
}
else
{
return "Volume must be in the range 1...100.";
}
}
elsif($what eq "volumeStraight")
{
if($a[2] >= $minVolume and $a[2] <= $maxVolume)
{
$target_volume = $a[2];
}
else
{
return "Volume must be in the range $minVolume...$maxVolume.";
}
}
$hash->{helper}{targetVolume} = $target_volume;
if(AttrVal($name, "smooth-volume-change", "1") eq "1" )
{
if($target_volume < $hash->{READINGS}{volumeStraight}{VAL})
{
$hash->{helper}{volumeChangeDir} = "DOWN";
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".($hash->{READINGS}{volumeStraight}{VAL} - 1)."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", ($hash->{READINGS}{volumeStraight}{VAL} - 1), 0);
}
elsif($target_volume > $hash->{READINGS}{volumeStraight}{VAL})
{
$hash->{helper}{volumeChangeDir} = "UP";
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".($hash->{READINGS}{volumeStraight}{VAL} + 1)."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", ($hash->{READINGS}{volumeStraight}{VAL} + 1), 0);
}
elsif($target_volume eq $hash->{READINGS}{volumeStraight}{VAL})
{
$hash->{helper}{volumeChangeDir} = "EQUAL";
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".($hash->{READINGS}{volumeStraight}{VAL})."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", ($hash->{READINGS}{volumeStraight}{VAL}), 0);
}
}
else
{
$hash->{helper}{volumeChangeDir} = "EQUAL";
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".$target_volume."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", $a[2], 0);
}
}
Log3 $name, 4, "YAMAHA_NP ($name) - new target volume: $target_volume";
}
#
# SLEEP
#
elsif($what eq "sleep")
{
if($a[2] eq "off")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Power_Control><Sleep>Off</Sleep></Power_Control></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] =~ /^(30min|60min|90min|120min)$/)
{
if($a[2] =~ /(.+)min/)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Power_Control><Sleep>".$1." min</Sleep></Power_Control></System></YAMAHA_AV>", $what, $a[2], 0);
}
}
else
{
return $usage;
}
}
#
# TUNER
#
elsif($what eq "tuner")
{
if($a[2] eq "presetUp")
{
YAMAHA_NP_SendCommand($hash,"<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Preset><Preset_Sel>Next</Preset_Sel></Preset></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "presetDown")
{
YAMAHA_NP_SendCommand($hash,"<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Preset><Preset_Sel>Prev</Preset_Sel></Preset></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "tuneUp")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Service>Next</Service></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "tuneDown")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Service>Prev</Service></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "bandDAB")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Band>DAB</Band></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "bandFM")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Band>FM</Band></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return $usage;
}
}
#
# Player
#
elsif($what eq "player")
{
if($a[2] =~ /^(play|pause|stop|next|prev)$/)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><Play_Control><Playback>".ucfirst($a[2])."</Playback></Play_Control></Player></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "shuffleToggle")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><Play_Control><Play_Mode><Shuffle>Toggle</Shuffle></Play_Mode></Play_Control></Player></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "repeatToggle")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><Play_Control><Play_Mode><Repeat>Toggle</Repeat></Play_Mode></Play_Control></Player></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return $usage;
}
}
#
# PlayerGetList
#
elsif($what eq "playerListGetList")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Player><List_Info>GetParam</List_Info></Player></YAMAHA_AV>", $what, "playerListGetList", 0);
}
elsif($what eq "playerListCursorReturn")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><List_Control><Cursor>Return</Cursor></List_Control></Player></YAMAHA_AV>", $what, "playerListCursorReturn", 0);
}
elsif($what eq "playerListCursorDown")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><List_Control><Cursor>Down</Cursor></List_Control></Player></YAMAHA_AV>", $what, "playerListCursorDown", 0);
}
elsif($what eq "playerListCursorUp")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><List_Control><Cursor>Up</Cursor></List_Control></Player></YAMAHA_AV>", $what, "playerListCursorUp", 0);
}
elsif($what eq "playerListJumpLine")
{
if($a[2] ne "")
{
if($a[2] =~ /^\d+$/ and $a[2] >= 1)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><List_Control><Jump_Line>".$a[2]."</Jump_Line></List_Control></Player></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "Argument must be numeric and >= 1.";
}
}
else
{
return "No argument given.";
}
}
#
# PlayerListSelectLine
#
elsif($what eq "playerListSelectLine")
{
if($a[2] ne "")
{
if($a[2] =~ /^\d+$/ and $a[2] >= 1)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Player><List_Control><Direct_Sel>Line_".$a[2]."</Direct_Sel></List_Control></Player></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "Argument must be numeric and >= 1.";
}
}
else
{
return "No argument given.";
}
}
#
# Standby Mode
#
elsif($what eq "standbyMode")
{
if(($a[2] eq "eco") or ($a[2] eq "normal"))
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Power_Control><Saving>".ucfirst($a[2])."</Saving></Power_Control></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return $usage;
}
}
#
# CD Tray
#
elsif($what eq "cdTray")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Tray>Open/Close</Tray></Misc></System></YAMAHA_AV>", $what, "Open/Close", 0);
}
#
# Clock Update
#
elsif($what eq "clockUpdate")
{
my $clockUpdateCurrentTime = Time::Piece->new();
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Clock><Param>".($clockUpdateCurrentTime->strftime('%Y:%m:%d:%H:%M:%S'))."</Param></Clock></Misc></System></YAMAHA_AV>", $what, ($clockUpdateCurrentTime->strftime('%Y:%m:%d:%H:%M:%S')), 0);
}
#
# Status Request
#
elsif($what eq "statusRequest")
{
if($a[2] eq "systemConfig")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Config>GetParam</Config></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "playerStatus")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Player><Play_Info>GetParam<\/Play_Info><\/Player><\/YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "tunerStatus")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Info>GetParam<\/Play_Info><\/Tuner><\/YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "basicStatus")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Basic_Status>GetParam</Basic_Status></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "timerStatus")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Timer><Mode>GetParam</Mode></Timer></Misc></System></YAMAHA_AV>", $what, "getTimer", 0);
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Timer><Param>GetParam</Param></Timer></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "networkInfo")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Misc><Network><Info>GetParam</Info></Network></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "tunerPresetFM")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><FM><Preset_Sel_Item>GetParam</Preset_Sel_Item></FM></Preset></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "tunerPresetDAB")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><Tuner><Play_Control><Preset><DAB><Preset_Sel_Item>GetParam</Preset_Sel_Item></DAB></Preset></Play_Control></Tuner></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "standbyMode")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Power_Control><Saving>GetParam</Saving></Power_Control></System></YAMAHA_AV>", $what, $a[2], 0);
}
elsif($a[2] eq "mediaRendererDesc")
{
YAMAHA_NP_getMediaRendererDesc($hash);
}
else
{
return $usage;
}
}
#
# Timer
#
elsif($what eq "timer")
{
if($a[2] eq "on")
{
# Check if standbyMode == 'Normal'
if($hash->{READINGS}{standbyMode}{VAL} eq "normal")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Timer><Mode>".ucfirst($a[2])."</Mode></Timer></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "Set 'standbyMode normal' first.";
}
}
elsif($a[2] eq "off")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Timer><Mode>".ucfirst($a[2])."</Mode></Timer></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return $usage;
}
}
#
# Timer Hour
#
elsif($what eq "timerHour")
{
if((int($a[2]) >= 0) and (int($a[2]) <= 23))
{
$hash->{helper}{timerHour} = $a[2];
}
else
{
return $usage;
}
}
#
# Timer Minute
#
elsif($what eq "timerMinute")
{
if((int($a[2]) >= 0) and (int($a[2]) <= 59))
{
$hash->{helper}{timerMinute} = $a[2];
}
else
{
return $usage;
}
}
#
# Timer Repeat
#
elsif($what eq "timerRepeat")
{
if($a[2] eq "once" or $a[2] eq "every")
{
$hash->{helper}{timerRepeat} = ucfirst($a[2]);
}
else
{
return $usage;
}
}
#
# TimerVolume
#
elsif($what eq "timerVolume")
{
# if lower than minimum VOLUMESTRAIGHTMIN or higher than max VOLUMESTRAIGHTMAX set target volume to the corresponding limits
if($a[2] >= $hash->{helper}{VOLUMESTRAIGHTMIN} and $a[2] <= $hash->{helper}{VOLUMESTRAIGHTMAX})
{
$hash->{helper}{timerVolume} = $a[2];
}
else
{
return "Please use straight device volume range :".$hash->{helper}{VOLUMESTRAIGHTMIN}."...".$hash->{helper}{VOLUMESTRAIGHTMAX}.".";
}
}
#
# TimerSet
#
elsif($what eq "timerSet")
{
if(defined($hash->{helper}{timerHour}) and defined($hash->{helper}{timerMinute}) and defined($hash->{helper}{timerRepeat}) and defined($hash->{helper}{timerVolume}))
{
# Configure Timer according to provided parameters
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Misc><Timer><Param><Start_Time>".sprintf("%02d", $hash->{helper}{timerHour}).":".sprintf("%02d", $hash->{helper}{timerMinute})."</Start_Time><Volume>".$hash->{helper}{timerVolume}."</Volume><Repeat>".$hash->{helper}{timerRepeat}."</Repeat></Param></Timer></Misc></System></YAMAHA_AV>", $what, $a[2], 0);
}
else
{
return "Please, define timerHour, timerMinute, timerRepeat and timerVolume first.";
}
}
#
# Tuner Preset DAB
#
elsif($what eq "tunerPresetDAB")
{
if($a[2] >= 1 and $a[2] <= 30 and $hash->{MODEL} eq "CRX-N560D")
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Preset><DAB><Preset_Sel>".$a[2]."<\/Preset_Sel><\/DAB><\/Preset><\/Play_Control><\/Tuner></YAMAHA_AV>", "tunerPresetDAB", $a[2], 0);
}
else
{
return $usage;
}
}
#
# Tuner Preset FM
#
elsif($what eq "tunerPresetFM")
{
if($a[2] >= 1 and $a[2] <= 30)
{
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Preset><FM><Preset_Sel>".$a[2]."<\/Preset_Sel><\/FM><\/Preset><\/Play_Control><\/Tuner></YAMAHA_AV>", "tunerPresetFM", $a[2], 0);
}
else
{
return $usage;
}
}
#
# Tuner FM Frequency
#
elsif($what eq "tunerFMFrequency")
{
if(length($a[2]) <= 6 and length($a[2]) >= 5) # Check the string length (x)xx.xx
{
if ( $a[2] =~ /^[0-9,.E]+$/ ) # Check if value is numeric
{
if(substr($a[2], -3, 1) eq '.') # Check for decimal point
{
if( $a[2] >= 87.50 and $a[2] <= 108.00) # Check if within the value range
{
my $lastDigit = substr($a[2], -1, 1);
if(($lastDigit eq "0") or ($lastDigit eq "5"))
{
my $frequency = $a[2];
$frequency =~ s/\.//; # Remove decimal point
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><Tuner><Play_Control><Tuning><FM><Freq>".$frequency."<\/Freq><\/FM><\/Tuning><\/Play_Control><\/Tuner></YAMAHA_AV>", "tunerFMFrequency", $a[2], 0);
}
else
{
return "Last digit must be '0' or '5'";
}
}
else
{
return "Frequency value must be in the range 87.50 ... 108.00 of the format (x)xx.xx";
}
}
else
{
return "Missing decimal point. Accepted format (x)xx.xx";
}
}
else
{
return "Frequency value must be numeric in the range 87.50 ... 108.00 of the format (x)xx.xx";
}
}
else
{
return "Frequency length must be 5 or 6 characters e.g. 89.50 or 108.00";
}
}
else
{
return $usage;
}
return;
}
#############################
sub YAMAHA_NP_Define
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $name = $hash->{NAME};
if(! @a >= 3)
{
my $msg = "Wrong syntax: define <name> YAMAHA_NP <ip-or-hostname> [<ON-statusinterval>] [<OFF-statusinterval>] ";
Log3 $name, 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(defined($a[4]) and $a[4] > 0)
{
$hash->{helper}{ON_INTERVAL} = $a[4];
}
else
{
$hash->{helper}{ON_INTERVAL} = $hash->{helper}{OFF_INTERVAL};
}
YAMAHA_NP_getInputs($hash);
unless(exists($hash->{helper}{AVAILABLE}) and ($hash->{helper}{AVAILABLE} == 0))
{
$hash->{helper}{AVAILABLE} = 1;
readingsSingleUpdate($hash, "presence", "present", 1);
}
# start the status update timer
$hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED}));
YAMAHA_NP_ResetTimer($hash,0);
return;
}
##########################
sub YAMAHA_NP_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_NP_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_NP_GetStatus($hash, 1);
}
# Start/Stop Timer according to new disabled-Value
YAMAHA_NP_ResetTimer($hash);
return;
}
#############################
#
#
sub YAMAHA_NP_Undefine
{
my($hash, $name) = @_;
# Stop the internal GetStatus-Loop and exit
RemoveInternalTimer($hash);
return;
}
#############################
# sends a command to the receiver via HTTP
#
sub YAMAHA_NP_SendCommand
{
my ($hash,$data,$cmd,$arg,$blocking) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
# Always use non-blocking http communication in case not specified
if(not defined($blocking))
{
$blocking = 0;
}
if($blocking == 1)
{
Log3 $name, 5, "YAMAHA_NP ($name) - execute blocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
my $param =
{
url => "http://".$address."/YamahaRemoteControl/ctrl",
timeout => AttrVal($name, "request-timeout", 4),
noshutdown => 1,
data => "<?xml version=\"1.0\" encoding=\"utf-8\"?>".$data,
loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
hash => $hash,
cmd => $cmd,
arg => $arg
};
my ($err, $data) = HttpUtils_BlockingGet($param);
YAMAHA_NP_ParseResponse($param, $err, $data);
}
else
{
Log3 $name, 5, "YAMAHA_NP ($name) - execute nonblocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
HttpUtils_NonblockingGet
({
url => "http://".$address."/YamahaRemoteControl/ctrl",
timeout => AttrVal($name, "request-timeout", 4),
noshutdown => 1,
data => "<?xml version=\"1.0\" encoding=\"utf-8\"?>".$data,
loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
hash => $hash,
cmd => $cmd,
arg => $arg,
callback => \&YAMAHA_NP_ParseResponse
});
}
return;
}
#############################
# parses HTTP response
# (HttpUtils_NonblockingGet) callback
#
sub YAMAHA_NP_ParseResponse
{
my ($param, $err, $data ) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
my $cmd = $param->{cmd};
my $arg = $param->{arg};
if(exists($param->{code}))
{
Log3 $name, 5, "YAMAHA_NP ($name) - received HTTP code ".$param->{code}." for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\"";
}
if($err ne "")
{
Log3 $name, 5, "YAMAHA_NP ($name) - could not execute command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $err";
if((not exists($hash->{helper}{AVAILABLE})) or (exists($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} == 1))
{
Log3 $name, 3, "YAMAHA_NP ($name) - could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress.";
readingsSingleUpdate($hash, "presence", "absent", 1);
readingsSingleUpdate($hash, "state", "absent", 1);
}
$hash->{helper}{AVAILABLE} = 0;
}
elsif($data ne "")
{
Log3 $name, 5, "YAMAHA_NP ($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_NP ($name) - device $name reappeared";
readingsSingleUpdate($hash, "presence", "present", 1);
}
$hash->{helper}{AVAILABLE} = 1;
if (($cmd ne "statusRequest") and ($arg ne "systemConfig")) # RC="0" is not delivered by that status Request
{
if(not $data =~ /RC="0"/)
{
# if the returncode != 0 -> HTTP command unsuccessful
Log3 $name, 3, "YAMAHA_NP ($name) - Could not execute \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\"";
}
}
readingsBeginUpdate($hash);
if($cmd eq "statusRequest")
{
if($arg eq "systemConfig")
{
if($data =~ /<Model_Name>(.+?)<\/Model_Name>.*<System_ID>(.+?)<\/System_ID>.*<Version>(.+?)<\/Version>.*<Volume><Min>(.+?)<\/Min>.*<Max>(.+?)<\/Max>.*<Step>(.+?)<\/Step><\/Volume>/)
{
delete($hash->{MODEL}) if(defined($hash->{MODEL}));
delete($hash->{helper}{VOLUMESTRAIGHTMIN}) if(defined($hash->{helper}{VOLUMESTRAIGHTMIN}));
delete($hash->{helper}{VOLUMESTRAIGHTMAX}) if(defined($hash->{helper}{VOLUMESTRAIGHTMAX}));
delete($hash->{helper}{VOLUMESTRAIGHTSTEP}) if(defined($hash->{helper}{VOLUMESTRAIGHTSTEP}));
$hash->{MODEL} = $1;
$hash->{SYSTEM_ID} = $2;
$hash->{FIRMWARE} = $3;
$hash->{helper}{VOLUMESTRAIGHTMIN} = $4;
$hash->{helper}{VOLUMESTRAIGHTMAX} = $5;
$hash->{helper}{VOLUMESTRAIGHTSTEP} = $6;
# Used by 'fheminfo' command for statistics
$attr{$name}{"model"} = $hash->{MODEL};
}
}
elsif($arg eq "getInputs")
{
delete($hash->{helper}{INPUTS}) if(defined($hash->{helper}{INPUTS}));
while($data =~ /<Feature_Existence>(.+?)<\/Feature_Existence>/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 "basicStatus")
{
if($data =~ /<Power>(.+?)<\/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 =~ /<Volume><Lvl>(.+?)<\/Lvl><Mute>(.+?)<\/Mute><\/Volume>/)
{
readingsBulkUpdate($hash, "volumeStraight", ($1));
readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $1));
readingsBulkUpdate($hash, "mute", lc($2));
}
# current input same as the corresponding set command name
if($data =~ /<Input_Sel>(.+?)<\/Input_Sel>/)
{
readingsBulkUpdate($hash, "input", YAMAHA_NP_Param2Fhem(lc($1), 0));
}
if($data =~ /<Sleep>(.+?)<\/Sleep>/)
{
readingsBulkUpdate($hash, "sleep", YAMAHA_NP_Param2Fhem($1, 0));
}
}
elsif($arg eq "playerStatus")
{
if($data =~ /<Playback_Info>(.+)<\/Playback_Info>/)
{
readingsBulkUpdate($hash, "playerPlaybackInfo", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerPlaybackInfo", "");
}
if($data =~ /<Device_Type>(.+)<\/Device_Type>/)
{
readingsBulkUpdate($hash, "playerDeviceType", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerDeviceType", "");
}
if($data =~ /<iPod_Mode>(.+)<\/iPod_Mode>/)
{
readingsBulkUpdate($hash, "playerIpodMode", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerIpodMode", "");
}
if($data =~ /<Repeat>(.+)<\/Repeat>/)
{
readingsBulkUpdate($hash, "playerRepeat", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerRepeat", "");
}
if($data =~ /<Shuffle>(.+)<\/Shuffle>/)
{
readingsBulkUpdate($hash, "playerShuffle", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerShuffle", "");
}
if($data =~ /<Play_Time>(.+)<\/Play_Time>/)
{
readingsBulkUpdate($hash, "playerPlayTime", strftime("\%H:\%M:\%S", gmtime($1)));
}
else
{
readingsBulkUpdate($hash, "playerPlayTime", "");
}
if($data =~ /<Track_Number>(.+)<\/Track_Number>/)
{
readingsBulkUpdate($hash, "playerTrackNumber", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerTrackNumber", "");
}
if($data =~ /<Total_Tracks>(.+)<\/Total_Tracks>/)
{
readingsBulkUpdate($hash, "playerTotalTracks", lc($1));
}
else
{
readingsBulkUpdate($hash, "playerTotalTracks", "");
}
if($data =~ /<Artist>(.+)<\/Artist>/)
{
readingsBulkUpdate($hash, "playerArtist", YAMAHA_NP_html2txt($1));
}
else
{
readingsBulkUpdate($hash, "playerArtist", "");
}
if($data =~ /<Album>(.+)<\/Album>/)
{
readingsBulkUpdate($hash, "playerAlbum", YAMAHA_NP_html2txt($1));
}
else
{
readingsBulkUpdate($hash, "playerAlbum", "");
}
if($data =~ /<Song>(.+)<\/Song>/)
{
readingsBulkUpdate($hash, "playerSong", YAMAHA_NP_html2txt($1));
}
else
{
readingsBulkUpdate($hash, "playerSong", "");
}
if($data =~ /<Album_ART><URL>(.+)<\/URL><ID>(.+)<\/ID><Format>(.+)<\/Format><\/Album_ART>/)
{
my $address = $hash->{helper}{ADDRESS};
readingsBulkUpdate($hash, "playerAlbumArtURL", "http://".$address."".YAMAHA_NP_html2txt($1));
readingsBulkUpdate($hash, "playerAlbumArtID", YAMAHA_NP_html2txt($2));
readingsBulkUpdate($hash, "playerAlbumArtFormat", YAMAHA_NP_html2txt($3));
}
else
{
readingsBulkUpdate($hash, "playerAlbumArtURL", "");
readingsBulkUpdate($hash, "playerAlbumArtID", "");
readingsBulkUpdate($hash, "playerAlbumArtFormat", "");
}
}
elsif($arg eq "tunerStatus")
{
if($data =~ /<Band>(.+)<\/Band>/)
{
readingsBulkUpdate($hash, "tunerBand", ($1));
}
if($hash->{READINGS}{tunerBand}{VAL} eq "FM")
{
if($data =~ /<FM><Preset><Preset_Sel>(.+)<\/Preset_Sel><\/Preset>(.*)<\/FM/)
{
readingsBulkUpdate($hash, "tunerPresetFM", ($1));
}
if($data =~ /<Tuning><Freq>(.+)<\/Freq><\/Tuning>/)
{
my $frequency = $1;
$frequency =~ s/(\d{2})$/.$1/; # Insert '.' to frequency
readingsBulkUpdate($hash, "tunerFrequencyFM", $frequency." MHz");
}
if($data =~ /<Program_Service>(.+)<\/Program_Service>/)
{
readingsBulkUpdate($hash, "tunerProgramServiceFM", YAMAHA_NP_html2txt($1));
}
if($data =~ /<Radio_Text_A>(.+)<\/Radio_Text_A>/)
{
readingsBulkUpdate($hash, "tunerRadioTextAFM", YAMAHA_NP_html2txt($1));
}
if($data =~ /<Radio_Text_B>(.+)<\/Radio_Text_B>/)
{
readingsBulkUpdate($hash, "tunerRadioTextBFM", YAMAHA_NP_html2txt($1));
}
}
if($hash->{READINGS}{tunerBand}{VAL} eq "DAB")
{
if($data =~ /<DAB><Preset><Preset_Sel>(.+)<\/Preset_Sel><\/Preset>(.*)<\/DAB>/)
{
readingsBulkUpdate($hash, "tunerPresetDAB", ($1));
}
if($data =~ /<Service_Label>(.+)<\/Service_Label>/)
{
readingsBulkUpdate($hash, "tunerServiceLabelDAB", YAMAHA_NP_html2txt($1));
}
if($data =~ /<Ch_Label>(.+)<\/Ch_Label>/)
{
readingsBulkUpdate($hash, "tunerChannelLabelDAB", ($1));
}
if($data =~ /<DLS>(.+)<\/DLS>/)
{
readingsBulkUpdate($hash, "tunerDLSDAB", YAMAHA_NP_html2txt($1));
}
if($data =~ /<Ensemble_Label>(.+)<\/Ensemble_Label>/)
{
readingsBulkUpdate($hash, "tunerEnsembleLabelDAB", YAMAHA_NP_html2txt($1));
}
if($data =~ /<Bit_Rate>(.+)<\/Bit_Rate>/)
{
readingsBulkUpdate($hash, "tunerBitRateDAB", $1." kbit\/s");
}
if($data =~ /<Audio_Mode>(.+)<\/Audio_Mode>/)
{
readingsBulkUpdate($hash, "tunerAudioModeDAB", $1);
}
if($data =~ /<DAB_PLUS>(.+)<\/DAB_PLUS>/)
{
if($1 eq "Negate")
{
readingsBulkUpdate($hash, "tunerModeDAB", "DAB");
}
elsif($1 eq "Assert")
{
readingsBulkUpdate($hash, "tunerModeDAB", "DAB+");
}
}
if($data =~ /<Signal_Info><Freq>(.+)<\/Freq>/)
{
my $frequency = $1;
$frequency =~ s/(\d{3})$/.$1/; # Insert '.' to frequency
readingsBulkUpdate($hash, "tunerFrequencyDAB", $frequency." MHz");
}
}
}
elsif($arg eq "timerStatus")
{
if($data =~ /<Volume><Lvl>(.+)<\/Lvl><\/Volume>/)
{
readingsBulkUpdate($hash, "timerVolume", $1);
}
if($data =~ /<Start_Time>(.+)<\/Start_Time>/)
{
readingsBulkUpdate($hash, "timerStartTime", $1);
}
if($data =~ /<Repeat>(.+)<\/Repeat>/)
{
readingsBulkUpdate($hash, "timerRepeat", lc($1));
}
}
elsif($arg eq "getTimer")
{
if($data =~ /<Mode>(.+)<\/Mode>/)
{
readingsBulkUpdate($hash, "timer", lc($1));
}
}
elsif($arg eq "networkInfo")
{
if($data =~ /<IP_Address>(.+)<\/IP_Address>/)
{
$hash->{IP_ADDRESS} = $1;
}
if($data =~ /<Subnet_Mask>(.+)<\/Subnet_Mask>/)
{
$hash->{SUBNET_MASK} = $1;
}
if($data =~ /<Default_Gateway>(.+)<\/Default_Gateway>/)
{
$hash->{DEFAULT_GATEWAY} = $1;
}
if($data =~ /<DNS_Server_1>(.+)<\/DNS_Server_1>/)
{
$hash->{DNS_SERVER_1} = $1;
}
if($data =~ /<DNS_Server_2>(.+)<\/DNS_Server_2>/)
{
$hash->{DNS_SERVER_2} = $1;
}
if($data =~ /<MAC_Address>(.+)<\/MAC_Address>/)
{
$hash->{MAC_ADDRESS} = $1;
# Add ':' after every two chars
$hash->{MAC_ADDRESS} =~ s/\w{2}\B/$&:/g;
}
}
elsif($arg eq "tunerPresetFM")
{
{
# May be also an empty string <Item_#></Item_#>
for (my $i = 1; $i < 31; $i++)
{
if ($data =~ /<Item_$i><\/Item_$i>/)
{
readingsBulkUpdate($hash, sprintf("tunerPresetFMItem_%02d", $i), "No Preset");
}
elsif($data =~ /<Item_$i>(.+?)<\/Item_$i>/)
{
readingsBulkUpdate($hash, sprintf("tunerPresetFMItem_%02d", $i), $1);
}
}
}
}
elsif($arg eq "tunerPresetDAB")
{
# May be also an empty string <Item_#></Item_#>
for (my $i = 1; $i < 31; $i++)
{
if ($data =~ /<Item_$i><\/Item_$i>/)
{
readingsBulkUpdate($hash, sprintf("tunerPresetDABItem_%02d", $i), "No Preset");
}
elsif($data =~ /<Item_$i>(.+?)<\/Item_$i>/)
{
readingsBulkUpdate($hash, sprintf("tunerPresetDABItem_%02d", $i), $1);
}
}
}
elsif ($arg eq "standbyMode")
{
if($data =~ /<Saving>(.+)<\/Saving>/)
{
readingsBulkUpdate($hash, "standbyMode", lc($1));
}
}
elsif ($arg eq "mediaRendererDesc")
{
if($data =~ /<friendlyName>(.+)<\/friendlyName>/)
{
$hash->{FRIENDLY_NAME} = $1;
}
if($data =~ /<UDN>(.+)<\/UDN>/)
{
my @uuid = split(/:/, $1);
$hash->{UNIQUE_DEVICE_NAME} = uc($uuid[1]);
}
# Replace \n, \r, \t from the string for XML parsing
# replace \n by ""
$data =~ s/\n//g;
# replace \t by ""
$data =~ s/\t//g;
# replace \r by ""
$data =~ s/\r//g;
if($data =~ /<iconList>(.+?)<\/iconList>/)
{
my $address = $hash->{helper}{ADDRESS};
my $i = 1;
while ($data =~ /<url>(.+?)<\/url>/g)
{
$hash->{"NP_ICON_$i"} = "http://".$address.":8080".$1;
$i++;
}
}
}
}
elsif($cmd eq "playerListGetList")
{
# Delete old List listLines
my $i = 1;
if($data =~ /<Menu_Status>(.*)<\/Menu_Status>/)
{
readingsBulkUpdate($hash, "playerListMenuStatus", $1);
}
if($data =~ /<Menu_Name>(.*)<\/Menu_Name>/)
{
readingsBulkUpdate($hash, "playerListMenuName", $1);
}
if($data =~ /<Menu_Layer>(.*)<\/Menu_Layer>/)
{
readingsBulkUpdate($hash, "playerListMenuLayer", $1);
}
if($data =~ /<Current_List>(.*)<\/Current_List>/)
{
# <Line_X><Txt>****</Txt><Attribute>Container|Item|Unselectable</Attribute></Line_X>
while($data =~ /<Line_$i><Txt>(.*?)<\/Txt><Attribute>(.*?)<\/Attribute><\/Line_$i>/gc)
{
readingsBulkUpdate($hash, "playerListLine_$i", $1);
readingsBulkUpdate($hash, "playerListLine_Attribute_$i", $2);
$i++;
}
}
if($data =~ /<Cursor_Position><Current_Line>(.*)<\/Current_Line><Max_Line>(.*)<\/Max_Line><\/Cursor_Position>/)
{
readingsBulkUpdate($hash, "playerListCurrentLine", $1);
readingsBulkUpdate($hash, "playerListMaxLine", $2);
}
}
elsif($cmd eq "on")
{
if($data =~ /RC="0"/ and $data =~ /<Power><\/Power>/)
{
readingsBulkUpdate($hash, "power", "on");
readingsBulkUpdate($hash, "state","on");
readingsEndUpdate($hash, 1);
YAMAHA_NP_ResetTimer($hash);
return;
}
}
elsif($cmd eq "off")
{
if($data =~ /RC="0"/ and $data =~ /<Power><\/Power>/)
{
readingsBulkUpdate($hash, "power", "off");
readingsBulkUpdate($hash, "state","off");
readingsEndUpdate($hash, 1);
blankTunerDABReadings($hash);
blankTunerFMReadings($hash);
blankPlayerReadings($hash);
YAMAHA_NP_ResetTimer($hash);
return;
}
}
elsif($cmd eq "mute")
{
if($data =~ /RC="0"/)
{
readingsBulkUpdate($hash, "mute", $arg);
}
}
elsif($cmd eq "standbyMode")
{
if($data =~ /RC="0"/)
{
readingsBulkUpdate($hash, "standbyMode", lc($arg));
}
}
elsif($cmd eq "volume" or $cmd eq "volumeStraight" or $cmd eq "volumeUp" or $cmd eq "volumeDown")
{
if($data =~ /RC="0"/)
{
if(AttrVal($name, "smooth-volume-change", "1") eq "1" )
{
my $volumeStraight;
$volumeStraight = $hash->{READINGS}{volumeStraight}{VAL};
if($hash->{helper}{targetVolume} eq $volumeStraight)
{
$hash->{helper}{volumeChangeDir} = "EQUAL";
}
if($hash->{helper}{volumeChangeDir} eq "EQUAL")
{
readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
}
elsif($hash->{helper}{volumeChangeDir} eq "UP")
{
# Reset timer in order to avoid status request collisions
# due to recursive volume change call
YAMAHA_NP_ResetTimer($hash);
readingsBulkUpdate($hash, "volumeStraight", $volumeStraight + 1);
readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $volumeStraight + 1));
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".($volumeStraight + 1)."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", ($volumeStraight + 1), 0);
}
elsif($hash->{helper}{volumeChangeDir} eq "DOWN")
{
# Reset timer in order to avoid status request collisions
# due to recursive volume change call
YAMAHA_NP_ResetTimer($hash);
readingsBulkUpdate($hash, "volumeStraight", $volumeStraight - 1);
readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $volumeStraight - 1));
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"PUT\"><System><Volume><Lvl>".($volumeStraight - 1)."</Lvl></Volume><\/System></YAMAHA_AV>", "volume", ($volumeStraight - 1), 0);
}
}
else
{
readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
$hash->{helper}{volumeChangeDir} = "EQUAL";
}
}
}
readingsEndUpdate($hash, 1);
#YAMAHA_NP_ResetTimer($hash, 0) if($cmd ne "statusRequest" and $cmd ne "on" and $cmd ne "volume");
}
return;
}
#############################
# Blanks dynamic DAB tuner readings
sub blankTunerDABReadings
{
my ($hash) = @_;
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "tunerDLSDAB", "");
readingsBulkUpdate($hash, "tunerEnsembleLabelDAB", "");
readingsBulkUpdate($hash, "tunerFrequencyDAB", "");
readingsBulkUpdate($hash, "tunerModeDAB", "");
readingsBulkUpdate($hash, "tunerServiceLabelDAB", "");
readingsBulkUpdate($hash, "tunerAudioModeDAB", "");
readingsBulkUpdate($hash, "tunerBitRateDAB", "");
readingsBulkUpdate($hash, "tunerChannelLabelDAB", "");
readingsBulkUpdate($hash, "tunerPresetDAB", "");
readingsEndUpdate($hash, 1);
return;
}
#############################
# Blanks dynamic FM tuner readings
sub blankTunerFMReadings
{
my ($hash) = @_;
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "tunerFrequencyFM", "");
readingsBulkUpdate($hash, "tunerProgramServiceFM", "");
readingsBulkUpdate($hash, "tunerRadioTextAFM", "");
readingsBulkUpdate($hash, "tunerRadioTextBFM", "");
readingsBulkUpdate($hash, "tunerPresetFM", "");
readingsEndUpdate($hash, 1);
return;
}
#############################
# Blanks dynamic Tuner readings
sub blankPlayerReadings
{
my ($hash) = @_;
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "playerAlbum", "");
readingsBulkUpdate($hash, "playerAlbumArtFormat", "");
readingsBulkUpdate($hash, "playerAlbumArtID", "");
readingsBulkUpdate($hash, "playerAlbumArtURL", "");
readingsBulkUpdate($hash, "playerArtist", "");
readingsBulkUpdate($hash, "playerDeviceType", "");
readingsBulkUpdate($hash, "playerIpodMode", "");
readingsBulkUpdate($hash, "playerListCurrentLine", "");
readingsBulkUpdate($hash, "playerListLine_1", "");
readingsBulkUpdate($hash, "playerListLine_2", "");
readingsBulkUpdate($hash, "playerListLine_3", "");
readingsBulkUpdate($hash, "playerListLine_4", "");
readingsBulkUpdate($hash, "playerListLine_5", "");
readingsBulkUpdate($hash, "playerListLine_6", "");
readingsBulkUpdate($hash, "playerListLine_7", "");
readingsBulkUpdate($hash, "playerListLine_8", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_1", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_2", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_3", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_4", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_5", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_6", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_7", "");
readingsBulkUpdate($hash, "playerListLine_Attribute_8", "");
readingsBulkUpdate($hash, "playerListMaxLine", "");
readingsBulkUpdate($hash, "playerListMenuLayer", "");
readingsBulkUpdate($hash, "playerListMenuName", "");
readingsBulkUpdate($hash, "playerListMenuStatus", "");
readingsBulkUpdate($hash, "playerPlayTime", "");
readingsBulkUpdate($hash, "playerPlaybackInfo", "");
readingsBulkUpdate($hash, "playerRepeat", "");
readingsBulkUpdate($hash, "playerShuffle", "");
readingsBulkUpdate($hash, "playerSong", "");
readingsBulkUpdate($hash, "playerTotalTracks", "");
readingsBulkUpdate($hash, "playerTrackNumber", "");
readingsEndUpdate($hash, 1);
return;
}
#############################
# Converts all Values to FHEM usable command lists
sub YAMAHA_NP_Param2Fhem
{
my ($param, $replace_pipes) = @_;
$param =~ s/\s+//g;
$param =~ s/,//g;
$param =~ s/_//g;
$param =~ s/\(/_/g;
$param =~ s/\)//g;
$param =~ s/\|/,/g if($replace_pipes == 1);
return lc $param;
}
#############################
# Returns the Yamaha Parameter Name for the FHEM like equivalent
sub YAMAHA_NP_getParamName
{
my ($hash, $name, $list) = @_;
return if(not defined($list));
my @commands = split("\\|", $list);
foreach my $item (@commands)
{
if(YAMAHA_NP_Param2Fhem($item, 0) eq $name)
{
return $item;
}
}
return;
}
#############################
# queries the NP model, system-id and version
sub YAMAHA_NP_getModel
{
my ($hash) = @_;
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Config>GetParam</Config></System></YAMAHA_AV>", "statusRequest","systemConfig", 0);
YAMAHA_NP_getMediaRendererDesc($hash);
return;
}
#############################
# queries the addition model descriptions
sub YAMAHA_NP_getMediaRendererDesc
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
Log3 $name, 5, "YAMAHA_NP ($name) - execute nonblocking \"MediaRendererDesc\"";
HttpUtils_NonblockingGet
({
url => "http://".$address.":8080/MediaRenderer/desc.xml",
timeout => AttrVal($name, "request-timeout", 4),
noshutdown => 1,
data => "",
loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
hash => $hash,
cmd => "statusRequest",
arg => "mediaRendererDesc",
callback => \&YAMAHA_NP_ParseResponse
});
return;
}
#############################
# converts straight volume in percentage volume (volumestraightmin .. volumestraightmax => 0 .. 100%)
sub YAMAHA_NP_volume_rel2abs
{
my ($hash, $percentage) = @_;
return int(($percentage * $hash->{helper}{VOLUMESTRAIGHTMAX} / 100 ));
}
#############################
# converts percentage volume in decibel volume (0 .. 100% => volumestraightmin .. volumestraightmax)
sub YAMAHA_NP_volume_abs2rel
{
my ($hash, $absolute) = @_;
# Prevent division by 0
if (defined($hash->{helper}{VOLUMESTRAIGHTMAX}) and $hash->{helper}{VOLUMESTRAIGHTMAX} ne "0")
{
return int($absolute * 100 / int($hash->{helper}{VOLUMESTRAIGHTMAX}));
}
else
{
return int(0)
}
}
#############################
# queries all available inputs
sub YAMAHA_NP_getInputs
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $address = $hash->{helper}{ADDRESS};
# query all inputs
YAMAHA_NP_SendCommand($hash, "<YAMAHA_AV cmd=\"GET\"><System><Config>GetParam</Config></System></YAMAHA_AV>", "statusRequest","getInputs", 0);
return;
}
#############################
# Restarts the internal status request timer according to the given interval or current NP state
sub YAMAHA_NP_ResetTimer
{
my ($hash, $interval) = @_;
RemoveInternalTimer($hash);
if($hash->{helper}{DISABLED} == 0)
{
if(defined($interval))
{
InternalTimer(gettimeofday()+ $interval, "YAMAHA_NP_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_NP_GetStatus", $hash, 0);
}
else
{
InternalTimer(gettimeofday() + $hash->{helper}{OFF_INTERVAL}, "YAMAHA_NP_GetStatus", $hash, 0);
}
}
return;
}
#############################
# convert all HTML entities into UTF-8 equivalent
sub YAMAHA_NP_html2txt
{
my ($string) = @_;
$string =~ s/&quot;/\"/g;
$string =~ s/&amp;/&/g;
$string =~ s/&amp;/&/g;
$string =~ s/&nbsp;/ /g;
$string =~ s/&apos;/'/g;
$string =~ s/(\xe4|&auml;)/ä/g;
$string =~ s/(\xc4|&Auml;)/Ä/g;
$string =~ s/(\xf6|&ouml;)/ö/g;
$string =~ s/(\xd6|&Ouml;)/Ö/g;
$string =~ s/(\xfc|&uuml;)/ü/g;
$string =~ s/(\xdc|&Uuml;)/Ü/g;
$string =~ s/(\xdf|&szlig;)/ß/g;
$string =~ s/<.+?>//g;
$string =~ s/(^\s+|\s+$)//g;
return $string;
}
1;
=pod
=begin html
<a name="YAMAHA_NP"></a>
<h3>YAMAHA_NP</h3>
<ul>
<a name="YAMAHA_NPdefine"></a>
<b>Define</b>
<br><br>
<ul>
<code>
define &lt;name&gt; YAMAHA_NP &lt;ip-address&gt; [&lt;status_interval&gt;]<br><br>
define &lt;name&gt; YAMAHA_NP &lt;ip-address&gt; [&lt;off_status_interval&gt;] [&lt;on_status_interval&gt;]
</code>
<br><br>
This module controls a Yamaha Network Player (such as MCR-N560, MCR-N560D, CRX-N560, CRX-N560D, CD-N500 or NP-S2000) via Ethernet.
Theoretically, any device understanding the communication protocol of the Yamaha Network Player App should work.
<br><br>
Currently implemented features:
<br><br>
<ul>
<li>Power on/off</li>
<li>Timer on/off</li>
<li>Input selection</li>
<li>Timer on/off</li>
<li>Volume +/-</li>
<li>Mute on/off</li>
<li>System Clock Update</li>
<li>Tuner: tune +/-, preset +/-, Station information (FM/DAB)</li>
<li>Stand-by mode: eco/normal</li>
<li>Player (play, stop, next, prev, shuffle, repeat)</li>
<li>Menu navigation</li>
<li>...</li>
</ul>
<br>
Defining a YAMAHA_NP device will schedule an internal task (interval can be set
with optional parameters &lt;off_status_interval&gt; and &lt;on_status_interval&gt; in seconds.<br>
&lt;off_status_interval&gt; is a parameter used in case the device is powered off or not available.<br>
&lt;on_status_interval&gt; is a parameter used in case the device is powered on.<br>
If both parameters are unset, a default value 30 (seconds) for both is used.<br>
If &lt;off_status_interval&gt; is set only the same value is used for both parameters.
<br>
The internal task periodically reads the status of the Network Player (power state, selected
input, volume and mute status etc.) and triggers notify/filelog commands.
<br><br>
Example:<br><br>
<ul><br>
Add the following code into the <b>fhem.cfg</b> configuration file and restart fhem:<br><br>
<code>
define NP_Player YAMAHA_NP 192.168.0.15<br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp<br><br>
# With custom status interval of 60 seconds<br>
define NP_Player YAMAHA_NP 192.168.0.15 <b>60</b><br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp<br><br>
# With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br>
define NP_Player YAMAHA_NP 192.168.0.15 <b>60 10</b><br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp
</code>
</ul>
</ul>
<br><br>
<a name="YAMAHA_NPset"></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.<br>
The available inputs are depending on the used network player.
The module offers only available inputs.<br><br>
<i>Note: Commands and parameters are case sensitive.</i><br>
<ul><br><br>
<u>Available commands:</u><br><br>
<li><b>cdTray</b>&nbsp;&nbsp;-&nbsp;&nbsp; open/close the CD tray.</li>
<li><b>clockUpdate</b>&nbsp;&nbsp;-&nbsp;&nbsp; updates the system clock with current time. The time information is taken from the FHEM server.</li>
<li><b>dimmer</b> [1..3] &nbsp;&nbsp;-&nbsp;&nbsp; Sets the display brightnes.</li>
<li><b>input</b> [&lt;parameter&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; selects the input channel. The inputs are read dynamically from the device. Available inputs can be set (e.g. cd, tuner, aux1, aux2, ...).</li>
<li><b>mute</b> [on|off] &nbsp;&nbsp;-&nbsp;&nbsp; activates/deactivates muting</li>
<li><b>off</b> &nbsp;&nbsp;-&nbsp;&nbsp; shuts down the device </li>
<li><b>on</b> &nbsp;&nbsp;-&nbsp;&nbsp; powers on the device</li>
<li><b>player [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; sets player related commands.</li>
<ul>
<li><b>play</b>&nbsp;&nbsp;-&nbsp;&nbsp; play.</li>
<li><b>stop</b>&nbsp;&nbsp;-&nbsp;&nbsp; stop.</li>
<li><b>pause</b>&nbsp;&nbsp;-&nbsp;&nbsp; pause.</li>
<li><b>next</b>&nbsp;&nbsp;-&nbsp;&nbsp; next item.</li>
<li><b>prev</b>&nbsp;&nbsp;-&nbsp;&nbsp; previous item.</li>
<li><b>shuffleToggle</b>&nbsp;&nbsp;-&nbsp;&nbsp; Toggles the shuffle mode.</li>
<li><b>repeatToggle</b>&nbsp;&nbsp;-&nbsp;&nbsp; Toggles the repeat modes.</li>
</ul>
<li><b>playerListCursorDown</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command moves the cursor down. Next line displayed.</li>
<li><b>playerListCursorReturn</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command returns from a hierarchical sub-menu. Higher level menu displayed.</li>
<li><b>playerListCursorUp</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command moves the cursor up. Previous line displayed.</li>
<li><b>playerListGetList</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command returns readings relevant for list/menu navigation.</li>
<li><b>playerListJumpLine [value]</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command jumps to a given line.</li>
<li><b>playerListSelectLine [value]</b>&nbsp;&nbsp;-&nbsp;&nbsp;Command for list navigation in inputs such as Net Radio or Server. Command selects the given line. In case the line is a 'Container' (folder) it's entered. In case of 'Item' the playback starts.</li>
<li><b>sleep</b> [off|30min|60min|90min|120min] &nbsp;&nbsp;-&nbsp;&nbsp; activates the internal sleep timer</li>
<li><b>standbyMode</b> [eco|normal] &nbsp;&nbsp;-&nbsp;&nbsp; set the standby mode.</li>
<li><b>statusRequest [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; requests the current status of the device</li>
<ul>
<li><b>basicStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests the basic status such as volume input etc.</li>
<li><b>playerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests the player status such as play status, song info, artist info etc.</li>
<li><b>standbyMode</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests the standby mode information</li>
<li><b>systemConfig</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests the system configuration</li>
<li><b>tunerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests the tuner status such as FM frequency, preset number, DAB information etc.</li>
<li><b>timerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests device's internal wake-up timer status</li>
<li><b>networkInfo</b>&nbsp;&nbsp;-&nbsp;&nbsp; requests device's network related information such as IP, Gateway, MAC address etc.</li>
</ul>
<li><b>timerHour</b> [0...23] &nbsp;&nbsp;-&nbsp;&nbsp; sets hour of device's internal wake-up timer</li>
<li><b>timerMinute</b> [0...59] &nbsp;&nbsp;-&nbsp;&nbsp; sets minutes of device's internal wake-up timer</li>
<li><b>timerRepeat</b> [once|every] &nbsp;&nbsp;-&nbsp;&nbsp; sets repetition mode of device's internal wake-up timer</li>
<li><b>timerSet</b> &nbsp;&nbsp;-&nbsp;&nbsp; configures the timer according to timerHour, timerMinute, timerRepeat, timerVolume. (ALL parameters must be set before. This command does not switch on the timer. &rarr; 'timer on'.)</li>
<li><b>timerVolume</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; sets volume of device's internal wake-up timer</li>
<li><b>timer</b> [on|off] &nbsp;&nbsp;-&nbsp;&nbsp; sets device's internal wake-up timer. <i>(Note: The timer will be activated according to the last stored timer parameters in the device. In order to modify please use the 'timerSet' command.)</i></li>
<li><b>tuner [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; sets tuner related commands.</li>
<ul>
<li><b>bandDAB</b>&nbsp;&nbsp;-&nbsp;&nbsp; sets the tuner band to DAB (if available).</li>
<li><b>bandFM</b>&nbsp;&nbsp;-&nbsp;&nbsp; sets the tuner band to FM.</li>
<li><b>tuneUp</b>&nbsp;&nbsp;-&nbsp;&nbsp; tuner tune up.</li>
<li><b>tuneDown</b>&nbsp;&nbsp;-&nbsp;&nbsp; tuner tune down.</li>
<li><b>presetUp</b>&nbsp;&nbsp;-&nbsp;&nbsp; tuner preset up.</li>
<li><b>presetDown</b>&nbsp;&nbsp;-&nbsp;&nbsp; tuner preset down.</li>
</ul>
<li><b>tunerFMFrequency</b> [87.50 ... 108.00] &nbsp;&nbsp;-&nbsp;&nbsp; Sets the FM frequency. The value must be 87.50 ... 108.00 including the decimal point ('.') with two digits after. Otherwise the value will be ignored.</li>
<li><b>tunerPresetDAB</b> [1...30] &nbsp;&nbsp;-&nbsp;&nbsp; Sets the DAB preset.</li>
<li><b>tunerPresetFM</b> [1...30] &nbsp;&nbsp;-&nbsp;&nbsp; Sets the FM preset.</li>
<li><b>volume</b> [0...100] &nbsp;&nbsp;-&nbsp;&nbsp; set the volume level in &#037;</li>
<li><b>volumeStraight</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; set the volume as used and displayed in the device. &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; are read and set from the device automatically.</li>
<li><b>volumeUp</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; increases the volume by one device's absolute step. &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; are read and set from the device automatically.</li>
<li><b>volumeDown</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; increases the volume by one device's absolute step. &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; are read and set from the device automatically.</li>
</ul><br><br>
A typical example is powering the device remotely and tuning the favourite radio station:<br><br>
Add the following code into the <b>fhem.cfg</b> configuration file:<br><br><br>
<ul>
<code>
define NP_player YAMAHA_NP 192.168.0.15 30 5<br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp
</code>
</ul><br><br>
Add the following code into the <b>99_MyUtils.pm</b> file:<br><br>
<ul>
<code>
sub startMyFavouriteRadioStation()<br>
{<br>
&nbsp;&nbsp;fhem "set NP_player on";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player input tuner";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player tunerPresetDAB 1";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player volume 30";<br>
}
</code>
</ul>
<br><br>
It's a good idea to insert a 'sleep' instruction between each fhem commands due to internal processing time of the network player. During that time the following commands might be ignored...<br><br>
Now the function can be called by typing the following line in the FHEM command line or by the notify-definitions:<br><br>
<ul>
<code>
{startMyFavouriteRadioStation()}<br><br>
</code>
</ul>
</ul>
<a name="YAMAHA_NPget"></a>
<b>Get</b>
<ul>
<code>
get &lt;name&gt; &lt;reading&gt;
</code>
<br><br>
Currently, the 'get' command returns reading values only. For a specific list of possible values, see section <b>"Generated Readings"</b>.<br><br>
</ul>
<a name="YAMAHA_NPattr"></a>
<b>Attributes</b><br><br>
<ul>
<ul>
<li><b><a href="#do_not_notify">do_not_notify</a></b></li>
<li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li>
<li><b><a name="request-timeout">request-timeout</a></b></li>
<br>Optional attribute change the response timeout in seconds for all queries to the receiver.
<br>Possible values: 1...5 seconds. Default value is 4 seconds.<br><br>
<li><b><a name="disable">disable</a></b></li>
<br>Optional attribute to disable the internal cyclic status update of the receiver. Manual status updates via statusRequest command is still possible.
<br>Possible values: 0 &rarr; perform cyclic status update, 1 &rarr; don't perform cyclic status updates.<br><br>
<li><b><a name="auto-update-player-readings">auto-update-player-readings</a></b></li>
<br>Optional attribute for auto refresh of player related readings. Default is 1.<br><br>
<li><b><a name="auto-update-tuner-readings">auto-update-tuner-readings</a></b></li>
<br>Optional attribute for auto refresh of tuner related readings. Default is 1.<br><br>
<li><b><a name="smooth-volume-change">smooth-volume-change</a></b></li>
<br>Optional attribute for smooth volume change (more Ethernet traffic is generated during volume change). Default is 1.<br><br>
<br><br>
</ul>
</ul>
<b>Readings</b><br>
<ul>
<ul>
<br><br><u>Basic readings:</u><br><br>
<li><b>input</b> - The selected input source according to the FHEM input commands</li>
<li><b>mute</b> - Reports the mute status of the receiver (on|off)</li>
<li><b>power</b> - Reports the power status of the receiver (on|off)</li>
<li><b>presence</b> - Reports the presence status of the receiver or zone (absent|present). <i>Note: In case of "absent", the device cannot be controlled by FHEM. Check standbyMode.</i></li>
<li><b>volume</b> - Reports the current volume level of the receiver in &#037; (0...100&#037;)</li>
<li><b>volumeStraight</b> - Reports the current volume level of the receiver as used and displayed in the device (values device specific)</li>
<li><b>sleep</b> - Reports the current sleep timer status (30min|60min|90min|120min|off).</li>
<li><b>standbyMode</b> - Reports the standby mode (eco|normal).</li>
<li><b>state</b> - Reports the current power state and an absence of the device (on|off|absent)</li>
<br><br><u>Player related readings:</u><br><br>
<i>Note: In order to update the following readings use "statusRequest playerStatus" first.</i><br><br>
<li><b>playerPlaybackInfo</b> - Reports current player state (play|stop|pause).</li>
<li><b>playerDeviceType</b> - Reports the device type (ipod|msc).</li>
<li><b>playerIpodMode</b> - Reports the Ipod Mode (normal|off)</li>
<li><b>playerRepeat</b> - Reports the Repeat Mode (one|off)</li>
<li><b>playerShuffle</b> - Reports the Shuffle Mode (on|off)</li>
<li><b>playerPlayTime</b> - Reports the play time of the currently played audio (HH:MM:SS).</li>
<li><b>playerTrackNumber</b> - Reports the track number of the currently played audio.</li>
<li><b>playerTotalTracks</b> - Reports the total number of tracks for playing.</li>
<li><b>playerArtist</b> - Reports the artist (if available) of the currently played audio.</li>
<li><b>playerAlbum</b> - Reports the album (if available) of the currently played audio.</li>
<li><b>playerSong</b> - Reports the song name (if available) of the currently played audio.</li>
<li><b>playerAlbumArtURL</b> - Reports the album art url (if available) of the currently played audio. The URL points to the network player.</li>
<li><b>playerAlbumArtID</b> - Reports the album art ID (if available) of the currently played audio.</li>
<li><b>playerAlbumArtFormat</b> - Reports the album art format (if available) of the currently played audio.</li>
<br><br><u>Player List (Menu) related readings:</u><br><br>
<i>Note: In order to update the following readings use "statusRequest playerStatus" first.</i><br><br>
<li><b>playerListCurrentLine</b> - Reports the current active list line as displayd.</li>
<li><b>playerListLine_1..._8</b> - Reports the content of the Line 1...8 as provided by the device.</li>
<li><b>playerListLine_Attribute_1..._8</b> - Reports the attribute of the Line 1...8 (Container|Item|Unselectable).</li>
<li><b>playerListMaxLine</b> - Reports the number of lines in current list/menu.</li>
<li><b>playerListMenuName</b> - Reports the name of the current list/menu.</li>
<li><b>playerListStatus</b> - Reports the status of the current list/menu (Busy|Ready).</li>
<br><br><u>Tuner related readings:</u><br><br>
<i>Note: In order to update the following readings use "statusRequest tunerStatus" first.</i><br><br>
<li><b>tunerAudioModeDAB</b> - Reports current audio mode (Mono|Stereo).</li>
<li><b>tunerBand</b> - Reports the currently selected tuner band (FM|DAB). DAB if available.</li>
<li><b>tunerBitRateDAB</b> - Reports current DAB stream bit rate (kbit/s).</li>
<li><b>tunerPresetFM</b> - Reports the currently selected FM preset. If stored as such (1...30).</li>
<li><b>tunerFrequencyDAB</b> - Reports the currently tuned DAB frequency. (xxx.xxx MHz)</li>
<li><b>tunerFrequencyFM</b> - Reports the currently tuned FM frequency. (xxx.xx MHz)</li>
<li><b>tunerModeDAB</b> - Reports current DAB audio mode (DAB|DAB+).</li>
<li><b>tunerProgramServiceFM</b> - Reports the FM service name.</li>
<li><b>tunerRadioTextAFM</b> - Reports the Radio Text A of the selected FM service.</li>
<li><b>tunerRadioTextBFM</b> - Reports the Radio Text B of the selected FM service.</li>
<li><b>tunerPresetDAB</b> - Reports the currently selected DAB preset. If stored as such (1...30).</li>
<li><b>tunerServiceLabelDAB</b> - Reports the service label of the selected DAB service.</li>
<li><b>tunerChannelLabelDAB</b> - Reports the channel label of the selected DAB service.</li>
<li><b>tunerDLSDAB</b> - Reports the dynamic label segment of the selected DAB service.</li>
<li><b>tunerEnsembleLabelDAB</b> - Reports the ensemble label of the selected DAB service.</li>
<br><br><u>Timer related readings:</u><br><br>
<i>Note: In order to update the following readings use "statusRequest timerStatus" first.</i><br><br>
<li><b>timer</b> - Reports the time mode (on|off).</li>
<li><b>timerRepeat</b> - Reports the timer repeat mode (once|every).</li>
<li><b>timerStartTime</b> - Reports the timer start time (HH:MM).</li>
<li><b>timerVolumeLevel</b> - Reports the timer volume level.</li>
</ul>
</ul><br>
<b>Implementer's note</b><br><br>
<ul>
Trivial: In order to use that module the network player must be connected to the Ethernet.<br>
The device must be in standbyMode "Normal" in order to power on.<br>
However, even if the standbyMode is set to "Eco" the device can be powered off. In that case it has to be switched on manually.<br>
</ul><br>
</ul>
=end html
=begin html_DE
<a name="YAMAHA_NP"></a>
<h3>YAMAHA_NP</h3>
<ul>
<a name="YAMAHA_NPdefine"></a>
<b>Define</b><br><br>
<ul>
<code>
define &lt;name&gt; YAMAHA_NP &lt;ip-address&gt; [&lt;status_interval&gt;]<br><br>
define &lt;name&gt; YAMAHA_NP &lt;ip-address&gt; [&lt;off_status_interval&gt;] [&lt;on_status_interval&gt;]
</code>
<br><br>
Mit Hilfe dieses Moduls lassen sich Yamaha Network Player (z.B. MCR-N560, MCR-N560D, CRX-N560, CRX-N560D, CD-N500 or NP-S2000) via Ethernet steuern.<br>
Theoretisch sollten alle Ger&auml;te, die mit der Yamaha Network Player App kompatibel sind, bedient werden k&ouml;nnen.<br><br>
Die aktuelle Implementierung erm&ouml;glicht u.a. den folgenden Funktionsumfang:<br><br>
<ul>
<li>Power on/off</li>
<li>Timer on/off</li>
<li>Input selection</li>
<li>Timer on/off</li>
<li>Volume +/-</li>
<li>Mute on/off</li>
<li>System Clock Update</li>
<li>Tuner: tune +/-, preset +/-, Senderinformation (FM/DAB)</li>
<li>Stand-by mode: eco/normal</li>
<li>Player (play, stop, next, prev, shuffle, repeat)</li>
<li>Men&uuml;navigation</li>
<li>...</li>
</ul>
<br>
Eine YAMAHA_NP Definition initiiert einen internen Task, der von FHEM zyklisch abgearbeitet wird.<br>
Das Intervall (in Sekunden) kann f&uuml;r die Zust&auml;nde &lt;on_status_interval&gt; und &lt;off_status_interval&gt; optional gesetzt werden.<br>
&lt;off_status_interval&gt; steht f&uuml;r das Intervall, wenn das Ger&auml;t ausgeschaltet/abwesend ist.<br>
&lt;on_status_interval&gt; steht f&uuml;r das Intervall, wenn das Ger&auml;t eingeschaltet/verf&uuml;gbar ist.<br>
Wenn keine Parametere angegeben wurden, wird ein Default-Wert von 30 Sekunden f&uuml;r beide gesetzt.<br>
Wenn nur &lt;off_status_interval&gt; gesetzt wird, gilt dieser Wert f&uuml;r beide Zust&auml;nde (eingeschaltet/ausgeschaltet).<br>
Der Task liest zyklisch grundlegende Parameter vom Network Player wie z.B. (Power-Status , gew&auml;hlter Eingang, Lautst&auml;rke etc.) und triggert notify/filelog Befehle.<br><br>
Beispiel:<br><br>
<ul><br>
Definition in der <b>fhem.cfg</b> Konfigurationsdatei:<br><br>
<code>
define NP_Player YAMAHA_NP 192.168.0.15<br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp<br><br>
# 60 Sekunden Intervall<br>
define NP_Player YAMAHA_NP 192.168.0.15 <b>60</b><br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp<br><br>
# 60 Sekunden Intervall f&uuml;r "off" und 10 Sekunden f&uuml;r "on"<br>
define NP_Player YAMAHA_NP 192.168.0.15 <b>60 10</b><br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp
</code>
</ul>
</ul><br><br>
<a name="YAMAHA_NPset"></a>
<b>Set</b>
<ul>
<code>
set &lt;name&gt; &lt;command&gt; [&lt;parameter&gt;]
</code>
<br><br>
Aktuell sind folgende Befehle implementiert:<br>
Die verf&uuml;gbaren Eing&auml;nge des Network Players werden vom diesem gelesen und dynamisch in FHEM angepasst.<br><br>
<i>Bemerkung: Bitte bei den Befehlen und Parametern die Gro&szlig;- und Kleinschreibung beachten.</i><br><br>
<ul><br><br>
<u>Verf&uuml;gbare Befehle:</u><br><br>
<li><b>cdTray</b>&nbsp;&nbsp;-&nbsp;&nbsp; &Ouml;ffnen und Schlie&szlig;en des CD-Fachs.</li>
<li><b>clockUpdate</b>&nbsp;&nbsp;-&nbsp;&nbsp; Aktualisierung der Systemzeit des Network Players. Die Zeitinformation wird von dem FHEM Server bezogen, auf dem das Modul ausgef&uuml;hrt wird.</li>
<li><b>dimmer</b> [1..3] &nbsp;&nbsp;-&nbsp;&nbsp; Einstellung der Anzeigenhelligkeit.</li>
<li><b>input</b> [&lt;parameter&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; Auswahl des Eingangs des NP. Der aktive Eingang wird vom Ger&auml;t gelesen und in FHEM dynamisch dargestellt (z.B. cd, tuner, aux1, aux2, ...).</li>
<li><b>mute</b> [on|off] &nbsp;&nbsp;-&nbsp;&nbsp; Aktiviert/Deaktiviert die Stummschaltung.</li>
<li><b>off</b> &nbsp;&nbsp;-&nbsp;&nbsp; Network Player ausschalten.</li>
<li><b>on</b> &nbsp;&nbsp;-&nbsp;&nbsp; Network Player einschalten.</li>
<li><b>player [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; Setzt Player relevante Befehle.</li>
<ul>
<li><b>play</b>&nbsp;&nbsp;-&nbsp;&nbsp; play.</li>
<li><b>stop</b>&nbsp;&nbsp;-&nbsp;&nbsp; stop.</li>
<li><b>pause</b>&nbsp;&nbsp;-&nbsp;&nbsp; pause.</li>
<li><b>next</b>&nbsp;&nbsp;-&nbsp;&nbsp; n&auml;chstes Audiost&uuml;ck.</li>
<li><b>prev</b>&nbsp;&nbsp;-&nbsp;&nbsp; vorheriges Audiost&uuml;ck.</li>
<li><b>shuffleToggle</b>&nbsp;&nbsp;-&nbsp;&nbsp; Umschaltung des Zufallswiedergabe.</li>
<li><b>repeatToggle</b>&nbsp;&nbsp;-&nbsp;&nbsp; Umschaltung des Wiederholungsmodes.</li>
</ul>
<li><b>playerListCursorDown</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl bewegt den Cursor nach unten. N&auml;chste Zeile wird im Ger&auml;t angezeit.</li>
<li><b>playerListCursorReturn</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl kehrt zur&uuml;ck vom hierarchischen, untergeordneten Men&uuml;. &Uuml;bergeordnetes Men&uuml; wird angezeigt.</li>
<li><b>playerListCursorUp</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl bewegt den Cursor nach oben. Vorherige Zeile wird im Ger&auml;t angezeit.</li>
<li><b>playerListGetList</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl liefert Informationen (Readings) relevant zur Men&uuml;navigation.</li>
<li><b>playerListJumpLine [value]</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl spring zur angegebenen Zeile.</li>
<li><b>playerListSelectLine [value]</b>&nbsp;&nbsp;-&nbsp;&nbsp;Befehl zur Navigation in Eing&auml;ngen wie Net Radio oder Server. Befehl aktiviert die angegebenen Zeile. Falls die Zeile das Attribut 'Container' (Ordner) besitzt, wird dieser ge&ouml;ffnet. Falls 'Item' wird die Wiedergabe gestartet.</li>
<li><b>sleep</b> [off|30min|60min|90min|120min] &nbsp;&nbsp;-&nbsp;&nbsp; Aktiviert/Deaktiviert den internen Sleep-Timer</li>
<li><b>standbyMode</b> [eco|normal] &nbsp;&nbsp;-&nbsp;&nbsp; Umschaltung des Standby Modus.</li>
<li><b>statusRequest [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; Abfrage des aktuellen Status des Network Players.</li>
<ul>
<li><b>basicStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage der Elementarparameter (z.B. Lautst&auml;rke, Eingang, etc.)</li>
<li><b>playerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage des Player-Status.</li>
<li><b>standbyMode</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage des standby Modus.</li>
<li><b>systemConfig</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage der Systemkonfiguration.</li>
<li><b>tunerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage des Tuner-Status (z.B. FM Frequenz, Preset-Nummer, DAB Information etc.)</li>
<li><b>timerStatus</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage des internen Wake-up timers.</li>
<li><b>networkInfo</b>&nbsp;&nbsp;-&nbsp;&nbsp; Abfrage von Netzwerk-relevanten Informationen (z.B: IP-Adresse, Gateway-Adresse, MAC-address etc.)</li>
</ul>
<li><b>timerHour</b> [0...23] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die Stunde des internen Wake-up Timers</li>
<li><b>timerMinute</b> [0...59] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die Minute des internen Wake-up Timers</li>
<li><b>timerRepeat</b> [once|every] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt den Wiederholungsmodus des internen Wake-up Timers</li>
<li><b>timerSet</b> &nbsp;&nbsp;-&nbsp;&nbsp; konfiguriert den Timer nach den Vorgaben: timerHour, timerMinute, timerRepeat, timerVolume. (ALLE Paremeter m&uuml;ssen zuvor gesetzt werden. Dieser Befehl schaltet den Timer nicht ein &rarr; 'timer on'.)</li>
<li><b>timerVolume</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die Lautst&auml;rke des internen Wake-up Timers</li>
<li><b>timer</b> [on|off] &nbsp;&nbsp;-&nbsp;&nbsp; Schaltet ein/aus den internen Wake-up Timer. <i>(Bemerkung: Der Timer wird basierend auf den im Ger&auml;t gespeicherten Parametern aktiviert. Um diese zu &auml;ndern, bitte den 'timerSet' Befehl benutzen.)</i></li>
<li><b>tuner [&lt;parameter&gt;] </b> &nbsp;&nbsp;-&nbsp;&nbsp; Tuner-relevante Befehle.</li>
<ul>
<li><b>bandDAB</b>&nbsp;&nbsp;-&nbsp;&nbsp; Setzt das Tuner-Band auf DAB (falls verf&uuml;gbar).</li>
<li><b>bandFM</b>&nbsp;&nbsp;-&nbsp;&nbsp; Setzt das Tuner-Band auf FM.</li>
<li><b>tuneUp</b>&nbsp;&nbsp;-&nbsp;&nbsp; Tuner Frequenz +.</li>
<li><b>tuneDown</b>&nbsp;&nbsp;-&nbsp;&nbsp; Tuner Frquenz -.</li>
<li><b>presetUp</b>&nbsp;&nbsp;-&nbsp;&nbsp; Tuner Voreinstellung hoch.</li>
<li><b>presetDown</b>&nbsp;&nbsp;-&nbsp;&nbsp; Tuner Voreinstellung runter.</li>
</ul>
<li><b>tunerFMFrequency</b> [87.50 ... 108.00] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die FM Frequenz. Der Wert muss zwischen 87.50 ... 108.00 liegen und muss den Digitalpunkt beinhalten ('.') mit zwei Nachkommastellen.</li>
<li><b>tunerPresetDAB</b> [1...30] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die DAB Voreinstellung.</li>
<li><b>tunerPresetFM</b> [1...30] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die FM Voreinstellung.</li>
<li><b>volume</b> [0...100] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt den Lautst&auml;rkepegel in &#037;</li>
<li><b>volumeStraight</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; Setzt die absolute Lautst&auml;rke wie vom Ger&auml;t benutzt und angezeigt. Die Parameter &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; werden automatisch ermittelt.</li>
<li><b>volumeUp</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; Erh&ouml;ht die Lautst&auml;rke um einen absoluten Schritt. Die Parameter &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; werden automatisch ermittelt.</li>
<li><b>volumeDown</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &nbsp;&nbsp;-&nbsp;&nbsp; Reduziert die Lautst&auml;rke um einen absoluten Schritt. Die Parameter &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; werden automatisch ermittelt.</li>
</ul><br><br>
Ein typisches Beispiel ist das Einschalten des Ger&auml;tes und das Umschalten auf den Lieblingsradiosender:<br><br>
Beispieldefinition in der <b>fhem.cfg</b> Konfigurationsdatei:<br><br><br>
<ul>
<code>
define NP_player YAMAHA_NP 192.168.0.15 30 5<br>
attr NP_player webCmd input:volume:mute:volumeDown:volumeUp
</code>
</ul><br><br>
Folgender Code kann anschlie&szlig;end in die Datei <b>99_MyUtils.pm</b> eingebunden werden:<br><br>
<ul>
<code>
sub startMyFavouriteRadioStation()<br>
{<br>
&nbsp;&nbsp;fhem "set NP_player on";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player input tuner";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player tunerPresetDAB 1";<br>
&nbsp;&nbsp;sleep 1;<br>
&nbsp;&nbsp;fhem "set NP_player volume 30";<br>
}
</code>
</ul><br><br>
<i>Bemerkung: Aufgrund der relativ langsamen Befehlsverarbeitung im Network Player im Vergleich zur asynchronen Ethernet-Kommunikation, kann es vorkommen, dass veraltete Statusinformationen zur&uuml;ckgesendet werden.<br>
Aus diesem Grund wird empfohlen, w&auml;hrend der Automatisierung zwischen den 'set' und 'get' Befehlen ein Delay einzubauen. Speziell beim Hochfahren des Network Players sollte dies beachtet werden.</i><br><br>
Die Funktion kann jetzt in der FHEM Befehlszeile eingegeben oder in die Notify-Definitionen eingebunden werden.<br><br>
<ul>
<code>
{startMyFavouriteRadioStation()}<br><br>
</code>
</ul>
</ul>
<a name="YAMAHA_NPget"></a>
<b>Get</b>
<code>
get &lt;name&gt; &lt;reading&gt;
</code><br><br>
Aktuell liefert der Befehl 'get' ausschlie&szlig;lich Reading-Werte (s. Abschnitt <b>"Readings"</b>).<br><br>
</ul>
<a name="YAMAHA_NPattr"></a>
<ul>
<b>Attribute</b><br><br>
<ul>
<ul>
<li><b><a href="#do_not_notify">do_not_notify</a></b></li>
<li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li><br>
<li><b><a name="request-timeout">request-timeout</a></b></li><br>
Optionales Attribut, um das HTTP response timeout zu beeinflu&szlig;en.<br>
M&ouml;gliche Werte: 1...5 Sekunden. Default Wert ist 4 Sekunden.<br><br>
<li><b><a name="disable">disable</a></b></li><br>
Optionales Attribut zum Deaktivieren des internen zyklischen Timers zum Aktualisieren des NP-Status. Manuelles Update ist nach wie vor m&ouml;glich.<br>
M&ouml;gliche Werte: 0 &rarr; Zyklisches Update aktiv., 1 &rarr; Zyklisches Update inaktiv.<br><br>
<li><b><a name="auto-update-player-readings">auto-update-player-readings</a></b></li>
<br>Optionales Attribut zum automtischen aktualisieren der Player-Readings. Default-Wert ist 1.<br><br>
<li><b><a name="auto-update-tuner-readings">auto-update-tuner-readings</a></b></li>
<br>Optionales Attribut zum automtischen aktualisieren der Tuner-Readings. Default-Wert ist 1.<br><br>
<li><b><a name="smooth-volume-change">smooth-volume-change</a></b></li>
<br>Optionales Attribut zur sanften Lautst&auml;rke&auml;nderung (Erzeugt mehr Ethernetkommunikation w&auml;hrend der Lautst&auml;rke&auml;nderung). Default-Wert ist 1.<br><br>
<br><br>
</ul>
</ul>
<b>Readings</b><br>
<ul>
<ul>
<br><br><u>Elementar-Readings:</u><br><br>
<li><b>input</b> - Aktivierter Eingang.</li>
<li><b>mute</b> - Abfrage des Mute Status (on|off)</li>
<li><b>power</b> - Abfrage des Power-Status (on|off)</li>
<li><b>presence</b> - Abfrage der Ger&auml;teanwesenheit im Netzwerk (absent|present). <i>Bemerkung: Falls abwesend ("absent"), l&auml;sst sich das Ger&auml;t nicht fernbedienen.</i></li>
<li><b>volume</b> - Abfrage der aktuell eingestellten Lautst&auml;rke in &#037; (0...100&#037;)</li>
<li><b>volumeStraight</b> - Abfrage der aktuellen absoluten Ger&auml;telautst&auml;rke im Ger&auml;t (ger&auml;tespezifisch)</li>
<li><b>sleep</b> - Abfrage des Sleep-Timer Status (30min|60min|90min|120min|off).</li>
<li><b>standbyMode</b> - Abfrage des standby Modus (eco|normal).</li>
<li><b>state</b> - Abfrage des aktuellen Power Zustands und Anwesenheit (on|off|absent).</li>
<br><br><u>Player Readings:</u><br><br>
<i>Bemerkung: Die folgenden Readings werden mit dem Befehl "statusRequest playerStatus" aktualisiert.</i><br><br>
<li><b>playerPlaybackInfo</b> - Abfrage des aktuellen Player Status (play|stop|pause).</li>
<li><b>playerDeviceType</b> - Abfrage des Device Typs (ipod|msc).</li>
<li><b>playerIpodMode</b> - Abfrage des *Pod/*Pad/*Phone Modus (normal|off)</li>
<li><b>playerRepeat</b> - Abfrage des Wiederholungsmodus (one|all)</li>
<li><b>playerShuffle</b> - Abfrage des Zufallswiedergabemodus (on|off)</li>
<li><b>playerPlayTime</b> - Abfrage der aktuellen Spielzeit (HH:MM:SS).</li>
<li><b>playerTrackNumber</b> - Abfrage der Audiotracknummer.</li>
<li><b>playerTotalTracks</b> - Abfrage der Gesamtzahl der zu wiedergebenden Tracks.</li>
<li><b>playerArtist</b> - Abfrage des K&uuml;nstler (Artist) (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<li><b>playerAlbum</b> - Abfrage des Albumnamens (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<li><b>playerSong</b> - Abfrage des Tracknamens (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<li><b>playerAlbumArtURL</b> - Abfrage der Album URL (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<li><b>playerAlbumArtID</b> - Abfrage der AlbumArtID (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<li><b>playerAlbumArtFormat</b> - Abfrage des AlbumArt Formats (falls verf&uuml;gbar) der aktuellen Wiedergabe.</li>
<br><br><u>Player List (Menu) Readings:</u><br><br>
<i>Bemerkung: Die folgenden Readings werden mit dem Befehl "statusRequest playerStatus" aktualisiert.</i><br><br>
<li><b>playerListCurrentLine</b> - Abfrage der aktuellen Listenzeile (wie im Ger&auml;t angezeigt).</li>
<li><b>playerListLine_1..._8</b> - Abfrage des Listeninhalts Zeile 1...8 (Das Ger&auml;t liefert 8 Zeilen Pakete).</li>
<li><b>playerListLine_Attribute_1..._8</b> - Abfrage der Listenzeilenattribute Zeile 1...8 (Container|Item|Unselectable).</li>
<li><b>playerListMaxLine</b> - Abfrage der Anzahl von Listenzeilen in der aktuellen Liste/Menu.</li>
<li><b>playerListMenuName</b> - Abfrage der bezeichnung der aktuellen Liste/Menus.</li>
<li><b>playerListStatus</b> - Abfrage des aktuellen Status der Liste/Menus (Busy|Ready).</li>
<br><br><u>Tuner Readings:</u><br><br>
<i>Bemerkung: Die folgenden Readings werden mit dem Befehl "statusRequest tunerStatus" aktualisiert.</i><br><br>
<li><b>tunerAudioModeDAB</b> - Abfrage des aktuellen DAB Audio-Modus (Mono|Stereo)..</li>
<li><b>tunerBand</b> - Abfrage des aktuellen Radio-Bandes (FM|DAB). DAB falls verf&uuml;gbar.</li>
<li><b>tunerBitRate</b> - Abfrage der aktuellen DAB Stream Bitrate (kbit/s).</li>
<li><b>tunerModeDAB</b> - Abfrage des aktuellen DAB Modus (DAB|DAB+).</li>
<li><b>tunerFrequencyDAB</b> - Abfrage der aktuellen DAB Frequenz. (xxx.xxx MHz)</li>
<li><b>tunerPresetFM</b> - Abfrage der aktuellen FM Voreinstellung. Falls gespeichtert (1...30).</li>
<li><b>tunerFrequencyFM</b> - Abfrage der aktuellen FM Frequenz. (xxx.xx MHz)</li>
<li><b>tunerProgramServiceFM</b> - Abfrage des FM Sendernamen.</li>
<li><b>tunerRadioTextAFM</b> - Abfrage des Radio Text A des FM Senders.</li>
<li><b>tunerRadioTextBFM</b> - Abfrage des Radio Text B des FM Senders.</li>
<li><b>tunerPresetDAB</b> - Abfrage der aktuellen DAB Voreinstellung. Falls gespeichtert (1...30).</li>
<li><b>tunerServiceLabelDAB</b> - Abfrage des DAB Sendernamen.</li>
<li><b>tunerChannelLabelDAB</b> - Abfrage des Channel Labels des gew&auml;hlten DAB Senders.</li>
<li><b>tunerDLSDAB</b> - Abfrage des 'Dynamic Label Segment' des gew&auml;hlten DAB Senders.</li>
<li><b>tunerEnsembleLabelDAB</b> - Abfrage des 'Ensemble Label' des gew&auml;hlten DAB Senders.</li>
<br><br><u>Timer Readings:</u><br><br>
<i>Bemerkung: Die folgenden Readings werden mit dem Befehl "statusRequest timerStatus" aktualisiert.</i><br><br>
<li><b>timer</b> - Abfrage des Time Modus (Wecker) (on|off).</li>
<li><b>timerRepeat</b> - Abfrage des Timer Wiederholungs Modus (once|every).</li>
<li><b>timerStartTime</b> - Abfrage der Timer Startzeit (HH:MM).</li>
<li><b>timerVolumeLevel</b> - Abfrage der Timer-Lautst&auml;rke.</li>
</ul>
</ul><br>
<b>Bemerkung des Entwicklers</b><br><br>
<ul>
Trivial: Um das Ger&auml;t fernbedienen zu k&ouml;nnen, muss es an das Ethernet-Netzwerk angeschlossen und erreichbar sein.<br>
Das Ger&auml;t muss sich im standbyMode "Normal" befinden, um es fergesteuert einzuschalten.<br>
Das Abschalten funktioniert auch standbyMode "Normal" Modus.<br>
</ul><br>
</ul>
=end html_DE
=cut