71_PIONEERAVRZONE.pm 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. # $Id: 71_PIONEERAVRZONE.pm 14579 2017-06-26 19:30:40Z 50watt $
  2. ##############################################################################
  3. #
  4. # 71_PIONEERAVRZONE.pm
  5. #
  6. # This file is part of Fhem.
  7. #
  8. # Fhem is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # Fhem is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with Fhem. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. ##############################################################################
  22. package main;
  23. use strict;
  24. use warnings;
  25. use Time::HiRes qw(gettimeofday);
  26. use SetExtensions qw/ :all /;
  27. sub PIONEERAVRZONE_Get($@);
  28. sub PIONEERAVRZONE_Set($@);
  29. sub PIONEERAVRZONE_Attr($@);
  30. sub PIONEERAVRZONE_Define($$);
  31. no if $] >= 5.017011, warnings => 'experimental::smartmatch';
  32. ###################################
  33. sub
  34. PIONEERAVRZONE_Initialize($)
  35. {
  36. my ($hash) = @_;
  37. $hash->{Match} = ".+";
  38. $hash->{GetFn} = "PIONEERAVRZONE_Get";
  39. $hash->{SetFn} = "PIONEERAVRZONE_Set";
  40. $hash->{DefFn} = "PIONEERAVRZONE_Define";
  41. $hash->{ParseFn} = "PIONEERAVRZONE_Parse";
  42. $hash->{AttrFn} = "PIONEERAVRZONE_Attr";
  43. $hash->{AttrList} = "IODev ".
  44. $readingFnAttributes;
  45. }
  46. ###################################
  47. sub
  48. PIONEERAVRZONE_Changed($$$)
  49. {
  50. my ($hash, $cmd, $value)= @_;
  51. readingsBeginUpdate($hash);
  52. my $state= $cmd;
  53. if(defined($value) && $value ne "") {
  54. readingsBulkUpdate($hash, $cmd, $value);
  55. $state.= " $value";
  56. }
  57. readingsBulkUpdate($hash, "state", $state);
  58. readingsEndUpdate($hash, 1);
  59. my $name= $hash->{NAME};
  60. Log3 $hash, 4 , "PIONEERAVRZONE $name $state";
  61. return $state;
  62. }
  63. ###################################
  64. sub
  65. PIONEERAVRZONE_Get($@)
  66. {
  67. my ($hash, @a)= @_;
  68. my $name= $hash->{NAME};
  69. my $zone= $hash->{helper}{ZONE};
  70. my $expect= ".*";
  71. return "get $name needs at least one argument" if(int(@a) < 2);
  72. my $cmdName= $a[1];
  73. my $IOhash= $hash->{IODev};
  74. if ($cmdName eq "input" ) {
  75. } elsif (!defined($IOhash->{helper}{GETS}{$zone}{$cmdName})) {
  76. my $gets= $IOhash->{helper}{GETS}{$zone};
  77. return "$name error: unknown argument $cmdName, choose one of " .
  78. (join " ", sort keys %$gets);
  79. }
  80. my $cmd= $IOhash->{helper}{GETS}{$zone}{$cmdName};
  81. my $v= IOWrite($hash, $cmd);
  82. # return PIONEERAVRZONE_Changed($hash, $cmdname, $v);;
  83. return undef;
  84. }
  85. #############################
  86. sub
  87. PIONEERAVRZONE_Set($@)
  88. {
  89. my ($hash, @a)= @_;
  90. my @args= @a; shift @args; shift @args;
  91. my $name= $hash->{NAME};
  92. my $type= $hash->{TYPE};
  93. return "set $name needs at least one argument" if(int(@a) < 2);
  94. my $cmd= $a[1];
  95. my $IOhash= $hash->{IODev};
  96. my $zone= $hash->{helper}{ZONE};
  97. my $vmax = 0;
  98. my $zahl= 0;
  99. my $muteStr ="";
  100. my @setsWithoutArg= ("off","toggle","volumeUp","volumeDown","muteOn","muteOff","muteToggle","inputUp","inputDown");
  101. Log3 $name, 5, "PIONEERAVRZONE $name: called function PIONEERAVR_Set($cmd)";
  102. return "No Argument given" if ( !defined( $cmd ) );
  103. my $inputNames= $IOhash->{helper}{INPUTNAMES};
  104. # get all input names (preferable the aliasName) of the enabled inputs for the drop down list of "set <device> input xxx"
  105. my @listInputNames = ();
  106. foreach my $key ( keys %{$IOhash->{helper}{INPUTNAMES}} ) {
  107. if (defined($IOhash->{helper}{INPUTNAMES}->{$key}{enabled})) {
  108. if ( $IOhash->{helper}{INPUTNAMES}->{$key}{enabled} eq "1" ) {
  109. if ($IOhash->{helper}{INPUTNAMES}{$key}{aliasName}) {
  110. push(@listInputNames,$IOhash->{helper}{INPUTNAMES}{$key}{aliasName});
  111. } elsif ($IOhash->{helper}{INPUTNAMES}{$key}{name}) {
  112. push(@listInputNames,$IOhash->{helper}{INPUTNAMES}{$key}{name});
  113. }
  114. }
  115. }
  116. }
  117. if (($zone eq "zone2") || ($zone eq "zone3")) {
  118. $muteStr = " mute:on,off,toggle";
  119. }
  120. my $list =
  121. "on:noArg off:noArg toggle:noArg input:"
  122. . join(',', sort @listInputNames)
  123. . " inputUp:noArg inputDown:noArg"
  124. . " volumeUp:noArg volumeDown:noArg"
  125. . $muteStr
  126. . " statusRequest:noArg volume:slider,0,1,100"
  127. . " volumeStraight:slider,-80,1,".$vmax;
  128. if ( $cmd eq "?" ) {
  129. Log3 $name, 5, "PIONEERAVRZONE set $name " . $cmd;
  130. return SetExtensions($hash, $list, $name, $cmd, @args);
  131. }
  132. if(@a == 2) {
  133. Log3 $name, 5, "PIONEERAVRZONE $name: Set $cmd";
  134. #### simple set commands without attributes
  135. #### we just "translate" the human readable command to the PioneerAvr command
  136. #### lookup in $IOhash->{helper}{SETS}{$zone} if the command exists and what to write to PioneerAvr
  137. if ( $cmd ~~ @setsWithoutArg ) {
  138. Log3 $name, 5, "PIONEERAVR $name: Set $cmd (setsWithoutArg)";
  139. my $setCmd= $IOhash->{helper}{SETS}{$zone}{$cmd};
  140. my $v= IOWrite($hash, $setCmd);
  141. Log3 $hash, 5, "PIONEERAVR $name: Set_IOwrite($zone ... $cmd ): $setCmd";
  142. return undef;
  143. ### Power on
  144. ### Command: PO
  145. ### according to "Elite & Pioneer FY14AVR IP & RS-232 7-31-13.xlsx" (notice) we need to send <cr> and
  146. ### wait 100ms before the first command is accepted by the Pioneer AVR
  147. } elsif ( $cmd eq "on" ) {
  148. Log3 $name, 5, "PIONEERAVR $name: Set $cmd ";
  149. my $setCmd= "";
  150. IOWrite($hash, $setCmd);
  151. select(undef, undef, undef, 0.1);
  152. if ( $zone eq "zone2" ) {
  153. $setCmd = "APO";
  154. } elsif ( $zone eq "zone3" ) {
  155. $setCmd = "BPO";
  156. } elsif ( $zone eq "hdZone" ) {
  157. $setCmd = "ZEO";
  158. }
  159. IOWrite($hash, $setCmd);
  160. select(undef, undef, undef, 0.1);
  161. Log3 $hash, 5, "PIONEERAVR $name: Set_IOwrite: $setCmd";
  162. return undef;
  163. # statusRequest: execute all "get" commands to update the readings
  164. } elsif ( $cmd eq "statusRequest") {
  165. Log3 $name, 5, "PIONEERAVR $name: Set $cmd ";
  166. foreach my $key ( keys %{$IOhash->{helper}{GETS}{$zone}} ) {
  167. IOWrite($hash, $IOhash->{helper}{GETS}->{$zone}->{$key});
  168. }
  169. return undef;
  170. }
  171. #### commands with argument(s)
  172. } elsif(@a > 2) {
  173. my $arg = $a[2];
  174. ####Input (all available Inputs of the Pioneer Avr -> see 'get $name loadInputNames')
  175. ####according to http://www.fhemwiki.de/wiki/DevelopmentGuidelinesAV
  176. if ( $cmd eq "input" ) {
  177. Log3 $name, 5, "PIONEERAVRZONE $name: set $cmd ".dq($arg);
  178. foreach my $key ( keys %{$IOhash->{helper}{INPUTNAMES}} ) {
  179. if ( $IOhash->{helper}{INPUTNAMES}->{$key}{aliasName} eq $arg ) {
  180. if ( $zone eq "zone2" ) {
  181. IOWrite($hash, sprintf "%02dZS", $key);
  182. } elsif ($zone eq "zone3") {
  183. IOWrite($hash, sprintf "%02dZT", $key);
  184. } elsif ($zone eq "hdZone") {
  185. IOWrite($hash, sprintf "%02dZEA", $key);
  186. }
  187. } elsif ( $IOhash->{helper}{INPUTNAMES}->{$key}{name} eq $arg ) {
  188. if ( $zone eq "zone2" ) {
  189. IOWrite($hash, sprintf "%02dZS", $key);
  190. } elsif ($zone eq "zone3") {
  191. IOWrite($hash, sprintf "%02dZT", $key);
  192. } elsif ($zone eq "hdZone") {
  193. IOWrite($hash, sprintf "%02dZEA", $key);
  194. }
  195. }
  196. }
  197. return undef;
  198. #####VolumeStraight (-80.5 - 12) in dB
  199. ####according to http://www.fhemwiki.de/wiki/DevelopmentGuidelinesAV
  200. } elsif ( $cmd eq "volumeStraight" ) {
  201. $zahl = 80.5 + $arg;
  202. if ( $zone eq "zone2" ) {
  203. IOWrite($hash, sprintf "%02dZV", $zahl);
  204. } elsif ( $zone eq "zone3" ) {
  205. IOWrite($hash, sprintf "%02dYV", $zahl);
  206. }
  207. readingsBeginUpdate($hash);
  208. readingsBulkUpdate($hash, "volumeStraight", $arg );
  209. readingsBulkUpdate($hash, "volume", sprintf "%d", ($a[2]+80)/0.8 );
  210. readingsEndUpdate($hash, 1);
  211. return undef;
  212. ####Volume (0 - 100) in %
  213. ####according to http://www.fhemwiki.de/wiki/DevelopmentGuidelinesAV
  214. } elsif ( $cmd eq "volume" ) {
  215. $zahl = sprintf "%d", $arg*0.8;
  216. if ( $zone eq "zone2" ) {
  217. IOWrite($hash, sprintf "%02dZV", $zahl);
  218. } elsif ( $zone eq "zone3" ) {
  219. IOWrite($hash, sprintf "%02dYV", $zahl);
  220. }
  221. readingsBeginUpdate($hash);
  222. readingsBulkUpdate($hash, "volumeStraight", $zahl - 80 );
  223. readingsBulkUpdate($hash, "volume", sprintf "%d", $a[2] );
  224. readingsEndUpdate($hash, 1);
  225. return undef;
  226. ####Mute (on|off|toggle)
  227. ####according to http://www.fhemwiki.de/wiki/DevelopmentGuidelinesAV
  228. } elsif ( $cmd eq "mute" ) {
  229. if ($arg eq "on") {
  230. IOWrite($hash, $IOhash->{helper}{SETS}{$zone}{muteOn});
  231. readingsSingleUpdate($hash, "mute", "on", 1 );
  232. }
  233. elsif ($arg eq "off") {
  234. IOWrite($hash, $IOhash->{helper}{SETS}{$zone}{muteOff});
  235. readingsSingleUpdate($hash, "mute", "off", 1 );
  236. }
  237. elsif ($arg eq "toggle") {
  238. IOWrite($hash, $IOhash->{helper}{SETS}{$zone}{muteToggle});
  239. }
  240. return undef;
  241. } else {
  242. return SetExtensions($hash, $list, $name, $cmd, @args);
  243. }
  244. } else {
  245. return SetExtensions($hash, $list, $name, $cmd, @args);
  246. }
  247. return undef;
  248. }
  249. #############################
  250. sub
  251. PIONEERAVRZONE_Parse($$)
  252. {
  253. # we are called from dispatch() from the PIONEERAVR device
  254. # we never come here if $msg does not match $hash->{MATCH} in the first place
  255. # NOTE: we will update all matching readings for all (logical) devices, not just the first!
  256. my ($IOhash, $msg) = @_; # IOhash points to the PIONEERAVR, not to the PIONEERAVRZONE
  257. my @matches;
  258. my $name= $IOhash->{NAME};
  259. my $state = '';
  260. #Debug "Trying to find a match for \"" . escapeLogLine($msg) ."\"";
  261. # walk over all clients
  262. foreach my $d (keys %defs) {
  263. my $hash= $defs{$d};
  264. if($hash->{TYPE} eq "PIONEERAVRZONE" && $hash->{IODev} eq $IOhash) {
  265. my $zone= $hash->{helper}{ZONE};
  266. readingsBeginUpdate($hash);
  267. # zone2
  268. if ($zone eq "zone2") {
  269. # volume zone2
  270. # ZVXX
  271. # XX 00 ... 81 -> -81dB ... 0dB
  272. if ( $msg =~ m/^ZV(\d\d)$/ ) {
  273. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone2 - New volume = " . $1 . " (raw volume data).";
  274. readingsBulkUpdate($hash, "volumeStraight", $1 - 81 );
  275. readingsBulkUpdate($hash, "volume", sprintf "%d", $1/0.8 );
  276. push @matches, $d;
  277. # Mute zone2
  278. # Z2MUTX
  279. # X = 0: Mute on; X = 1: Mute off
  280. } elsif ( $msg =~ m/^Z2MUT(\d)$/) {
  281. if ($1) {
  282. readingsBulkUpdate($hash, "mute", "off" );
  283. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone2 - Mute off.";
  284. }
  285. else {
  286. readingsBulkUpdate($hash, "mute", "on" );
  287. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone2 - Mute on.";
  288. }
  289. push @matches, $d;
  290. # Input zone2
  291. # Z2FXX
  292. # XX -> input number 00 ... 49
  293. } elsif ($msg =~ m/^Z2F(\d\d)$/ ) {
  294. my $inputNr = $1;
  295. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone2 - Input is set to inputNr: $inputNr ";
  296. if ( $IOhash->{helper}{INPUTNAMES}->{$inputNr}{aliasName} ne "") {
  297. Log3 $hash,5,"PIONEERAVRZONE $name: Zone2 - Input aliasName for input $inputNr is " . $IOhash->{helper}{INPUTNAMES}{$inputNr}{aliasName};
  298. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$inputNr}{aliasName} );
  299. } elsif ( $IOhash->{helper}{INPUTNAMES}->{$inputNr}{name} ne "" ) {
  300. Log3 $hash,5,"PIONEERAVRZONE $name: Zone2 - Input Name for input $inputNr is " . $IOhash->{helper}{INPUTNAMES}{$inputNr}{name};
  301. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$inputNr}{name} );
  302. } else {
  303. readingsBulkUpdate($hash, "input", $msg );
  304. Log3 $hash,5,"PIONEERAVRZONE $name: Zone2 - InputName: can't find Name for input $inputNr";
  305. }
  306. push @matches, $d;
  307. # Power zone2
  308. # APRX
  309. # X = 0: Power on; X = 1: Power off
  310. } elsif ( $msg =~ m/^APR(0|1)$/ ) {
  311. if ($1 == "0") {
  312. readingsBulkUpdate($hash, "power", "on" );
  313. $state = "on";
  314. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone2 - Power: on";
  315. } elsif ($1 == "1") {
  316. readingsBulkUpdate($hash, "power", "off" );
  317. $state = "off";
  318. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone2 - Power: off";
  319. }
  320. # Set reading for state
  321. #
  322. if ( !defined( $hash->{READINGS}{state}{VAL} )
  323. || $hash->{READINGS}{state}{VAL} ne $state )
  324. {
  325. readingsBulkUpdate( $hash, "state", $state );
  326. }
  327. }
  328. push @matches, $d;
  329. # zone3
  330. } elsif ($zone eq "zone3") {
  331. # volume zone3
  332. # YVXX
  333. # XX 00 ... 81 -> -81dB ... 0dB
  334. if ( $msg =~ m/^YV(\d\d)$/ ) {
  335. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone3 - New volume = " . $1 . " (raw volume data).";
  336. readingsBulkUpdate($hash, "volumeStraight", $1 - 81 );
  337. readingsBulkUpdate($hash, "volume", sprintf "%d", $1/0.8 );
  338. push @matches, $d;
  339. # Mute zone3
  340. # Z3MUTX
  341. # X = 0: Mute on; X = 1: Mute off
  342. } elsif ( $msg =~ m/^Z3MUT(\d)$/) {
  343. if ($1) {
  344. readingsBulkUpdate($hash, "mute", "off" );
  345. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone3 - Mute off.";
  346. }
  347. else {
  348. readingsBulkUpdate($hash, "mute", "on" );
  349. Log3 $name, 5, "PIONEERAVRZONE $name: ". dq($msg) ." interpreted as: Zone3 - Mute on.";
  350. }
  351. push @matches, $d;
  352. # Input zone3
  353. # Z3FXX
  354. # XX -> input number 00 ... 49
  355. } elsif ($msg =~ m/^Z3F(\d\d)$/ ) {
  356. my $inputNr = $1;
  357. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone3 - Input is set to inputNr: $inputNr ";
  358. if ( defined ( $IOhash->{helper}{INPUTNAMES}->{$inputNr}{aliasName}) ) {
  359. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$inputNr}{aliasName} );
  360. Log3 $hash,5,"PIONEERAVRZONE $name: Zone3 - Input aliasName for input $inputNr is " . $hash->{helper}{INPUTNAMES}{$inputNr}{aliasName};
  361. } elsif ( defined ( $IOhash->{helper}{INPUTNAMES}->{$inputNr}{name}) ) {
  362. Log3 $hash,5,"PIONEERAVRZONE $name: Zone3 - Input Name for input $inputNr is " . $hash->{helper}{INPUTNAMES}{$inputNr}{name};
  363. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$inputNr}{name} );
  364. } else {
  365. Log3 $hash,5,"PIONEERAVRZONE $name: Zone3 - InputName: can't find Name for input $inputNr";
  366. readingsBulkUpdate($hash, "input", $msg );
  367. }
  368. push @matches, $d;
  369. # Power zone3
  370. # BPRX
  371. # X = 0: Power on; X = 1: Power off
  372. } elsif ( $msg =~ m/^BPR(0|1)$/ ) {
  373. if ($1 == "0") {
  374. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone3 - Power: on";
  375. readingsBulkUpdate($hash, "power", "on" );
  376. $state = "on";
  377. } elsif ($1 == "1") {
  378. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: Zone3 - Power: off";
  379. readingsBulkUpdate($hash, "power", "off" );
  380. $state = "off";
  381. }
  382. # Set reading for state
  383. #
  384. if ( !defined( $hash->{READINGS}{state}{VAL} )
  385. || $hash->{READINGS}{state}{VAL} ne $state )
  386. {
  387. readingsBulkUpdate( $hash, "state", $state );
  388. }
  389. push @matches, $d;
  390. }
  391. # hdZone
  392. } elsif ($zone eq "hdZone") {
  393. # Input hdZone
  394. # ZEAXX
  395. # XX -> input number 00 ... 49
  396. if ($msg =~ m/^ZEA(\d\d)$/ ) {
  397. my $inputNr = $1;
  398. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: hdZone - Input is set to inputNr: $inputNr ";
  399. if ( defined ( $IOhash->{helper}{INPUTNAMES}->{$1}{aliasName}) ) {
  400. Log3 $hash,5,"PIONEERAVRZONE $name: hdZone - Input aliasName for input $inputNr is " . $IOhash->{helper}{INPUTNAMES}{$inputNr}{aliasName};
  401. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$1}{aliasName} );
  402. } elsif ( defined ( $IOhash->{helper}{INPUTNAMES}->{$1}{name}) ) {
  403. Log3 $hash,5,"PIONEERAVRZONE $name: hdZone - Input Name for input $inputNr is " . $IOhash->{helper}{INPUTNAMES}{$inputNr}{name};
  404. readingsBulkUpdate($hash, "input", $IOhash->{helper}{INPUTNAMES}->{$1}{name} );
  405. } else {
  406. Log3 $hash,5,"PIONEERAVRZONE $name: Zone3 - InputName: can't find Name for input $inputNr";
  407. readingsBulkUpdate($hash, "input", $msg );
  408. }
  409. push @matches, $d;
  410. # Power hdZone
  411. # ZEPX
  412. # X = 0: Power on; X = 1: Power off
  413. } elsif ( $msg =~ m/^ZEP(0|1)$/ ) {
  414. if ($1 == "0") {
  415. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: hdZone - Power: on";
  416. readingsBulkUpdate($hash, "power", "on" );
  417. $state = "on";
  418. } elsif ($1 == "1") {
  419. Log3 $hash,5,"PIONEERAVRZONE $name: ".dq($msg) ." interpreted as: hdZone - Power: off";
  420. readingsBulkUpdate($hash, "power", "off" );
  421. $state = "off";
  422. }
  423. # Set reading for state
  424. #
  425. if ( !defined( $hash->{READINGS}{state}{VAL} )
  426. || $hash->{READINGS}{state}{VAL} ne $state )
  427. {
  428. readingsBulkUpdate( $hash, "state", $state );
  429. }
  430. push @matches, $d;
  431. }
  432. }
  433. readingsEndUpdate($hash, 1);
  434. }
  435. }
  436. return @matches if(@matches);
  437. return "UNDEFINED PIONEERAVRZONE message1 $msg";
  438. }
  439. #####################################
  440. sub
  441. PIONEERAVRZONE_Attr($@)
  442. {
  443. my @a = @_;
  444. my $hash= $defs{$a[1]};
  445. return undef;
  446. }
  447. #############################
  448. sub
  449. PIONEERAVRZONE_Define($$)
  450. {
  451. my ($hash, $def) = @_;
  452. my @a = split("[ \t]+", $def);
  453. return "Usage: define <name> PIONEERAVRZONE <zone> ... wrong paramter count: ".int(@a) if(int(@a) != 3);
  454. my $name= $a[0];
  455. AssignIoPort($hash);
  456. my $IOhash= $hash->{IODev};
  457. if(!defined($IOhash)) {
  458. my $err= "PIONEERAVRZONE $name error: no I/O device.";
  459. Log3 $hash, 1, $err;
  460. return $err;
  461. }
  462. #Parameter (Zone)
  463. my $zone="";
  464. if ($a[2] =~ m/^(zone\d|hdZone)$/) {
  465. $zone= $a[2];
  466. } else {
  467. my $err= "PIONEERAVRZONE define $name error: unknown Zone ".dq($a[2])." -> must be one of [zone2|zone3|hdZone] (I/O device is "
  468. . $IOhash->{NAME} . "). Usage: define <name> PIONEERAVRZONE <zone>";
  469. Log3 $hash, 1, $err;
  470. return $err;
  471. }
  472. # for autocreate: we store here a pointer of defined devices
  473. # so we can check if the device exists
  474. $modules{PIONEERAVRZONE}{defptr}{$zone} = $hash;
  475. if(!defined($IOhash->{helper}{SETS}{$zone})) {
  476. my $err= "PIONEERAVRZONE define $name error: unknown Zone $zone (I/O device is "
  477. . $IOhash->{NAME} . ").";
  478. Log3 $hash, 1, $err;
  479. return $err;
  480. }
  481. $hash->{helper}{ZONE}= $zone;
  482. # set default attributes
  483. unless ( exists( $attr{$name}{webCmd} ) ) {
  484. $attr{$name}{webCmd} = 'volume:mute:input';
  485. }
  486. unless ( exists( $attr{$name}{devStateIcon} ) ) {
  487. $attr{$name}{devStateIcon} =
  488. 'on:rc_GREEN:off off:rc_STOP:on absent:rc_RED';
  489. }
  490. return undef;
  491. }
  492. #####################################
  493. #Function to show special chars (e.g. \n\r) in logs
  494. #sub
  495. #dq($)
  496. #{
  497. # my ($s)= @_;
  498. # $s= "<nothing>" unless(defined($s));
  499. # return "\"" . escapeLogLine($s) . "\"";
  500. #}
  501. 1;
  502. =pod
  503. =item device
  504. =item summary control for the zones of a PIONEER AV receivers via network or serial connection
  505. =item summary_DE Steuerung der Zonen eines PIONEER AV Receiver per Netzwerk oder seriell
  506. =begin html
  507. <a name="PIONEERAVRZONE"></a>
  508. <h3>PIONEERAVRZONE</h3>
  509. <ul>
  510. <br>
  511. <a name="PIONEERAVRZONEdefine"></a>
  512. <b>Define</b>
  513. <ul>
  514. <code>define &lt;name&gt; PIONEERAVRZONE &lt;zone&gt; </code>
  515. <br><br>
  516. Defines a Zone (zone2, zone3 or hdZone) of a PioneerAVR device.<br>
  517. Note: devices to control zone2, zone3 and/or HD-zone are autocreated on reception of the first message for those zones.<br><br>
  518. Normally, the PIONEERAVRZONE device is attached to the latest previously defined PIONEERAVR device
  519. for I/O. Use the <code>IODev</code> attribute of the PIONEERAVRZONE device to attach to any
  520. PIONEERAVR device, e.g. <code>attr myPioneerAvrZone2 IODev myPioneerAvr</code>.
  521. <br><br>
  522. Examples:
  523. <ul>
  524. <code>define myPioneerAvrZone2 PIONEERAVRZONE zone2</code><br>
  525. <code>attr myPioneerAvrZone2 IODev myPIONEERAVR</code>
  526. </ul>
  527. <br>
  528. </ul>
  529. <a name="PIONEERAVRZONEset"></a>
  530. <b>Set</b>
  531. <ul>
  532. <code>set &lt;name&gt; &lt;what&gt; [&lt;value&gt;]</code>
  533. <br><br>
  534. where &lt;what&gt; is one of
  535. <li>reopen</li>
  536. <li>off <br>put zone into standby</li>
  537. <li>on <br>turn zone on from standby</li>
  538. <li>toggle <br>toggles zone power</li>
  539. <li>volume <0 ... 100><br>zone volume in % of the maximum volume</li>
  540. <li>volumeUp<br>increases the zone volume by 0.5dB</li>
  541. <li>volumeDown<br>decreases the zone volume by 0.5dB</li>
  542. <li>volumeStraight<-80.5 ... 12><br>same values for zone volume as shown on the display of the Pioneer AV receiver</li>
  543. <li>mute <on|off|toggle></li>
  544. <li>input <not on the Pioneer hardware deactivated input><br>the list of possible (i.e. not deactivated)
  545. inputs is read in during Fhem start and with <code>get <name> statusRequest</code></li>
  546. <li>inputUp<br>change zone input to next input</li>
  547. <li>inputDown<br>change zone input to previous input</li>
  548. <li><a href="#setExtensions">set extensions</a> are supported (except <code>&lt;name&gt;</code>)</li>
  549. <br><br>
  550. Example:
  551. <ul>
  552. <code>set VSX923Zone2 on</code><br>
  553. </ul>
  554. <br><br>
  555. </ul>
  556. <a name="PIONEERAVRZONEget"></a>
  557. <b>Get</b>
  558. <ul>
  559. <li><code>get &lt;name&gt; input</code>
  560. <br><br>
  561. Update the reading for the zone input
  562. </li>
  563. </ul>
  564. <br><br>
  565. <a name="PIONEERAVRattr"></a>
  566. <b>Attributes</b>
  567. <br><br>
  568. <ul>
  569. <li>IOdev Name of the device which communicates with the phisical Pioneer AV receiver via ethernet or rs232</li>
  570. <li><a href="#verbose">verbose</a></li>
  571. </ul>
  572. <br><br>
  573. </ul>
  574. =end html
  575. =begin html_DE
  576. <a name="PIONEERAVRZONE"></a>
  577. <h3>PIONEERAVRZONE</h3>
  578. <ul>
  579. <br>
  580. <a name="PIONEERAVRZONEdefine"></a>
  581. <b>Define</b>
  582. <ul>
  583. <code>define &lt;name&gt; PIONEERAVRZONE &lt;zone&gt; </code>
  584. <br><br>
  585. Definiert ein PioneerAVR device für eine Zone Zone (zone2, zone3 or hdZone).<p>
  586. Im Allgemeinen verwendet das logische device PIONEERAVRZONE das zuletzt definierte PIONEERAVR device für die Kommunikation mit dem Pioneer AV Receiver.
  587. Mit dem Atribut <code>IODev</code> kann das PIONEERAVRZONE device jedes PIONEERAVR device zur Kommunikation verwenden,
  588. z.B. <code>attr myPioneerAvrZone2 IODev myPioneerAvr</code>.
  589. <br><br>
  590. Examples:
  591. <ul>
  592. <code>define myPioneerAvrZone2 PIONEERAVRZONE zone2</code><br>
  593. <code>attr myPioneerAvrZone2 IODev myPIONEERAVR</code>
  594. </ul>
  595. <br>
  596. </ul>
  597. <a name="PIONEERAVRZONEset"></a>
  598. <b>Set</b>
  599. <ul>
  600. <code>set &lt;name&gt; &lt;was&gt; [&lt;value&gt;]</code>
  601. <br><br>
  602. wobei &lt;was&gt; eines der folgenden Befehle sein kann:
  603. <li>reopen</li>
  604. <li>off <br>Zone in den Standby-Modus schalten</li>
  605. <li>on <br>Zone aus dem Standby-Modus Einschalten</li>
  606. <li>toggle <br>Zone Ein/Ausschalten</li>
  607. <li>volume <0 ... 100><br>Zonenlautstärke in % der maximalen Lautstärke</li>
  608. <li>volumeUp<br>Zonenlautstärke um 0.5dB erhöhen</li>
  609. <li>volumeDown<br>Zonenlautstärke um 0.5dB verringern</li>
  610. <li>volumeStraight<-80.5 ... 12><br>Einstellen der Zonenlautstärke mit einem Wert, wie er am Display des Pioneer AV Receiver angezeigt wird</li>
  611. <li>mute <on|off|toggle></li>
  612. <li>input <nicht am Pioneer AV Receiver deaktivierte Eingangsquelle><br> Die Liste der verfügbaren (also der nicht deaktivierten)
  613. Eingangsquellen wird beim Start von Fhem und auch mit <code>get <name> statusRequest</code> eingelesen</li>
  614. <li>inputUp<br>nächste Eingangsquelle für die Zone auswählen</li>
  615. <li>inputDown<br>vorherige Eingangsquelle für die Zone auswählen</li>
  616. <li><a href="#setExtensions">set extensions</a> (ausser <code>&lt;name&gt;</code>) werden unterstützt</li>
  617. <br><br>
  618. Beispiel:
  619. <ul>
  620. <code>set VSX923Zone2 on</code><br>
  621. </ul>
  622. <br><br>
  623. </ul>
  624. <a name="PIONEERAVRZONEget"></a>
  625. <b>Get</b>
  626. <ul>
  627. <li><code>get &lt;name&gt; input</code>
  628. <br><br>
  629. reading für die Eingangsquelle aktualisieren
  630. </li>
  631. </ul>
  632. <br><br>
  633. <a name="PIONEERAVRattr"></a>
  634. <b>Attributes</b>
  635. <br><br>
  636. <ul>
  637. <li>IOdev Name des device welches die Kommunikation mit dem Pioneer AV Receiver zur Verfügung stellt</li>
  638. <li><a href="#verbose">verbose</a></li>
  639. </ul>
  640. <br><br>
  641. </ul>
  642. =end html_DE
  643. =cut