71_YAMAHA_NP.pm 121 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039
  1. # $Id: 71_YAMAHA_NP.pm 16025 2018-01-28 17:48:28Z ra666ack $
  2. ###############################################################################
  3. #
  4. # 71_YAMAHA_NP.pm
  5. #
  6. # Fhem Perl module for controlling the Yamaha PianoCraft(TM) HiFi
  7. # Network Audiosystem MCR-N560(D) over Ethernet.
  8. # The system is also marketed as CRX-N560(D).
  9. #
  10. # The module might also work with other devices such as
  11. # NP-S2000, CD-N500, CD-N301, R-N500, R-N301 or any other device
  12. # implementing the Yamaha Network Player Controller(TM) protocol:
  13. #
  14. # i*S:
  15. # https://itunes.apple.com/us/app/network-player-controller-us/id467502483?mt=8
  16. #
  17. # Andr*id:
  18. # https://play.google.com/store/apps/details?id=com.yamaha.npcontroller
  19. #
  20. # Since the used communication protocol is undisclosed the module bases on
  21. # entirely reverse engineered implementation.
  22. # Some features may be unavailable.
  23. # (Online check for new firmware was excluded intentionally.)
  24. #
  25. # Many thanks go to martinp876 for his contribution to the source code
  26. # and improved usability of the module.
  27. #
  28. # Copyright by ra666ack (ra666ack a t 9 m a 1 l d 0 t c 0 m)
  29. #
  30. # This file is part of fhem.
  31. #
  32. # Fhem is free software: you can redistribute it and/or modify
  33. # it under the terms of the GNU general Public License as published by
  34. # the Free Software Foundation, either version 2 of the License, or
  35. # (at your option) any later version.
  36. #
  37. # Fhem is distributed in the hope that it will be useful,
  38. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  39. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  40. # GNU general Public License for more details.
  41. #
  42. # You should have received a copy of the GNU general Public License
  43. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  44. #
  45. ###############################################################################
  46. package main;
  47. use strict;
  48. use warnings;
  49. use Time::HiRes qw(gettimeofday sleep);
  50. use Time::Piece;
  51. use POSIX qw{strftime};
  52. use HttpUtils;
  53. use List::Util qw(first);
  54. sub YAMAHA_NP_Initialize
  55. {
  56. my ($hash) = @_;
  57. $hash->{DefFn} = "YAMAHA_NP_Define";
  58. $hash->{GetFn} = "YAMAHA_NP_Get";
  59. $hash->{SetFn} = "YAMAHA_NP_Set";
  60. $hash->{AttrFn} = "YAMAHA_NP_Attr";
  61. $hash->{UndefFn} = "YAMAHA_NP_Undefine";
  62. $hash->{NotifyFn} = "YAMAHA_NP_Notify";
  63. # Generate pulldown menu for the Timer Volume
  64. # according to device specific range
  65. my $name = $hash->{NAME};
  66. my $volumeStraightMin = ReadingsVal($name,".volumeStraightMin",0);
  67. my $volumeStraightMax = ReadingsVal($name,".volumeStraightMax",60);
  68. my $timerVolume = "timerVolume:";
  69. my $i;
  70. for($i = $volumeStraightMin; $i < $volumeStraightMax; $i++)
  71. {
  72. $timerVolume .= "$i,";
  73. }
  74. $timerVolume .= "$i";
  75. $hash->{AttrList} = "do_not_notify:0,1"
  76. ." disable:0,1"
  77. ." requestTimeout:1,2,3,4,5"
  78. ." model"
  79. ." autoUpdatePlayerReadings:1,0"
  80. ." autoUpdateTunerReadings:1,0"
  81. ." autoUpdatePlayerlistReadings:1,0"
  82. ." searchAttempts"
  83. ." directPlaySleepNetradio: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"
  84. ." directPlaySleepServer: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"
  85. ." smoothVolumeChange:1,0"
  86. ." .favoriteList" # Hidden attribute for favorites storage
  87. ." .DABList" # Hidden attribute for DAB list storage
  88. ." maxPlayerListItems"
  89. ." $timerVolume"
  90. ." timerRepeat:once,every"
  91. ." 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"
  92. ." 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"
  93. ." ".$readingFnAttributes;
  94. }
  95. sub YAMAHA_NP_Define
  96. {
  97. my ($hash, $def) = @_;
  98. my @a = split("[ \t][ \t]*", $def);
  99. my $name = $hash->{NAME};
  100. if(! @a >= 3)
  101. {
  102. my $msg = "Wrong syntax: define <name> YAMAHA_NP <ip-or-hostname> [<OFF-statusinterval>] [<ON-statusinterval>] ";
  103. Log3 $name, 2, $msg;
  104. return $msg;
  105. }
  106. my $address = $a[2];
  107. $hash->{helper}{ADDRESS} = $address;
  108. # if an update interval was given >0, use it.
  109. if(defined($a[3]) and $a[3] > 0)
  110. {
  111. $hash->{helper}{OFF_INTERVAL} = $a[3];
  112. }
  113. else
  114. {
  115. $hash->{helper}{OFF_INTERVAL} = 30;
  116. }
  117. if(defined($a[4]) and $a[4] > 0)
  118. {
  119. $hash->{helper}{ON_INTERVAL} = $a[4];
  120. }
  121. else
  122. {
  123. $hash->{helper}{ON_INTERVAL} = $hash->{helper}{OFF_INTERVAL};
  124. }
  125. YAMAHA_NP_getInputs($hash);
  126. unless(exists($hash->{helper}{AVAILABLE}) and ($hash->{helper}{AVAILABLE} == 0))
  127. {
  128. $hash->{helper}{AVAILABLE} = 1;
  129. }
  130. # Timeout for directPlay
  131. $attr{$name}{"searchAttempts"} = 15;
  132. $attr{$name}{".favoriteList"} = ""
  133. ."aux1:aux1;"
  134. ."aux2:aux2;"
  135. ."airplay:airplay;"
  136. ."cd:cd;"
  137. ."digital1:digital1;"
  138. ."digital2:digital2;"
  139. ."netradio:netradio;"
  140. ."server:server;"
  141. ."spotify:spotify;"
  142. ."DAB:DAB;"
  143. ."FM:FM;"
  144. ."usb:usb;"
  145. ;
  146. YAMAHA_NP_favoriteList($name);
  147. # start the status update timer
  148. $hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED}));
  149. YAMAHA_NP_ResetTimer($hash,0);
  150. }
  151. sub YAMAHA_NP_Undefine
  152. {
  153. my($hash, $name) = @_;
  154. # Stop the internal GetStatus-Loop and exit
  155. RemoveInternalTimer($hash);
  156. }
  157. sub YAMAHA_NP_Attr
  158. {
  159. my ($cmd, $name, $attrName, $attrVal) = @_;
  160. my $hash = $defs{$name};
  161. if($attrName eq "disable")
  162. {
  163. if ($cmd eq "set")
  164. {
  165. $hash->{helper}{DISABLED} = $attrVal;
  166. if ($attrVal eq "0")
  167. {
  168. YAMAHA_NP_GetStatus($hash, 1);
  169. }
  170. }
  171. else
  172. {
  173. $hash->{helper}{DISABLED} = 0;
  174. YAMAHA_NP_GetStatus($hash, 1);
  175. }
  176. }
  177. elsif($attrName eq "timerVolume")
  178. {
  179. my $volumeStraightMin = ReadingsVal($name,".volumeStraightMin",0);
  180. my $volumeStraightMax = ReadingsVal($name,".volumeStraightMax",60);
  181. if ($cmd eq "set" && (($attrVal < $volumeStraightMin) || ($attrVal > $volumeStraightMax)))
  182. {
  183. return "$attrName must be between $volumeStraightMin and $volumeStraightMax";
  184. }
  185. }
  186. elsif($attrName eq "timerRepeat")
  187. {
  188. if ($cmd eq "set" && $attrVal !~ /^(once|every)$/)
  189. {
  190. return "Use 'once' or 'every'";
  191. }
  192. }
  193. elsif($attrName eq "timerHour")
  194. {
  195. if ($cmd eq "set" && (($attrVal < 0) || ($attrVal > 23)))
  196. {
  197. return "$attrName must be between 0 and 23";
  198. }
  199. }
  200. elsif($attrName eq "timerMin")
  201. {
  202. if ($cmd eq "set" && (($attrVal < 0) || ($attrVal > 59)))
  203. {
  204. return "$attrName must be between 0 and 59";
  205. }
  206. }
  207. elsif($attrName eq "searchAttempts")
  208. {
  209. if ($cmd eq "set" && (($attrVal < 15) || ($attrVal > 100)))
  210. {
  211. return "$attrName must be between 15 and 100";
  212. }
  213. }
  214. elsif(($attrName eq ".favoriteList") && defined($attrVal))
  215. {
  216. if ($cmd eq "set")
  217. {
  218. $attr{$name}{$attrName} = $attrVal; #need to set first!
  219. }
  220. YAMAHA_NP_favoriteList($name);
  221. }
  222. elsif(($attrName eq ".DABList") && defined($attrVal))
  223. {
  224. if ($cmd eq "set")
  225. {
  226. foreach (split(";", $attrVal))
  227. {
  228. my ($id, $sender) = split(":", $_, 2);
  229. next if (!defined $sender);
  230. next if ($id !~ m/.DAB_ID/);
  231. $hash->{READINGS}{$id}{VAL} = $sender;
  232. $hash->{READINGS}{$id}{TIME} = "-";
  233. }
  234. }
  235. }
  236. elsif(($attrName eq "directPlaySleepNetradio") && defined($attrVal))
  237. {
  238. if ($cmd eq "set" && (($attrVal < 3) || ($attrVal > 30)))
  239. {
  240. return "$attrName must be between 3 and 30";
  241. }
  242. }
  243. elsif(($attrName eq "directPlaySleepServer") && defined($attrVal))
  244. {
  245. if ($cmd eq "set" && (($attrVal < 2) || ($attrVal > 30)))
  246. {
  247. return "$attrName must be between 2 and 30";
  248. }
  249. }
  250. elsif(($attrName eq "maxPlayerListItems") && defined($attrVal))
  251. {
  252. if ($cmd eq "set" && (($attrVal < 8) || ($attrVal > 999)))
  253. {
  254. return "$attrName must be between 8 and 999";
  255. }
  256. }
  257. elsif($attrName eq "autoUpdatePlayerlistReadings" && defined($attrName))
  258. {
  259. if($cmd eq "set" && (($attrVal < 0) || ($attrVal > 1)))
  260. {
  261. return "$attrName must be 0 or 1";
  262. }
  263. else
  264. {
  265. if($attrVal eq "0")
  266. {
  267. foreach (grep /playerListLvl.*$/,keys %{$hash->{READINGS}})
  268. {
  269. #delete level information
  270. delete $hash->{READINGS}{$_};
  271. }
  272. # delete playerlist items
  273. delete $hash->{READINGS}{$_} foreach (grep /listItem_...$/,keys %{$hash->{READINGS}});
  274. delete $hash->{READINGS}{playerListMenuStatus};
  275. }
  276. }
  277. }
  278. # Start/Stop Timer according to new disabled-Value
  279. YAMAHA_NP_ResetTimer($hash);
  280. }
  281. sub YAMAHA_NP_Notify
  282. {
  283. my ($hash, $dev) = @_;
  284. my $name = $hash->{NAME};
  285. return "" if ($dev->{NAME} ne "global");
  286. my $events = deviceEvents($dev, AttrVal($name, "addStateEvent", 0));
  287. return undef if(!$events); # Some previous notify deleted the array.
  288. # Save DAB list on save or shutdown
  289. if (grep /(SAVE|SHUTDOWN)/, @{$events})
  290. {
  291. $attr{$name}{".DABList"} = "";
  292. foreach (grep /^(.DAB_ID)/, keys %{$hash->{READINGS}})
  293. {
  294. $attr{$name}{".DABList"} .= ";".$_.":".$hash->{READINGS}{$_}{VAL};
  295. }
  296. }
  297. return undef;
  298. }
  299. sub YAMAHA_NP_GetStatus
  300. {
  301. my ($hash, $local) = @_;
  302. my $name = $hash->{NAME};
  303. my $power;
  304. # Local means a timer reset by the module itself
  305. $local = 0 unless(defined($local));
  306. return "" if((!defined($hash->{helper}{ADDRESS})) or (!defined($hash->{helper}{OFF_INTERVAL})) or (!defined($hash->{helper}{ON_INTERVAL})));
  307. my $device = $hash->{helper}{ADDRESS};
  308. # Get model and firmware information
  309. if(not defined($hash->{MODEL}))
  310. {
  311. YAMAHA_NP_getModel($hash);
  312. # Get network related information from the NP
  313. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Network,Info:GetParam", "statusRequest", "networkInfo" , 0);
  314. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam" , "statusRequest", "systemConfig", 0);
  315. }
  316. elsif((not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0))
  317. {
  318. # Get available inputs if not defined
  319. YAMAHA_NP_getInputs($hash);
  320. }
  321. else
  322. {
  323. if(not defined($hash->{READINGS}{timerVolume}))
  324. {
  325. # Timer readings available?
  326. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Timer,Mode:GetParam" , "statusRequest", "getTimer" , 0);
  327. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Timer,Param:GetParam", "statusRequest", "timerStatus", 0);
  328. }
  329. if(not defined($hash->{READINGS}{standbyMode}))
  330. {
  331. # Standby mode readings available?
  332. YAMAHA_NP_SendCmd($hash, "GET:System,Power_Control,Saving:GetParam", "statusRequest", "standbyMode", 0);
  333. }
  334. # Basic status request
  335. YAMAHA_NP_SendCmd($hash, "GET:System,Basic_Status:GetParam", "statusRequest", "basicStatus", 0);
  336. }
  337. # Reset Timer for the next loop.
  338. YAMAHA_NP_ResetTimer($hash) unless($local == 1);
  339. }
  340. sub YAMAHA_NP_favoriteList
  341. {
  342. # Process favorites list
  343. # Format of favorite list:
  344. # .favoriteList = name:input:lvl1,lvl2,lvl3;name:input:lvl1,lvl2,lvl3; ...
  345. my ($name) = @_;
  346. my $hash = $defs{$name};
  347. # Put favorites attribute .favoriteList separated by ';' to an array
  348. my @favEntry = split(";",$attr{$name}{".favoriteList"});
  349. # Delete existing favorites
  350. delete $hash->{helper}{fav};
  351. # Parse favorites
  352. foreach my $entry (@favEntry)
  353. {
  354. next if (!$entry);
  355. # NAME:INPUT:[STREAM,...] (stream may be empty)
  356. my ($entryName, $entryInput, $entryStream) = split(":", $entry);
  357. next if (!$entryName || !$entryInput);
  358. $hash->{helper}{fav}{$entryName}{input} = $entryInput;
  359. $hash->{helper}{fav}{$entryName}{stream} = $entryStream ? $entryStream : "";
  360. }
  361. }
  362. sub YAMAHA_NP_statTimeOut
  363. {
  364. # timeout occured during operation. Some problems. Clear.
  365. my ($para) = @_;
  366. my ($cmd, $name) = split(":", $para, 2);
  367. my $hash = $defs{$name};
  368. #Log 1,"General YAMAHA_NP_statTimeOut";
  369. $hash->{helper}{statReq}{$_} = 0 foreach (keys% {$hash->{helper}{statReq}});
  370. }
  371. sub YAMAHA_NP_directRestartTimer
  372. {
  373. my ($name,$wait,$a,$inputTarget,$stream) = @_;
  374. my $hash = $defs{$name};
  375. RemoveInternalTimer("directPlay:".$name);
  376. InternalTimer(gettimeofday() + $wait, "YAMAHA_NP_directSet", "directPlay:".$name, 0);
  377. $hash->{helper}{directPlayQueue}{state} = "selectInput";
  378. $hash->{helper}{directPlayQueue}{sleep} = $wait;
  379. $hash->{helper}{directPlayQueue}{a} = $a;
  380. $hash->{helper}{directPlayQueue}{input} = $inputTarget;
  381. $hash->{helper}{directPlayQueue}{stream} = $stream;
  382. }
  383. sub YAMAHA_NP_directSet
  384. {
  385. my ($para) = @_;
  386. my ($cmd, $name) = split(":", $para, 2);
  387. my $hash = $defs{$name};
  388. #Log 1,"directSet, directPlay ". $hash->{helper}{directPlayQueue}{input}.":".$hash->{helper}{directPlayQueue}{stream};
  389. $hash->{helper}{directPlayQueue}{stream} = "noStream" if(not($hash->{helper}{directPlayQueue}{stream}));
  390. # Due to asyncronous timers possible race condition. Supress if already playing.
  391. if(ReadingsVal($name,"playerPlaybackInfo", "stop") ne "play")
  392. {
  393. YAMAHA_NP_Set($hash,"","directPlay",$hash->{helper}{directPlayQueue}{input}.":".$hash->{helper}{directPlayQueue}{stream});
  394. }
  395. }
  396. sub YAMAHA_NP_Get
  397. {
  398. my ($hash, @a) = @_;
  399. return "Argument missing." if(int(@a) < 2);
  400. my $what = $a[1];
  401. my $return;
  402. if ($what eq "reading"){
  403. if(exists($hash->{READINGS}{$a[2]}))
  404. {
  405. if(defined($hash->{READINGS}{$a[2]}))
  406. {
  407. return $hash->{READINGS}{$a[2]}{VAL};
  408. }
  409. else
  410. {
  411. return "No such reading: $what";
  412. }
  413. }
  414. }
  415. elsif($what eq "deviceInfo")
  416. {
  417. my $deviceInfo = join("\n", map {sprintf("%-15s: %-15s", $_, $hash->{helper}{dInfo}{$_})} sort keys %{$hash->{helper}{dInfo}});
  418. return "Device info:\n\n$deviceInfo";
  419. }
  420. elsif($what eq "favoriteList" )
  421. {
  422. return "No favorites defined" if(!$hash->{helper}{fav});
  423. my $favoriteList = "Favorite list:\n\n"
  424. ."name :input -> stream\n";
  425. foreach my $fav (sort keys%{$hash->{helper}{fav}})
  426. {
  427. $favoriteList .= sprintf("%-15s:%-10s -> %s\n",$fav
  428. ,$hash->{helper}{fav}{$fav}{input}
  429. ,$hash->{helper}{fav}{$fav}{stream});
  430. }
  431. return $favoriteList;
  432. }
  433. else
  434. {
  435. $return = "Unknown argument $what, choose one of"
  436. ." deviceInfo:noArg"
  437. ." favoriteList:noArg"
  438. ." reading:".(join(",",(sort keys %{$hash->{READINGS}})));
  439. return $return;
  440. }
  441. }
  442. sub YAMAHA_NP_Set
  443. {
  444. my ($hash, @a) = @_;
  445. my $name = $hash->{NAME};
  446. my $address = $hash->{helper}{ADDRESS};
  447. # Get model info in case not defined
  448. if(not defined($hash->{MODEL}) or not defined($hash->{FIRMWARE}))
  449. {
  450. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Network,Info:GetParam", "statusRequest", "networkInfo" , 0);
  451. YAMAHA_NP_getModel($hash);
  452. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam" , "statusRequest", "systemConfig", 0);
  453. }
  454. # Setting default values. Update from device during existing communication.
  455. my $volumeStraightMin = ReadingsVal($name,".volumeStraightMin",0);
  456. my $volumeStraightMax = ReadingsVal($name,".volumeStraightMax",60);
  457. if((!ReadingsVal($name,".volumeStraightMax","")) || (!ReadingsVal($name,".volumeStraightMin","")))
  458. {
  459. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam" , "statusRequest", "systemConfig", 0);
  460. }
  461. # Get available inputs in case of an empty list
  462. if(not defined($hash->{helper}{INPUTS}) or length($hash->{helper}{INPUTS}) == 0)
  463. {
  464. YAMAHA_NP_getInputs($hash);
  465. }
  466. my $inputs_piped = defined($hash->{helper}{INPUTS}) ? YAMAHA_NP_Param2Fhem(lc($hash->{helper}{INPUTS}), 0) : "" ;
  467. my $inputs_comma = defined($hash->{helper}{INPUTS}) ? YAMAHA_NP_Param2Fhem(lc($hash->{helper}{INPUTS}), 1) : "" ;
  468. return "No Argument given" if(!defined($a[1]));
  469. my $what = $a[1];
  470. my $usage = "";
  471. # DAB available? Suffix D stands for DAB. "CRX-N560D"
  472. my $input = ReadingsVal($name,"input","");
  473. if (defined($hash->{MODEL}))
  474. {
  475. my $model = $hash->{MODEL};
  476. my $favLst = join(",",sort keys%{$hash->{helper}{fav}});
  477. # Minimum set commands for simplified power-on
  478. $usage = "Unknown argument $what, choose one of"
  479. ." on:noArg"
  480. ." off:noArg"
  481. ." favoritePlay:".$favLst
  482. ." directPlay";
  483. # Context-sensitive command availability
  484. if (ReadingsVal($name,"power","") !~ m/(off|absent)/)
  485. {
  486. $usage .=" input:".$inputs_comma
  487. ." volumeStraight:slider,".$volumeStraightMin.",1,".$volumeStraightMax
  488. ." volume:slider,0,1,100"
  489. ." volumeUp:noArg"
  490. ." volumeDown:noArg"
  491. ." mute:on,off"
  492. ." statusRequest:basicStatus,mediaRendererDesc,playerStatus,standbyMode,systemConfig,timerStatus,tunerStatus"
  493. ." CDTray:noArg"
  494. ." clockUpdate:noArg"
  495. ." standbyMode:eco,normal"
  496. ." sleep:off,30min,60min,90min,120min"
  497. ." timerSet:noArg"
  498. ." timer:on,off"
  499. ." dimmer:1,2,3"
  500. ." favoriteDefine"
  501. ." favoriteDelete:".$favLst
  502. ." ";
  503. # Add additional set commands in case of netradio|usb|server|cd|DAB|FM
  504. if($input =~ m/^(netradio|usb|server|cd|DAB|FM)/)
  505. {
  506. # Process 'playerListLvl' and 'listItem_' readings and provide them for 'selStream' command
  507. # playerListLvl -> Player Menu Directory Level
  508. # listItem_ -> Item. May be container (directory) or item (file/audio stream)
  509. my @playerList;
  510. # Scan all readings and reformat the contents of
  511. # playerListLvlX -> lvlX_NAME and listItem_XXX -> XXX_NAME into an array
  512. # Limit to 25 chars
  513. foreach my $readings (keys %{$hash->{READINGS}})
  514. {
  515. push @playerList, "lvl$1"."_".substr($hash->{READINGS}{$readings}{VAL} ,0, 25) if($readings =~ m/^playerListLvl(.*)/);
  516. push @playerList, $2."_" .substr($hash->{READINGS}{$readings}{VAL} ,0, 25) if($readings =~ m/(listItem_)(...)$/);
  517. }
  518. # Sort playerList first numeric items XXX_NAME -> lvlX_XXX -> ...
  519. # Replace not allowed characters
  520. @playerList = sort map{s/[ :;,'.]/_/g;$_;} grep/._..*$/,@playerList;
  521. # Sort CD tracks as 'Track_XX'
  522. if($input eq "cd")
  523. {
  524. push @playerList,(sort map { "Track_".sprintf("%02d",$_) } (1 .. ReadingsVal($name,"playerTotalTracks",0)));
  525. }
  526. # Add next, prev as set command
  527. push @playerList,("next","prev");
  528. # Add tuneUp/tuneDown in case of tuner input
  529. if($input =~ m/^(DAB|FM)/)
  530. {
  531. push @playerList, ("tuneUp","tuneDown");
  532. }
  533. # Add selectStream as set command. In addition '---' as dummy for web interface.
  534. # Otherwise the first item cannot be executed
  535. $usage .="selectStream:".join(",",("---",(sort @playerList)));
  536. # Add direct FM frequency input in case of FM tuner band
  537. if(ReadingsVal($name,"tunerBand","") eq "FM")
  538. {
  539. $usage .= " tunerFMFrequency"
  540. }
  541. $usage .= " player:play,stop,pause,next,prev";
  542. if ($input =~ m/^(usb|server|cd)/)
  543. {
  544. $usage .= " playMode:shuffleAll,shuffleOff,repeatOff,repeatOne,repeatAll";
  545. }
  546. }
  547. # In case of DAB capable NP replace tuner by DAB and FM for direct command
  548. # Otherwise limit to tuner -> FM
  549. if ($model eq "CRX-N560D")
  550. {
  551. $usage =~ s/,tuner/,DAB,FM/; # direct select tuner band
  552. }
  553. else
  554. {
  555. $usage =~ s/,tuner/,FM/; # direct select tuner band
  556. }
  557. }
  558. $usage .= " ";
  559. #Log 1, "$usage";
  560. Log3 $name, 5, "Model: $model.";
  561. }
  562. Log3 $name, 5, "YAMAHA_NP ($name) - set ".join(" ", @a);
  563. #Simplified commands
  564. if($what eq "?"){ return $usage}
  565. if($what eq "favoritePlay")
  566. {
  567. if(!defined $a[2] || !defined $hash->{helper}{fav}{$a[2]})
  568. {
  569. return "Entry $a[2] unknown, check favoriteList.";
  570. }
  571. $what = "directPlay";
  572. $a[2] = $hash->{helper}{fav}{$a[2]}{input}.":".$hash->{helper}{fav}{$a[2]}{stream};
  573. }
  574. elsif($what eq "favoriteDefine")
  575. {
  576. return "Specify favorite" if(!$a[2]);
  577. # Favorites are defined as NAME:INPUT:[STREAM_LVL1,STREAM_LVL2,...]
  578. my ($favName, $favInput, $favSelect) = split(":", $a[2]);
  579. if(!$favInput)
  580. {
  581. return "No input defined. Use <name>:<input>:[stream]. Provide minimum name and input.";
  582. }
  583. elsif($favInput eq "current")
  584. {
  585. my $input = ReadingsVal($name, "input", "");
  586. my $stream = "$favName:$input:";
  587. if ($input eq "DAB")
  588. {
  589. $stream .= ReadingsVal($name, "tunerStation", "");
  590. }
  591. elsif ($input eq "FM")
  592. {
  593. $stream .= ReadingsVal($name, "tunerFrequency", "");
  594. $stream =~ s/ MHZ//;
  595. }
  596. #elsif ($input =~ m/^(usb)$/)
  597. #{
  598. #
  599. #}
  600. else
  601. {
  602. foreach (sort grep /playerListLvl/, keys %{$hash->{READINGS}})
  603. {
  604. $stream .= $hash->{READINGS}{$_}{VAL}."," if ($_ ne "playerListLvl1");# level 1 is not necessary
  605. }
  606. $stream .= ReadingsVal($name, "playerPlayArtist", "");
  607. }
  608. $stream =~ s/ /./g; #replace spaces
  609. $attr{$name}{".favoriteList"} .= ";" .$stream; # Append to the .favoriteList attribute
  610. YAMAHA_NP_favoriteList($name);
  611. return;
  612. }
  613. else
  614. {
  615. $attr{$name}{".favoriteList"} .= ";$a[2]"; # Append to the .favoriteList attribute
  616. YAMAHA_NP_favoriteList($name);
  617. return;
  618. }
  619. }
  620. elsif($what eq "favoriteDelete")
  621. {
  622. if ( defined $a[2]
  623. && defined $hash->{helper}{fav}
  624. && defined $hash->{helper}{fav}{$a[2]})
  625. {
  626. delete $hash->{helper}{fav}{$a[2]};
  627. }
  628. # Reset favorites attribute
  629. $attr{$name}{".favoriteList"} = "";
  630. foreach my $favorite (keys %{$hash->{helper}{fav}})
  631. {
  632. next if (!$favorite);
  633. $attr{$name}{".favoriteList"} .= $favorite.":".$hash->{helper}{fav}{$favorite}{input}.":".$hash->{helper}{fav}{$favorite}{stream}.";";
  634. }
  635. return;
  636. }
  637. if($what eq "directPlay")
  638. {
  639. # Format INPUT:STREAM_LVL1,STREAM_LVL2,...
  640. delete $hash->{helper}{directPlayQueue};
  641. return "Please enter stream -> INPUT:STREAM_LVL1,STREAM_LVL2,..." if(!$a[2]);
  642. if (!defined $hash->{helper}{directPlayQueueTry})
  643. {
  644. $hash->{helper}{directPlayQueueTry} = 1 ; # 1st try
  645. readingsSingleUpdate($hash, "directPlay", "started", 1);
  646. }
  647. else
  648. {
  649. # Increment and limit number to searchAttempts
  650. $hash->{helper}{directPlayQueueTry}++;
  651. if ($hash->{helper}{directPlayQueueTry} > AttrVal($name,"searchAttempts", 15))
  652. {
  653. # Timeout
  654. YAMAHA_NP_directPlayFinish($hash, "abort-timeout");
  655. return;
  656. }
  657. }
  658. # INPUT:STREAM_LVL1,STREAM_LVL2,...
  659. my ($inputTarget, $stream) = split(":",$a[2],2);
  660. $inputTarget = lc($inputTarget);
  661. # Set default stream name in case none provided
  662. $stream = "noStream" if(not $stream);
  663. # Check if device unpowered
  664. if (ReadingsVal($name, "state", 0) ne "on")
  665. {
  666. $what = "on";
  667. $hash->{helper}{directPlayQueue}{sleep} = 2;
  668. $hash->{helper}{directPlayQueue}{state} = "directPlay";
  669. $hash->{helper}{directPlayQueue}{a} = $a[2];
  670. $hash->{helper}{directPlayQueue}{input} = $inputTarget;
  671. $hash->{helper}{directPlayQueue}{stream} = $stream;
  672. }
  673. else
  674. {
  675. my $input = ReadingsVal($name, "input", "");
  676. #Log 1, "InputTarget: $inputTarget";
  677. #Log 1, "Input: $input";
  678. if ($inputTarget eq $input)
  679. {
  680. # Force Playerlist status update.
  681. YAMAHA_NP_SendCmd($hash, "GET:Player,List_Info:GetParam", "statusRequest", "playerListGetList", 0);
  682. if($inputTarget =~ m/(aux|digital|spotify|airplay)/)
  683. {
  684. # These inputs don't have streams. Finish.
  685. YAMAHA_NP_directPlayFinish($hash);
  686. return;
  687. }
  688. elsif($inputTarget =~ m/(DAB|FM|cd)/)
  689. {
  690. # Single level selection Stream CD:Track_01 etc.
  691. $stream = 1 if (!defined $stream);
  692. if($inputTarget eq "cd")
  693. {
  694. # Remove header
  695. $stream =~ s/^Track_//;
  696. # Get track # and total tracks information
  697. my ($totalTracks, $currentTrack) =
  698. (ReadingsVal($name,"playerTotalTracks", 0),
  699. ReadingsVal($name,"playerPlayTrackNb", 0)
  700. );
  701. if ( ($stream !~ m/\d+/) # non numeric
  702. ||($stream < 1) # too small
  703. ||($stream > $totalTracks ) # too big
  704. )
  705. {
  706. YAMAHA_NP_directPlayFinish($hash, "abort-not found");
  707. return ;
  708. }
  709. elsif ($currentTrack == $stream)
  710. {
  711. # match: we are done
  712. YAMAHA_NP_directPlayFinish($hash);
  713. return ;
  714. }
  715. $a[2] = "Track_".$stream; # select stream
  716. }
  717. else
  718. {
  719. # DAB or FM
  720. if ( (ReadingsVal($name,"tunerPreset" ,"")
  721. .ReadingsVal($name,"tunerFrequency","")) =~ m/$stream/)
  722. {
  723. # Match. No further action. Finish.
  724. YAMAHA_NP_directPlayFinish($hash);
  725. return;
  726. }
  727. if($inputTarget eq "FM")
  728. {
  729. $what = "tunerFMFrequency";
  730. $a[2] = $stream;
  731. }
  732. else
  733. {
  734. # $inputTarget eq "DAB"
  735. my $found = 0;
  736. foreach my $listItemReading (sort grep /^(listItem_)/,keys %{$hash->{READINGS}})
  737. {
  738. my $listItemReadingValue = $hash->{READINGS}{$listItemReading}{VAL};
  739. if($listItemReadingValue =~ m/$stream/)
  740. {
  741. $a[2] = substr($listItemReading, 9, 3);
  742. $found = 1;
  743. last;
  744. }
  745. }
  746. if($found == 0)
  747. {
  748. YAMAHA_NP_directPlayFinish($hash,"abort-not found");
  749. return ;
  750. }
  751. }
  752. }
  753. $what = "selectStream" if ($what eq "directPlay");
  754. $hash->{helper}{directPlayQueue}{sleep} = 1;
  755. }
  756. # Server, Netradio
  757. elsif(ReadingsVal($name, "playerListMenuStatus", "-") ne "Ready")
  758. {
  759. # Depending on input and server/network speed the duration is unknown
  760. # Customization of polling intervall for Server (LAN) and Netradio (vTuner)
  761. my $sleep = 3; # default
  762. if (lc($inputTarget) eq "server")
  763. {
  764. $sleep = AttrVal($name,"directPlaySleepServer", 2);
  765. }
  766. elsif(lc($inputTarget) eq "netradio")
  767. {
  768. $sleep = AttrVal($name,"directPlaySleepNetradio", 3);
  769. }
  770. # take another chance: data was not complete
  771. YAMAHA_NP_directRestartTimer($name, $sleep, $a[2], $inputTarget, $stream);
  772. return;
  773. }
  774. # Streams with multilevel selection e.g. server, netradio
  775. else
  776. {
  777. my $level = 1;
  778. my @desiredList = split(",", $stream);
  779. my $desiredListLast = scalar (@desiredList);
  780. desiredListNloop:
  781. foreach my $desiredListN(@desiredList)
  782. {
  783. $level++;
  784. my $currentLevel = ReadingsVal($name,"playerListLvl$level", undef);
  785. if (!defined $currentLevel)
  786. {
  787. if ($level > $desiredListLast)
  788. {
  789. #last level - might be an item, not a container
  790. #playerPlaySong i_04 FelizNavidad.mp3
  791. my $currentStream = $inputTarget eq "netradio"
  792. ? ReadingsVal($name, "playerPlayArtist", "")
  793. : ReadingsVal($name, "playerPlaySong" , "");
  794. if ($currentStream =~ m/$desiredListN/)
  795. {
  796. YAMAHA_NP_directPlayFinish($hash);# we are done!!
  797. return ;
  798. }
  799. # Depending on input and server/network speed the duration is unknown
  800. # Customization of polling intervall for Server (LAN) and Netradio (vTuner)
  801. my $sleep = 2; # default
  802. if (lc($inputTarget) eq "server")
  803. {
  804. $sleep = AttrVal($name,"directPlaySleepServer", 2);
  805. }
  806. elsif(lc($inputTarget) eq "netradio")
  807. {
  808. $sleep = AttrVal($name,"directPlaySleepNetradio", 3);
  809. }
  810. $hash->{helper}{directPlayQueue}{sleep} = $sleep;
  811. }
  812. my $found = 0;
  813. foreach (grep /listItem_...$/,keys %{$hash->{READINGS}})
  814. {
  815. if ($hash->{READINGS}{$_}{VAL} =~ m/$desiredListN/)
  816. {
  817. $a[2] = substr($_, 9);
  818. $found = 1; $level = 0; # force next step
  819. last desiredListNloop;
  820. }
  821. }
  822. if($desiredListN =~ m/^[0-9]{3}$/ && defined $hash->{READINGS}{"listItem_".$desiredListN})
  823. {
  824. # go by number
  825. my $desiredSong = ReadingsVal($name,"listItem_".$desiredListN, undef);
  826. my $playerSong = ReadingsVal($name,"playerPlaySong",undef);
  827. if (!defined $desiredSong)
  828. {# no list item - problem. abort
  829. YAMAHA_NP_directPlayFinish($hash, "abort-not found");
  830. return;
  831. }
  832. elsif (!defined $playerSong)
  833. {
  834. # Depending on input and server/network speed the duration is unknown
  835. # Customization of polling intervall for Server (LAN) and Netradio (vTuner)
  836. my $sleep = 2; # default
  837. if (lc($inputTarget) eq "server")
  838. {
  839. $sleep = AttrVal($name,"directPlaySleepServer", 2);
  840. }
  841. elsif(lc($inputTarget) eq "netradio")
  842. {
  843. $sleep = AttrVal($name,"directPlaySleepNetradio", 3);
  844. }
  845. # not yet playing?
  846. YAMAHA_NP_directRestartTimer($name, $sleep, $a[2], $inputTarget, $stream); # take another chance: data was not complete
  847. return;
  848. }
  849. elsif ($desiredSong =~ m/$playerSong/)
  850. {
  851. YAMAHA_NP_directPlayFinish($hash);
  852. return;
  853. }
  854. $a[2] = $desiredListN;
  855. $level = 0;
  856. last desiredListNloop;
  857. }
  858. elsif ($hash->{helper}{playlist}{state} ne "complete")
  859. {
  860. my $sleep = 2; # default
  861. if (lc($inputTarget) eq "server")
  862. {
  863. $sleep = AttrVal($name, "directPlaySleepServer", 2);
  864. }
  865. elsif(lc($inputTarget) eq "netradio")
  866. {
  867. $sleep = AttrVal($name, "directPlaySleepNetradio", 3);
  868. }
  869. YAMAHA_NP_directRestartTimer($name, $sleep, $a[2], $inputTarget, $stream);# take another chance: data was not complete
  870. }
  871. else
  872. {
  873. YAMAHA_NP_directPlayFinish($hash, "abort-not found");
  874. } #no chance
  875. return;
  876. }
  877. elsif ($currentLevel !~ m/$desiredListN/)
  878. {
  879. # current level does not match
  880. $a[2] = "lvl".($level - 1)."_";
  881. $level = 0; # force next step
  882. last;
  883. }
  884. next;
  885. }
  886. if ($level > $desiredListLast)
  887. {
  888. #$level is one less then desiredListLast!
  889. YAMAHA_NP_directPlayFinish($hash, "abort-not found");
  890. return;
  891. }
  892. $what = "selectStream";
  893. }
  894. $hash->{helper}{directPlayQueue}{state} = "selectInput";
  895. $hash->{helper}{directPlayQueue}{sleep} = 3; # default
  896. # Depending on input and server/network speed the duration is unknown
  897. # Customization of polling intervall for Server (LAN) and Netradio (vTuner)
  898. if (lc($inputTarget) eq "server")
  899. {
  900. $hash->{helper}{directPlayQueue}{sleep} = AttrVal($name, "directPlaySleepServer", 2);
  901. }
  902. elsif(lc($inputTarget) eq "netradio")
  903. {
  904. $hash->{helper}{directPlayQueue}{sleep} = AttrVal($name, "directPlaySleepNetradio", 3);
  905. }
  906. $hash->{helper}{directPlayQueue}{a} = $a[2];
  907. $hash->{helper}{directPlayQueue}{input} = $inputTarget;
  908. $hash->{helper}{directPlayQueue}{stream} = $stream;
  909. }
  910. else
  911. {
  912. if ($inputTarget !~ m/(aux|digital|spotify|airplay)/)
  913. {
  914. # stream set necessary?
  915. delete $hash->{helper}{directPlayQueue};
  916. $hash->{helper}{directPlayQueue}{state} = "selectInput";
  917. $hash->{helper}{directPlayQueue}{sleep} = 3; # default
  918. # Depending on input and server/network speed the duration is unknown
  919. # Customization of polling intervall for Server (LAN) and Netradio (vTuner)
  920. if (lc($inputTarget) eq "server")
  921. {
  922. $hash->{helper}{directPlayQueue}{sleep} = AttrVal($name, "directPlaySleepServer", 2);
  923. }
  924. elsif(lc($inputTarget) eq "netradio")
  925. {
  926. $hash->{helper}{directPlayQueue}{sleep} = AttrVal($name, "directPlaySleepNetradio", 3);
  927. }
  928. $hash->{helper}{directPlayQueue}{a} = $a[2];
  929. $hash->{helper}{directPlayQueue}{input} = $inputTarget;
  930. $hash->{helper}{directPlayQueue}{stream} = $stream;
  931. }
  932. $what = "input";
  933. $a[2] = $inputTarget;
  934. YAMAHA_NP_directRestartTimer($name, 2, $a[2], $inputTarget, $stream);
  935. }
  936. }
  937. }
  938. else
  939. {
  940. # Remove directPlay helper
  941. delete $hash->{helper}{directPlayQueue};
  942. delete $hash->{helper}{directPlayQueueTry};
  943. RemoveInternalTimer("statTimeOut:".$hash->{NAME});
  944. }
  945. #Log 1,"General process $what ++++$a[2] --------->$hash->{helper}{directPlayQueue}{a}";
  946. if($what eq "selectStream")
  947. {
  948. readingsSingleUpdate($hash, "selectStream", "select", 1);
  949. my $input = ReadingsVal($name,"input","");
  950. if($input eq "---")
  951. {
  952. # dummy entry for web interface
  953. return;
  954. }
  955. elsif($input =~ m/^(cd|netradio|server|usb)/)
  956. {
  957. # player stream supported
  958. if ($a[2] =~ m/(next|prev)/)
  959. {
  960. $what = "player";
  961. }
  962. elsif($a[2] =~ m/^Track_(.*)/)
  963. {
  964. # cd counts tracks
  965. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Track_Number:$1", $what, $a[2], 0); # cd only
  966. readingsSingleUpdate($hash, "audioSource", ReadingsVal($name, "input", "") . " (reading status...)", 1);
  967. }
  968. elsif($a[2] =~ m/^lvl(.*?)_/)
  969. {
  970. my ($targetLevel, $currentLevel) = ($1, split(":",$hash->{helper}{playlist}{mnCur}));
  971. return "Level must bei between $currentLevel and 1" if($targetLevel < 1 || $targetLevel > $currentLevel);
  972. return if ($targetLevel eq $currentLevel); # nothing to do
  973. $hash->{helper}{playlist}{desiredDirectoryLevel} = $targetLevel;
  974. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Cursor:Return", "playerListCursorReturn", $targetLevel,0);
  975. }
  976. elsif($a[2] eq "---")
  977. {
  978. # Do nothing. Dummy entry for the web interface.
  979. return;
  980. }
  981. else
  982. {
  983. $a[2] = substr($a[2],0,3);
  984. return "Argument must be numeric and >= 1. Entered is $a[2]" if($a[2] !~ /^\d{1,3}$/ || $a[2] < 1);
  985. my $selection = (($a[2]-1)%8)+1;
  986. $hash->{helper}{playlist}{selection} = $selection;# remember: more to do.
  987. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Jump_Line:".$a[2], $what, "jump_$a[2]_$selection", 0);
  988. readingsSingleUpdate($hash, "audioSource", ReadingsVal($name, "input", "") . " (reading status...)", 1);
  989. }
  990. }
  991. elsif($input eq "DAB" || $input eq "FM")
  992. {
  993. if ($a[2] =~ m/(tuneUp|tuneDown|next|prev)/)
  994. {
  995. $what = "tuner";
  996. }
  997. else
  998. {
  999. $what = "tunerPreset".ReadingsVal($name,"tunerBand","");# DAB or FM
  1000. $a[2] = substr($a[2], 0, 3);
  1001. return "Argument must be numeric and >= 1. Entered is $a[2]" if($a[2] !~ /^\d{1,3}$/ || $a[2] < 1);
  1002. }
  1003. }
  1004. elsif($input =~ m/^(digital|aux|airplay|spotify)/)
  1005. {
  1006. # Direct input ... no further stream required
  1007. }
  1008. }
  1009. # Processing of SET commands.
  1010. if($what =~ m/^(on|off)/)
  1011. {
  1012. # Device Power ON/OFF
  1013. my $arg;
  1014. if($what eq "on")
  1015. {
  1016. $what = "on";
  1017. $arg = "On";
  1018. }
  1019. elsif($what eq "off")
  1020. {
  1021. $what = "off";
  1022. $arg = "Standby";
  1023. }
  1024. else
  1025. {
  1026. return "Invalid argument $a[2] - Select on or off";
  1027. }
  1028. YAMAHA_NP_SendCmd($hash, "PUT:System,Power_Control,Power:$arg", $what, $arg, 0);
  1029. }
  1030. elsif($what eq "input")
  1031. {
  1032. if(defined($a[2]))
  1033. {
  1034. if(not $inputs_piped eq "")
  1035. {
  1036. if( $a[2] =~ /^($inputs_piped)$/)
  1037. {
  1038. my $command = YAMAHA_NP_getParamName($hash, $a[2], $hash->{helper}{INPUTS});
  1039. if(defined($command) and length($command) > 0)
  1040. {
  1041. YAMAHA_NP_SendCmd($hash, "PUT:System,Input,Input_Sel:$command", $what, $a[2], 0);
  1042. }
  1043. else
  1044. {
  1045. return "Invalid input: ".$a[2];
  1046. }
  1047. }
  1048. elsif($a[2] =~ m/^(FM|DAB)$/)
  1049. {
  1050. my $command = YAMAHA_NP_getParamName($hash, "tuner", $hash->{helper}{INPUTS});
  1051. YAMAHA_NP_SendCmd($hash, "PUT:System,Input,Input_Sel:$command", $what, $a[2], 0);
  1052. }
  1053. else
  1054. {
  1055. return $usage;
  1056. }
  1057. }
  1058. else
  1059. {
  1060. return "No inputs available. Please try statusRequest.";
  1061. }
  1062. }
  1063. else
  1064. {
  1065. return $inputs_piped eq "" ? "No inputs available. Please try statusRequest." : "No input parameter given.";
  1066. }
  1067. }
  1068. elsif($what eq "mute")
  1069. {
  1070. # MUTE
  1071. return "Power on the device first." if($hash->{READINGS}{power}{VAL} ne "on");
  1072. if(defined($a[2]))
  1073. {
  1074. if($a[2] =~ /^(on|off)$/)
  1075. {
  1076. YAMAHA_NP_SendCmd($hash, "PUT:System,Volume,Mute:".ucfirst($a[2]), $what, ucfirst($a[2]), 0);
  1077. }
  1078. else
  1079. {
  1080. return $usage;
  1081. }
  1082. }
  1083. }
  1084. elsif($what eq "dimmer")
  1085. {
  1086. # DISPLAY DIMMER
  1087. if($a[2] >= 1 and $a[2] <= 3)
  1088. {
  1089. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Display,FL_Dimmer:$a[2]", $what, $a[2], 0);
  1090. }
  1091. else{
  1092. return "Dimmer value must be 1 .. 3";
  1093. }
  1094. }
  1095. #
  1096. # VolumeStraight is device specific e.g. 0...60, Volume 0...100, VolumeUp/Down one step
  1097. #
  1098. elsif($what =~ /^(volumeStraight|volume|volumeUp|volumeDown)$/)
  1099. {
  1100. return "Power on the device first." if($hash->{READINGS}{power}{VAL} ne "on");
  1101. my $target_volume;
  1102. my $minVolume = ReadingsVal($name,".volumeStraightMin",0);
  1103. my $maxVolume = ReadingsVal($name,".volumeStraightMax",60);
  1104. if ($what eq "volumeDown")
  1105. {
  1106. $target_volume = $hash->{READINGS}{volumeStraight}{VAL} - 1;
  1107. }
  1108. elsif($what eq "volumeUp")
  1109. {
  1110. $target_volume = $hash->{READINGS}{volumeStraight}{VAL} + 1;
  1111. }
  1112. else
  1113. {
  1114. if ($what eq "volume")
  1115. {
  1116. if($a[2] >= 0 and $a[2] <= 100)
  1117. {
  1118. $target_volume = YAMAHA_NP_volume_rel2abs($hash, $a[2]);
  1119. }
  1120. else
  1121. {
  1122. return "Volume must be in the range 1...100.";
  1123. }
  1124. }
  1125. elsif($what eq "volumeStraight")
  1126. {
  1127. if($a[2] >= $minVolume and $a[2] <= $maxVolume)
  1128. {
  1129. $target_volume = $a[2];
  1130. }
  1131. else
  1132. {
  1133. return "Volume must be in the range $minVolume...$maxVolume.";
  1134. }
  1135. }
  1136. $hash->{helper}{targetVolume} = $target_volume;# final destination
  1137. if(AttrVal($name, "smoothVolumeChange", "1") eq "1" )
  1138. {
  1139. if ($target_volume < $hash->{READINGS}{volumeStraight}{VAL})
  1140. {
  1141. $target_volume = $hash->{READINGS}{volumeStraight}{VAL} - 1;
  1142. }
  1143. elsif($target_volume > $hash->{READINGS}{volumeStraight}{VAL})
  1144. {
  1145. $target_volume = $hash->{READINGS}{volumeStraight}{VAL} + 1;
  1146. }
  1147. elsif($target_volume eq $hash->{READINGS}{volumeStraight}{VAL})
  1148. {
  1149. $target_volume = $hash->{READINGS}{volumeStraight}{VAL};
  1150. }
  1151. }
  1152. }
  1153. $hash->{helper}{volumeChangeDir} = ($hash->{helper}{targetVolume} < $target_volume)? "DOWN"
  1154. :(($hash->{helper}{targetVolume} > $target_volume)? "UP"
  1155. : "EQUAL");
  1156. YAMAHA_NP_SendCmd($hash, "PUT:System,Volume,Lvl:$target_volume", "volume", $target_volume, 0);
  1157. Log3 $name, 4, "YAMAHA_NP ($name) - new target volume: $hash->{helper}{targetVolume}";
  1158. }
  1159. elsif($what eq "sleep")
  1160. {
  1161. if($a[2] eq "off")
  1162. {
  1163. YAMAHA_NP_SendCmd($hash, "PUT:System,Power_Control,Sleep:Off", $what, $a[2], 0);
  1164. }
  1165. elsif($a[2] =~ /^(30min|60min|90min|120min)$/)
  1166. {
  1167. if($a[2] =~ /(.+)min/)
  1168. {
  1169. YAMAHA_NP_SendCmd($hash, "PUT:System,Power_Control,Sleep:$1 min", $what, $a[2], 0);
  1170. }
  1171. }
  1172. else
  1173. {
  1174. return $usage;
  1175. }
  1176. }
  1177. elsif($what eq "tuner")
  1178. {
  1179. # TUNER
  1180. if ($a[2] eq "next")
  1181. {
  1182. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Preset,Preset_Sel:Next", $what, $a[2], 0);
  1183. }
  1184. elsif($a[2] eq "prev")
  1185. {
  1186. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Preset,Preset_Sel:Prev", $what, $a[2], 0);
  1187. }
  1188. elsif($a[2] eq "tuneUp")
  1189. {
  1190. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Service:Next" , $what, $a[2], 0);
  1191. }
  1192. elsif($a[2] eq "tuneDown")
  1193. {
  1194. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Service:Prev" , $what, $a[2], 0);
  1195. }
  1196. elsif($a[2] eq "bandDAB")
  1197. {
  1198. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Band:DAB" , $what, $a[2], 0);
  1199. }
  1200. elsif($a[2] eq "bandFM")
  1201. {
  1202. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Band:FM" , $what, $a[2], 0);
  1203. }
  1204. else
  1205. {
  1206. return $usage;
  1207. }
  1208. }
  1209. elsif($what eq "player")
  1210. {
  1211. # Player
  1212. if( $a[2] =~ /^(play|pause|stop|next|prev|prevCD)$/)
  1213. {
  1214. my $postCmd = ($input eq "cd" && $a[2] eq "prev") ? "prevCD" : $a[2]; # need prev twice for CD
  1215. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Playback:".ucfirst($a[2]), $what, $postCmd, 0);
  1216. }
  1217. else
  1218. {
  1219. return $usage;
  1220. }
  1221. }
  1222. elsif($what eq "playMode")
  1223. {
  1224. # Playermode
  1225. my $sh = ReadingsVal($name,"playerShuffle",""); # on/off
  1226. my $rp = ReadingsVal($name,"playerRepeat" ,""); # off/one/all
  1227. # Shuffle toggles between ON/OFF
  1228. if ( (($sh eq "off") && $a[2] eq "shuffleAll" )
  1229. ||(($sh eq "on") && $a[2] eq "shuffleOff"))
  1230. {
  1231. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Play_Mode,Shuffle:Toggle", $what, $a[2], 0);
  1232. }
  1233. # Repeat Mode toggles between OFF/ONE/ALL
  1234. elsif( (($rp eq "off") && ($a[2] eq "repeatOne" || $a[2] eq "repeatAll"))
  1235. || (($rp eq "one") && ($a[2] eq "repeatOff" || $a[2] eq "repeatAll"))
  1236. || (($rp eq "all") && ($a[2] eq "repeatOff" || $a[2] eq "repeatOne"))
  1237. )
  1238. {
  1239. $hash->{helper}{playerRepeatModeTarget} = $a[2];
  1240. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Play_Mode,Repeat:Toggle", $what, $a[2], 0);
  1241. }
  1242. else
  1243. {
  1244. return $usage;
  1245. }
  1246. }
  1247. elsif($what eq "playerListSelectLine")
  1248. {
  1249. # PlayerListSelectLine
  1250. if($a[2] ne "")
  1251. {
  1252. $a[2] = substr($a[2],0,2);
  1253. if($a[2] =~ /^\d\d+$/ and $a[2] >= 1)
  1254. {
  1255. $a[2] = int($a[2]);
  1256. YAMAHA_NP_SendCmd($hash,"PUT:Player,List_Control,Direct_Sel:Line_$a[2]", $what, $a[2], 0);
  1257. }
  1258. else
  1259. {
  1260. return "Argument must be numeric and >= 1.";
  1261. }
  1262. }
  1263. else
  1264. {
  1265. return "No argument given.";
  1266. }
  1267. }
  1268. elsif($what eq "standbyMode")
  1269. {
  1270. # Standby Mode
  1271. if(($a[2] eq "eco") or ($a[2] eq "normal"))
  1272. {
  1273. YAMAHA_NP_SendCmd($hash, "PUT:System,Power_Control,Saving:".ucfirst($a[2]), $what, $a[2], 0);
  1274. }
  1275. else{
  1276. return $usage;
  1277. }
  1278. }
  1279. elsif($what eq "CDTray")
  1280. {
  1281. # Toggle CD Tray
  1282. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Tray:Open/Close", $what, "Open/Close", 0);
  1283. }
  1284. elsif($what eq "clockUpdate")
  1285. { # Clock Update
  1286. my $clockUpdateCurrentTime = Time::Piece->new();
  1287. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Clock,Param:".($clockUpdateCurrentTime->strftime('%Y:%m:%d:%H:%M:%S')), $what, ($clockUpdateCurrentTime->strftime('%Y:%m:%d:%H:%M:%S')), 0);
  1288. }
  1289. elsif($what eq "statusRequest")
  1290. {
  1291. # Status Request
  1292. if( $a[2] eq "systemConfig")
  1293. {
  1294. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam" , $what, $a[2], 0);
  1295. }
  1296. elsif($a[2] eq "playerStatus")
  1297. {
  1298. YAMAHA_NP_SendCmd($hash, "GET:Player,Play_Info:GetParam" , $what, $a[2], 0);
  1299. }
  1300. elsif($a[2] eq "tunerStatus")
  1301. {
  1302. YAMAHA_NP_SendCmd($hash, "GET:Tuner,Play_Info:GetParam" , $what, $a[2], 0);
  1303. }
  1304. elsif($a[2] eq "basicStatus")
  1305. {
  1306. YAMAHA_NP_SendCmd($hash, "GET:System,Basic_Status:GetParam" , $what, $a[2], 0);
  1307. }
  1308. elsif($a[2] eq "timerStatus")
  1309. {
  1310. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Timer,Mode:GetParam" , $what, "getTimer", 0);
  1311. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Timer,Param:GetParam" , $what, $a[2], 0);
  1312. }
  1313. elsif($a[2] eq "networkInfo")
  1314. {
  1315. YAMAHA_NP_SendCmd($hash, "GET:System,Misc,Network,Info:GetParam" , $what, $a[2], 0);
  1316. }
  1317. elsif($a[2] eq "standbyMode")
  1318. {
  1319. YAMAHA_NP_SendCmd($hash, "GET:System,Power_Control,Saving:GetParam", $what, $a[2], 0);
  1320. }
  1321. elsif($a[2] eq "mediaRendererDesc")
  1322. {
  1323. YAMAHA_NP_getMediaRendererDesc($hash);
  1324. }
  1325. else
  1326. {
  1327. return $usage;
  1328. }
  1329. }
  1330. elsif($what eq "timer")
  1331. {
  1332. # Timer
  1333. if($a[2] eq "on")
  1334. {
  1335. # Check if standbyMode == 'Normal'
  1336. if($hash->{READINGS}{standbyMode}{VAL} eq "normal")
  1337. {
  1338. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Timer,Mode:".ucfirst($a[2]), $what, $a[2], 0);
  1339. }
  1340. else
  1341. {
  1342. return "Set 'standbyMode normal' first.";
  1343. }
  1344. }
  1345. elsif($a[2] eq "off")
  1346. {
  1347. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Timer,Mode:".ucfirst($a[2]), $what, $a[2], 0);
  1348. }
  1349. else
  1350. {
  1351. return $usage;
  1352. }
  1353. }
  1354. elsif($what eq "timerVolume")
  1355. {
  1356. # TimerVolume
  1357. # if lower than minimum VOLUMESTRAIGHTMIN or higher than max VOLUMESTRAIGHTMAX set target volume to the corresponding limits
  1358. if($a[2] >= $hash->{helper}{VOLUMESTRAIGHTMIN} and $a[2] <= $hash->{helper}{VOLUMESTRAIGHTMAX})
  1359. {
  1360. $hash->{helper}{timerVolume} = $a[2];
  1361. }
  1362. else
  1363. {
  1364. return "Please use straight device volume range :".$hash->{helper}{VOLUMESTRAIGHTMIN}."...".$hash->{helper}{VOLUMESTRAIGHTMAX}.".";
  1365. }
  1366. }
  1367. elsif($what eq "timerSet")
  1368. {
  1369. # TimerSet
  1370. my ($timerHour, $timerMinute, $timerRepeat, $timerVolume) =
  1371. ( AttrVal($name,"timerHour" ,undef)
  1372. ,AttrVal($name,"timerMinute",undef)
  1373. ,AttrVal($name,"timerRepeat",undef)
  1374. ,AttrVal($name,"timerVolume",undef)
  1375. );
  1376. if( defined($timerHour)
  1377. and defined($timerMinute)
  1378. and defined($timerRepeat)
  1379. and defined($timerVolume))
  1380. {
  1381. # Configure Timer according to provided parameters
  1382. YAMAHA_NP_SendCmd($hash, "PUT:System,Misc,Timer,Param:"
  1383. ."<Start_Time>".sprintf("%02d", $timerHour).":".sprintf("%02d", $timerMinute)."</Start_Time>"
  1384. ."<Volume>$timerVolume</Volume>"
  1385. ."<Repeat>$timerRepeat</Repeat>", $what, $a[2], 0);
  1386. }
  1387. else
  1388. {
  1389. return "Please, define attributes timerHour, timerMinute, timerRepeat and timerVolume first.";
  1390. }
  1391. }
  1392. elsif($what =~ m/^tunerPreset(DAB|FM)/)
  1393. {
  1394. # Tuner Preset DAB/FM
  1395. if($a[2] >= 1 and $a[2] <= 30)
  1396. {
  1397. # DAB only for$hash->{MODEL} eq "CRX-N560D"
  1398. $hash->{helper}{tuner}{station} = "";# need to delete here to prevent station naming
  1399. $hash->{helper}{tuner}{stationID} = "";
  1400. YAMAHA_NP_SendCmd($hash,"PUT:Tuner,Play_Control,Preset,$1,Preset_Sel:".$a[2], "tunerPreset", $a[2], 0);
  1401. }
  1402. else
  1403. {
  1404. return $usage;
  1405. }
  1406. }
  1407. elsif($what eq "tunerFMFrequency")
  1408. {
  1409. # Tuner FM Frequency
  1410. if(length($a[2]) <= 6 and length($a[2]) >= 5)
  1411. { # Check the string length (x)xx.xx
  1412. if ( $a[2] =~ /^[0-9,.E]+$/ )
  1413. { # Check if value is numeric
  1414. if(substr($a[2], -3, 1) eq '.')
  1415. { # Check for decimal point
  1416. if( $a[2] >= 87.50 and $a[2] <= 108.00)
  1417. { # Check if within the value range
  1418. my $lastDigit = substr($a[2], -1, 1);
  1419. if(($lastDigit eq "0") or ($lastDigit eq "5"))
  1420. {
  1421. my $frequency = $a[2];
  1422. $frequency =~ s/\.//; # Remove decimal point
  1423. YAMAHA_NP_SendCmd($hash, "PUT:Tuner,Play_Control,Tuning,FM,Freq:$frequency", $what, $a[2], 0);
  1424. }
  1425. else
  1426. {
  1427. return "Last digit must be '0' or '5'";
  1428. }
  1429. }
  1430. else
  1431. {
  1432. return "Frequency value must be in the range 87.50 ... 108.00 of the format (x)xx.xx";
  1433. }
  1434. }
  1435. else
  1436. {
  1437. return "Missing decimal point. Accepted format (x)xx.xx";
  1438. }
  1439. }
  1440. else
  1441. {
  1442. return "Frequency value must be numeric in the range 87.50 ... 108.00 of the format (x)xx.xx";
  1443. }
  1444. }
  1445. else
  1446. {
  1447. return "Frequency length must be 5 or 6 characters e.g. 89.50 or 108.00";
  1448. }
  1449. }
  1450. elsif($what eq "selectStream")
  1451. {
  1452. #dummy
  1453. }
  1454. else
  1455. {
  1456. return $usage;
  1457. }
  1458. }
  1459. sub YAMAHA_NP_SendCmd
  1460. {
  1461. # Pre-process the HTTP request.
  1462. my ($hash,$di,$cmd,$arg,$blocking) = @_;
  1463. my ($c,$x,$d) = split(":",$di, 3);
  1464. my @xa = split(",",$x);
  1465. my $data = "<YAMAHA_AV cmd=\"$c\"><".join("><",@xa).">$d</".join("></",reverse @xa)."></YAMAHA_AV>";
  1466. if ($cmd eq "statusRequest")
  1467. {
  1468. # avoid multiple status request
  1469. return if ($hash->{helper}{statReq}{$arg}); # we are already waiting for an answer
  1470. $hash->{helper}{statReq}{$arg} = 1;
  1471. RemoveInternalTimer("statTimeOut:".$hash->{NAME});
  1472. InternalTimer(gettimeofday() + 1, "YAMAHA_NP_statTimeOut", "statTimeOut:".$hash->{NAME}, 0);
  1473. }
  1474. YAMAHA_NP_SendCommand($hash,$data,$cmd,$arg,$blocking);
  1475. }
  1476. sub YAMAHA_NP_SendCommand
  1477. {
  1478. # sends a command to the NP via HTTP
  1479. my ($hash,$data,$cmd,$arg,$blocking) = @_;
  1480. my $name = $hash->{NAME};
  1481. my $address = $hash->{helper}{ADDRESS};
  1482. #Log 1,"2 >>>> : #$cmd # $arg";
  1483. if(defined($blocking) && $blocking == 1)
  1484. {
  1485. # use non-blocking http communication if not specified
  1486. Log3 $name, 5, "YAMAHA_NP ($name) - execute blocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
  1487. my $param ={
  1488. url => "http://".$address."/YamahaRemoteControl/ctrl",
  1489. timeout => AttrVal($name, "requestTimeout", 4),
  1490. noshutdown => 1,
  1491. data => "<?xml version=\"1.0\" encoding=\"utf-8\"?>".$data,
  1492. loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
  1493. hash => $hash,
  1494. cmd => $cmd,
  1495. arg => $arg
  1496. };
  1497. my ($err, $data) = HttpUtils_BlockingGet($param);
  1498. YAMAHA_NP_ParseResponse($param, $err, $data);
  1499. }
  1500. else
  1501. {
  1502. Log3 $name, 5, "YAMAHA_NP ($name) - execute nonblocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
  1503. HttpUtils_NonblockingGet({
  1504. url => "http://".$address."/YamahaRemoteControl/ctrl",
  1505. timeout => AttrVal($name, "requestTimeout", 4),
  1506. noshutdown => 1,
  1507. data => "<?xml version=\"1.0\" encoding=\"utf-8\"?>".$data,
  1508. loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
  1509. hash => $hash,
  1510. cmd => $cmd,
  1511. arg => $arg,
  1512. callback => \&YAMAHA_NP_ParseResponse
  1513. });
  1514. }
  1515. }
  1516. sub YAMAHA_NP_ParseResponse
  1517. {
  1518. # parses HTTP response
  1519. my ($param, $err, $data ) = @_;
  1520. my $hash = $param->{hash};
  1521. my $name = $hash->{NAME};
  1522. my $cmd = $param->{cmd};
  1523. my $arg = $param->{arg};
  1524. #d1-input
  1525. #d2-source
  1526. #d3-song
  1527. if(exists($param->{code}))
  1528. {
  1529. Log3 $name, 5, "YAMAHA_NP ($name) - received HTTP code ".$param->{code}." for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\"";
  1530. }
  1531. if($err ne "")
  1532. {
  1533. Log3 $name, 5, "YAMAHA_NP ($name) - could not execute command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $err";
  1534. if((not exists($hash->{helper}{AVAILABLE})) or ($hash->{helper}{AVAILABLE} == 1)){
  1535. 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.";
  1536. readingsSingleUpdate($hash, "power", "absent", 1);
  1537. readingsSingleUpdate($hash, "state", "absent", 1);
  1538. }
  1539. $hash->{helper}{AVAILABLE} = 0;
  1540. }
  1541. elsif($data ne "")
  1542. {
  1543. Log3 $name, 5, "YAMAHA_NP ($name) - got response for \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $data";
  1544. if (defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 0)
  1545. {
  1546. Log3 $name, 3, "YAMAHA_NP ($name) - device $name reappeared";
  1547. readingsSingleUpdate($hash, "power", "present", 1);
  1548. }
  1549. $hash->{helper}{AVAILABLE} = 1;
  1550. if (($cmd ne "statusRequest") and ($arg ne "systemConfig"))
  1551. { # RC="0" is not delivered by that status Request
  1552. if(not $data =~ /RC="0"/){
  1553. # if the returncode != 0 -> HTTP command unsuccessful
  1554. Log3 $name, 3, "YAMAHA_NP ($name) - Could not execute \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\"";
  1555. }
  1556. }
  1557. # Start readings update
  1558. readingsBeginUpdate($hash);
  1559. if($cmd eq "statusRequest")
  1560. {
  1561. $hash->{helper}{statReq}{$arg} = 0;
  1562. if ($arg eq "systemConfig")
  1563. {
  1564. if($data =~ /<Model_Name>(.+?)<\/Model_Name>.*<System_ID>(.+?)<\/System_ID>.*<Version>(.+?)<\/Version>.*<Volume><Min>(.+?)<\/Min>.*<Max>(.+?)<\/Max>.*<Step>(.+?)<\/Step><\/Volume>/)
  1565. {
  1566. $hash->{MODEL} = $1;
  1567. $hash->{helper}{dInfo}{MODEL} = $1;
  1568. $hash->{FIRMWARE} = $3;
  1569. $hash->{helper}{dInfo}{FIRMWARE} = $3;
  1570. $hash->{helper}{dInfo}{SYSTEM_ID} = $2;
  1571. readingsBulkUpdate($hash, ".volumeStraightMin" , int($4));
  1572. readingsBulkUpdate($hash, ".volumeStraightMax" , int($5));
  1573. readingsBulkUpdate($hash, ".volumeStraightStep", int($6));
  1574. # Used by 'fheminfo' command for statistics
  1575. $attr{$name}{"model"} = $hash->{MODEL};
  1576. }
  1577. }
  1578. elsif($arg eq "getInputs")
  1579. {
  1580. my @ip;
  1581. while($data =~ /<Feature_Existence>(.+?)<\/Feature_Existence>/gc)
  1582. {
  1583. push @ip,split(",",$1);
  1584. }
  1585. $hash->{helper}{INPUTS} = join("|", sort @ip);
  1586. }
  1587. elsif($arg eq "basicStatus")
  1588. {
  1589. if($data =~ /<Power>(.+?)<\/Power>/)
  1590. {
  1591. my $power = ($1 eq "Standby") ? "off":$1;
  1592. $hash->{helper}{power} = lc($power);
  1593. readingsBulkUpdate($hash, "power", $hash->{helper}{power});
  1594. readingsBulkUpdate($hash, "state", $hash->{helper}{power});
  1595. readingsBulkUpdate($hash, "audioSource", $hash->{helper}{power});
  1596. }
  1597. # current volume and mute status
  1598. if($data =~ /<Volume><Lvl>(.+?)<\/Lvl><Mute>(.+?)<\/Mute><\/Volume>/)
  1599. {
  1600. readingsBulkUpdate($hash, "mute", lc($2));
  1601. if($1 eq "0")
  1602. {
  1603. readingsBulkUpdate($hash, "mute", "on");
  1604. # Bug in the NP firmware. Even if volume = 0. Mute remains off.
  1605. }
  1606. # Surpress Readings update during smooth volume change
  1607. $hash->{helper}{volumeChangeProcessing} = "0" if(not defined($hash->{helper}{volumeChangeProcessing}));
  1608. if ($hash->{helper}{volumeChangeProcessing} eq "0")
  1609. {
  1610. readingsBulkUpdate($hash, "volumeStraight", ($1));
  1611. readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $1));
  1612. }
  1613. if($hash->{helper}{power} eq "on" && (ReadingsVal($name, "volumeStraight", "") eq "0" || ReadingsVal($name, "mute", "") eq "on"))
  1614. {
  1615. if(ReadingsVal($name, "input", "") =~ m/(server|netradio|cd|usb)/)
  1616. {
  1617. my $playerInfo = ReadingsVal($name, "playerPlaybackInfo", "");
  1618. if ($playerInfo eq "")
  1619. {
  1620. $playerInfo = ("reading status...");
  1621. }
  1622. readingsBulkUpdate($hash, "audioSource", ReadingsVal($name, "input", "") . " ($playerInfo, muted)");
  1623. }
  1624. else
  1625. {
  1626. readingsBulkUpdate($hash, "audioSource", ReadingsVal($name, "input", "") . " (muted)");
  1627. }
  1628. }
  1629. elsif($hash->{helper}{power} eq "on")
  1630. {
  1631. if(ReadingsVal($name, "input", "") =~ m/(server|netradio|cd|usb)/)
  1632. {
  1633. my $playerInfo = ReadingsVal($name, "playerPlaybackInfo", "");
  1634. if ($playerInfo eq "")
  1635. {
  1636. $playerInfo = ("reading status...");
  1637. }
  1638. readingsBulkUpdate($hash, "audioSource", ReadingsVal($name, "input", "") . " ($playerInfo)");
  1639. }
  1640. else
  1641. {
  1642. readingsBulkUpdate($hash, "audioSource", ReadingsVal($name, "input", ""));
  1643. }
  1644. }
  1645. }
  1646. if($data =~ /<Input_Sel>(.+?)<\/Input_Sel>/)
  1647. {
  1648. # current input same as the corresponding set command name
  1649. my $input = lc($1);
  1650. my $tb = ReadingsVal($name, "tunerBand", "tuner");
  1651. $input = ($input eq "tuner") ? $tb : YAMAHA_NP_Param2Fhem($input, 0);
  1652. if($input ne ReadingsVal($name,"input",""))
  1653. {
  1654. #input changed: clean readings and settings
  1655. readingsBulkUpdate($hash, "input", $input);
  1656. readingsBulkUpdate($hash, "audioSource", $input . " (reading status...)");
  1657. blankReadings4InChange($hash);
  1658. }
  1659. if($input =~ m/(FM|DAB|tuner)/)
  1660. {
  1661. if(AttrVal($name, "autoUpdateTunerReadings","1") eq "1")
  1662. {
  1663. YAMAHA_NP_SendCmd($hash, "GET:Tuner,Play_Info:GetParam", "statusRequest", "tunerStatus", 0);
  1664. }
  1665. }
  1666. else
  1667. {
  1668. delete $hash->{READINGS}{tunerBand};
  1669. if(AttrVal($name, "autoUpdatePlayerReadings", "1") eq "1" )
  1670. {
  1671. # Inputs don't use any player readings. Blank them.
  1672. if($input !~ m/^(aux|digital)/)
  1673. {
  1674. YAMAHA_NP_SendCmd($hash, "GET:Player,Play_Info:GetParam", "statusRequest", "playerStatus", 0);
  1675. }
  1676. }
  1677. }
  1678. }
  1679. #Log 1, "Sleep: $data";
  1680. if($data =~ /<Sleep>(.+?)<\/Sleep>/)
  1681. {
  1682. # Buggy NP firmware.
  1683. # SLEEP does not reset in case of manual switch off...
  1684. #my $sl = YAMAHA_NP_Param2Fhem($1, 0);
  1685. my $sl = lc($1);
  1686. $hash->{helper}{sleep} = $sl;
  1687. readingsBulkUpdate($hash, "sleep", $sl);
  1688. }
  1689. }
  1690. elsif($arg eq "playerStatus")
  1691. {
  1692. my $input = ReadingsVal($name,"input","");
  1693. my $song = ($data =~ /<Song>(.+)<\/Song>/) ? YAMAHA_NP_html2txt($1) : "";
  1694. $song = ReadingsVal($name,"listItem_$1","-") if ($song =~ /^Track(.*)/);
  1695. readingsBulkUpdate($hash, "playerPlaySong" , $song);
  1696. readingsBulkUpdate($hash, "playerPlaybackInfo", ($data !~ /<Playback_Info>(.+)<\/Playback_Info>/)? "" : lc($1));
  1697. if ($data =~ /<Play_Time>(.+)<\/Play_Time>/)
  1698. {
  1699. if(int($1) < 3600) # 00:00
  1700. {
  1701. readingsBulkUpdate($hash, "playerPlayTime", strftime("\%M:\%S", gmtime($1)));
  1702. }
  1703. else # 00:00:00
  1704. {
  1705. readingsBulkUpdate($hash, "playerPlayTime", strftime("\%H:\%M:\%S", gmtime($1)));
  1706. }
  1707. }
  1708. else
  1709. {
  1710. readingsBulkUpdate($hash, "playerPlayTime", "");
  1711. }
  1712. readingsBulkUpdate($hash, "playerPlayArtist" , ($data !~ /<Artist>(.+)<\/Artist>/) ? "" : YAMAHA_NP_html2txt($1));
  1713. readingsBulkUpdate($hash, "playerPlayAlbum" , ($data !~ /<Album>(.+)<\/Album>/) ? "" : YAMAHA_NP_html2txt($1));
  1714. readingsBulkUpdate($hash, "playerDeviceType" , ($data !~ /<Device_Type>(.+)<\/Device_Type>/) ? "" : lc($1));
  1715. readingsBulkUpdate($hash, "playerIpodMode" , ($data !~ /<iPod_Mode>(.+)<\/iPod_Mode>/) ? "" : lc($1));
  1716. readingsBulkUpdate($hash, "playerRepeat" , ($data !~ /<Repeat>(.+)<\/Repeat>/) ? "" : lc($1));
  1717. # Repeat toggles between OFF/ONE/ALL
  1718. # Depending on the chosen command value the HTTP request command request has to be executed twice.
  1719. # Check if different repeate mode is desired --> $hash->{helper}{playerRepeatModeTarget}
  1720. if(defined($hash->{helper}{playerRepeatModeTarget})) # RepeatMode change requested previously
  1721. {
  1722. if(ReadingsVal($name, "playerRepeat", "") ne lc(substr($hash->{helper}{playerRepeatModeTarget}, -3))) # repeatOff,repeatOne,repeatAll
  1723. {
  1724. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Play_Mode,Repeat:Toggle", "playMode", $hash->{helper}{playerRepeatModeTarget}, 0);
  1725. }
  1726. else
  1727. {
  1728. # The right mode selected. Delete helper.
  1729. delete $hash->{helper}{playerRepeatModeTarget};
  1730. }
  1731. }
  1732. readingsBulkUpdate($hash, "playerShuffle" , ($data !~ /<Shuffle>(.+)<\/Shuffle>/) ? "" : lc($1));
  1733. if($data =~ /<Album_ART><URL>(.+)<\/URL><ID>(.+)<\/ID><Format>(.+)<\/Format><\/Album_ART>/)
  1734. {
  1735. readingsBulkUpdate($hash, "playerAlbumArtURL" , "http://".$hash->{helper}{ADDRESS}.YAMAHA_NP_html2txt($1));
  1736. readingsBulkUpdate($hash, "playerAlbumArtID" , YAMAHA_NP_html2txt($2));
  1737. readingsBulkUpdate($hash, "playerAlbumArtFormat", YAMAHA_NP_html2txt($3));
  1738. }
  1739. else
  1740. {
  1741. readingsBulkUpdate($hash, "playerAlbumArtURL" , "");
  1742. readingsBulkUpdate($hash, "playerAlbumArtID" , "");
  1743. readingsBulkUpdate($hash, "playerAlbumArtFormat", "");
  1744. }
  1745. if($input !~ m/^(cd|aux|digital|airplay|spotify)/)
  1746. {
  1747. # Don't update readings if not desired
  1748. if(AttrVal($name, "autoUpdatePlayerlistReadings", "1") eq "1")
  1749. {
  1750. YAMAHA_NP_SendCmd($hash, "GET:Player,List_Info:GetParam", "statusRequest", "playerListGetList", 0);
  1751. delete $hash->{helper}{playlist}{ready};
  1752. }
  1753. else
  1754. {
  1755. foreach (grep /playerListLvl.*$/,keys %{$hash->{READINGS}})
  1756. {
  1757. #delete level information
  1758. delete $hash->{READINGS}{$_};
  1759. }
  1760. # delete playerlist items
  1761. delete $hash->{READINGS}{$_} foreach (grep /listItem_...$/,keys %{$hash->{READINGS}});
  1762. delete $hash->{READINGS}{playerListMenuStatus};
  1763. }
  1764. }
  1765. elsif($input eq "cd")
  1766. {
  1767. my $tr = ($data =~ /<Track_Number>(.+)<\/Track_Number>/) ? sprintf("%02d",lc($1)) : "";
  1768. readingsBulkUpdate($hash, "playerPlayTrackNb" , $tr);
  1769. readingsBulkUpdate($hash, "playerTotalTracks" , ($data !~ /<Total_Tracks>(.+)<\/Total_Tracks>/) ? "" : lc($1));
  1770. }
  1771. }
  1772. elsif($arg eq "tunerStatus")
  1773. {
  1774. if ($hash->{READINGS}{input}{VAL} =~ m/(FM|DAB|tuner)/)
  1775. {
  1776. # don't update if tuner not selected
  1777. if($data =~ /<Band>(.+)<\/Band>/)
  1778. {
  1779. $hash->{helper}{tuner}{band} = $1;
  1780. readingsBulkUpdate($hash, "tunerBand", $hash->{helper}{tuner}{band});
  1781. }
  1782. if ($hash->{helper}{tuner}{band} eq "FM")
  1783. {
  1784. my $id = "-";
  1785. my $frequency = "-";
  1786. my $tunerInfo1 = "-";
  1787. if($data =~ /<FM><Preset><Preset_Sel>(.+)<\/Preset_Sel><\/Preset><Tuning><Freq>(.+)<\/Freq>(.*)<\/FM/)
  1788. {
  1789. $id = $1;
  1790. }
  1791. if($data =~ /<Program_Service>(.*)<\/Program_Service>/)
  1792. {
  1793. readingsBulkUpdate($hash, "tunerInfo1" , ($1 ? YAMAHA_NP_html2txt($1) : "-"));
  1794. $tunerInfo1 = $1;
  1795. }
  1796. if($data =~ /<Radio_Text_A>(.*)<\/Radio_Text_A>/)
  1797. {
  1798. readingsBulkUpdate($hash, "tunerInfo2_A" , ($1 ? YAMAHA_NP_html2txt($1) : "-"));
  1799. }
  1800. if($data =~ /<Radio_Text_B>(.*)<\/Radio_Text_B>/)
  1801. {
  1802. readingsBulkUpdate($hash, "tunerInfo2_B" , ($1 ? YAMAHA_NP_html2txt($1) : "-"));
  1803. }
  1804. if($data =~ /<Tuning><Freq>(.*)<\/Freq><\/Tuning>/)
  1805. {
  1806. if(ReadingsVal($name, "power","") eq "off")
  1807. {
  1808. # Bug in the firmware. Last tuned frequency is send also in Standby mode.
  1809. $frequency = "-";
  1810. }
  1811. else
  1812. {
  1813. $frequency = $1 ? $1 : "";
  1814. $frequency =~ s/(\d{2})$/.$1/; # Insert '.' to frequency
  1815. }
  1816. readingsBulkUpdate($hash, "tunerFrequency", $frequency." MHz");
  1817. }
  1818. # No presets stored
  1819. if ($id eq "No Preset")
  1820. {
  1821. readingsBulkUpdate($hash, "tunerPreset" , "-");
  1822. }
  1823. else
  1824. {
  1825. # NP sends <Preset_Sel>[Number]</Preset_Sel>
  1826. # In case the station has been changed manually the number remains.
  1827. # resulting in mismatch between preset and actual frequency.
  1828. # NP Firmware bug?
  1829. my $j = sprintf("%02d", $id);
  1830. my $storedPreset = ReadingsVal($name,"listItem_0$j","");
  1831. if ("FM $frequency MHz" eq $storedPreset)
  1832. {
  1833. readingsBulkUpdate($hash, "tunerPreset" , "$j $storedPreset $tunerInfo1");
  1834. }
  1835. else
  1836. {
  1837. readingsBulkUpdate($hash, "tunerPreset" , "-");
  1838. }
  1839. }
  1840. YAMAHA_NP_SendCmd($hash, "GET:Tuner,Play_Control,Preset,FM,Preset_Sel_Item:GetParam", "statusRequest", "tunerPreset", 0);
  1841. }
  1842. elsif($hash->{helper}{tuner}{band} eq "DAB")
  1843. {
  1844. my ($fq,$br,$qu,$am,$ch,$es,$dp,$sId) = ("-","-","-","-","-","-","DAB+","");
  1845. if($data =~ /<Signal_Info><Freq>(.+)<\/Freq>/)
  1846. {
  1847. $fq = $1;
  1848. $fq =~ s/(\d{3})$/.$1/; # Insert '.' to frequency
  1849. }
  1850. $br = $1 if($data =~ /<Bit_Rate>(.+)<\/Bit_Rate>/);
  1851. $qu = $1 if($data =~ /<Quality>(.+)<\/Quality>/);
  1852. $am = $1 if($data =~ /<Audio_Mode>(.+)<\/Audio_Mode>/);
  1853. $ch = $1 if($data =~ /<Ch_Label>(.*)<\/Ch_Label>/);
  1854. $ch = "-" if($ch eq "");
  1855. $es = YAMAHA_NP_html2txt($1) if($data =~ /<Ensemble_Label>(.*)<\/Ensemble_Label>/);
  1856. $es = "-" if($es eq "");
  1857. $dp = "DAB" if($data =~ /<DAB_PLUS>Negate<\/DAB_PLUS>/);
  1858. if($fq eq "-")
  1859. {
  1860. $am = "-";
  1861. $dp = "-";
  1862. $qu = "-";
  1863. }
  1864. # remember station name
  1865. my $stName = "-";
  1866. my $dls = "-";
  1867. my $ID = "-";
  1868. if($data =~ /<DLS>(.*)<\/DLS>/)
  1869. {
  1870. readingsBulkUpdate($hash, "tunerInfo1" , ($1 ? YAMAHA_NP_html2txt($1) : "-"));
  1871. }
  1872. if($data =~ /<Service_Label>(.*)<\/Service_Label>/)
  1873. {
  1874. $stName = $1 ? YAMAHA_NP_html2txt($1) : "-";
  1875. readingsBulkUpdate($hash, "tunerStation", $stName);
  1876. }
  1877. if($data =~ /<ID>(.+)<\/ID>/)
  1878. {
  1879. # we remember the channel names in hidden readings
  1880. if ($stName)
  1881. {
  1882. #if DLS not set the ID/Name correlation will likely not match. Just a workaround
  1883. $ID = YAMAHA_NP_html2txt($1);
  1884. # workaround: we need to see the station/ID combi twice before we assign it.
  1885. if ( $hash->{helper}{tuner}{station}
  1886. && $hash->{helper}{tuner}{station} eq $stName
  1887. && $hash->{helper}{tuner}{stationID} eq $ID)
  1888. {
  1889. $hash->{READINGS}{".DAB_ID$ID"}{VAL} = $stName;
  1890. $hash->{READINGS}{".DAB_ID$ID"}{TIME} = "-";
  1891. }
  1892. else
  1893. {
  1894. $hash->{helper}{tuner}{station} = $stName;
  1895. $hash->{helper}{tuner}{stationID} = $ID;
  1896. }
  1897. }
  1898. }
  1899. if($data =~ /<DAB><Preset><Preset_Sel>(.*)<\/Preset_Sel><\/Preset>(.*)<\/DAB>/)
  1900. {
  1901. my $presetSel = $1;
  1902. #Log 1,"sID $2";
  1903. if ($presetSel eq "No Preset")
  1904. {
  1905. readingsBulkUpdate($hash, "tunerPreset" , "-");
  1906. }
  1907. else
  1908. {
  1909. # NP sends <Preset_Sel>[Number]</Preset_Sel>
  1910. # In case the station has been chosen manually the number remains.
  1911. # resulting in mismatch between preset and actual frequency.
  1912. # NP Firmware bug?
  1913. my $j = sprintf("%02d", $presetSel);
  1914. my $storedPreset = ReadingsVal($name,"listItem_0$j","");
  1915. #Log 1, "StorePreset: $storedPreset, ID: $ID";
  1916. if ($storedPreset eq "ID $ID $stName")
  1917. {
  1918. readingsBulkUpdate($hash, "tunerPreset" , "$j DAB $fq MHz $stName");
  1919. }
  1920. else
  1921. {
  1922. readingsBulkUpdate($hash, "tunerPreset" , "-");
  1923. }
  1924. }
  1925. }
  1926. readingsBulkUpdate($hash, "tunerDABSignal", "$fq MHz, $qu %, $br kbit/s, $am");
  1927. readingsBulkUpdate($hash, "tunerDABStation", "$dp, Channel: $ch, Ensemble: $es" );
  1928. YAMAHA_NP_SendCmd($hash, "GET:Tuner,Play_Control,Preset,DAB,Preset_Sel_Item:GetParam", "statusRequest", "tunerPreset", 0);
  1929. }
  1930. }
  1931. }
  1932. elsif($arg eq "timerStatus")
  1933. {
  1934. if($data =~ /<Volume><Lvl>(.+)<\/Lvl><\/Volume>/){readingsBulkUpdate($hash, "timerVolume" , $1);}
  1935. if($data =~ /<Start_Time>(.+)<\/Start_Time>/) {readingsBulkUpdate($hash, "timerStartTime", $1);}
  1936. if($data =~ /<Repeat>(.+)<\/Repeat>/) {readingsBulkUpdate($hash, "timerRepeat" , lc($1));}
  1937. }
  1938. elsif($arg eq "getTimer")
  1939. {
  1940. if($data =~ /<Mode>(.+)<\/Mode>/){readingsBulkUpdate($hash, "timer", lc($1));}
  1941. }
  1942. elsif($arg eq "networkInfo")
  1943. {
  1944. if($data =~ /<IP_Address>(.+)<\/IP_Address>/) {$hash->{helper}{dInfo}{IP_ADDRESS} = $1;}
  1945. if($data =~ /<Subnet_Mask>(.+)<\/Subnet_Mask>/) {$hash->{helper}{dInfo}{SUBNET_MASK} = $1;}
  1946. if($data =~ /<Default_Gateway>(.+)<\/Default_Gateway>/){$hash->{helper}{dInfo}{DEFAULT_GATEWAY} = $1;}
  1947. if($data =~ /<DNS_Server_1>(.+)<\/DNS_Server_1>/) {$hash->{helper}{dInfo}{DNS_SERVER_1} = $1;}
  1948. if($data =~ /<DNS_Server_2>(.+)<\/DNS_Server_2>/) {$hash->{helper}{dInfo}{DNS_SERVER_2} = $1;}
  1949. if($data =~ /<MAC_Address>(.+)<\/MAC_Address>/) {$hash->{helper}{dInfo}{MAC_ADDRESS} = $1;
  1950. # Add ':' after every two chars -> AA:BB:CC:DD:EE:FF
  1951. $hash->{helper}{dInfo}{MAC_ADDRESS} =~ s/\w{2}\B/$&:/g;
  1952. }
  1953. }
  1954. elsif($arg eq "tunerPreset")
  1955. {
  1956. # May be also an empty string <Item_#></Item_#>
  1957. if (ReadingsVal($name,"tunerBand","") eq "FM")
  1958. {
  1959. # Max 30 presets
  1960. for (my $i = 1; $i < 31; $i++)
  1961. {
  1962. my $s = $1 if ($data =~ /<Item_$i>(.+?)<\/Item_$i>/);
  1963. $s =~ s/.*?: // if ($s);
  1964. if($s){readingsBulkUpdate($hash,sprintf("listItem_%03d", $i), $s);}
  1965. else {delete $hash->{READINGS}{sprintf("listItem_%03d", $i)};}
  1966. }
  1967. }
  1968. else
  1969. {
  1970. #Band eq "DAB"
  1971. # May be also an empty string <Item_#></Item_#>
  1972. for (my $i = 1; $i < 31; $i++)
  1973. {
  1974. my $s = $1 if ($data =~ /<Item_$i>(.+?)<\/Item_$i>/);
  1975. if ($s)
  1976. {
  1977. $s =~ s/.*?: //;
  1978. my $ID = $s;
  1979. $ID =~ s/^ID //;
  1980. $s .= " ".$hash->{READINGS}{".DAB_ID$ID"}{VAL} if ($hash->{READINGS}{".DAB_ID$ID"});
  1981. readingsBulkUpdate($hash,sprintf("listItem_%03d", $i), $s);
  1982. }
  1983. else
  1984. {
  1985. delete $hash->{READINGS}{sprintf("listItem_%03d", $i)};
  1986. }
  1987. }
  1988. }
  1989. }
  1990. elsif($arg eq "standbyMode")
  1991. {
  1992. if($data =~ /<Saving>(.+)<\/Saving>/){readingsBulkUpdate($hash, "standbyMode", lc($1));}
  1993. }
  1994. elsif($arg eq "mediaRendererDesc")
  1995. {
  1996. if($data =~ /<friendlyName>(.+)<\/friendlyName>/)
  1997. {
  1998. $hash->{FRIENDLY_NAME} = $1;
  1999. $hash->{helper}{dInfo}{FRIENDLY_NAME} = $1;
  2000. }
  2001. if($data =~ /<UDN>(.+)<\/UDN>/)
  2002. {
  2003. my @uuid = split(/:/, $1);
  2004. $hash->{helper}{dInfo}{UUID} = uc($uuid[1]);
  2005. }
  2006. $data =~ s/[\n\t\r]//g;# replace \n\t\r by ""
  2007. if($data =~ /<iconList>(.+?)<\/iconList>/)
  2008. {
  2009. my $address = $hash->{helper}{ADDRESS};
  2010. my $i = 1;
  2011. while ($data =~ /<url>(.+?)<\/url>/g)
  2012. {
  2013. # MAy have several urls according to the UPNP/DLNA standard
  2014. $hash->{helper}{dInfo}{"NP_ICON_$i"} = "http://".$address.":8080".$1;
  2015. $i++;
  2016. }
  2017. }
  2018. }
  2019. elsif($arg eq "playerListGetList")
  2020. {
  2021. if($data =~ /<Menu_Status>(.*)<\/Menu_Status>/)
  2022. {
  2023. $hash->{helper}{playlist}{ready} = $1;
  2024. readingsBulkUpdate($hash, "playerListMenuStatus", $hash->{helper}{playlist}{ready});
  2025. }
  2026. my $lay = ($data =~ /<Menu_Layer>(.*)<\/Menu_Layer>/) ? $1 : "-";
  2027. my $nam = ($data =~ /<Menu_Name>(.*)<\/Menu_Name>/) ? $1 : "-";
  2028. my ($lnMax,$lnCur,$lnPg) = (1,1,1);# maxline, currentline, currentpage
  2029. if($data =~ /<Cursor_Position><Current_Line>(.*)<\/Current_Line><Max_Line>(.*)<\/Max_Line><\/Cursor_Position>/)
  2030. {
  2031. ($lnMax,$lnCur,$lnPg) = ($2,$1,int(($1-1)/8));
  2032. }
  2033. $lnMax = AttrVal($name, "maxPlayerListItems", 999) if ($lnMax >= AttrVal($name, "maxPlayerListItems", 999)); # Limit to given attribute value
  2034. if (!$hash->{helper}{playlist}{mnCur} || $hash->{helper}{playlist}{mnCur} ne "$lay:$nam")
  2035. {
  2036. # did we change our context? Clean up
  2037. $hash->{helper}{playlist}{mnCur} = "$lay:$nam";
  2038. foreach (grep /playerListLvl.*$/,keys %{$hash->{READINGS}})
  2039. {
  2040. #delete level information
  2041. delete $hash->{READINGS}{$_} if (substr($_,13)>$lay);
  2042. }
  2043. readingsBulkUpdate($hash, "playerListLvl$lay", "$nam");
  2044. delete $hash->{READINGS}{$_} foreach (grep /listItem_...$/,keys %{$hash->{READINGS}});#delete playlist
  2045. for (my $pln = 1;$pln <= $lnMax;$pln++)
  2046. {
  2047. #prefill entries as unknown
  2048. $pln = sprintf("%03d",$pln);
  2049. next if ($pln > 999);
  2050. $hash->{READINGS}{"listItem_$pln"}{VAL} = "unknown";
  2051. $hash->{READINGS}{"listItem_$pln"}{TIME}= "-";
  2052. }
  2053. my $lnNext = (($lnPg + 1) % (int(($lnMax-1)/8)+1))*8 + 1;
  2054. $hash->{helper}{playlist}{state} = ($lnNext == 1) ? "complete" : "incomplete";
  2055. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Jump_Line:1","statusRequest", "playerListJumpLine", 0);
  2056. }
  2057. else
  2058. {
  2059. if ($hash->{helper}{playlist}{state} eq "incomplete")
  2060. {
  2061. my $lnNext = (($lnPg + 1) % (int(($lnMax-1)/8)+1))*8 + 1;
  2062. $hash->{helper}{playlist}{state} = "complete" if($lnNext == 1);
  2063. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Jump_Line:$lnNext","statusRequest", "playerListJumpLine", 0);
  2064. }
  2065. }
  2066. if($data =~ /<Current_List>(.*)<\/Current_List>/)
  2067. {
  2068. # write list entries
  2069. # <Line_X><Txt>****</Txt><Attribute>Container|Item|Unselectable</Attribute></Line_X>
  2070. my ($i,$ip) = (1,1);
  2071. my %pla =( Container => "c_",Item => "i_"); #PlayListAttr - convert to prefix
  2072. while($data =~ /<Line_$i><Txt>(.*?)<\/Txt><Attribute>(.*?)<\/Attribute><\/Line_$i>/gc)
  2073. {
  2074. last if($ip >= AttrVal($name, "maxPlayerListItems", 999)); # Limit to giver attribute value
  2075. $ip = sprintf("%03d",($lnPg * 8) + $i);
  2076. if($1){readingsBulkUpdate($hash, "listItem_$ip", $pla{$2}.YAMAHA_NP_html2txt($1));}
  2077. $i++;
  2078. }
  2079. }
  2080. $hash->{helper}{playlist}{lnCur} = $lnCur;
  2081. if (ReadingsVal($name,"playerListMenuStatus","") eq "Ready")
  2082. {
  2083. # see whether more action is required
  2084. if ($hash->{helper}{playlist}{selection})
  2085. {
  2086. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Direct_Sel:Line_$hash->{helper}{playlist}{selection}", "selectStream", $hash->{helper}{playlist}{selection}, 0);
  2087. delete $hash->{helper}{playlist}{selection};
  2088. }
  2089. elsif ($hash->{helper}{playlist}{desiredDirectoryLevel})
  2090. {
  2091. # want to change directory level
  2092. my ($currentLevel) = split(":",$hash->{helper}{playlist}{mnCur});# currentLevel,
  2093. if ($hash->{helper}{playlist}{desiredDirectoryLevel} < $currentLevel)
  2094. {
  2095. YAMAHA_NP_SendCmd($hash, "PUT:Player,List_Control,Cursor:Return", "playerListCursorReturn", $hash->{helper}{playlist}{desiredDirectoryLevel},0);
  2096. }
  2097. else
  2098. {
  2099. delete $hash->{helper}{playlist}{desiredDirectoryLevel};
  2100. }
  2101. }
  2102. }
  2103. }
  2104. elsif($arg eq "playerListJumpLine")
  2105. {
  2106. YAMAHA_NP_SendCmd($hash, "GET:Player,List_Info:GetParam" ,"statusRequest", "playerListGetList" , 0);
  2107. }
  2108. }
  2109. elsif($cmd eq "on")
  2110. {
  2111. if($data =~ /RC="0"/ and $data =~ /<Power><\/Power>/)
  2112. {
  2113. $hash->{helper}{power} = "on";
  2114. readingsBulkUpdate($hash, "power", "on");
  2115. readingsBulkUpdate($hash, "state","on");
  2116. readingsBulkUpdate($hash, "audioSource","- (reading status...)");
  2117. readingsEndUpdate($hash, 1);
  2118. YAMAHA_NP_ResetTimer($hash);
  2119. # Used for direct play if device unpowered
  2120. $cmd = $hash->{helper}{directPlayQueue}{state} if($hash->{helper}{directPlayQueue});
  2121. return if(!defined $hash->{helper}{directPlayQueue});
  2122. }
  2123. }
  2124. elsif($cmd eq "off")
  2125. {
  2126. if($data =~ /RC="0"/ and $data =~ /<Power><\/Power>/)
  2127. {
  2128. $hash->{helper}{power} = "on";
  2129. readingsBulkUpdate($hash, "power", "off");
  2130. readingsBulkUpdate($hash, "state","off");
  2131. readingsBulkUpdate($hash, "audioSource","off");
  2132. readingsEndUpdate($hash, 1);
  2133. blankReadings4InChange($hash);
  2134. YAMAHA_NP_ResetTimer($hash);
  2135. return;
  2136. }
  2137. }
  2138. elsif($cmd eq "mute")
  2139. {
  2140. if($data =~ /RC="0"/){readingsBulkUpdate($hash, "mute", $arg);}
  2141. }
  2142. elsif($cmd eq "standbyMode")
  2143. {
  2144. if($data =~ /RC="0"/)
  2145. {
  2146. readingsBulkUpdate($hash, "standbyMode", lc($arg));
  2147. }
  2148. }
  2149. elsif($cmd =~ m/^volume/)
  2150. {
  2151. if($data =~ /RC="0"/)
  2152. {
  2153. if(AttrVal($name, "smoothVolumeChange", "1") eq "1" )
  2154. {
  2155. my $volumeStraight = $hash->{READINGS}{volumeStraight}{VAL};
  2156. if($hash->{helper}{targetVolume} eq $volumeStraight)
  2157. {
  2158. $hash->{helper}{volumeChangeDir} = "EQUAL";
  2159. }
  2160. if($hash->{helper}{volumeChangeDir} eq "EQUAL")
  2161. {
  2162. $hash->{helper}{volumeChangeProcessing} = "0";
  2163. readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
  2164. readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
  2165. }
  2166. elsif($hash->{helper}{volumeChangeDir} =~ m/(UP|DOWN)/)
  2167. {
  2168. $hash->{helper}{volumeChangeProcessing} = "1";
  2169. if($hash->{helper}{volumeChangeDir} eq "UP")
  2170. {
  2171. $volumeStraight += 1;
  2172. }
  2173. elsif($hash->{helper}{volumeChangeDir} eq "DOWN")
  2174. {
  2175. $volumeStraight -= 1;
  2176. }
  2177. readingsBulkUpdate($hash, "volumeStraight", $volumeStraight);
  2178. readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $volumeStraight));
  2179. YAMAHA_NP_SendCmd($hash, "PUT:System,Volume,Lvl:$volumeStraight", "volume", $volumeStraight, 0);
  2180. }
  2181. }
  2182. else
  2183. {
  2184. readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
  2185. readingsBulkUpdate($hash, "volume", YAMAHA_NP_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
  2186. $hash->{helper}{volumeChangeDir} = "EQUAL";
  2187. $hash->{helper}{volumeChangeProcessing} = "0";
  2188. }
  2189. }
  2190. }
  2191. elsif($cmd eq "input")
  2192. {
  2193. if ($arg =~ m/(FM|DAB)/)
  2194. {
  2195. # we have to select the correct band
  2196. YAMAHA_NP_SendCmd($hash, "PUT:Tuner,Play_Control,Band:$arg", "tuner", $arg, 0);
  2197. YAMAHA_NP_GetStatus($hash, 1);
  2198. }
  2199. }
  2200. elsif($cmd eq "player")
  2201. {
  2202. if ($arg eq "prevCD" && ReadingsVal($name,"playerPlaybackInfo","") eq "play")
  2203. {# we have to select the correct band
  2204. YAMAHA_NP_SendCmd($hash,"PUT:Player,Play_Control,Playback:prev", "player", "prevCDDone", 0);
  2205. YAMAHA_NP_GetStatus($hash, 1);
  2206. }
  2207. }
  2208. # Reset internal timer for direct play.
  2209. #Log 1,"General << : $cmd # $arg ".ReadingsVal($name,"playerListMenuStatus","-");
  2210. if ($cmd ne "statusRequest")
  2211. {
  2212. if ($hash->{helper}{directPlayQueue})
  2213. {
  2214. RemoveInternalTimer("directPlay:".$name);
  2215. my $slp = $hash->{helper}{directPlayQueue}{sleep} ? $hash->{helper}{directPlayQueue}{sleep} : 0.5;
  2216. InternalTimer(gettimeofday() + $slp, "YAMAHA_NP_directSet", "directPlay:".$name, 0);
  2217. }
  2218. YAMAHA_NP_GetStatus($hash, 1) ;# got to update if parameter changed
  2219. }
  2220. elsif
  2221. (
  2222. ($hash->{helper}{playlist}{ready} && $hash->{helper}{playlist}{ready} ne "Ready")
  2223. && ($arg ne "playerListJumpLine")
  2224. )
  2225. {
  2226. # fast poll
  2227. my $slp = $hash->{helper}{directPlayQueue}{sleep} ? $hash->{helper}{directPlayQueue}{sleep} : 0.5;
  2228. RemoveInternalTimer($hash);
  2229. InternalTimer(gettimeofday() + $slp, "YAMAHA_NP_GetStatus", $hash, 0);
  2230. }
  2231. readingsEndUpdate($hash, 1);
  2232. }
  2233. }
  2234. sub blankReadings4InChange
  2235. {
  2236. # Blanks input relarted readings
  2237. my ($hash) = @_;
  2238. delete $hash->{READINGS}{$_} foreach(grep /^(player|tuner)/,keys %{$hash->{READINGS}});
  2239. delete $hash->{helper}{playlist}{ready};
  2240. blankLineItem($hash);
  2241. }
  2242. sub blankLineItem
  2243. {
  2244. # Blanks list item entries
  2245. my ($hash) = @_;
  2246. delete $hash->{READINGS}{$_} foreach(grep /^listItem_/,keys %{$hash->{READINGS}});
  2247. }
  2248. sub YAMAHA_NP_directPlayFinish
  2249. {
  2250. my ($hash, $status) = @_;
  2251. delete $hash->{helper}{directPlayQueueTry};
  2252. delete $hash->{helper}{directPlayQueue};
  2253. RemoveInternalTimer("statTimeOut:".$hash->{NAME});
  2254. readingsSingleUpdate($hash, "directPlay", ($status ? $status : "completed"), 1);
  2255. }
  2256. sub YAMAHA_NP_Param2Fhem
  2257. {
  2258. # Converts all Values to FHEM usable command lists
  2259. my ($param, $replace_pipes) = @_;
  2260. $param =~ s/\s+//g;
  2261. $param =~ s/[,_\)]//g;
  2262. $param =~ s/\(/_/g;
  2263. $param =~ s/\|/,/g if($replace_pipes == 1);
  2264. return lc $param;
  2265. }
  2266. sub YAMAHA_NP_getParamName
  2267. {
  2268. # Returns the Yamaha Parameter Name for the FHEM like equivalent
  2269. my ($hash, $name, $list) = @_;
  2270. return if(not defined($list));
  2271. foreach my $item (split("\\|", $list)){
  2272. return $item if(YAMAHA_NP_Param2Fhem($item, 0) eq $name);
  2273. }
  2274. }
  2275. sub YAMAHA_NP_getModel
  2276. {
  2277. # queries the NP model, system-id and version
  2278. my ($hash) = @_;
  2279. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam", "statusRequest","systemConfig", 0);
  2280. YAMAHA_NP_getMediaRendererDesc($hash);
  2281. return;
  2282. }
  2283. sub YAMAHA_NP_getMediaRendererDesc
  2284. {
  2285. # queries the addition model descriptions
  2286. my ($hash) = @_;
  2287. my $name = $hash->{NAME};
  2288. Log3 $name, 5, "YAMAHA_NP ($name) - execute nonblocking \"MediaRendererDesc\"";
  2289. HttpUtils_NonblockingGet({
  2290. url => "http://".$hash->{helper}{ADDRESS}.":8080/MediaRenderer/desc.xml",
  2291. timeout => AttrVal($name, "requestTimeout", 4),
  2292. noshutdown => 1,
  2293. data => "",
  2294. loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
  2295. hash => $hash,
  2296. cmd => "statusRequest",
  2297. arg => "mediaRendererDesc",
  2298. callback => \&YAMAHA_NP_ParseResponse
  2299. });
  2300. return;
  2301. }
  2302. sub YAMAHA_NP_volume_rel2abs
  2303. {
  2304. # converts straight volume in percentage volume (volumestraightmin .. volumestraightmax => 0 .. 100%)
  2305. my ($hash, $percentage) = @_;
  2306. return int($percentage * ReadingsVal($hash->{NAME},".volumeStraightMax",60) / 100 );
  2307. }
  2308. sub YAMAHA_NP_volume_abs2rel
  2309. {
  2310. # converts relative volume in straight volume (0 .. 100% => volumestraightmin .. volumestraightmax)
  2311. my ($hash, $absolute) = @_;
  2312. return int($absolute * 100 / ReadingsVal($hash->{NAME},".volumeStraightMax",100000)); #high default will return 0 if not set.
  2313. }
  2314. sub YAMAHA_NP_getInputs
  2315. {
  2316. # queries available inputs
  2317. my ($hash) = @_;
  2318. my $name = $hash->{NAME};
  2319. my $address = $hash->{helper}{ADDRESS};
  2320. YAMAHA_NP_SendCmd($hash, "GET:System,Config:GetParam", "statusRequest","getInputs", 0);
  2321. return;
  2322. }
  2323. sub YAMAHA_NP_ResetTimer
  2324. {
  2325. # Restarts the internal status request timer according to the given interval or current NP state
  2326. my ($hash, $interval) = @_;
  2327. RemoveInternalTimer($hash);
  2328. if($hash->{helper}{DISABLED} == 0){
  2329. my $dly = 0;
  2330. if(defined($interval)){
  2331. $dly = $interval;
  2332. }
  2333. elsif(ReadingsVal($hash->{NAME},"power" ,"") eq "on"){
  2334. $dly = $hash->{helper}{ON_INTERVAL};
  2335. }
  2336. else{
  2337. $dly = $hash->{helper}{OFF_INTERVAL};
  2338. }
  2339. InternalTimer(gettimeofday() + $dly, "YAMAHA_NP_GetStatus", $hash, 0) if ($dly);
  2340. }
  2341. }
  2342. sub YAMAHA_NP_html2txt
  2343. {
  2344. # convert HTML entities into UTF-8 equivalent
  2345. my ($string) = @_;
  2346. $string =~ s/\\'//g;
  2347. $string =~ s/(&amp;amp;quot;|&amp;quot;|&quot;)/\"/g;
  2348. $string =~ s/(&amp;amp;|&amp;)/&/g;
  2349. $string =~ s/&nbsp;/ /g;
  2350. $string =~ s/&apos;/'/g;
  2351. $string =~ s/(\xe4|&auml;)/ä;/g;
  2352. $string =~ s/(\xc4|&Auml;)/Ä;/g;
  2353. $string =~ s/(\xf6|&ouml;)/ö;/g;
  2354. $string =~ s/(\xd6|&Ouml;)/Ö;/g;
  2355. $string =~ s/(\xfc|&uuml;)/ü;/g;
  2356. $string =~ s/(\xdc|&Uuml;)/Ü;/g;
  2357. $string =~ s/(\xdf|&szlig;)/ß/g;
  2358. $string =~ s/<.+?>//g;
  2359. $string =~ s/(^\s+|\s+$)//g;
  2360. return $string;
  2361. }
  2362. 1;
  2363. =pod
  2364. =item device
  2365. =item summary controls a Yamaha Network Player in a local network
  2366. =item summary_DE steuert einen Yamaha Netzwerkplayer im lokalen Netzwerk
  2367. =begin html
  2368. <a name="YAMAHA_NP"></a>
  2369. <h3>YAMAHA_NP</h3>
  2370. <ul>
  2371. <a name="YAMAHA_NPdefine"></a>
  2372. <b>Define</b>
  2373. <br><br>
  2374. <ul>
  2375. <code>
  2376. define &lt;name&gt; YAMAHA_NP &lt;ip&ndash;address&gt; [&lt;status_interval&gt;]
  2377. </code>
  2378. <br><br>Alternatively with different two off/on interval definitions (default is 30 seconds).<br><br>
  2379. <code>
  2380. define &lt;name&gt; YAMAHA_NP &lt;ip&ndash;address&gt; [&lt;off_status_interval&gt;] [&lt;on_status_interval&gt;]
  2381. </code>
  2382. <br><br>This FHEM module controls a Yamaha Network Player (such as MCR&ndash;N560, MCR&ndash;N560D, CRX&ndash;N560, CRX&ndash;N560D, CD&ndash;N500 or NP&ndash;S2000) connected to local network.
  2383. <br>Devices implementing the communication protocol of the Yamaha Network Player App for i*S and Andr*id might also work.
  2384. <br><br>
  2385. Example:<br>
  2386. <ul><br>
  2387. <code>
  2388. define NP_Player YAMAHA_NP 192.168.0.15<br>
  2389. attr NP_player webCmd input:selectStream:volume<br><br>
  2390. # With custom status interval of 60 seconds<br>
  2391. define NP_Player YAMAHA_NP 192.168.0.15 <b>60</b><br>
  2392. attr NP_player webCmd input:selectStream:volume<br><br>
  2393. # With custom "off"&ndash;interval of 60 seconds and "on"&ndash;interval of 10 seconds<br>
  2394. define NP_Player YAMAHA_NP 192.168.0.15 <b>60 10</b><br>
  2395. attr NP_player webCmd input:selectStream:volume
  2396. </code>
  2397. </ul>
  2398. </ul>
  2399. <br>
  2400. <a name="YAMAHA_NPset"></a>
  2401. <b>Set</b>
  2402. <ul><br>
  2403. <code>
  2404. set &lt;name&gt; &lt;command&gt; [&lt;parameter&gt;]
  2405. </code>
  2406. <br>
  2407. <br>
  2408. <i>Note: Commands and parameters are case&ndash;sensitive. The module provides available inputs depending on the connected device. Commands are context&ndash;sensitive depending on the current input or action.</i><br>
  2409. <ul>
  2410. <br>
  2411. <u>Available commands:</u><br><br>
  2412. <li><b>CDTray</b> &ndash; open/close the CD tray.</li>
  2413. <li><b>clockUpdate</b> &ndash; updates the system clock with current time. The local time information is taken from the FHEM server.</li>
  2414. <li><b>dimmer</b> < 1..3 > &ndash; Sets the display brightness.</li>
  2415. <li><b>directPlay</b> < input:Stream Level 1,Stream Level 2,... > &ndash; allows direct stream selection e.g. CD:1, DAB:1, netradio:Bookmarks,SWR3 (case&ndash;sensitive)</li>
  2416. <li><b>favoriteDefine</b> < name:input[,Stream Level 1,Stream Level 2,...] > &ndash; defines and stores a favorite stream e.g. CoolSong:CD,1 (predefined favorites are the available inputs)</li>
  2417. <li><b>favoriteDelete</b> < name > &ndash; deletes a favorite stream</li>
  2418. <li><b>favoritePlay</b> < name > &ndash; plays a favorite stream</li>
  2419. <li><b>input</b> [&lt;parameter&gt;] &ndash; selects the input channel. The inputs are read dynamically from the device. Available inputs can be set (e.g. cd, tuner, aux1, aux2, ...).</li>
  2420. <li><b>mute</b> [on|off] &ndash; activates/deactivates muting</li>
  2421. <li><b>off</b> &ndash; shuts down the device </li>
  2422. <li><b>on</b> &ndash; powers on the device</li>
  2423. <li><b>player [&lt;parameter&gt;] </b> &ndash; sets player related commands</li>
  2424. <ul>
  2425. <li><b>play</b> &ndash; play</li>
  2426. <li><b>stop</b> &ndash; stop</li>
  2427. <li><b>pause</b> &ndash; pause</li>
  2428. <li><b>next</b> &ndash; next item</li>
  2429. <li><b>prev</b> &ndash; previous item</li>
  2430. </ul>
  2431. <li><b>playMode [&lt;parameter&gt;] </b> &ndash; sets player mode shuffle or repeat</li>
  2432. <ul>
  2433. <li><b>shuffleAll</b> &ndash; Set shuffle mode</li>
  2434. <li><b>shuffleOff</b> &ndash; Remove shuffle mode</li>
  2435. <li><b>repeatOff</b> &ndash; Set repeat mode Off</li>
  2436. <li><b>repeatOne</b> &ndash; Set repeat mode One</li>
  2437. <li><b>repeatAll</b> &ndash; Set repeat mode All</li>
  2438. </ul>
  2439. <li><b>selectStream</b> &ndash; direct context&ndash;sensitive stream selection depending on the input and available streams. Available streams are read out from device automatically. Depending on the number, this may take some time... (Limited to 999 list entries.) (see also 'maxPlayerLineItems' attribute</li>
  2440. <li><b>sleep</b> [off|30min|60min|90min|120min] &ndash; activates the internal sleep timer</li>
  2441. <li><b>standbyMode</b> [eco|normal] &ndash; set the standby mode</li>
  2442. <li><b>statusRequest [&lt;parameter&gt;] </b> &ndash; requests the current status of the device</li>
  2443. <ul>
  2444. <li><b>basicStatus</b> &ndash; requests the basic status such as volume input etc.</li>
  2445. <li><b>playerStatus</b> &ndash; requests the player status such as play status, song info, artist info etc.</li>
  2446. <li><b>standbyMode</b> &ndash; requests the standby mode information</li>
  2447. <li><b>systemConfig</b> &ndash; requests the system configuration</li>
  2448. <li><b>tunerStatus</b> &ndash; requests the tuner status such as FM frequency, preset number, DAB information etc.</li>
  2449. <li><b>timerStatus</b> &ndash; requests device's internal wake&ndash;up timer status</li>
  2450. <li><b>networkInfo</b> &ndash; requests device's network related information such as IP, Gateway, MAC address etc.</li>
  2451. </ul>
  2452. <li><b>timerSet</b> &ndash; configures the timer according to timerHour, timerMinute, timerRepeat, timerVolume attributes that must be set before. This command does not switch on the timer. &rarr; 'timer on'.)</li>
  2453. <li><b>timer</b> [on|off] &ndash; sets device's internal wake&ndash;up timer. <i><br>(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>
  2454. <li><b>tunerFMFrequency</b> [87.50 ... 108.00] &ndash; Sets the FM frequency. The value must be 87.50 ... 108.00 including the decimal point ('.') with two following decimals. Otherwise the value will be ignored. Available if input was set to FM.</li>
  2455. <li><b>volume</b> [0...100] &ndash; set the volume level in &#037;</li>
  2456. <li><b>volumeStraight</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; 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>
  2457. <li><b>volumeUp</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; 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>
  2458. <li><b>volumeDown</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; 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>
  2459. </ul>
  2460. </ul>
  2461. <br>
  2462. <a name="YAMAHA_NPget"></a>
  2463. <b>Get</b>
  2464. <ul>
  2465. <code>
  2466. get &lt;name&gt; &lt;reading&gt;
  2467. </code>
  2468. <br><br>
  2469. The 'get' command returns reading values. Readings are context&ndash;sensitive depending on the current input or action taken.<br><br>
  2470. </ul>
  2471. <a name="YAMAHA_NPattr"></a>
  2472. <b>Attributes</b><br><br>
  2473. <ul>
  2474. <ul>
  2475. <li><b>.DABList</b> &ndash; (internal) attribute used for DAB preset storage.</li>
  2476. <li><b>.favoriteList</b> &ndash; (internal) attribute used for favorites storage.</li>
  2477. <li><b>autoUpdatePlayerReadings</b> &ndash; optional attribute for auto refresh of player related readings (default is 1).</li>
  2478. <li><b>autoUpdatePlayerlistReadings</b> &ndash; optional attribute for auto scanning of the playerlist content (default is 1). (Due to the playerlist information transfer concept this function might slow down the reaction time of the Yamaha App when used at the same time.)</li>
  2479. <li><b>autoUpdateTunerReadings</b> &ndash; optional attribute for auto refresh of tuner related readings (default is 1).</li>
  2480. <li><b>directPlaySleepNetradio</b> &ndash; optional attribute to define a sleep time between two netradio requests to the vTuner server while using the directPlay command. Increase in case of slow internet connection (default is 5 seconds).</li>
  2481. <li><b>directPlaySleepServer</b> &ndash; optional attribute to define a sleep time between two multimedia server requests while using the directPlay command. Increase in case of slow server connection (default is 2 seconds).</li>
  2482. <li><b>disable</b> &ndash; optional attribute to disable the internal cyclic status update of the NP. Manual status updates via statusRequest command is still possible. Possible values: 0 &rarr; perform cyclic status update, 1 &rarr; don't perform cyclic status updates (default is 1).</li>
  2483. <li><b>do_not_notify</b></li>
  2484. <li><b>maxPlayerListItems</b> &ndash; optional attribute to limit the max number of player list items (default is 999).</li>
  2485. <li><b>readingFnAttributes</b></li><br>
  2486. <li><b>requestTimeout</b> &ndash; optional attribute change the response timeout in seconds for all queries to the receiver. Possible values: 1...5 seconds (default value is 4).</li>
  2487. <li><b>searchAttempts</b> &ndash; optional attribute used by the directPlay command defining the max. number of finding the provided directory content tries before giving up. Possible values: 15...100 (default is 15).</li>
  2488. <li><b>smoothVolumeChange</b> &ndash; optional attribute for smooth volume change (significantly more Ethernet traffic is generated during volume change if set to 1) (default is 1).</li>
  2489. <li><b>timerHour</b> [0...23] &ndash; sets hour of device's internal wake&ndash;up timer</li>
  2490. <li><b>timerMinute</b> [0...59] &ndash; sets minutes of device's internal wake&ndash;up timer</li>
  2491. <li><b>timerRepeat</b> [once|every] &ndash; sets repetition mode of device's internal wake&ndash;up timer</li>
  2492. <li><b>timerVolume</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; sets volume of device's internal wake&ndash;up timer.</li>
  2493. <br>
  2494. </ul>
  2495. </ul>
  2496. <b>Readings</b><br>
  2497. <ul>
  2498. <ul>
  2499. <br><u>General readings:</u><br><br>
  2500. <li><b>deviceInfo</b> &ndash; Reports device specific grouped information such as uuid, ip address, etc.</li>
  2501. <li><b>favoriteList</b> &ndash; Reports stored favorites</li>
  2502. <li><b>reading [reading]</b> &ndash; Reports readings values</li>
  2503. <ul><br>
  2504. <li>.volumeStraightMax &ndash; device specific maximum volume</li>
  2505. <li>.volumeStraightMin &ndash; device specific minimum volume</li>
  2506. <li>.volumeStraightStep &ndash; device specific volume in&#47;decrement step</li>
  2507. <li>audioSource &ndash; consolidated audio stream information with currently selected input, player status (if used) and volume muting information (off|reading status...|input [(play|stop|pause[, muted])]])</li>
  2508. <li>directPlay &ndash; status of directPlay command</li>
  2509. <li>input &ndash; currently selected input</li>
  2510. <li>mute &ndash; mute status on/off</li>
  2511. <li>power &ndash; current device status on/off</li>
  2512. <li>presence &ndash; presence status of the device (present|absent)</li>
  2513. <li>selectStream &ndash; status of the selectStream command</li>
  2514. <li>sleep &ndash; sleep timer value (off|30 min|60 min|90 min|120 min)</li>
  2515. <li>standbyMode &ndash; status of the standby mode (normal|eco)</li>
  2516. <li>state &ndash; current state information (on|off)</li>
  2517. <li>volume &ndash; relative volume (0...100)</li>
  2518. <li>volumeStraight &ndash; device specific absolute volume [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;]</li>
  2519. </ul>
  2520. <br><u>Player related readings:</u><br><br>
  2521. <li><b>playerAlbumArtFormat</b> &ndash; Reports the album art format (if available) of the currently played audio</li>
  2522. <li><b>playerAlbumArtID</b> &ndash; Reports the album art ID (if available) of the currently played audio</li>
  2523. <li><b>playerAlbumArtURL</b> &ndash; Reports the album art url (if available) of the currently played audio. The URL points to the network player</li>
  2524. <li><b>playerDeviceType</b> &ndash; Reports the device type (ipod|msc)</li>
  2525. <li><b>playerIpodMode</b> &ndash; Reports the Ipod Mode (normal|off)</li>
  2526. <li><b>playerAlbum</b> &ndash; Reports the album (if available) of the currently played audio</li>
  2527. <li><b>playerArtist</b> &ndash; Reports the artist (if available) of the currently played audio</li>
  2528. <li><b>playerSong</b> &ndash; Reports the song name (if available) of the currently played audio</li>
  2529. <li><b>playerPlayTime</b> &ndash; Reports the play time of the currently played audio (HH:MM:SS)</li>
  2530. <li><b>playerTrackNb</b> &ndash; Reports the track number of the currently played audio</li>
  2531. <li><b>playerPlaybackInfo</b> &ndash; Reports current player state (play|stop|pause)</li>
  2532. <li><b>playerRepeat</b> &ndash; Reports the Repeat Mode (one|all|off)</li>
  2533. <li><b>playerShuffle</b> &ndash; Reports the Shuffle Mode (on|off)</li>
  2534. <li><b>playerTotalTracks</b> &ndash; Reports the total number of tracks for playing</li>
  2535. <br><u>Player list (menu) related readings:</u><br><br>
  2536. <li>listItem_XXX &ndash; Reports the content of the device's current directory. Prefix 'c_' indicates a container (directory), prefix 'i_' an item (audio file/stream). Number of lines can be limited by the attribute 'maxPlayerLineItems' (default is 999).</li>
  2537. <li>lvlX_ &ndash; Reports the hierarchical directory tree level.</li>
  2538. <br><u>Tuner related readings:</u><br><br>
  2539. <li>listItem_XXX &ndash; Reports the stored presets.</li>
  2540. <li>tunerBand &ndash; Reports the tuner band (DAB|FM)</li>
  2541. <br>
  2542. <li>DAB</li>
  2543. <ul><li>tunerDABStation &ndash; (DAB|DAB+), Channel: (value), Ensemble: (name)</li></ul>
  2544. <ul><li>tunerDABSignal &ndash; (Frequency), (Signal quality), (Bitrate), (Mono|Stereo)</li></ul>
  2545. <ul><li>tunerInfo1 &ndash; DAB program service</li></ul>
  2546. <ul><li>tunerPreset &ndash; (Preset number DAB Frequency Station) or '&ndash;' if not stored as preset</li></ul>
  2547. <ul><li>tunerStation &ndash; DAB Station Name</li></ul>
  2548. <br>
  2549. <li>FM</li>
  2550. <ul><li>tunerFrequency &ndash; FM frequency</li></ul>
  2551. <ul><li>tunerInfo1 &ndash; FM station name</li></ul>
  2552. <ul><li>tunerInfo2_A &ndash; Additional RDS information A</li></ul>
  2553. <ul><li>tunerInfo2_A &ndash; Additional RDS information B</li></ul>
  2554. <ul><li>tunerPreset &ndash; (Preset number FM Frequency Station) or '&ndash;' if not stored as preset</li></ul>
  2555. <br><u>Timer related readings:</u><br><br>
  2556. <li>timer &ndash; current timer status (on|off)</li>
  2557. <li>timerRepeat &ndash; timer repeat mode (once|every)</li>
  2558. <li>timerStartTime &ndash; timer start time HH:MM</li>
  2559. <li>timerVolume &ndash; timer volume [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;]</li>
  2560. </ul>
  2561. </ul>
  2562. </ul>
  2563. =end html
  2564. =begin html_DE
  2565. <a name="YAMAHA_NP"></a>
  2566. <h3>YAMAHA_NP</h3>
  2567. <ul>
  2568. <a name="YAMAHA_NPdefine"></a>
  2569. <b>Define</b>
  2570. <br><br>
  2571. <ul>
  2572. <code>
  2573. define &lt;name&gt; YAMAHA_NP &lt;ip&ndash;address&gt; [&lt;status_interval&gt;]
  2574. </code>
  2575. <br><br>Alternatitv mit unterschiedlichen off/on Intervalldefinitionen (Default 30 Sek).<br><br>
  2576. <code>
  2577. define &lt;name&gt; YAMAHA_NP &lt;ip&ndash;address&gt; [&lt;off_status_interval&gt;] [&lt;on_status_interval&gt;]
  2578. </code>
  2579. <br><br>Dieses FHEM&ndash;Modul steuert einen Yamaha Network Player (z.B. MCR&ndash;N560, MCR&ndash;N560D, CRX&ndash;N560, CRX&ndash;N560D, CD&ndash;N500 or NP&ndash;S2000) im lokalen Netzwerk.
  2580. <br>Ger&auml;te, die das Kommunikationsprotokoll der Yamaha Network Player App f&uuml;r i*S und Andr*id implementieren, sollten ebenfalls unterst&uuml;tzen werden k&ouml;nnen.
  2581. <br><br>
  2582. Beispiel:<br>
  2583. <ul><br>
  2584. <code>
  2585. define NP_Player YAMAHA_NP 192.168.0.15<br>
  2586. attr NP_player webCmd input:selectStream:volume<br><br>
  2587. # Mit einem Statusintervall von 60 Sek.<br>
  2588. define NP_Player YAMAHA_NP 192.168.0.15 <b>60</b><br>
  2589. attr NP_player webCmd input:selectStream:volume<br><br>
  2590. # Mit unterschiedlichen Statusintervallen f&uuml;r off/on, 60/10 Sekunden<br>
  2591. define NP_Player YAMAHA_NP 192.168.0.15 <b>60 10</b><br>
  2592. attr NP_player webCmd input:selectStream:volume
  2593. </code>
  2594. </ul>
  2595. </ul>
  2596. <br>
  2597. <a name="YAMAHA_NPset"></a>
  2598. <b>Set</b>
  2599. <ul><br>
  2600. <code>
  2601. set &lt;name&gt; &lt;command&gt; [&lt;parameter&gt;]
  2602. </code>
  2603. <br>
  2604. <br>
  2605. <i>Bemerkung: Bei den Befehlen und Parametern ist die Groß&ndash;/Kleinschreibung zu bachten. Das Modul zeigt ausschließlich verf&uuml;gbare Eing&auml;nge, die vom jeweiligen Ger&auml;t unterst&uuml;tzt werden. Dar&uuml;ber hinaus sind die Befehle kontextsensitiv, abh&auml;ngig von dem jeweils gew&auml;hlten Eingang bzw. Betriebsmodus.</i><br>
  2606. <ul>
  2607. <br>
  2608. <u>Verf&uuml;gbare Befehle:</u><br><br>
  2609. <li><b>CDTray</b> &ndash; &Ouml;ffnen und Schlie&szlig;en des CD&ndash;Fachs.</li>
  2610. <li><b>clockUpdate</b> &ndash; Aktualisierung der Systemzeit des Network Players. Die Zeitinformation wird von dem FHEM Server bezogen, auf dem das Modul ausgef&uuml;hrt wird.</li>
  2611. <li><b>dimmer</b> [1..3] &ndash; Einstellung der Anzeigehelligkeit</li>
  2612. <li><b>directPlay</b> < input:Stream Level 1,Stream Level 2,... > &ndash; erm&ouml;glicht direktes Abspielen eines Audiostreams/einer Audiodatei z.B. CD:1, DAB:1, netradio:Bookmarks,SWR3 </li>
  2613. <li><b>favoriteDefine</b> < name:input[,Stream Level 1,Stream Level 2,...] > &ndash; Speichert einen Favoriten e.g. CoolSong:CD,1 (vordefinierte Favoriten sind die verf&uuml;gbaren Eing&auml;nge)</li>
  2614. <li><b>favoriteDelete</b> < name > &ndash; L&ouml;scht einen Favoriten</li>
  2615. <li><b>favoritePlay</b> < name > &ndash; Spielt einen Favoriten ab</li>
  2616. <li><b>input</b> [&lt;parameter&gt;] &ndash; Auswahl des Eingangs des Network Players. (Nicht verf&uuml;gbar beim ausgeschaltetem Ger&auml;t)</li>
  2617. <li><b>mute</b> [on|off] &ndash; Aktiviert/Deaktiviert die Stummschaltung</li>
  2618. <li><b>off</b> &ndash; Network Player ausschalten</li>
  2619. <li><b>on</b> &ndash; Network Player einschalten</li>
  2620. <li><b>player [&lt;parameter&gt;] </b> &ndash; Setzt Player relevante Befehle.</li>
  2621. <ul>
  2622. <li><b>play</b> &ndash; play</li>
  2623. <li><b>stop</b> &ndash; stop</li>
  2624. <li><b>pause</b> &ndash; pause</li>
  2625. <li><b>next</b> &ndash; n&auml;chstes Audiost&uuml;ck</li>
  2626. <li><b>prev</b> &ndash; vorheriges Audiost&uuml;ck</li>
  2627. </ul>
  2628. <li><b>playMode [&lt;parameter&gt;] </b> &ndash; Setzt Player relevante Befehle</li>
  2629. <ul>
  2630. <li><b>shuffleAll</b> &ndash; setzt shuffle</li>
  2631. <li><b>shuffleOff</b> &ndash; setzt no Shuffle mode</li>
  2632. <li><b>repeatOff</b> &ndash; repeat off</li>
  2633. <li><b>repeatOne</b> &ndash; repeat one</li>
  2634. <li><b>repeatAll</b> &ndash; repeat all</li>
  2635. </ul>
  2636. <li><b>selectStream</b> &ndash; Direkte kontextsensitive Streamauswahl. Ver&uuml;gbare Men&uuml;eintr&auml;ge werden automatisch generiert. Bedingt durch das KOnzept des Yamaha&ndash;Protokolls kann dies etwas Zeit in Anspruch nehmen. (Defaultm&auml;ssig auf 999 Listeneint&auml;ge limitiert. s.a. maxPlayerLineItems Attribut.)</li>
  2637. <li><b>sleep</b> [off|30min|60min|90min|120min] &ndash; Aktiviert/Deaktiviert den internen Sleep&ndash;Timer</li>
  2638. <li><b>standbyMode</b> [eco|normal] &ndash; Umschaltung des Standby Modus.</li>
  2639. <li><b>statusRequest [&lt;parameter&gt;] </b> &ndash; Abfrage des aktuellen Status des Network Players.</li>
  2640. <ul>
  2641. <li><b>basicStatus</b> &ndash; Abfrage der Elementarparameter (z.B. Lautst&auml;rke, Eingang, etc.)</li>
  2642. <li><b>playerStatus</b> &ndash; Abfrage des Player&ndash;Status.</li>
  2643. <li><b>standbyMode</b> &ndash; Abfrage des standby Modus.</li>
  2644. <li><b>systemConfig</b> &ndash; Abfrage der Systemkonfiguration.</li>
  2645. <li><b>tunerStatus</b> &ndash; Abfrage des Tuner&ndash;Status (z.B. FM Frequenz, Preset&ndash;Nummer, DAB Information etc.)</li>
  2646. <li><b>timerStatus</b> &ndash; Abfrage des internen Wake&ndash;up timers.</li>
  2647. <li><b>networkInfo</b> &ndash; Abfrage von Netzwerk&ndash;relevanten Informationen (z.B: IP&ndash;Adresse, Gateway&ndash;Adresse, MAC&ndash;address etc.)</li>
  2648. </ul>
  2649. <li><b>timerSet</b> &ndash; konfiguriert den Timer nach den Vorgaben: timerHour, timerMinute, timerRepeat, timerVolume (s. entprechende Attribute). (ALLE Attribute m&uuml;ssen zuvor gesetzt sein. Dieser Befehl schaltet den Timer nicht ein &rarr; 'timer on'.)</li>
  2650. <li><b>timer</b> [on|off] &ndash; Schaltet ein/aus den internen Wake&ndash;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>
  2651. <li><b>tunerFMFrequency</b> [87.50 ... 108.00] &ndash; Setzt die FM Frequenz. Der Wert muss zwischen 87.50 ... 108.00 liegen und muss den Digitalpunkt beinhalten ('.') mit zwei Nachkommastellen.</li>
  2652. <li><b>volume</b> [0...100] &ndash; Setzt den relativen Lautst&auml;rkepegel in &#037;</li>
  2653. <li><b>volumeStraight</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; 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>
  2654. <li><b>volumeUp</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; 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>
  2655. <li><b>volumeDown</b> [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;] &ndash; Reduziert die Lautst&auml;rke um einen absoluten Schritt. Die Parameter &lt;VOL_MIN&gt; and &lt;VOL_MAX&gt; werden automatisch ermittelt.</li>
  2656. </ul>
  2657. </ul>
  2658. <br>
  2659. <a name="YAMAHA_NPget"></a>
  2660. <b>Get</b>
  2661. <ul>
  2662. <code>
  2663. get &lt;name&gt; &lt;reading&gt;
  2664. </code>
  2665. <br><br>
  2666. Der 'get' Befehl liest Readingwerte zur&uuml;ck. Die Readings sind kontextsensitiv und h&auml;ngen von dem/der jeweils gew&auml;hlten Eingang bzw. Aktion ab.<br><br>
  2667. </ul>
  2668. <a name="YAMAHA_NPattr"></a>
  2669. <b>Attributes</b><br><br>
  2670. <ul>
  2671. <ul>
  2672. <li><b>.DABList</b> &ndash; (internes) Attribut zum Speichern von DAB Presets</li>
  2673. <li><b>.favoriteList</b> &ndash; (internes) Attribut zum Speichern von Favoriten</li>
  2674. <li><b>autoUpdatePlayerReadings</b> &ndash; optionales Attribut zum automtischen aktualisieren der Player&ndash;Readings (Default 1)</li>
  2675. <li><b>autoUpdatePlayerlistReadings</b> &ndash; optionales Attribut zum automatischen Scannen der Playerlist (Men&uuml;) (Default 1). (Aufgrund des Kommunikationskonzeptes bei der &Uuml;bertragung der Playerlistinformation kann diese Funktion zu l&auml;ngeren Reaktionszeiten bei der Yamaha App f&uuml;hren, wenn gleichzeitig auf den Netzwerkplayer zugegriffen wird.)</li>
  2676. <li><b>autoUpdateTunerReadings</b> &ndash; optionales Attribut zum automtischen aktualisieren der Tuner&ndash;Readings (Default 1)</li>
  2677. <li><b>directPlaySleepNetradio</b> &ndash; optionales Attribut zum Definieren der Sleep-Zeit zwischen zwei netradio Anfragen zum vTuner Server, wenn der Befehl directPlay benutzt wird. Kann bei langsamen Interneverbindungen n&uuml;tzlich sein. (Default 5 Sek.).</li>
  2678. <li><b>directPlaySleepServer</b> &ndash; optionales Attribut zum Definieren der Sleep-Zeit zwischen zwei Multimediaserver-Anfragen, wenn der Befehl directPlay benutzt wird. Kann bei langsamen Verbindungen n&uuml;tzlich sein. (Default 2 Sek.).</li>
  2679. <li><b>disable</b> &ndash; optionales Attribut zum Deaktivieren des internen zyklischen Timers zum Aktualisieren des NP&ndash;Status. Manuelles Update ist nach wie vor m&ouml;glich. M&ouml;gliche Werte: 0 &rarr; Zyklisches Update aktiv., 1 &rarr; Zyklisches Update inaktiv (Default 1).</li>
  2680. <li><b>do_not_notify</b></li>
  2681. <li><b>maxPlayerListItems</b> &ndash; optionales Attribut zum Limitieren der maximalen Anzahl von Men&uuml;eintr&auml;gen (Default 999).</li>
  2682. <li><b>readingFnAttributes</b></li>
  2683. <li><b>requestTimeout</b> &ndash; optionales Attribut zum setzen des HTTP response Timeouts (Default 4)</li>
  2684. <li><b>searchAttempts</b> &ndash; optionales Attribut zur Definition von max. Anzahl der Suchversuche des angegebenen Direktoryinhalts bei der Benutzng des directPlay Befehls. M&ouml;gliche Werte: 15...100 (Default 15 Sek.).</li>
  2685. <li><b>smoothVolumeChange</b> &ndash; optionales Attribut zur sanften Lautst&auml;rke&auml;nderung (Erzeugt deutlich mehr Ethernetkommunikation w&auml;hrend der Lautst&auml;rke&auml;nderung). (Default 1)</li>
  2686. <li><b>timerHour</b> [0...23] &ndash; Setzt die Stunde des internen Wake&ndash;up Timers</li>
  2687. <li><b>timerMinute</b> [0...59] &ndash; Setzt die Minute des internen Wake&ndash;up Timers</li>
  2688. <li><b>timerRepeat</b> [once|every] &ndash; Setzt den Wiederholungsmodus des internen Wake&ndash;up Timers</li>
  2689. <br>
  2690. </ul>
  2691. </ul>
  2692. <b>Readings</b><br>
  2693. <ul>
  2694. <ul>
  2695. <br><u>Generelle Readings:</u><br><br>
  2696. <li><b>deviceInfo</b> &ndash; Devicespezifische, konsolidierte Informationen wie z.B. uuid, IP&ndash;Adresse, usw.</li>
  2697. <li><b>favoriteList</b> &ndash; Listet gespeicherte Favoriten auf</li>
  2698. <li><b>reading [reading]</b> &ndash; Gibt Readingwerte zur&uuml;ck</li>
  2699. <ul><br>
  2700. <li>.volumeStraightMax &ndash; Devicespezifische maximale Lautst&aumlrke</li>
  2701. <li>.volumeStraightMin &ndash; Devicespezifische minimale Lautst&aumlrke</li>
  2702. <li>.volumeStraightStep &ndash; Devicespezifischer minimales Lautst&aumlrkenin&ndash;&#47;dekrement</li>
  2703. <li>audioSource &ndash; Konsolidierte Audiostreaminformation mit aktuell gew&auml;hltem Eingang, Playerstatus (wenn aktiv) und Mute Information. (off|reading status...|input [(play|stop|pause[, muted])]])</li>
  2704. <li>directPlay &ndash; Status des directPlay Befehls</li>
  2705. <li>input &ndash; Aktuell gew&aumlhlter Eingang</li>
  2706. <li>mute &ndash; Mute status</li>
  2707. <li>power &ndash; Aktueller Devicestatus (on|off)</li>
  2708. <li>presence &ndash; Ger&aumlteverf&uuml;gbarkeit im Netzwerk (present|absent)</li>
  2709. <li>selectStream &ndash; Status des selectStream Befehls</li>
  2710. <li>sleep &ndash; Sleeptimer Wert (off|30 min|60 min|90 min|120 min)</li>
  2711. <li>standbyMode &ndash; Standby Mode Status (normal|eco)</li>
  2712. <li>state &ndash; Aktueller Ger&auml;tezusand (on|off)</li>
  2713. <li>volume &ndash; Relative Lautst&aumlrke [0 ... 100]</li>
  2714. <li>volumeStraight &ndash; Devicespezifische absolute Lautst&aumlrke [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;]</li>
  2715. </ul>
  2716. <br><u>Playerspezifische Readings:</u><br><br>
  2717. <li><b>playerPlaybackInfo</b> &ndash; Abfrage des aktuellen Player Status (play|stop|pause)</li>
  2718. <li><b>playerAlbum</b> &ndash; Abfrage des Albumnamens (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2719. <li><b>playerAlbumArtURL</b> &ndash; Abfrage der Album URL (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2720. <li><b>playerAlbumArtID</b> &ndash; Abfrage der AlbumArtID (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2721. <li><b>playerAlbumArtFormat</b> &ndash; Abfrage des AlbumArt Formats (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2722. <li><b>playerArtist</b> &ndash; Abfrage des K&uuml;nstler (Artist) (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2723. <li><b>playerDeviceType</b> &ndash; Abfrage des Device Typs (ipod|msc)</li>
  2724. <li><b>playerIpodMode</b> &ndash; Abfrage des iP*d/iPh*ne Modus (normal|off)</li>
  2725. <li><b>playerPlayTime</b> &ndash; Abfrage der aktuellen Spielzeit (HH:MM:SS)</li>
  2726. <li><b>playerRepeat</b> &ndash; Abfrage des Wiederholungsmodus (one|all)</li>
  2727. <li><b>playerShuffle</b> &ndash; Abfrage des Zufallswiedergabemodus (on|off)</li>
  2728. <li><b>playerSong</b> &ndash; Abfrage des Tracknamens (falls verf&uuml;gbar) der aktuellen Wiedergabe</li>
  2729. <li><b>playerTotalTracks</b> &ndash; Abfrage der Gesamtzahl der zu wiedergebenden Tracks</li>
  2730. <li><b>playerTrackNb</b> &ndash; Abfrage der Audiotracknummer</li>
  2731. <br><u>Playerlistspezifische (Men&uuml;) Readings:</u><br><br>
  2732. <li>listItem_XXX &ndash; Inhalt der Men&uuml;eintr&auml;ge. Prefix 'c_' steht f&uuml;r Container (Directory), Prefix 'i_' f&uuml;r Item (Audiofile/Stream). Die Anzahl kann mit dem Attribut 'maxPlayerLineItems' limitiert werden (Default 999).</li>
  2733. <li>lvlX_ &ndash; Zeigt den hierarchischen Directorylevel im Directory Tree an</li>
  2734. <br><u>Tunerspezifische Readings:</u><br><br>
  2735. <li>listItem_XXX &ndash; Gespeicherter Preset</li>
  2736. <li>tunerBand &ndash; Tuner Band (DAB|FM)</li>
  2737. <br>
  2738. <li>DAB</li>
  2739. <ul><li>tunerDABStation &ndash; (DAB|DAB+), Channel: (value), Ensemble: (name)</li></ul>
  2740. <ul><li>tunerDABSignal &ndash; (Frequenz), (Signalqualit&auml;), (Bitrate), (Mono|Stereo)</li></ul>
  2741. <ul><li>tunerInfo1 &ndash; DAB program service</li></ul>
  2742. <ul><li>tunerPreset &ndash; (Preset number DAB Frequenz Sender) oder '&ndash;' wenn aktueller Sender nicht als Preset gespeichert wurde</li></ul>
  2743. <ul><li>tunerStation &ndash; DAB Sendername</li></ul>
  2744. <br>
  2745. <li>FM</li>
  2746. <ul><li>tunerFrequency &ndash; FM Frequenz</li></ul>
  2747. <ul><li>tunerInfo1 &ndash; FM Sendername</li></ul>
  2748. <ul><li>tunerInfo2_A &ndash; Zus&auml;tzliche RDS Information A</li></ul>
  2749. <ul><li>tunerInfo2_A &ndash; Zus&auml;tzliche RDS Information B</li></ul>
  2750. <ul><li>tunerPreset &ndash; (Presetnummer FM Frequenz Sender) oder '&ndash;' wenn aktueller Sender nicht als Preset gespeichert wurde</li></ul>
  2751. <br><u>Timerspezifische Readings:</u><br><br>
  2752. <li>timer &ndash; Aktueller Timerstatus (on|off)</li>
  2753. <li>timerRepeat &ndash; Timer repeat mode (once|every)</li>
  2754. <li>timerStartTime &ndash; Timer Startzeit HH:MM</li>
  2755. <li>timerVolume &ndash; Timerlautst&auml;rke [&lt;VOL_MIN&gt;...&lt;VOL_MAX&gt;]</li>
  2756. </ul>
  2757. </ul>
  2758. </ul>
  2759. =end html_DE
  2760. =cut