21_HEOSGroup.pm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. ###############################################################################
  2. #
  3. # Developed with Kate
  4. #
  5. # (c) 2017 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
  6. # All rights reserved
  7. #
  8. # Special thanks goes to comitters:
  9. # - Olaf Schnicke Thanks for many many Code
  10. # - Dieter Hehlgans Thanks for Commandref
  11. #
  12. #
  13. # This script is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # any later version.
  17. #
  18. # The GNU General Public License can be found at
  19. # http://www.gnu.org/copyleft/gpl.html.
  20. # A copy is found in the textfile GPL.txt and important notices to the license
  21. # from the author is found in LICENSE.txt distributed with these scripts.
  22. #
  23. # This script is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU General Public License for more details.
  27. #
  28. #
  29. # $Id: 21_HEOSGroup.pm 16288 2018-02-28 09:11:34Z CoolTux $
  30. #
  31. ###############################################################################
  32. package main;
  33. use strict;
  34. use warnings;
  35. use JSON qw(decode_json);
  36. use Encode qw(encode_utf8);
  37. my $version = "1.0.3";
  38. # Declare functions
  39. sub HEOSGroup_Initialize($);
  40. sub HEOSGroup_Define($$);
  41. sub HEOSGroup_Undef($$);
  42. sub HEOSGroup_Attr(@);
  43. sub HEOSGroup_Notify($$);
  44. sub HEOSGroup_Parse($$);
  45. sub HEOSGroup_WriteReadings($$);
  46. sub HEOSGroup_Set($$@);
  47. sub HEOSGroup_PreProcessingReadings($$);
  48. sub HEOSGroup_GetGroupInfo($);
  49. sub HEOSGroup_GetGroupVolume($);
  50. sub HEOSGroup_GetGroupMute($);
  51. sub HEOSGroup_Initialize($) {
  52. my ($hash) = @_;
  53. $hash->{Match} = '.*{"command":."group.*|.*{"command":."event\/group.*';
  54. # Provider
  55. $hash->{SetFn} = "HEOSGroup_Set";
  56. $hash->{DefFn} = "HEOSGroup_Define";
  57. $hash->{UndefFn} = "HEOSGroup_Undef";
  58. $hash->{NotifyFn} = "HEOSGroup_Notify";
  59. $hash->{AttrFn} = "HEOSGroup_Attr";
  60. $hash->{ParseFn} = "HEOSGroup_Parse";
  61. $hash->{AttrList} = "IODev ".
  62. "disable:1 ".
  63. $readingFnAttributes;
  64. foreach my $d(sort keys %{$modules{HEOSGroup}{defptr}}) {
  65. my $hash = $modules{HEOSGroup}{defptr}{$d};
  66. $hash->{VERSION} = $version;
  67. }
  68. }
  69. sub HEOSGroup_Define($$) {
  70. my ( $hash, $def ) = @_;
  71. my @a = split( "[ \t]+", $def );
  72. splice( @a, 1, 1 );
  73. my $iodev;
  74. my $i = 0;
  75. foreach my $param ( @a ) {
  76. if( $param =~ m/IODev=([^\s]*)/ ) {
  77. $iodev = $1;
  78. splice( @a, $i, 3 );
  79. last;
  80. }
  81. $i++;
  82. }
  83. return "too few parameters: define <name> HEOSGroup <gid>" if( @a < 2 );
  84. my ($name,$gid) = @a;
  85. $hash->{GID} = $gid;
  86. $hash->{VERSION} = $version;
  87. $hash->{NOTIFYDEV} = "HEOSPlayer".abs($gid);
  88. AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
  89. if(defined($hash->{IODev}->{NAME})) {
  90. Log3 $name, 3, "HEOSGroup ($name) - I/O device is " . $hash->{IODev}->{NAME};
  91. } else {
  92. Log3 $name, 1, "HEOSGroup ($name) - no I/O device";
  93. }
  94. $iodev = $hash->{IODev}->{NAME};
  95. my $code = abs($gid);
  96. $code = $iodev."-".$code if( defined($iodev) );
  97. my $d = $modules{HEOSGroup}{defptr}{$code};
  98. return "HEOSGroup device $hash->{GID} on HEOSMaster $iodev already defined as $d->{NAME}."
  99. if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
  100. Log3 $name, 3, "HEOSGroup ($name) - defined with Code: $code";
  101. $attr{$name}{room} = "HEOS" if( !defined( $attr{$name}{room} ) );
  102. $attr{$name}{devStateIcon} = "on:10px-kreis-gruen off:10px-kreis-rot" if( !defined( $attr{$name}{devStateIcon} ) );
  103. if( $init_done ) {
  104. InternalTimer( gettimeofday()+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 );
  105. InternalTimer( gettimeofday()+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
  106. InternalTimer( gettimeofday()+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
  107. } else {
  108. InternalTimer( gettimeofday()+15+int(rand(2)), "HEOSGroup_GetGroupInfo", $hash, 0 );
  109. InternalTimer( gettimeofday()+15+int(rand(4)), "HEOSGroup_GetGroupVolume", $hash, 0 );
  110. InternalTimer( gettimeofday()+15+int(rand(6)), "HEOSGroup_GetGroupMute", $hash, 0 );
  111. }
  112. readingsBeginUpdate($hash);
  113. readingsBulkUpdate($hash, 'state','Initialized');
  114. readingsBulkUpdate($hash, 'volumeUp', 5);
  115. readingsBulkUpdate($hash, 'volumeDown', 5);
  116. readingsEndUpdate($hash, 1);
  117. $modules{HEOSGroup}{defptr}{$code} = $hash;
  118. return undef;
  119. }
  120. sub HEOSGroup_Undef($$) {
  121. my ( $hash, $arg ) = @_;
  122. my $name = $hash->{NAME};
  123. RemoveInternalTimer($hash);
  124. my $code = abs($hash->{GID});
  125. $code = $hash->{IODev}->{NAME} ."-". $code if( defined($hash->{IODev}->{NAME}) );
  126. delete($modules{HEOSGroup}{defptr}{$code});
  127. Log3 $name, 3, "HEOSGroup ($name) - device $name deleted with Code: $code";
  128. return undef;
  129. }
  130. sub HEOSGroup_Attr(@) {
  131. my ( $cmd, $name, $attrName, $attrVal ) = @_;
  132. my $hash = $defs{$name};
  133. my $token = $hash->{IODev}->{TOKEN};
  134. if( $attrName eq "disable" ) {
  135. if( $cmd eq "set" and $attrVal eq "1" ) {
  136. readingsSingleUpdate ( $hash, "state", "disabled", 1 );
  137. Log3 $name, 3, "HEOSGroup ($name) - disabled";
  138. } elsif( $cmd eq "del" ) {
  139. readingsSingleUpdate ( $hash, "state", "active", 1 );
  140. Log3 $name, 3, "HEOSGroup ($name) - enabled";
  141. }
  142. }
  143. if( $attrName eq "disabledForIntervals" ) {
  144. if( $cmd eq "set" ) {
  145. Log3 $name, 3, "HEOSGroup ($name) - enable disabledForIntervals";
  146. readingsSingleUpdate ( $hash, "state", "Unknown", 1 );
  147. } elsif( $cmd eq "del" ) {
  148. readingsSingleUpdate ( $hash, "state", "active", 1 );
  149. Log3 $name, 3, "HEOSGroup ($name) - delete disabledForIntervals";
  150. }
  151. }
  152. }
  153. sub HEOSGroup_Notify($$) {
  154. my ($hash,$dev) = @_;
  155. my $name = $hash->{NAME};
  156. return undef if(IsDisabled($name));
  157. my $events = deviceEvents($dev,1);
  158. return if( !$events );
  159. readingsBeginUpdate($hash);
  160. my %playerEevents = map { my ( $key, $value ) = split /:\s/; ( $key, $value ) } @$events;
  161. foreach my $key ( keys %playerEevents ) {
  162. #### playing Infos
  163. readingsBulkUpdate( $hash, $key, $playerEevents{$key} ) if( grep { $_ =~ /$key/ } ("channel", "currentAlbum", "currentArtist", "currentImageUrl", "currentMedia", "currentMid", "currentQid", "currentSid", "currentStation", "currentTitle", "error", "playStatus", "repeat", "shuffle" ) );
  164. }
  165. readingsEndUpdate( $hash, 1 );
  166. }
  167. sub HEOSGroup_Set($$@) {
  168. my ($hash, $name, @aa) = @_;
  169. my ($cmd, @args) = @aa;
  170. my $gid = $hash->{GID};
  171. my $action;
  172. my $heosCmd;
  173. my $rvalue;
  174. my $favorit;
  175. my $favoritcount = 1;
  176. my $string = "gid=$gid";
  177. #senden von Befehlen unterdrücken solange state nicht on ist
  178. return undef unless ( ReadingsVal($name, "state", "off") eq "on" );
  179. if( $cmd eq 'getGroupInfo' ) {
  180. return "usage: $cmd" if( @args != 0 );
  181. $heosCmd = $cmd;
  182. } elsif( $cmd eq 'mute' ) {
  183. my $param = "on|off";
  184. return "usage: $cmd $param" if( @args != 1 || ! grep { $_ =~ /$args[0]/ } split(/\|/, $param) );
  185. $heosCmd = 'setGroupMute';
  186. $action = "state=$args[0]";
  187. } elsif( $cmd eq 'volume' ) {
  188. return "usage: $cmd 0-100" if( @args != 1 || $args[0] !~ /(\d+)/ || $args[0] > 100 || $args[0] < 0 );
  189. $heosCmd = 'setGroupVolume';
  190. $action = "level=$args[0]";
  191. } elsif( $cmd eq 'volumeUp' ) {
  192. return "usage: $cmd 0-10" if( @args != 1 || $args[0] !~ /(\d+)/ || $args[0] > 10 || $args[0] < 1 );
  193. $heosCmd = 'GroupVolumeUp';
  194. $action = "step=$args[0]";
  195. } elsif( $cmd eq 'volumeDown' ) {
  196. return "usage: $cmd 0-10" if( @args != 1 || $args[0] !~ /(\d+)/ || $args[0] > 10 || $args[0] < 1 );
  197. $heosCmd = 'groupVolumeDown';
  198. $action = "step=$args[0]";
  199. } elsif( $cmd eq 'clearGroup' ) {
  200. return "usage: $cmd" if( @args != 0 );
  201. $heosCmd = 'createGroup';
  202. $string = "pid=$gid";
  203. } elsif( grep { $_ eq $cmd } ("play", "stop", "pause", "next", "prev", "channel", "channelUp", "channelDown", "playlist" ) ) {
  204. #ab hier Playerbefehle emuliert
  205. $string = "pid=$gid";
  206. if( $cmd eq 'repeat' ) {
  207. return "usage: repeat one,all,off" if( @args != 1 );
  208. $heosCmd = 'setPlayMode';
  209. $rvalue = 'on_'.$args[0];
  210. $rvalue = 'off' if($rvalue eq 'on_off');
  211. $action = "repeat=$rvalue&shuffle=".ReadingsVal($name,'shuffle','off');
  212. } elsif( $cmd eq 'shuffle' ) {
  213. return "usage: shuffle on,off" if( @args != 1 );
  214. $heosCmd = 'setPlayMode';
  215. $rvalue = 'on_'.ReadingsVal($name,'repeat','off');
  216. $rvalue = 'off' if($rvalue eq 'on_off');
  217. $action = "repeat=$rvalue&shuffle=$args[0]";
  218. } elsif( $cmd eq 'play' ) {
  219. return "usage: play" if( @args != 0 );
  220. $heosCmd = 'setPlayState';
  221. $action = "state=$cmd";
  222. } elsif( $cmd eq 'stop' ) {
  223. return "usage: stop" if( @args != 0 );
  224. $heosCmd = 'setPlayState';
  225. $action = "state=$cmd";
  226. } elsif( $cmd eq 'pause' ) {
  227. return "usage: pause" if( @args != 0 );
  228. $heosCmd = 'setPlayState';
  229. $action = "state=$cmd";
  230. } elsif( $cmd eq 'next' ) {
  231. return "usage: next" if( @args != 0 );
  232. $heosCmd = 'playNext';
  233. } elsif( $cmd eq 'prev' ) {
  234. return "usage: prev" if( @args != 0 );
  235. $heosCmd = 'playPrev';
  236. } elsif ( $cmd =~ /channel/ ) {
  237. my $favorit = ReadingsVal($name,"channel", 1);
  238. $favoritcount = scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
  239. $heosCmd = 'playPresetStation';
  240. if ( $cmd eq 'channel' ) {
  241. return "usage: $cmd 1-$favoritcount" if( @args != 1 || $args[0] !~ /(\d+)/ || $args[0] > $favoritcount || $args[0] < 1);
  242. $action = "preset=$args[0]";
  243. } elsif( $cmd eq 'channelUp' ) {
  244. return "usage: $cmd" if( @args != 0 );
  245. ++$favorit;
  246. if ( $favorit > $favoritcount ) {
  247. if ( AttrVal($name, 'channelring', 0) == 1 ) {
  248. $favorit = 1;
  249. } else {
  250. $favorit = $favoritcount;
  251. }
  252. }
  253. $action = "preset=".$favorit;
  254. } elsif( $cmd eq 'channelDown' ) {
  255. return "usage: $cmd" if( @args != 0 );
  256. --$favorit;
  257. if ( $favorit <= 0 ) {
  258. if ( AttrVal($name, 'channelring', 0) == 1 ) {
  259. $favorit = $favoritcount;
  260. } else {
  261. $favorit = 1;
  262. }
  263. }
  264. $action = "preset=".$favorit;
  265. }
  266. } elsif ( $cmd =~ /Playlist/ ) {
  267. my @cids = map { $_->{cid} } grep { $_->{name} =~ /\Q$args[0]\E/i } (@{ $hash->{IODev}{helper}{playlists} });
  268. if ( scalar @args == 1 && scalar @cids > 0 ) {
  269. if ( $cmd eq 'playPlaylist' ) {
  270. $heosCmd = $cmd;
  271. $action = "sid=1025&cid=$cids[0]&aid=4";
  272. } elsif ( $cmd eq 'deletePlaylist' ) {
  273. $heosCmd = $cmd;
  274. $action = "cid=$cids[0]";
  275. $string = "sid=1025";
  276. }
  277. } else {
  278. IOWrite($hash,'browseSource','sid=1025');
  279. my @playlists = map { $_->{name} } (@{ $hash->{IODev}{helper}{playlists}});
  280. return "usage: $cmd ".join(",",@playlists);
  281. }
  282. }
  283. } else {
  284. my $list = "getGroupInfo:noArg mute:on,off volume:slider,0,5,100 volumeUp:slider,0,1,10 volumeDown:slider,0,1,10 clearGroup:noArg repeat:one,all,off shuffle:on,off play:noArg stop:noArg pause:noArg next:noArg prev:noArg channelUp:noArg channelDown:noArg ";
  285. $list .= " channel:slider,1,1,".scalar(@{$hash->{IODev}{helper}{favorites}}) if ( defined $hash->{IODev}{helper}{favorites} );
  286. if ( defined $hash->{IODev}{helper}{playlists} ) {
  287. my @playlists = map { my %n; $n{name} = $_->{name}; $n{name} =~ s/\s+/\&nbsp;/g; $n{name} } (@{ $hash->{IODev}{helper}{playlists}});
  288. $list .= " playlist:".join(",",@playlists) if( scalar @playlists > 0 );
  289. }
  290. return "Unknown argument $cmd, choose one of $list";
  291. }
  292. $string .= "&$action" if( defined($action));
  293. IOWrite($hash,"$heosCmd","$string");
  294. Log3 $name, 4, "HEOSGroup ($name) - IOWrite: $heosCmd $string IODevHash=$hash->{IODev}";
  295. return undef;
  296. }
  297. sub HEOSGroup_Parse($$) {
  298. my ($io_hash,$json) = @_;
  299. my $name = $io_hash->{NAME};
  300. my $gid;
  301. my $decode_json;
  302. my $code;
  303. $decode_json = eval{decode_json(encode_utf8($json))};
  304. if($@){
  305. Log3 $name, 3, "HEOSGroup ($name) - JSON error while request: $@";
  306. return;
  307. }
  308. Log3 $name, 4, "HEOSGroup ($name) - ParseFn wurde aufgerufen";
  309. if( defined($decode_json->{gid}) ) {
  310. $gid = $decode_json->{gid};
  311. $code = abs($gid);
  312. $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
  313. if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
  314. IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}");
  315. readingsSingleUpdate( $hash, "state", "on", 1 );
  316. Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}";
  317. Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find GID in root from decode_json";
  318. return $hash->{NAME};
  319. } else {
  320. my $devname = "HEOSGroup".abs($gid);
  321. return "UNDEFINED $devname HEOSGroup $gid IODev=$name";
  322. }
  323. } else {
  324. my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
  325. $gid = $message{pid} if( defined($message{pid}) );
  326. $gid = $message{gid} if( defined($message{gid}) );
  327. $gid = $decode_json->{payload}{gid} if( defined($decode_json->{payload}{gid}) );
  328. Log3 $name, 4, "HEOSGroup ($name) - GID: $gid";
  329. $code = abs($gid);
  330. $code = $io_hash->{NAME} ."-". $code if( defined($io_hash->{NAME}) );
  331. if( my $hash = $modules{HEOSGroup}{defptr}{$code} ) {
  332. HEOSGroup_WriteReadings($hash,$decode_json);
  333. Log3 $hash->{NAME}, 4, "HEOSGroup ($hash->{NAME}) - find logical device: $hash->{NAME}";
  334. return $hash->{NAME};
  335. } else {
  336. my $devname = "HEOSGroup".abs($gid);
  337. return "UNDEFINED $devname HEOSGroup $gid IODev=$name";
  338. }
  339. }
  340. }
  341. sub HEOSGroup_WriteReadings($$) {
  342. my ($hash,$decode_json) = @_;
  343. my $name = $hash->{NAME};
  344. Log3 $name, 4, "HEOSGroup ($name) - processing data to write readings";
  345. ############################
  346. #### Aufbereiten der Daten soweit nötig (bei Events zum Beispiel)
  347. my $readingsHash = HEOSGroup_PreProcessingReadings($hash,$decode_json)
  348. if( $decode_json->{heos}{message} =~ /^gid=/ );
  349. ############################
  350. #### schreiben der Readings
  351. readingsBeginUpdate($hash);
  352. ### Event Readings
  353. if( ref($readingsHash) eq "HASH" ) {
  354. Log3 $name, 4, "HEOSGroup ($name) - response json Hash back from HEOSGroup_PreProcessingReadings";
  355. my $t;
  356. my $v;
  357. while( ( $t, $v ) = each (%{$readingsHash}) ) {
  358. readingsBulkUpdate( $hash, $t, $v ) if( defined( $v ) );
  359. }
  360. }
  361. #readingsBulkUpdate( $hash, 'state', 'on' );
  362. ### GroupInfos
  363. readingsBulkUpdate( $hash, 'name', $decode_json->{payload}{name} );
  364. readingsBulkUpdate( $hash, 'gid', $decode_json->{payload}{gid} );
  365. if ( ref($decode_json->{payload}{players}) eq "ARRAY" ) {
  366. my @members;
  367. foreach my $player (@{ $decode_json->{payload}{players} }) {
  368. readingsBulkUpdate( $hash, 'leader', $player->{name} ) if ( $player->{role} eq "leader" );
  369. push( @members, $player->{name}) if ( $player->{role} eq "member" );
  370. }
  371. if ( scalar @members > 1 ) {
  372. readingsBulkUpdate( $hash, 'member', join(",",@members) );
  373. } else {
  374. readingsBulkUpdate( $hash, 'member', $members[0] );
  375. }
  376. }
  377. readingsEndUpdate( $hash, 1 );
  378. Log3 $name, 5, "HEOSGroup ($name) - readings set for $name";
  379. return undef;
  380. }
  381. ###############
  382. ### my little Helpers
  383. sub HEOSGroup_PreProcessingReadings($$) {
  384. my ($hash,$decode_json) = @_;
  385. my $name = $hash->{NAME};
  386. my $reading;
  387. my %buffer;
  388. my %message = map { my ( $key, $value ) = split "="; $key => $value } split('&', $decode_json->{heos}{message});
  389. Log3 $name, 4, "HEOSGroup ($name) - preprocessing readings";
  390. if ( $decode_json->{heos}{command} =~ /volume_changed/ or $decode_json->{heos}{command} =~ /set_volume/ or $decode_json->{heos}{command} =~ /get_volume/ ) {
  391. my @value = split('&', $decode_json->{heos}{message});
  392. $buffer{'volume'} = substr($value[1],6);
  393. $buffer{'mute'} = substr($value[2],5) if( $decode_json->{heos}{command} =~ /volume_changed/ );
  394. } elsif ( $decode_json->{heos}{command} =~ /volume_up/ or $decode_json->{heos}{command} =~ /volume_down/ ) {
  395. my @value = split('&', $decode_json->{heos}{message});
  396. $buffer{'volumeUp'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_up/ );
  397. $buffer{'volumeDown'} = substr($value[1],5) if( $decode_json->{heos}{command} =~ /volume_down/ );
  398. } elsif ( $decode_json->{heos}{command} =~ /get_mute/ ) {
  399. my @value = split('&', $decode_json->{heos}{message});
  400. $buffer{'mute'} = substr($value[1],6);
  401. } else {
  402. Log3 $name, 4, "HEOSGroup ($name) - no match found";
  403. return undef;
  404. }
  405. Log3 $name, 4, "HEOSGroup ($name) - Match found for decode_json";
  406. return \%buffer;
  407. }
  408. sub HEOSGroup_GetGroupInfo($) {
  409. my $hash = shift;
  410. RemoveInternalTimer($hash,'HEOSGroup_GetGroupInfo');
  411. IOWrite($hash,'getGroupInfo',"gid=$hash->{GID}");
  412. }
  413. sub HEOSGroup_GetGroupVolume($) {
  414. my $hash = shift;
  415. RemoveInternalTimer($hash,'HEOSGroup_GetGroupVolume');
  416. IOWrite($hash,'getGroupVolume',"gid=$hash->{GID}");
  417. }
  418. sub HEOSGroup_GetGroupMute($) {
  419. my $hash = shift;
  420. RemoveInternalTimer($hash,'HEOSGroup_GetGroupMute');
  421. IOWrite($hash,'getGroupMute',"gid=$hash->{GID}");
  422. }
  423. 1;
  424. =pod
  425. =item device
  426. =item summary Modul to controls the Denon multiroom soundsystem
  427. =item summary_DE Modul zum steuern des Denon Multiroom-Soundsystem
  428. =begin html
  429. <a name="HEOSGroup"></a>
  430. <h3>HEOSGroup</h3>
  431. <ul>
  432. <u><b>HEOSGroup</b></u>
  433. <br><br>
  434. In combination with HEOSMaster and HEOSPlayer this FHEM Module controls the Denon multiroom soundsystem using a telnet socket connection and the HEOS Command Line Interface (CLI).
  435. <br><br>
  436. Once the master device is created, the players and groups of Your system are automatically recognized and created in FHEM. From now on the players and groups can be controlled and changes in the HEOS app or at the Receiver are synchronized with the state and media readings of the players and groups.
  437. <br>
  438. <br>
  439. Groups can be created from a player with "groupWithMember".
  440. <br><br>
  441. Example:
  442. <ul><br>
  443. <code>set living groupWithMember kitchen</code><br>
  444. </ul>
  445. <br>
  446. ... creates a group named "living+kitchen" with player "living" as leader and player "kitchen" as member.
  447. <a name="HEOSGroupreadings"></a>
  448. <br><br>
  449. <a name="HEOSGroupreadings"></a>
  450. <br><br>
  451. <b>Readings</b>
  452. <ul>
  453. <li>channel - nr of now playing favorite</li>
  454. <li>currentAlbum - name of now playing album</li>
  455. <li>currentArtist - name of now playing artist</li>
  456. <li>currentImageUrl - URL of cover art, station logo, etc.</li>
  457. <li>currentMedia - type of now playing media (song|station|genre|artist|album|container)</li>
  458. <li>currentMid - media ID</li>
  459. <li>currentQid - queue ID</li>
  460. <li>currentSid - source ID</li>
  461. <li>currentStation - name of now playing station</li>
  462. <li>currentTitle - name of now playing title</li>
  463. <li>error - last error</li>
  464. <li>gid - group ID</li>
  465. <li>leader - leader of the group</li>
  466. <li>member - member(s) of the group</li>
  467. <li>mute - player mute state (on|off)</li>
  468. <li>name - name of player (received from app)</li>
  469. <li>playStatus - state of player (play|pause|stop)</li>
  470. <li>repeat - player repeat state (on_all|on_one|off)</li>
  471. <li>shuffle - player shuffle state (on|off)</li>
  472. <li>state - state of player connection (on|off)</li>
  473. <li>volume - player volume level (0-100)</li>
  474. <li>volumeDown - player volume step level (1-10, default 5)</li>
  475. <li>volumeUp - player volume step level (1-10, default 5)</li>
  476. </ul>
  477. <br><br>
  478. <a name="HEOSGroupset"></a>
  479. <b>set</b>
  480. <ul>
  481. <li>channel &ltnr&gt - plays favorite &ltnr&gt created with app</li>
  482. <li>channelUp - switches to next favorite</li>
  483. <li>channelDown- switches to previous favorite</li>
  484. <li>clearGroup - dissolves the group (sets state to off)</li>
  485. <li>getGroupInfo - get media info of the group</li>
  486. <li>mute on|off - set mute state on|off</li>
  487. <li>next - play next title in queue</li>
  488. <li>pause - set state of player to "pause"</li>
  489. <li>play - set state of player to "play"</li>
  490. <li>playPlaylist &ltmyList&gt - play playlist &ltmyList&gt</li>
  491. <li>prev - play previous title in queue</li>
  492. <li>repeat - set player repeat state (on_all|on_one|off)</li>
  493. <li>shuffle - set player shuffle state on|off</li>
  494. <li>stop - set state of player to "stop"</li>
  495. <li>volume - set volume 0..100</li>
  496. <li>volumeDown - reduce volume by &ltvolumeDown&gt</li>
  497. <li>volumeUp - increase volume by &ltvolumeUp&gt</li>
  498. </ul>
  499. <br><br>
  500. <a name="HEOSGroupstate"></a>
  501. <b>state</b>
  502. <ul>
  503. <li>state of group (on|off)</li>
  504. </ul>
  505. </ul>
  506. =end html
  507. =begin html_DE
  508. <a name="HEOSGroup"></a>
  509. <h3>HEOSGroup</h3>
  510. <ul>
  511. <u><b>HEOSGroup</b></u>
  512. <br><br>
  513. In Kombination mit HEOSMaster and HEOSPlayer steuert dieses FHEM Modul das Denon Multiroom-Soundsystem mit Hilfe einer telnet Socket-Verbindung und dem HEOS Command Line Interface (CLI).
  514. <br><br>
  515. Nachdem der Master einmal angelegt ist werden die Player und Gruppierungen des Systems automatisch erkannt und in FHEM angelegt. Von da an k&oumlnnen die Player und Gruppierungen gesteuert werden und Ver&aumlnderungen in der HEOS App oder am Reveiver werden mit dem Status und den Media Readings der Player und Gruppierungen synchronisiert.
  516. <br>
  517. <br>
  518. Gruppierungen k&oumlnnen aus einem Player heraus mit "groupWithMember" erzeugt werden.
  519. <br><br>
  520. Beispiel:
  521. <ul><br>
  522. <code>set Wohnzimmer groupWithMember K&uumlche</code><br>
  523. </ul>
  524. <br>
  525. ... erzeugt eine Gruppierung namens "Wohnzimmer+K&uumlche" mit dem Player "Wohnzimmer" als Leader und dem Player "K&uumlche" als Mitglied.
  526. <a name="HEOSGroupreadings"></a>
  527. <br><br>
  528. <b>Readings</b>
  529. <ul>
  530. <li>channel - Nr des gerade abgespielten Favoriten</li>
  531. <li>currentAlbum - Name des gerade abgespielten Albums</li>
  532. <li>currentArtist - Name des gerade abgespielten K&uumlnstlers</li>
  533. <li>currentImageUrl - URL des Albumcovers, Senderlogos, etc.</li>
  534. <li>currentMedia - Medientyp des gerade abgespielten Streams (song|station|genre|artist|album|container)</li>
  535. <li>currentMid - media ID</li>
  536. <li>currentQid - queue ID</li>
  537. <li>currentSid - source ID</li>
  538. <li>currentStation - Name des gerade abgespielten Senders</li>
  539. <li>currentTitle - Name des gerade abgespielten Titels</li>
  540. <li>error - letzte Fehlermeldung</li>
  541. <li>gid - Gruppen-ID</li>
  542. <li>leader - Leader der Gruppierung</li>
  543. <li>member - Mitglied(er) der Gruppierung</li>
  544. <li>mute - Player mute Status (on|off)</li>
  545. <li>name - Name der Gruppierung</li>
  546. <li>playStatus - Status des Players (play|pause|stop)</li>
  547. <li>repeat - Player Repeat Status (on_all|on_one|off) </li>
  548. <li>shuffle - Player Shuffle Status (on|off)</li>
  549. <li>state - Status der Player-Verbindung (on|off)</li>
  550. <li>volume - aktuelle Lautst&aumlrke (0-100)</li>
  551. <li>volumeDown - Schrittweite Lautst&aumlrke (1-10, default 5)</li>
  552. <li>volumeUp - Schrittweite Lautst&aumlrke (1-10, default 5)</li>
  553. </ul>
  554. <br><br>
  555. <a name="HEOSGroupset"></a>
  556. <b>set</b>
  557. <ul>
  558. <li>channel &ltnr&gt - spielt den vorher mit der App erstellten Favoriten &ltnr&gt ab</li>
  559. <li>channelUp - schaltet auf den n&aumlchsten Favoriten in der Favoritenliste um</li>
  560. <li>channelDown- schaltet auf vorherigen Favoriten in der Favoritenliste um</li>
  561. <li>clearGroup - Aufl&oumlsen der Gruppierung (setzt state auf off)</li>
  562. <li>getGroupInfo - holt die Media-Informationen der Gruppierung</li>
  563. <li>mute on|off - setze den mute Status on|off</li>
  564. <li>next - spielt n&aumlchsten Titel in Warteschlange</li>
  565. <li>pause - setzt den Status des Players auf "pause"</li>
  566. <li>play - setzt den Status des Players auf "play"</li>
  567. <li>playPlaylist &ltmyList&gt - spielt die Playlist &ltmyList&gt ab</li>
  568. <li>prev - spielt vorherigen Titel in Warteschlange</li>
  569. <li>repeat - setzt den Player Repeat Status (on_all|on_one|off) </li>
  570. <li>shuffle - setzt den Player Shuffle Status auf on|off</li>
  571. <li>stop - setzt den Status des Players auf "stop"</li>
  572. <li>volume - setzt die Lautst&aumlrke auf 0..100</li>
  573. <li>volumeDown - verringert die Lautst&aumlrke um &ltvolumeDown&gt</li>
  574. <li>volumeUp - erh&oumlht die Lautst&aumlrke um &ltvolumeUp&gt</li>
  575. </ul>
  576. <br><br>
  577. <a name="HEOSGroupstate"></a>
  578. <b>state</b>
  579. <ul>
  580. <li>Status der Gruppierung (on|off)</li>
  581. </ul>
  582. </ul>
  583. =end html_DE
  584. =cut