98_Hyperion.pm 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836
  1. #####################################################################################
  2. # $Id: 98_Hyperion.pm 15533 2017-12-01 11:40:09Z DeeSPe $
  3. #
  4. # Usage
  5. #
  6. # define <name> Hyperion <IP or HOSTNAME> <PORT> <INTERVAL>
  7. #
  8. #####################################################################################
  9. package main;
  10. use strict;
  11. use warnings;
  12. use Color;
  13. use DevIo;
  14. use JSON;
  15. use SetExtensions;
  16. use Blocking;
  17. my %Hyperion_sets =
  18. (
  19. "addEffect" => "textField",
  20. "dim" => "slider,0,1,100",
  21. "dimDown" => "textField",
  22. "dimUp" => "textField",
  23. "clear" => "textField",
  24. "clearall" => "noArg",
  25. "mode" => "clearall,effect,off,rgb",
  26. "off" => "noArg",
  27. "on" => "noArg",
  28. "reopen" => "noArg",
  29. "rgb" => "colorpicker,RGB",
  30. "toggle" => "noArg",
  31. "toggleMode" => "noArg",
  32. "valueGainDown" => "textField",
  33. "valueGainUp" => "textField"
  34. );
  35. my $Hyperion_requiredVersion = "1.03.2";
  36. my $Hyperion_serverinfo = {"command" => "serverinfo"};
  37. my $Hyperion_webCmd = "rgb:effect:mode:dimDown:dimUp:on:off";
  38. my $Hyperion_webCmd_config = "rgb:effect:configFile:mode:dimDown:dimUp:on:off";
  39. my $Hyperion_homebridgeMapping = "On=state,subtype=TV.Licht,valueOn=/rgb.*/,cmdOff=off,cmdOn=mode+rgb ".
  40. "On=state,subtype=Umgebungslicht,valueOn=clearall,cmdOff=off,cmdOn=clearall ".
  41. "On=state,subtype=Effekt,valueOn=/effect.*/,cmdOff=off,cmdOn=mode+effect ";
  42. # "On=state,subtype=Knight.Rider,valueOn=/.*Knight_rider/,cmdOff=off,cmdOn=effect+Knight_rider " .
  43. # "On=configFile,subtype=Eingang.HDMI,valueOn=hyperion-hdmi,cmdOff=configFile+hyperion,cmdOn=configFile+hyperion-hdmi ";
  44. sub Hyperion_Initialize($)
  45. {
  46. my ($hash) = @_;
  47. $hash->{AttrFn} = "Hyperion_Attr";
  48. $hash->{DefFn} = "Hyperion_Define";
  49. $hash->{GetFn} = "Hyperion_Get";
  50. $hash->{NotifyFn} = "Hyperion_Notify";
  51. $hash->{ReadFn} = "Hyperion_Read";
  52. $hash->{SetFn} = "Hyperion_Set";
  53. $hash->{UndefFn} = "Hyperion_Undef";
  54. $hash->{AttrList} = "disable:1,0 ".
  55. "disabledForIntervals ".
  56. "hyperionBin ".
  57. "hyperionConfigDir ".
  58. "hyperionCustomEffects:textField-long ".
  59. "hyperionDefaultDuration ".
  60. "hyperionDefaultPriority ".
  61. "hyperionDimStep ".
  62. "hyperionGainStep ".
  63. "hyperionNoSudo:1 ".
  64. "hyperionSshUser ".
  65. "hyperionToggleModes ".
  66. "hyperionVersionCheck:0 ".
  67. "queryAfterSet:0 ".
  68. $readingFnAttributes;
  69. FHEM_colorpickerInit();
  70. }
  71. sub Hyperion_Define($$)
  72. {
  73. my ($hash,$def) = @_;
  74. my @args = split " ",$def;
  75. return "Usage: define <name> Hyperion <IP> <PORT> [<INTERVAL>]"
  76. if (@args < 4);
  77. my ($name,$type,$host,$port,$interval) = @args;
  78. if ($interval)
  79. {
  80. $hash->{INTERVAL} = $interval;
  81. }
  82. else
  83. {
  84. delete $hash->{INTERVAL};
  85. }
  86. $hash->{IP} = $host;
  87. $hash->{PORT} = $port;
  88. $interval = 5 if ($interval && $interval < 5);
  89. $hash->{NOTIFYDEV} = "global";
  90. $hash->{DeviceName} = "$host:$port";
  91. RemoveInternalTimer($hash);
  92. if ($init_done && !defined $hash->{OLDDEF})
  93. {
  94. addToDevAttrList($name,"lightSceneParamsToSave") if (!grep /^lightSceneParamsToSave/,split(" ",$attr{"global"}{userattr}));
  95. addToDevAttrList($name,"homebridgeMapping:textField-long") if (!grep /^homebridgeMapping/,split(" ",$attr{"global"}{userattr}));
  96. $attr{$name}{alias} = "Ambilight";
  97. $attr{$name}{cmdIcon} = "on:general_an off:general_aus dimDown:dimdown dimUp:dimup";
  98. $attr{$name}{devStateIcon} = '{Hyperion_devStateIcon($name)}';
  99. $attr{$name}{homebridgeMapping} = $Hyperion_homebridgeMapping;
  100. $attr{$name}{icon} = "light_led_stripe_rgb";
  101. $attr{$name}{lightSceneParamsToSave} = "state";
  102. $attr{$name}{room} = "Hyperion";
  103. $attr{$name}{webCmd} = $Hyperion_webCmd;
  104. $attr{$name}{widgetOverride} = "dimUp:noArg dimDown:noArg";
  105. }
  106. return Hyperion_OpenDev($hash);
  107. }
  108. sub Hyperion_Notify($$)
  109. {
  110. my ($hash,$dev) = @_;
  111. my $name = $hash->{NAME};
  112. return if (IsDisabled($name));
  113. return if (!grep /^REREADCFG|MODIFIED\s$name$/,@{$dev->{CHANGED}});
  114. return Hyperion_OpenDev($hash);
  115. }
  116. sub Hyperion_OpenDev($)
  117. {
  118. my ($hash) = @_;
  119. DevIo_CloseDev($hash);
  120. DevIo_OpenDev($hash,1,DevIo_SimpleWrite($hash,encode_json($Hyperion_serverinfo),2,1),sub($$$)
  121. {
  122. my ($h,$err) = @_;
  123. InternalTimer(gettimeofday() + 5,"Hyperion_GetUpdate",$hash);
  124. if ($err)
  125. {
  126. readingsBeginUpdate($hash);
  127. readingsBulkUpdate($hash,"lastError",$err);
  128. readingsBulkUpdate($hash,"serverResponse","ERROR");
  129. readingsBulkUpdate($hash,"state","ERROR");
  130. readingsEndUpdate($hash,1);
  131. return "ERROR: $err";
  132. }
  133. else
  134. {
  135. return $hash->{DeviceName}." connected";
  136. }
  137. });
  138. }
  139. sub Hyperion_Undef($$)
  140. {
  141. my ($hash,$name) = @_;
  142. RemoveInternalTimer($hash);
  143. BlockingKill($hash->{helper}{RUNNING_PID}) if ($hash->{helper}{RUNNING_PID});
  144. DevIo_CloseDev($hash);
  145. return;
  146. }
  147. sub Hyperion_list2array($$)
  148. {
  149. my ($list,$round) = @_;
  150. my @arr;
  151. foreach my $part (split /,/,$list)
  152. {
  153. $part = sprintf($round,$part) * 1;
  154. push @arr,$part;
  155. }
  156. return \@arr;
  157. }
  158. sub Hyperion_isLocal($)
  159. {
  160. my ($ip) = @_;
  161. return ($ip =~ /^(localhost|127\.0{1,3}\.0{1,3}\.0{0,2}1|::1)$/) ? 1 : undef;
  162. }
  163. sub Hyperion_Get($@)
  164. {
  165. my ($hash,$name,$cmd) = @_;
  166. return if (IsDisabled($name) && $cmd ne "?");
  167. my $params = "devStateIcon:noArg ".
  168. "statusRequest:noArg ".
  169. "configFiles:noArg ";
  170. return "get $name needs one parameter: $params"
  171. if (!$cmd);
  172. if ($cmd eq "configFiles")
  173. {
  174. return "Work already/still in progress... Please wait for the current process to finish." if ($hash->{helper}{RUNNING_PID} && !$hash->{helper}{RUNNING_PID}{terminated});
  175. Hyperion_GetConfigs($hash);
  176. }
  177. elsif ($cmd eq "devStateIcon")
  178. {
  179. return Hyperion_devStateIcon($hash);
  180. }
  181. elsif ($cmd eq "statusRequest")
  182. {
  183. Hyperion_GetUpdate($hash);
  184. }
  185. else
  186. {
  187. return "Unknown argument $cmd for $name, choose one of $params";
  188. }
  189. }
  190. sub Hyperion_Read($)
  191. {
  192. my ($hash) = @_;
  193. my $name = $hash->{NAME};
  194. my $buf = DevIo_SimpleRead($hash);
  195. return if (!$buf);
  196. $buf =~ s/[\r\n]//gm;
  197. my $result = $hash->{PARTIAL} ? $hash->{PARTIAL}.$buf : $buf;
  198. $hash->{PARTIAL} = $result;
  199. return if ($buf !~ /(^.+"success":(true|false)\}$)/);
  200. Log3 $name,5,"$name: url $hash->{DeviceName} returned result: $result";
  201. delete $hash->{PARTIAL};
  202. if ($result =~ /^\{"success":true\}$/)
  203. {
  204. AnalyzeCommandChain(undef,"sleep 1; get $name statusRequest")
  205. if (AttrVal($name,"queryAfterSet",1) == 1 || !$hash->{INTERVAL});
  206. return;
  207. }
  208. elsif ($result =~ /^\{"info":\{.+\},"success":true\}$/)
  209. {
  210. my $obj = eval {decode_json($result)};
  211. my $data = $obj->{info};
  212. if (AttrVal($name,"hyperionVersionCheck",1) == 1)
  213. {
  214. my $error;
  215. $error = "Can't detect your version of hyperion!"
  216. if (!$data->{hyperion_build}->[0]->{version});
  217. if (!$error)
  218. {
  219. my $ver = (split /V/,(split " ",$data->{hyperion_build}->[0]->{version})[0])[1];
  220. $ver =~ s/\.//g;
  221. $ver = $ver * 1;
  222. my $rver = $Hyperion_requiredVersion;
  223. $rver =~ s/\.//g;
  224. $rver = $rver * 1;
  225. $error = "Your version of hyperion (detected version: ".$data->{hyperion_build}->[0]->{version}.") is not (longer) supported by this module!" if ($ver<$rver);
  226. }
  227. else
  228. {
  229. $error = "ATTENTION!!! $error Please update your hyperion to V$Hyperion_requiredVersion at least using HyperCon...";
  230. Log3 $name,1,$error;
  231. readingsBeginUpdate($hash);
  232. readingsBulkUpdate($hash,"serverResponse","ERROR");
  233. readingsBulkUpdate($hash,"lastError",$error);
  234. readingsBulkUpdate($hash,"state","ERROR");
  235. readingsEndUpdate($hash,1);
  236. return;
  237. }
  238. }
  239. my $vers = $data->{hyperion_build}->[0]->{version} ? $data->{hyperion_build}->[0]->{version} : "";
  240. my $prio = (defined $data->{priorities}->[0]->{priority}) ? $data->{priorities}->[0]->{priority} : "";
  241. my $duration = (defined $data->{priorities}->[0]->{duration_ms} && $data->{priorities}->[0]->{duration_ms} > 999) ? int($data->{priorities}->[0]->{duration_ms} / 1000) : 0;
  242. $duration = $duration >= 1 ? $duration : "infinite";
  243. my $adj = $data->{adjustment}->[0] ? $data->{adjustment}->[0] : undef;
  244. my $col = $data->{activeLedColor}->[0]->{"HEX Value"}->[0] ? $data->{activeLedColor}->[0]->{"HEX Value"}->[0] : "";
  245. $col = "" if ($col =~ /000000$/);
  246. my $configs = ReadingsVal($name,".configs",undef);
  247. my $corr = $data->{correction}->[0] ? $data->{correction}->[0] : undef;
  248. my $effects = $data->{effects} ? $data->{effects} : undef;
  249. if ($hash->{helper}{customeffects})
  250. {
  251. foreach my $eff (@{$hash->{helper}{customeffects}})
  252. {
  253. push @{$effects},$eff;
  254. }
  255. }
  256. my $effectList = $effects ? join(",",map {"$_->{name}"} @{$effects}) : "";
  257. $effectList =~ s/ /_/g;
  258. my $effargs = $data->{activeEffects}->[0]->{args} ? JSON->new->convert_blessed->canonical->encode($data->{activeEffects}->[0]->{args}) : undef;
  259. my $script = $data->{activeEffects}->[0]->{script} ? $data->{activeEffects}->[0]->{script} : undef;
  260. my $temp = $data->{temperature}->[0] ? $data->{temperature}->[0] : undef;
  261. my $trans = $data->{transform}->[0] ? $data->{transform}->[0] : undef;
  262. my $id = $trans->{id} ? $trans->{id} : undef;
  263. my $adjR = $adj ? join(",",@{$adj->{redAdjust}}) : undef;
  264. my $adjG = $adj ? join(",",@{$adj->{greenAdjust}}) : undef;
  265. my $adjB = $adj ? join(",",@{$adj->{blueAdjust}}) : undef;
  266. my $corS = $corr ? join(",",@{$corr->{correctionValues}}) : undef;
  267. my $temP = $temp ? join(",",@{$temp->{correctionValues}}) : undef;
  268. my $blkL = $trans->{blacklevel} ? sprintf("%.2f",$trans->{blacklevel}->[0]).",".sprintf("%.2f",$trans->{blacklevel}->[1]).",".sprintf("%.2f",$trans->{blacklevel}->[2]) : undef;
  269. my $gamM = $trans->{gamma} ? sprintf("%.2f",$trans->{gamma}->[0]).",".sprintf("%.2f",$trans->{gamma}->[1]).",".sprintf("%.2f",$trans->{gamma}->[2]) : undef;
  270. my $thrE = $trans->{threshold} ? sprintf("%.2f",$trans->{threshold}->[0]).",".sprintf("%.2f",$trans->{threshold}->[1]).",".sprintf("%.2f",$trans->{threshold}->[2]) : undef;
  271. my $whiL = $trans->{whitelevel} ? sprintf("%.2f",$trans->{whitelevel}->[0]).",".sprintf("%.2f",$trans->{whitelevel}->[1]).",".sprintf("%.2f",$trans->{whitelevel}->[2]) : undef;
  272. my $lumG = defined $trans->{luminanceGain} ? sprintf("%.2f",$trans->{luminanceGain}) : undef;
  273. my $lumM = defined $trans->{luminanceMinimum} ? sprintf("%.2f",$trans->{luminanceMinimum}) : undef;
  274. my $satG = defined $trans->{saturationGain} ? sprintf("%.2f",$trans->{saturationGain}) : undef;
  275. my $satL = defined $trans->{saturationLGain} ? sprintf("%.2f",$trans->{saturationLGain}) : undef;
  276. my $valG = defined $trans->{valueGain} ? sprintf("%.2f",$trans->{valueGain}) : undef;
  277. $hash->{hostname} = $data->{hostname} if (($data->{hostname} && !$hash->{hostname}) || ($data->{hostname} && $hash->{hostname} ne $data->{hostname}));
  278. $hash->{build_version} = $vers if (($vers && !$hash->{build_version}) || ($vers && $hash->{build_version} ne $vers));
  279. $hash->{build_time} = $data->{hyperion_build}->[0]->{time} if (($data->{hyperion_build}->[0]->{time} && !$hash->{build_time}) || ($data->{hyperion_build}->[0]->{time} && $hash->{build_time} ne $data->{hyperion_build}->[0]->{time}));
  280. readingsBeginUpdate($hash);
  281. readingsBulkUpdate($hash,"adjustRed",$adjR);
  282. readingsBulkUpdate($hash,"adjustGreen",$adjG);
  283. readingsBulkUpdate($hash,"adjustBlue",$adjB);
  284. readingsBulkUpdate($hash,"blacklevel",$blkL);
  285. readingsBulkUpdate($hash,"colorTemperature",$temP);
  286. readingsBulkUpdate($hash,"correction",$corS);
  287. readingsBulkUpdate($hash,"effect",(split /,/,$effectList)[0]) if (!defined ReadingsVal($name,"effect",undef));
  288. readingsBulkUpdate($hash,".effects",$effectList);
  289. readingsBulkUpdate($hash,"effectArgs",$effargs);
  290. readingsBulkUpdate($hash,"duration",$duration);
  291. readingsBulkUpdate($hash,"gamma",$gamM);
  292. readingsBulkUpdate($hash,"id",$id);
  293. readingsBulkUpdate($hash,"luminanceGain",$lumG);
  294. readingsBulkUpdate($hash,"luminanceMinimum",$lumM);
  295. readingsBulkUpdate($hash,"priority",$prio);
  296. readingsBulkUpdate($hash,"rgb","ff0d0d") if (!defined ReadingsVal($name,"rgb",undef));
  297. readingsBulkUpdate($hash,"saturationGain",$satG);
  298. readingsBulkUpdate($hash,"saturationLGain",$satL);
  299. readingsBulkUpdate($hash,"threshold",$thrE);
  300. readingsBulkUpdate($hash,"valueGain",$valG);
  301. readingsBulkUpdate($hash,"whitelevel",$whiL);
  302. if ($script)
  303. {
  304. my $effname;
  305. my $tempname;
  306. foreach my $e (@$effects)
  307. {
  308. if ($e->{script} && $e->{script} eq $script)
  309. {
  310. $tempname = $e->{name};
  311. $effname = $e->{name} if (JSON->new->convert_blessed->canonical->encode($e->{args}) eq $effargs);
  312. }
  313. }
  314. if (!$effname)
  315. {
  316. foreach my $e (@{$hash->{helper}{customeffects}})
  317. {
  318. $effname = $e->{name} if (JSON->new->convert_blessed->canonical->encode($e->{args}) eq $effargs);
  319. }
  320. }
  321. $effname = $effname ? $effname : $tempname;
  322. $effname =~ s/ /_/g;
  323. readingsBulkUpdate($hash,"effect",$effname);
  324. readingsBulkUpdate($hash,"mode","effect");
  325. readingsBulkUpdate($hash,"state","effect $effname");
  326. readingsBulkUpdate($hash,"mode_before_off","effect");
  327. Log3 $name,4,"$name: effect $effname";
  328. }
  329. elsif ($col)
  330. {
  331. my $rgb = lc((split /x/,$col)[1]);
  332. my ($r,$g,$b) = Color::hex2rgb($rgb);
  333. my ($h,$s,$v) = Color::rgb2hsv($r / 255,$g / 255,$b / 255);
  334. my $dim = int($v * 100);
  335. readingsBulkUpdate($hash,"rgb",$rgb);
  336. readingsBulkUpdate($hash,"dim",$dim);
  337. readingsBulkUpdate($hash,"mode","rgb");
  338. readingsBulkUpdate($hash,"mode_before_off","rgb");
  339. readingsBulkUpdate($hash,"state","rgb $rgb");
  340. Log3 $name,4,"$name: rgb $rgb";
  341. }
  342. else
  343. {
  344. if ($prio && defined $data->{priorities}->[0]->{duration_ms} && !defined $data->{priorities}->[1]->{priority})
  345. {
  346. readingsBulkUpdate($hash,"mode","clearall");
  347. readingsBulkUpdate($hash,"mode_before_off","clearall");
  348. readingsBulkUpdate($hash,"state","clearall");
  349. Log3 $name,4,"$name: clearall";
  350. }
  351. else
  352. {
  353. readingsBulkUpdate($hash,"mode","off");
  354. readingsBulkUpdate($hash,"state","off");
  355. Log3 $name,4,"$name: off";
  356. }
  357. }
  358. readingsBulkUpdate($hash,"serverResponse","success");
  359. readingsEndUpdate($hash,1);
  360. }
  361. else
  362. {
  363. Log3 $name,4,"$name: error while requesting ".$hash->{DeviceName}." - $result";
  364. readingsBeginUpdate($hash);
  365. readingsBulkUpdate($hash,"lastError","error while requesting ".$hash->{DeviceName});
  366. readingsBulkUpdate($hash,"serverResponse","ERROR");
  367. readingsBulkUpdate($hash,"state","ERROR");
  368. readingsEndUpdate($hash,1);
  369. }
  370. return;
  371. }
  372. sub Hyperion_GetConfigs($)
  373. {
  374. my ($hash) = @_;
  375. my $name = $hash->{NAME};
  376. my $ip = $hash->{IP};
  377. my $dir = AttrVal($name,"hyperionConfigDir","/etc/hyperion/");
  378. my $com = "ls $dir";
  379. if (!Hyperion_isLocal($ip))
  380. {
  381. my $ssh = qx(which ssh);
  382. chomp $ssh;
  383. return "SSH client could NOT be found!" if (!$ssh);
  384. my $user = AttrVal($name,"hyperionSshUser","pi");
  385. $com = "$ssh $user\@$ip '$com'";
  386. }
  387. Log3 $name,4,"$name: lsCmd: $com";
  388. $com = encode_base64($com);
  389. $hash->{helper}{RUNNING_PID} = BlockingCall("Hyperion_ExecCmd","$name|$com","Hyperion_GetConfigs_finished",20,"Hyperion_ExecCmd_aborted",$hash);
  390. return "Working in background...";
  391. }
  392. sub Hyperion_GetConfigs_finished($)
  393. {
  394. my ($string) = @_;
  395. my @a = split /\|/,$string;
  396. my $name = $a[0];
  397. my @files;
  398. @files = split " ",$a[1] if ($a[1]);
  399. my $hash = $defs{$name};
  400. my $ip = $hash->{IP};
  401. my $dir = AttrVal($name,"hyperionConfigDir","/etc/hyperion/");
  402. delete $hash->{helper}{RUNNING_PID};
  403. my @filelist;
  404. foreach (@files)
  405. {
  406. my $file = $_;
  407. next if ($file !~ /^([\-\.\w]+)\.config\.json$/);
  408. $file = $1;
  409. push @filelist,$file;
  410. Log3 $name,4,"$name: matching config file: \"$_\"";
  411. }
  412. if (@filelist)
  413. {
  414. my $configs = join(",",@filelist);
  415. readingsSingleUpdate($hash,".configs",$configs,0);
  416. CommandAttr(undef,"$name webCmd $Hyperion_webCmd_config") if (AttrVal($name,"webCmd","") eq $Hyperion_webCmd && @filelist > 1);
  417. CommandAttr(undef,"$name webCmd $Hyperion_webCmd") if (AttrVal($name,"webCmd","") eq $Hyperion_webCmd_config && @filelist < 2);
  418. }
  419. else
  420. {
  421. CommandDeleteReading(undef,"$name .configs") if (ReadingsVal($name,".configs",""));
  422. CommandAttr(undef,"$name webCmd $Hyperion_webCmd") if (AttrVal($name,"webCmd","") eq $Hyperion_webCmd_config);
  423. Log3 $name,3,"$name: No files found on server \"$ip\" in directory \"$dir\". Maybe the wrong directory? If SSH is used, has the user \"".AttrVal($name,"hyperionSshUser","pi")."\" been configured to log in without entering a password (http://www.linuxproblem.org/art_9.html)?";
  424. }
  425. Hyperion_GetUpdate($hash);
  426. return;
  427. }
  428. sub Hyperion_GetUpdate(@)
  429. {
  430. my ($hash) = @_;
  431. my $name = $hash->{NAME};
  432. RemoveInternalTimer($hash);
  433. return if (IsDisabled($name));
  434. InternalTimer(gettimeofday() + $hash->{INTERVAL},"Hyperion_GetUpdate",$hash) if ($hash->{INTERVAL});
  435. if (!$hash->{FD})
  436. {
  437. Hyperion_OpenDev($hash);
  438. return;
  439. }
  440. Hyperion_Call($hash);
  441. return;
  442. }
  443. sub Hyperion_ExecCmd($)
  444. {
  445. my ($string) = @_;
  446. my @a = split /\|/,$string;
  447. my $name = $a[0];
  448. my $cmd = decode_base64($a[1]);
  449. my $hash = $defs{$name};
  450. my @qx = qx($cmd);
  451. my @ret;
  452. my $re = "";
  453. foreach (@qx)
  454. {
  455. chomp $_;
  456. $_ =~ s/[\s\t\| ;]{1,}/ /g;
  457. $_ =~ s/(^ {1,}| {1,}$)//g;
  458. push @ret,$_ if ($_);
  459. }
  460. $re .= join " ",@ret if (@ret);
  461. return "$name|$re";
  462. }
  463. sub Hyperion_Kill_finished($)
  464. {
  465. my ($string) = @_;
  466. my @a = split /\|/,$string;
  467. my $name = $a[0];
  468. my $error = $a[1];
  469. my $hash = $defs{$name};
  470. delete $hash->{helper}{RUNNING_PID};
  471. if ($error)
  472. {
  473. if ($error =~ /^Usage:/)
  474. {
  475. Log3 $name,3,"$name: Hyperion couldn't be stopped because no running pid was found!";
  476. }
  477. else
  478. {
  479. Log3 $name,3,"$name: Not able to stop Hyperion! Error: $error";
  480. readingsSingleUpdate($hash,"lastError",$error,1);
  481. }
  482. }
  483. else
  484. {
  485. Log3 $name,3,"$name: Hyperion has been stopped";
  486. RemoveInternalTimer($hash);
  487. DevIo_Disconnected($hash);
  488. }
  489. return undef;
  490. }
  491. sub Hyperion_ExecCmd_aborted($)
  492. {
  493. my ($hash) = @_;
  494. my $name = $hash->{NAME};
  495. delete $hash->{helper}{RUNNING_PID};
  496. delete $hash->{helper}{configFile} if ($hash->{helper}{configFile});
  497. delete $hash->{helper}{startCmd} if ($hash->{helper}{startCmd});
  498. my $er = "Hyperion_ExecCmd aborted due to timeout of 20 sec.";
  499. Log3 $name,2,"$name: $er";
  500. readingsSingleUpdate($hash,"lastError",$er,1);
  501. return undef;
  502. }
  503. sub Hyperion_Restart($)
  504. {
  505. my ($string) = @_;
  506. my @a = split /\|/,$string;
  507. my $name = $a[0];
  508. my $error = $a[1];
  509. my $hash = $defs{$name};
  510. delete $hash->{helper}{RUNNING_PID};
  511. if ($error && $error !~ /^Usage:/)
  512. {
  513. Log3 $name,3,"$name: Not able to stop Hyperion! Error: $error";
  514. readingsSingleUpdate($hash,"lastError",$error,1);
  515. }
  516. else
  517. {
  518. my $cmd = $hash->{helper}{startCmd};
  519. $hash->{helper}{RUNNING_PID} = BlockingCall("Hyperion_ExecCmd","$name|$cmd","Hyperion_Restart_finished",20,"Hyperion_ExecCmd_aborted",$hash);
  520. }
  521. return undef;
  522. }
  523. sub Hyperion_Restart_finished($)
  524. {
  525. my ($string) = @_;
  526. my @a = split /\|/,$string;
  527. my $name = $a[0];
  528. my $error = $a[1];
  529. my $hash = $defs{$name};
  530. delete $hash->{helper}{RUNNING_PID};
  531. my $file = $hash->{helper}{configFile};
  532. delete $hash->{helper}{configFile};
  533. delete $hash->{helper}{startCmd};
  534. if ($error)
  535. {
  536. Log3 $name,3,"$name: Hyperion could not be restarted! Error: $error";
  537. readingsSingleUpdate($hash,"lastError",$error,1);
  538. }
  539. else
  540. {
  541. Log3 $name,3,"$name: Hyperion restarted with configFile $file";
  542. RemoveInternalTimer($hash);
  543. DevIo_Disconnected($hash);
  544. $file =~ s/\.config\.json$//;
  545. readingsSingleUpdate($hash,"configFile",$file,1);
  546. InternalTimer(gettimeofday() + 3,"Hyperion_OpenDev",$hash);
  547. }
  548. return undef;
  549. }
  550. sub Hyperion_Set($@)
  551. {
  552. my ($hash,$name,@aa) = @_;
  553. my ($cmd,@args) = @aa;
  554. return if (IsDisabled($name) && $cmd ne "?");
  555. my $value = (defined($args[0])) ? $args[0] : undef;
  556. return "\"set $name\" needs at least one argument and maximum five arguments" if (@aa < 1 || @aa > 5);
  557. my $duration = defined $args[1] ? int $args[1] : AttrNum($name,"hyperionDefaultDuration",0);
  558. my $priority = defined $args[2] ? int $args[2] : AttrNum($name,"hyperionDefaultPriority",0);
  559. my %Hyperion_sets_local = %Hyperion_sets;
  560. if (ReadingsVal($name,".configs",""))
  561. {
  562. $Hyperion_sets_local{configFile} = ReadingsVal($name,".configs","");
  563. $Hyperion_sets_local{binary} = "restart,stop";
  564. }
  565. $Hyperion_sets_local{adjustRed} = "textField" if (ReadingsVal($name,"adjustRed",""));
  566. $Hyperion_sets_local{adjustGreen} = "textField" if (ReadingsVal($name,"adjustGreen",""));
  567. $Hyperion_sets_local{adjustBlue} = "textField" if (ReadingsVal($name,"adjustBlue",""));
  568. $Hyperion_sets_local{correction} = "textField" if (ReadingsVal($name,"correction",""));
  569. $Hyperion_sets_local{effect} = ReadingsVal($name,".effects","") if (ReadingsVal($name,".effects",""));
  570. $Hyperion_sets_local{colorTemperature} = "textField" if (ReadingsVal($name,"colorTemperature",""));
  571. $Hyperion_sets_local{blacklevel} = "textField" if (ReadingsVal($name,"blacklevel",""));
  572. $Hyperion_sets_local{gamma} = "textField" if (ReadingsVal($name,"gamma",""));
  573. $Hyperion_sets_local{threshold} = "textField" if (ReadingsVal($name,"threshold",""));
  574. $Hyperion_sets_local{whitelevel} = "textField" if (ReadingsVal($name,"whitelevel",""));
  575. $Hyperion_sets_local{luminanceGain} = "slider,0,0.01,5,1" if (ReadingsVal($name,"luminanceGain",""));
  576. $Hyperion_sets_local{luminanceMinimum} = "slider,0,0.01,5,1" if (ReadingsVal($name,"luminanceMinimum",""));
  577. $Hyperion_sets_local{saturationGain} = "slider,0,0.01,5,1" if (ReadingsVal($name,"saturationGain",""));
  578. $Hyperion_sets_local{saturationLGain} = "slider,0,0.01,5,1" if (ReadingsVal($name,"saturationLGain",""));
  579. $Hyperion_sets_local{valueGain} = "slider,0,0.01,5,1" if (ReadingsVal($name,"valueGain",""));
  580. my $params = join(" ",map {"$_:$Hyperion_sets_local{$_}"} keys %Hyperion_sets_local);
  581. my %obj;
  582. Log3 $name,4,"$name: Hyperion_Set cmd: $cmd";
  583. Log3 $name,4,"$name: Hyperion_Set value: $value" if ($value);
  584. Log3 $name,4,"$name: Hyperion_Set duration: $duration, priority: $priority" if ($cmd =~ /^rgb|dim|dimUp|dimDown|effect$/);
  585. if ($cmd =~ /^configFile|binary$/)
  586. {
  587. return "Work already/still in progress... Please wait for the current process to finish." if ($hash->{helper}{RUNNING_PID} && !$hash->{helper}{RUNNING_PID}{terminated});
  588. my $binpath = AttrVal($name,"hyperionBin","/usr/bin/hyperiond");
  589. my $bin = (split "/",$binpath)[scalar(split "/",$binpath) - 1];
  590. $bin =~ s/\.sh$// if ($bin =~ /\.sh$/);
  591. my $confdir = AttrVal($name,"hyperionConfigDir","/etc/hyperion/");
  592. my $user = AttrVal($name,"hyperionSshUser","pi");
  593. my $ip = $hash->{IP};
  594. my $sudo = ($user eq "root" || int AttrVal($name,"hyperionNoSudo",0) == 1) ? "" : "sudo ";
  595. my $kill = $sudo."kill `pidof $bin` 2>&1 1>/dev/null";
  596. my $ssh;
  597. if (!Hyperion_isLocal($ip))
  598. {
  599. $ssh = qx(which ssh);
  600. chomp $ssh;
  601. return "SSH client could NOT be found!" if (!$ssh);
  602. }
  603. my $com = Hyperion_isLocal($ip)?"":"$ssh $user\@$ip '";
  604. if ($cmd eq "binary")
  605. {
  606. return "Value of $cmd has to be 'restart' or 'stop'" if ($value !~ /^(stop|restart)$/);
  607. }
  608. else
  609. {
  610. return "Value of $cmd must be given and must be an available config file!" if (!$value || !grep(/^$value$/,split /,/,ReadingsVal($name,".configs","")));
  611. }
  612. if ($cmd eq "binary" && $value eq "stop")
  613. {
  614. $com .= $kill;
  615. $com .= Hyperion_isLocal($ip)?"":"'";
  616. Log3 $name,4,"$name: stopCmd: $com";
  617. $com = encode_base64($com);
  618. $hash->{helper}{RUNNING_PID} = BlockingCall("Hyperion_ExecCmd","$name|$com","Hyperion_Kill_finished",20,"Hyperion_ExecCmd_aborted",$hash);
  619. }
  620. elsif (($cmd eq "binary" && $value eq "restart") || $cmd eq "configFile")
  621. {
  622. my $file;
  623. if ($value eq "restart")
  624. {
  625. $file = ReadingsVal($name,"configFile","")?ReadingsVal($name,"configFile",""):ReadingsVal($name,".configs","")?(split /,/,ReadingsVal($name,".configs",""))[0]:"";
  626. return "No restart possible because no configFile is available." if (!$file);
  627. }
  628. else
  629. {
  630. $file = $value;
  631. }
  632. my $start = $com;
  633. $file .= ".config.json";
  634. $com .= $kill;
  635. $start .= "$sudo$binpath $confdir".$file." > /dev/null 2>&1 &";
  636. if (!Hyperion_isLocal($ip))
  637. {
  638. $com .= "'";
  639. $start .= "'";
  640. }
  641. Log3 $name,4,"$name: stopCmd: $com";
  642. Log3 $name,4,"$name: startCmd: $start";
  643. $com = encode_base64($com);
  644. $hash->{helper}{configFile} = $file;
  645. $hash->{helper}{startCmd} = encode_base64($start);
  646. $hash->{helper}{RUNNING_PID} = BlockingCall("Hyperion_ExecCmd","$name|$com","Hyperion_Restart",20,"Hyperion_ExecCmd_aborted",$hash);
  647. }
  648. return;
  649. }
  650. elsif ($cmd eq "rgb")
  651. {
  652. return "Value of $cmd has to be in RGB hex format like ffffff or 3F7D90"
  653. if ($value !~ /^[\dA-Fa-f]{6}$/);
  654. $value = lc $value;
  655. my ($r,$g,$b) = Color::hex2rgb($value);
  656. $obj{color} = [$r,$g,$b];
  657. $obj{command} = "color";
  658. $obj{priority} = $priority * 1;
  659. $obj{duration} = $duration * 1000 if ($duration > 0);
  660. }
  661. elsif ($cmd eq "dim")
  662. {
  663. return "Value of $cmd has to be between 1 and 100"
  664. if ($value !~ /^(\d+)$/ || $1 > 100 || $1 < 1);
  665. my $rgb = ReadingsVal($name,"rgb","ffffff");
  666. $value = $value + 1
  667. if ($cmd eq "dim" && $value < 100);
  668. $value = $value / 100;
  669. my ($r,$g,$b) = Color::hex2rgb($rgb);
  670. my ($h,$s,$v) = Color::rgb2hsv($r / 255,$g / 255,$b / 255);
  671. my ($rn,$gn,$bn);
  672. ($rn,$gn,$bn) = Color::hsv2rgb($h,$s,$value)
  673. if ($cmd eq "dim");
  674. $rn = int($rn * 255);
  675. $gn = int($gn * 255);
  676. $bn = int($bn * 255);
  677. $obj{color} = [$rn,$gn,$bn];
  678. $obj{command} = "color";
  679. $obj{priority} = $priority * 1;
  680. $obj{duration} = $duration * 1000
  681. if ($duration > 0);
  682. }
  683. elsif ($cmd =~ /^(dimUp|dimDown)$/)
  684. {
  685. return "Value of $cmd has to be between 1 and 99"
  686. if (defined $value && ($value !~ /^(\d+)$/ || $1 > 99 || $1 < 1));
  687. my $dim = ReadingsVal($name,"dim",100);
  688. my $dimStep = $value ? $value : AttrVal($name,"hyperionDimStep",10);
  689. my $dimUp = ($dim + $dimStep < 100) ? $dim + $dimStep : 100;
  690. my $dimDown = ($dim - $dimStep > 0) ? $dim - $dimStep : 1;
  691. my $set = $cmd eq "dimUp" ? $dimUp : $dimDown;
  692. CommandSet(undef,"$name dim $set");
  693. return;
  694. }
  695. elsif ($cmd eq "effect")
  696. {
  697. return "Effect $value is not available in the effect list of $name!"
  698. if ($value !~ /^([\w-]+)$/ || index(ReadingsVal($name,".effects",""),$value) == -1);
  699. my $arg = $args[3] ? eval{decode_json $args[3]} : "";
  700. my $ce = $hash->{helper}{customeffects};
  701. if (!$arg && $ce)
  702. {
  703. foreach my $eff (@{$ce})
  704. {
  705. if ($eff->{name} eq $value)
  706. {
  707. $value = $eff->{oname};
  708. $arg = $eff->{args};
  709. }
  710. }
  711. }
  712. $value =~ s/_/ /g;
  713. my %ef = ("name" => $value);
  714. $ef{args} = $arg if ($arg);
  715. $obj{effect} = \%ef;
  716. $obj{command} = "effect";
  717. $obj{priority} = $priority * 1;
  718. $obj{duration} = $duration * 1000 if ($duration > 0);
  719. }
  720. elsif ($cmd eq "clearall")
  721. {
  722. return "$cmd need no additional value of $value" if (defined $value);
  723. $obj{command} = $cmd;
  724. }
  725. elsif ($cmd eq "clear")
  726. {
  727. return "Value of $cmd has to be between 0 and 65536 in steps of 1"
  728. if (defined $value && $value !~ /^(\d+)$/ || $1 > 65536);
  729. $obj{command} = $cmd;
  730. $value = defined $1 ? $1 : AttrVal($name,"hyperionDefaultPriority",0);
  731. $obj{priority} = $value*1;
  732. }
  733. elsif ($cmd eq "off")
  734. {
  735. return "$cmd need no additional value of $value" if (defined $value);
  736. $obj{command} = "color";
  737. $obj{color} = [0,0,0];
  738. $obj{priority} = AttrVal($name,"hyperionDefaultPriority",0)*1;
  739. }
  740. elsif ($cmd eq "on")
  741. {
  742. return "$cmd need no additional value of $value" if (defined $value);
  743. my $rmode = ReadingsVal($name,"mode_before_off","rgb");
  744. my $rrgb = ReadingsVal($name,"rgb","");
  745. my $reffect = ReadingsVal($name,"effect","");
  746. my ($r,$g,$b) = Color::hex2rgb($rrgb);
  747. my $set = "$rmode $rrgb";
  748. $set = "$rmode $reffect" if ($rmode eq "effect");
  749. $set = $rmode if ($rmode eq "clearall");
  750. CommandSet(undef,"$name $set");
  751. return;
  752. }
  753. elsif ($cmd eq "toggle")
  754. {
  755. return "$cmd need no additional value of $value" if (defined $value);
  756. my $state = Value($name);
  757. my $nstate = $state ne "off" ? "off" : "on";
  758. CommandSet(undef,"$name $nstate");
  759. return;
  760. }
  761. elsif ($cmd eq "toggleMode")
  762. {
  763. return "$cmd need no additional value of $value" if (defined $value);
  764. my $mode = ReadingsVal($name,"mode","off");
  765. my $nmode;
  766. my @modeorder = split /,/,AttrVal($name,"hyperionToggleModes","clearall,rgb,effect,off");
  767. for (my $i = 0; $i < @modeorder; $i++)
  768. {
  769. $nmode = $i < @modeorder - 1 ? $modeorder[$i+1] : $modeorder[0] if ($modeorder[$i] eq $mode);
  770. }
  771. $nmode = $nmode ? $nmode : $modeorder[0];
  772. CommandSet(undef,"$name mode $nmode");
  773. return;
  774. }
  775. elsif ($cmd eq "mode")
  776. {
  777. return "The value of mode has to be rgb,effect,clearall,off" if ($value !~ /^(off|clearall|rgb|effect)$/);
  778. Log3 $name,4,"$name: cmd: $cmd, value: $value";
  779. my $rmode = $value;
  780. my $rrgb = ReadingsVal($name,"rgb","");
  781. my $reffect = ReadingsVal($name,"effect","");
  782. my ($r,$g,$b) = Color::hex2rgb($rrgb);
  783. my $set = "$rmode $rrgb";
  784. $set = "$rmode $reffect" if ($rmode eq "effect");
  785. $set = $rmode if ($rmode eq "clearall");
  786. $set = $rmode if ($rmode eq "off");
  787. CommandSet(undef,"$name $set");
  788. return;
  789. }
  790. elsif ($cmd =~ /^(luminanceGain|luminanceMinimum|saturationGain|saturationLGain|valueGain)$/)
  791. {
  792. return "The value of $cmd has to be from 0.00 to 5.00 in steps of 0.01."
  793. if ($value !~ /^((\d)\.(\d){1,2})?$/ || $1 > 5);
  794. $value = sprintf("%.4f",$value) * 1;
  795. my %tr = ($cmd => $value);
  796. $obj{command} = "transform";
  797. $obj{transform} = \%tr;
  798. }
  799. elsif ($cmd =~ /^(blacklevel|gamma|threshold|whitelevel)$/)
  800. {
  801. return "Each of the three comma separated values of $cmd must be from 0.00 to 1.00 in steps of 0.01"
  802. if ($cmd =~ /^blacklevel|threshold|whitelevel$/ && ($value !~ /^((\d)\.(\d){1,2}),((\d)\.(\d){1,2}),((\d)\.(\d){1,2})$/ || $1 > 1 || $4 > 1 || $7 > 1));
  803. return "Each of the three comma separated values of $cmd must be from 0.00 to 5.00 in steps of 0.01"
  804. if ($cmd eq "gamma" && ($value !~ /^((\d)\.(\d){1,2}),((\d)\.(\d){1,2}),((\d)\.(\d){1,2})$/ || $1 > 5 || $4 > 5 || $7 > 5));
  805. my $arr = Hyperion_list2array($value,"%.4f");
  806. my %ar = ($cmd => $arr);
  807. $obj{command} = "transform";
  808. $obj{transform} = \%ar;
  809. }
  810. elsif ($cmd =~ /^(correction|colorTemperature)$/)
  811. {
  812. $cmd = "temperature" if ($cmd eq "colorTemperature");
  813. return "Each of the three comma separated values of $cmd must be from 0 to 255 in steps of 1"
  814. if ($value !~ /^(\d{1,3})?,(\d{1,3})?,(\d{1,3})?$/ || $1 > 255 || $2 > 255 || $3 > 255);
  815. my $arr = Hyperion_list2array($value,"%d");
  816. my %ar = ("correctionValues" => $arr);
  817. $obj{command} = $cmd;
  818. $obj{$cmd} = \%ar;
  819. }
  820. elsif ($cmd =~ /^(adjustRed|adjustGreen|adjustBlue)$/)
  821. {
  822. return "Each of the three comma separated values of $cmd must be from 0 an 255 in steps of 1"
  823. if ($value !~ /^(\d{1,3})?,(\d{1,3})?,(\d{1,3})?$/ || $1 > 255 || $2 > 255 || $3 > 255);
  824. $cmd = "redAdjust" if ($cmd eq "adjustRed");
  825. $cmd = "greenAdjust" if ($cmd eq "adjustGreen");
  826. $cmd = "blueAdjust" if ($cmd eq "adjustBlue");
  827. my $arr = Hyperion_list2array($value,"%d");
  828. my %ar = ($cmd => $arr);
  829. $obj{command} = "adjustment";
  830. $obj{adjustment} = \%ar;
  831. }
  832. elsif ($cmd =~ /^(valueGainUp|valueGainDown)$/)
  833. {
  834. return "Value of $cmd has to be between 0.1 and 1.0 in steps of 0.1"
  835. if (defined $value && ($value !~ /^(\d\.\d)$/ || $1 > 1 || $1 < 0.1));
  836. my $gain = ReadingsNum($name,"valueGain",1);
  837. my $gainStep = $value ? $value : AttrVal($name,"hyperionGainStep",0.1);
  838. my $gainUp = ($gain + $gainStep < 5) ? $gain + $gainStep : 5;
  839. my $gainDown = ($gain - $gainStep > 0) ? $gain - $gainStep : 0.1;
  840. my $set = $cmd eq "valueGainUp" ? $gainUp : $gainDown;
  841. CommandSet(undef,"$name valueGain $set");
  842. return;
  843. }
  844. elsif ($cmd eq "addEffect")
  845. {
  846. return "$name must be in effect mode!" if (ReadingsVal($name,"mode","off") ne "effect");
  847. return "Value of $cmd has to be a name like My_custom_EffeKt1 or my-effect!" if (!defined $value || $value !~ /^[a-zA-Z0-9_-]+$/);
  848. return "Effect with name $value already defined! Please choose a different name!" if (grep(/^$value$/,split /,/,ReadingsVal($name,".effects","")));
  849. my $eff = ReadingsVal($name,"effect","");
  850. foreach my $e (@{$hash->{helper}{customeffects}})
  851. {
  852. return "The base effect can't be a custom effect! Please set a non-custom effect first!" if ($e->{name} eq $eff);
  853. }
  854. my $effs = AttrVal($name,"hyperionCustomEffects","");
  855. $effs .= " " if ($effs);
  856. $effs .= '{"name":"'.$value.'","oname":"'.$eff.'","args":'.ReadingsVal($name,"effectArgs","").'}';
  857. CommandAttr(undef,"$name hyperionCustomEffects $effs");
  858. return;
  859. }
  860. elsif ($cmd eq "reopen")
  861. {
  862. Hyperion_OpenDev($hash);
  863. return;
  864. }
  865. if (keys %obj)
  866. {
  867. Log3 $name,5,"$name: $cmd obj json: ".encode_json(\%obj);
  868. SetExtensionsCancel($hash);
  869. Hyperion_Call($hash,\%obj);
  870. return;
  871. }
  872. return SetExtensions($hash,$params,$name,@aa);
  873. }
  874. sub Hyperion_Attr(@)
  875. {
  876. my ($cmd,$name,$attr_name,$attr_value) = @_;
  877. my $hash = $defs{$name};
  878. my $err;
  879. my $local = Hyperion_isLocal($hash->{IP});
  880. if ($cmd eq "set")
  881. {
  882. if ($attr_name eq "hyperionBin")
  883. {
  884. if ($attr_value !~ /^(\/.+){2,}$/)
  885. {
  886. $err = "Invalid value $attr_value for attribute $attr_name. Must be a path like /usr/bin/hyperiond.";
  887. }
  888. elsif ($local && !-e $attr_value)
  889. {
  890. $err = "The given file $attr_value is not available.";
  891. }
  892. }
  893. elsif ($attr_name eq "hyperionCustomEffects")
  894. {
  895. if ($attr_value !~ /^\{"name":"[a-zA-Z0-9_-]+","oname":"[a-zA-Z0-9_-]+","args":\{[a-zA-Z0-9:_\[\]\.",-]+\}\}([\s(\r\n)]\{"name":"[a-zA-Z0-9_-]+","oname":"[a-zA-Z0-9_-]+","args":\{[a-zA-Z0-9:_\[\]\.",-]+\}\}){0,}$/)
  896. {
  897. $err = "Invalid value $attr_value for attribute $attr_name. Must be a space separated list of JSON strings.";
  898. }
  899. else
  900. {
  901. my @custeffs = split " ",$attr_value;
  902. my @effs;
  903. if (@custeffs > 1)
  904. {
  905. foreach my $eff (@custeffs)
  906. {
  907. push @effs,eval{decode_json $eff};
  908. }
  909. }
  910. else
  911. {
  912. push @effs,eval{decode_json $attr_value};
  913. }
  914. $hash->{helper}{customeffects} = \@effs;
  915. Hyperion_Call($hash);
  916. }
  917. }
  918. elsif ($attr_name eq "hyperionConfigDir")
  919. {
  920. if ($attr_value !~ /^\/(.+\/){2,}/)
  921. {
  922. $err = "Invalid value $attr_value for attribute $attr_name. Must be a path with trailing slash like /etc/hyperion/.";
  923. }
  924. elsif ($local && !-d $attr_value)
  925. {
  926. $err = "The given directory $attr_value is not available.";
  927. }
  928. else
  929. {
  930. Hyperion_GetConfigs($hash);
  931. Hyperion_Call($hash);
  932. }
  933. }
  934. elsif ($attr_name =~ /^hyperionDefault(Priority|Duration)$/)
  935. {
  936. $err = "Invalid value $attr_value for attribute $attr_name. Must be a number between 0 and 65536." if ($attr_value !~ /^(\d+)$/ || $1 < 0 || $1 > 65536);
  937. }
  938. elsif ($attr_name eq "hyperionDimStep")
  939. {
  940. $err = "Invalid value $attr_value for attribute $attr_name. Must be between 1 and 50 in steps of 1, default is 5." if ($attr_value !~ /^(\d+)$/ || $1 < 1 || $1 > 50);
  941. }
  942. elsif ($attr_name eq "hyperionNoSudo")
  943. {
  944. $err = "Invalid value $attr_value for attribute $attr_name. Can only be value 1." if ($attr_value !~ /^1$/);
  945. }
  946. elsif ($attr_name eq "hyperionSshUser")
  947. {
  948. if ($attr_value !~ /^\w+$/)
  949. {
  950. $err = "Invalid value $attr_value for attribute $attr_name. Must be a name like pi or fhem.";
  951. }
  952. else
  953. {
  954. Hyperion_GetConfigs($hash);
  955. Hyperion_Call($hash);
  956. }
  957. }
  958. elsif ($attr_name eq "hyperionToggleModes")
  959. {
  960. $err = "Invalid value $attr_value for attribute $attr_name. Must be a comma separated list of available modes of clearall,rgb,effect,off. Each mode only once in the list." if ($attr_value !~ /^(clearall|rgb|effect|off),(clearall|rgb|effect|off)(,(clearall|rgb|effect|off)){0,2}$/);
  961. }
  962. elsif ($attr_name eq "hyperionVersionCheck")
  963. {
  964. $err = "Invalid value $attr_value for attribute $attr_name. Can only be value 0." if ($attr_value !~ /^0$/);
  965. }
  966. elsif ($attr_name eq "queryAfterSet")
  967. {
  968. $err = "Invalid value $attr_value for attribute $attr_name. Must be 0 if set, default is 1." if ($attr_value !~ /^0$/);
  969. }
  970. elsif ($attr_name eq "disable")
  971. {
  972. $err = "Invalid value $attr_value for attribute $attr_name. Must be 1 if set, default is 0." if ($attr_value !~ /^0|1$/);
  973. return $err if ($err);
  974. if ($attr_value == 1)
  975. {
  976. BlockingKill($hash->{helper}{RUNNING_PID}) if ($hash->{helper}{RUNNING_PID});
  977. RemoveInternalTimer($hash);
  978. DevIo_Disconnected($hash);
  979. }
  980. else
  981. {
  982. Hyperion_OpenDev($hash);
  983. }
  984. }
  985. }
  986. else
  987. {
  988. delete $hash->{helper}{customeffects} if ($attr_name eq "hyperionCustomEffects");
  989. Hyperion_GetUpdate($hash) if (!IsDisabled($name));
  990. Hyperion_OpenDev($hash) if ($attr_name eq "disable");
  991. }
  992. return $err ? $err : undef;
  993. }
  994. sub Hyperion_Call($;$)
  995. {
  996. my ($hash,$obj) = @_;
  997. $obj = $obj ? $obj : $Hyperion_serverinfo;
  998. my $name = $hash->{NAME};
  999. my $json = encode_json($obj);
  1000. return if (IsDisabled($name));
  1001. Log3 $name,5,"$name: Hyperion_Call: json object: $json";
  1002. DevIo_SimpleWrite($hash,$json,2,1);
  1003. }
  1004. sub Hyperion_devStateIcon($;$)
  1005. {
  1006. my ($hash,$state) = @_;
  1007. $hash = $defs{$hash} if (ref $hash ne "HASH");
  1008. return if (!$hash);
  1009. my $name = $hash->{NAME};
  1010. my $rgb = ReadingsVal($name,"rgb","");
  1011. my $dim = ReadingsVal($name,"dim",10);
  1012. my $val = ReadingsVal($name,"state","off");
  1013. my $mode = ReadingsVal($name,"mode","");
  1014. my $ico = int($dim / 10) * 10 < 10 ? 10 : int($dim / 10) * 10;
  1015. return ".*:off:on"
  1016. if ($val =~ /^off|rgb\s000000$/);
  1017. return ".*:light_exclamation"
  1018. if (($val =~ /^(ERROR|disconnected)$/ && !$hash->{INTERVAL}) || ($val eq "ERROR" && $hash->{INTERVAL}));
  1019. return ".*:light_light_dim_$ico@#".$rgb.":off"
  1020. if ($val ne "off" && $mode eq "rgb");
  1021. return ".*:light_led_stripe_rgb@#FFFF00:off"
  1022. if ($val ne "off" && $mode eq "effect");
  1023. return ".*:it_television@#0000FF:off"
  1024. if ($val ne "off" && $mode eq "clearall");
  1025. return ".*:light_question";
  1026. }
  1027. 1;
  1028. =pod
  1029. =item device
  1030. =item summary provides access to the Hyperion JSON server
  1031. =item summary_DE stellt Zugang zum Hyperion JSON Server zur Verf&uuml;gung
  1032. =begin html
  1033. <a name="Hyperion"></a>
  1034. <h3>Hyperion</h3>
  1035. <ul>
  1036. With <i>Hyperion</i> it is possible to change the color or start an effect on a hyperion server.<br>
  1037. It's also possible to control the complete color calibration (changes are temorary and will not be written to the config file).<br>
  1038. The Hyperion server must have enabled the JSON server.<br>
  1039. You can also restart Hyperion with different configuration files (p.e. switch input/grabber)<br>
  1040. <br>
  1041. <a name="Hyperion_define"></a>
  1042. <p><b>Define</b></p>
  1043. <ul>
  1044. <code>define &lt;name&gt; Hyperion &lt;IP or HOSTNAME&gt; &lt;PORT&gt; [&lt;INTERVAL&gt;]</code><br>
  1045. </ul>
  1046. <br>
  1047. &lt;INTERVAL&gt; is optional for periodically polling.<br>
  1048. <br>
  1049. <i>After defining "get &lt;name&gt; statusRequest" will be called once automatically to get the list of available effects and the current state of the Hyperion server.</i><br>
  1050. <br>
  1051. Example for running Hyperion on local system:
  1052. <br><br>
  1053. <ul>
  1054. <code>define Ambilight Hyperion localhost 19444 10</code><br>
  1055. </ul>
  1056. <br>
  1057. Example for running Hyperion on remote system:
  1058. <br><br>
  1059. <ul>
  1060. <code>define Ambilight Hyperion 192.168.1.4 19444 10</code><br>
  1061. </ul>
  1062. <br><br>
  1063. To change config files on your running Hyperion server or to stop/restart your Hyperion server you have to put the following code into your sudoers file (/etc/sudoers) (visudo):
  1064. <br><br>
  1065. <ul>
  1066. <code>fhem ALL=(ALL) NOPASSWD:/usr/bin/hyperiond,/bin/kill</code>
  1067. </ul>
  1068. <br>
  1069. <a name="Hyperion_set"></a>
  1070. <p><b>set &lt;required&gt; [optional]</b></p>
  1071. <ul>
  1072. <li>
  1073. <i>addEffect &lt;custom_name&gt;</i><br>
  1074. add the current effect with the given name to the custom effects<br>
  1075. can be altered after adding in attribute hyperionCustomEffects<br>
  1076. device has to be in effect mode with a non-custom effect and given name must be a unique effect name
  1077. </li>
  1078. <li>
  1079. <i>adjustBlue &lt;0,0,255&gt;</i><br>
  1080. adjust each color of blue separately (comma separated) (R,G,B)<br>
  1081. values from 0 to 255 in steps of 1
  1082. </li>
  1083. <li>
  1084. <i>adjustGreen &lt;0,255,0&gt;</i><br>
  1085. adjust each color of green separately (comma separated) (R,G,B)<br>
  1086. values from 0 to 255 in steps of 1
  1087. </li>
  1088. <li>
  1089. <i>adjustRed &lt;255,0,0&gt;</i><br>
  1090. adjust each color of red separately (comma separated) (R,G,B)<br>
  1091. values from 0 to 255 in steps of 1
  1092. </li>
  1093. <li>
  1094. <i>binary &lt;restart/stop&gt;</i><br>
  1095. restart or stop the hyperion binary<br>
  1096. only available after successful "get &lt;name&gt; configFiles"
  1097. </li>
  1098. <li>
  1099. <i>blacklevel &lt;0.00,0.00,0.00&gt;</i><br>
  1100. adjust blacklevel of each color separately (comma separated) (R,G,B)<br>
  1101. values from 0.00 to 1.00 in steps of 0.01
  1102. </li>
  1103. <li>
  1104. <i>clear &lt;1000&gt;</i><br>
  1105. clear a specific priority channel
  1106. </li>
  1107. <li>
  1108. <i>clearall</i><br>
  1109. clear all priority channels / switch to Ambilight mode
  1110. </li>
  1111. <li>
  1112. <i>colorTemperature &lt;255,255,255&gt;</i><br>
  1113. adjust temperature of each color separately (comma separated) (R,G,B)<br>
  1114. values from 0 to 255 in steps of 1
  1115. </li>
  1116. <li>
  1117. <i>configFile &lt;filename&gt;</i><br>
  1118. restart the Hyperion server with the given configuration file (files will be listed automatically from the given directory in attribute hyperionConfigDir)<br>
  1119. please omit the double extension of the file name (.config.json)<br>
  1120. only available after successful "get &lt;name&gt; configFiles"
  1121. </li>
  1122. <li>
  1123. <i>correction &lt;255,255,255&gt;</i><br>
  1124. adjust correction of each color separately (comma separated) (R,G,B)<br>
  1125. values from 0 to 255 in steps of 1
  1126. </li>
  1127. <li>
  1128. <i>dim &lt;percent&gt; [duration] [priority]</i><br>
  1129. dim the rgb light to given percentage with optional duration in seconds and optional priority
  1130. </li>
  1131. <li>
  1132. <i>dimDown [delta]</i><br>
  1133. dim down rgb light by steps defined in attribute hyperionDimStep or by given value (default: 10)
  1134. </li>
  1135. <li>
  1136. <i>dimUp [delta]</i><br>
  1137. dim up rgb light by steps defined in attribute hyperionDimStep or by given value (default: 10)
  1138. </li>
  1139. <li>
  1140. <i>effect &lt;effect&gt; [duration] [priority] [effectargs]</i><br>
  1141. set effect (replace blanks with underscore) with optional duration in seconds and priority<br>
  1142. effectargs can also be set as very last argument - must be a JSON string without any whitespace
  1143. </li>
  1144. <li>
  1145. <i>gamma &lt;1.90,1.90,1.90&gt;</i><br>
  1146. adjust gamma of each color separately (comma separated) (R,G,B)<br>
  1147. values from 0.00 to 5.00 in steps of 0.01
  1148. </li>
  1149. <li>
  1150. <i>luminanceGain &lt;1.00&gt;</i><br>
  1151. adjust luminanceGain<br>
  1152. values from 0.00 to 5.00 in steps of 0.01
  1153. </li>
  1154. <li>
  1155. <i>luminanceMinimum &lt;0.00&gt;</i><br>
  1156. adjust luminanceMinimum<br>
  1157. values from 0.00 to 5.00 in steps of 0.01
  1158. </li>
  1159. <li>
  1160. <i>mode &lt;clearall|effect|off|rgb&gt;</i><br>
  1161. set the light in the specific mode with its previous value
  1162. </li>
  1163. <li>
  1164. <i>off</i><br>
  1165. set the light off while the color is black
  1166. </li>
  1167. <li>
  1168. <i>on</i><br>
  1169. set the light on and restore previous state
  1170. </li>
  1171. <li>
  1172. <i>reopen</i><br>
  1173. reopen the connection to the hyperion server
  1174. </li>
  1175. <li>
  1176. <i>rgb &lt;RRGGBB&gt; [duration] [priority]</i><br>
  1177. set color in RGB hex format with optional duration in seconds and priority
  1178. </li>
  1179. <li>
  1180. <i>saturationGain &lt;1.10&gt;</i><br>
  1181. adjust saturationGain<br>
  1182. values from 0.00 to 5.00 in steps of 0.01
  1183. </li>
  1184. <li>
  1185. <i>saturationLGain &lt;1.00&gt;</i><br>
  1186. adjust saturationLGain<br>
  1187. values from 0.00 to 5.00 in steps of 0.01
  1188. </li>
  1189. <li>
  1190. <i>threshold &lt;0.16,0.16,0.16&gt;</i><br>
  1191. adjust threshold of each color separately (comma separated) (R,G,B)<br>
  1192. values from 0.00 to 1.00 in steps of 0.01
  1193. </li>
  1194. <li>
  1195. <i>toggle</i><br>
  1196. toggles the light between on and off
  1197. </li>
  1198. <li>
  1199. <i>toggleMode</i><br>
  1200. toggles through all modes
  1201. </li>
  1202. <li>
  1203. <i>valueGain &lt;1.70&gt;</i><br>
  1204. adjust valueGain<br>
  1205. values from 0.00 to 5.00 in steps of 0.01
  1206. </li>
  1207. <li>
  1208. <i>whitelevel &lt;0.70,0.80,0.90&gt;</i><br>
  1209. adjust whitelevel of each color separately (comma separated) (R,G,B)<br>
  1210. values from 0.00 to 1.00 in steps of 0.01
  1211. </li>
  1212. </ul>
  1213. <br>
  1214. <a name="Hyperion_get"></a>
  1215. <p><b>Get</b></p>
  1216. <ul>
  1217. <li>
  1218. <i>configFiles</i><br>
  1219. get the available config files in directory from attribute hyperionConfigDir<br>
  1220. File names must have no spaces and must end with .config.json .<br>
  1221. For non-local Hyperion servers you have to configure passwordless SSH login for the user running fhem to the Hyperion server host (http://www.linuxproblem.org/art_9.html), with attribute hyperionSshUser you can set the SSH user for login.<br>
  1222. Please watch the log for possible errors while getting config files.
  1223. </li>
  1224. <li>
  1225. <i>devStateIcon</i><br>
  1226. get the current devStateIcon
  1227. </li>
  1228. <li>
  1229. <i>statusRequest</i><br>
  1230. get the state of the Hyperion server,<br>
  1231. get also the internals of Hyperion including available effects
  1232. </li>
  1233. </ul>
  1234. <br>
  1235. <a name="Hyperion_attr"></a>
  1236. <p><b>Attributes</b></p>
  1237. <ul>
  1238. <li>
  1239. <i>disable</i><br>
  1240. stop polling and disconnect<br>
  1241. default: 0
  1242. </li>
  1243. <li>
  1244. <i>disabledForIntervals</i><br>
  1245. stop polling in given time frames<br>
  1246. default:
  1247. </li>
  1248. <li>
  1249. <i>hyperionBin</i><br>
  1250. path to the hyperion daemon<br>
  1251. OpenELEC users may set hyperiond.sh as daemon<br>
  1252. default: /usr/bin/hyperiond
  1253. </li>
  1254. <li>
  1255. <i>hyperionConfigDir</i><br>
  1256. path to the hyperion configuration files<br>
  1257. default: /etc/hyperion/
  1258. </li>
  1259. <li>
  1260. <i>hyperionCustomEffects</i><br>
  1261. space separated list of JSON strings (without spaces - please replace spaces in effect names with underlines)<br>
  1262. must include name (as diplay name), oname (name of the base effect) and args (the different effect args), only this order is allowed (if different an error will be thrown on attribute save and the attribut value will not be saved).<br>
  1263. example: {"name":"Knight_Rider_speed_2","oname":"Knight_rider","args":{"color":[255,0,255],"speed":2}} {"name":"Knight_Rider_speed_4","oname":"Knight_rider","args":{"color":[0,0,255],"speed":4}}
  1264. </li>
  1265. <li>
  1266. <i>hyperionDefaultDuration</i><br>
  1267. default duration<br>
  1268. default: 0 = infinity
  1269. </li>
  1270. <li>
  1271. <i>hyperionDefaultPriority</i><br>
  1272. default priority<br>
  1273. default: 0 = highest priority
  1274. </li>
  1275. <li>
  1276. <i>hyperionDimStep</i><br>
  1277. dim step for dimDown/dimUp<br>
  1278. default: 10 (percent)
  1279. </li>
  1280. <li>
  1281. <i>hyperionGainStep</i><br>
  1282. valueGain step for valueGainDown/valueGainUp<br>
  1283. default: 0.1
  1284. </li>
  1285. <li>
  1286. <i>hyperionNoSudo</i><br>
  1287. disable sudo for non-root ssh user<br>
  1288. default: 0
  1289. </li>
  1290. <li>
  1291. <i>hyperionSshUser</i><br>
  1292. user name for executing SSH commands<br>
  1293. default: pi
  1294. </li>
  1295. <li>
  1296. <i>hyperionToggleModes</i><br>
  1297. modes and order of toggleMode as comma separated list (min. 2 modes, max. 4 modes, each mode only once)<br>
  1298. default: clearall,rgb,effect,off
  1299. </li>
  1300. <li>
  1301. <i>hyperionVersionCheck</i><br>
  1302. disable hyperion version check to (maybe) support prior versions<br>
  1303. DO THIS AT YOUR OWN RISK! FHEM MAY CRASH UNEXPECTEDLY!<br>
  1304. default: 1
  1305. </li>
  1306. <li>
  1307. <i>queryAfterSet</i><br>
  1308. If set to 0 the state of the Hyperion server will not be queried after setting, instead the state will be queried on next interval query.<br>
  1309. This is only used if periodically polling is enabled, without this polling the state will be queried automatically after set.<br>
  1310. default: 1
  1311. </li>
  1312. </ul>
  1313. <br>
  1314. <a name="Hyperion_read"></a>
  1315. <p><b>Readings</b></p>
  1316. <ul>
  1317. <li>
  1318. <i>adjustBlue</i><br>
  1319. each color of blue separately (comma separated) (R,G,B)
  1320. </li>
  1321. <li>
  1322. <i>adjustGreen</i><br>
  1323. each color of green separately (comma separated) (R,G,B)
  1324. </li>
  1325. <li>
  1326. <i>adjustRed</i><br>
  1327. each color of red separately (comma separated) (R,G,B)
  1328. </li>
  1329. <li>
  1330. <i>blacklevel</i><br>
  1331. blacklevel of each color separately (comma separated) (R,G,B)
  1332. </li>
  1333. <li>
  1334. <i>colorTemperature</i><br>
  1335. temperature of each color separately (comma separated) (R,G,B)
  1336. </li>
  1337. <li>
  1338. <i>configFile</i><br>
  1339. active/previously loaded configuration file, double extension (.config.json) will be omitted
  1340. </li>
  1341. <li>
  1342. <i>correction</i><br>
  1343. correction of each color separately (comma separated) (R,G,B)
  1344. </li>
  1345. <li>
  1346. <i>dim</i><br>
  1347. active/previous dim value (rgb light)
  1348. </li>
  1349. <li>
  1350. <i>duration</i><br>
  1351. active/previous/remaining primary duration in seconds or infinite
  1352. </li>
  1353. <li>
  1354. <i>effect</i><br>
  1355. active/previous effect
  1356. </li>
  1357. <li>
  1358. <i>effectArgs</i><br>
  1359. active/previous effect arguments as JSON
  1360. </li>
  1361. <li>
  1362. <i>gamma</i><br>
  1363. gamma for each color separately (comma separated) (R,G,B)
  1364. </li>
  1365. <li>
  1366. <i>id</i><br>
  1367. id of the Hyperion server
  1368. </li>
  1369. <li>
  1370. <i>lastError</i><br>
  1371. last occured error while communicating with the Hyperion server
  1372. </li>
  1373. <li>
  1374. <i>luminanceGain</i><br>
  1375. current luminanceGain
  1376. </li>
  1377. <li>
  1378. <i>luminanceMinimum</i><br>
  1379. current luminanceMinimum
  1380. </li>
  1381. <li>
  1382. <i>mode</i><br>
  1383. current mode
  1384. </li>
  1385. <li>
  1386. <i>mode_before_off</i><br>
  1387. previous mode before off
  1388. </li>
  1389. <li>
  1390. <i>priority</i><br>
  1391. active/previous priority
  1392. </li>
  1393. <li>
  1394. <i>rgb</i><br>
  1395. active/previous rgb
  1396. </li>
  1397. <li>
  1398. <i>saturationGain</i><br>
  1399. active saturationGain
  1400. </li>
  1401. <li>
  1402. <i>saturationLGain</i><br>
  1403. active saturationLGain
  1404. </li>
  1405. <li>
  1406. <i>serverResponse</i><br>
  1407. last Hyperion server response (success/ERROR)
  1408. </li>
  1409. <li>
  1410. <i>state</i><br>
  1411. current state
  1412. </li>
  1413. <li>
  1414. <i>threshold</i><br>
  1415. threshold of each color separately (comma separated) (R,G,B)
  1416. </li>
  1417. <li>
  1418. <i>valueGain</i><br>
  1419. valueGain - gain of the Ambilight
  1420. </li>
  1421. <li>
  1422. <i>whitelevel</i><br>
  1423. whitelevel of each color separately (comma separated) (R,G,B)
  1424. </li>
  1425. </ul>
  1426. </ul>
  1427. =end html
  1428. =begin html_DE
  1429. <a name="Hyperion"></a>
  1430. <h3>Hyperion</h3>
  1431. <ul>
  1432. Mit <i>Hyperion</i> ist es m&ouml;glich auf einem Hyperion Server die Farbe oder den Effekt einzustellen.<br>
  1433. Es ist auch m&ouml;glich eine komplette Farbkalibrierung vorzunehmen (&Auml;nderungen sind tempor&auml;r und werden nicht in die Konfigurationsdatei geschrieben).<br>
  1434. Der Hyperion Server muss dem JSON Server aktiviert haben.<br>
  1435. Es ist auch m&ouml;glich Hyperion mit verschiedenen Konfigurationsdateien zu starten (z.B. mit anderem Eingang/Grabber)<br>
  1436. <br>
  1437. <a name="Hyperion_define"></a>
  1438. <p><b>Define</b></p>
  1439. <ul>
  1440. <code>define &lt;name&gt; Hyperion &lt;IP oder HOSTNAME&gt; &lt;PORT&gt; [&lt;INTERVAL&gt;]</code><br>
  1441. </ul>
  1442. <br>
  1443. &lt;INTERVAL&gt; ist optional f&uuml;r automatisches Abfragen.<br>
  1444. <br>
  1445. <i>Nach dem Definieren des Ger&auml;tes wird einmalig und automatisch "get &lt;name&gt; statusRequest" aufgerufen um den aktuellen Status und die verf&uuml;gbaren Effekte vom Hyperion Server zu holen.</i><br>
  1446. <br>
  1447. Beispiel f&uuml;r Hyperion auf dem lokalen System:
  1448. <br><br>
  1449. <ul>
  1450. <code>define Ambilight Hyperion localhost 19444 10</code><br>
  1451. </ul>
  1452. <br>
  1453. Beispiel f&uuml;r Hyperion auf einem entfernten System:
  1454. <br><br>
  1455. <ul>
  1456. <code>define Ambilight Hyperion 192.168.1.4 19444 10</code><br>
  1457. </ul>
  1458. <br>
  1459. <a name="Hyperion_set"></a>
  1460. <p><b>set &lt;ben&ouml;tigt&gt; [optional]</b></p>
  1461. <ul>
  1462. <li>
  1463. <i>addEffect &lt;eigener_name&gt;</i><br>
  1464. f&uuml;gt den aktuellen Effekt mit dem &uuml;bergebenen Namen den eigenen Effekten hinzu<br>
  1465. kann nachtr&auml;glich im Attribut hyperionCustomEffects ge&auml;ndert werden<br>
  1466. Ger&auml;t muss dazu im Effekt Modus in einen nicht-eigenen Effekt sein und der &uuml;bergebene Name muss ein einmaliger Effektname sein
  1467. </li>
  1468. <li>
  1469. <i>adjustBlue &lt;0,0,255&gt;</i><br>
  1470. Justiert jede Farbe von Blau separat (Komma separiert) (R,G,B)<br>
  1471. Werte von 0 bis 255 in Schritten von 1
  1472. </li>
  1473. <li>
  1474. <i>adjustGreen &lt;0,255,0&gt;</i><br>
  1475. Justiere jede Farbe von Gr&uuml;n separat (Komma separiert) (R,G,B)<br>
  1476. Werte von 0 bis 255 in Schritten von 1
  1477. </li>
  1478. <li>
  1479. <i>adjustRed &lt;255,0,0&gt;</i><br>
  1480. Justiert jede Farbe von Rot separat (Komma separiert) (R,G,B)<br>
  1481. Werte von 0 bis 255 in Schritten von 1
  1482. </li>
  1483. <li>
  1484. <i>blacklevel &lt;0.00,0.00,0.00&gt;</i><br>
  1485. Justiert den Schwarzwert von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1486. Werte von 0.00 bis 1.00 in Schritten von 0.01
  1487. </li>
  1488. <li>
  1489. <i>clear &lt;1000&gt;</i><br>
  1490. einen bestimmten Priorit&auml;tskanal l&ouml;schen
  1491. </li>
  1492. <li>
  1493. <i>clearall</i><br>
  1494. alle Priorit&auml;tskan&auml;le l&ouml;schen / Umschaltung auf Ambilight
  1495. </li>
  1496. <li>
  1497. <i>colorTemperature &lt;255,255,255&gt;</i><br>
  1498. Justiert die Temperatur von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1499. Werte von 0 bis 255 in Schritten von 1
  1500. </li>
  1501. <li>
  1502. <i>configFile &lt;Dateiname&gt;</i><br>
  1503. Neustart des Hyperion Servers mit der angegebenen Konfigurationsdatei (Dateien werden automatisch aufgelistet aus Verzeichnis welches im Attribut hyperionConfigDir angegeben ist)<br>
  1504. Bitte die doppelte Endung weglassen (.config.json)<br>
  1505. Nur verf&uuml;gbar nach erfolgreichem "get &lt;name&gt; configFiles"
  1506. </li>
  1507. <li>
  1508. <i>correction &lt;255,255,255&gt;</i><br>
  1509. Justiert die Korrektur von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1510. Werte von 0 bis 255 in Schritten von 1
  1511. </li>
  1512. <li>
  1513. <i>dim &lt;Prozent&gt; [Dauer] [Priorit&auml;t]</i><br>
  1514. Dimmt das RGB Licht auf angegebenen Prozentwert, mit optionaler Dauer in Sekunden und optionaler Priorit&auml;t
  1515. </li>
  1516. <li>
  1517. <i>dimDown [delta]</i><br>
  1518. Abdunkeln des RGB Lichts um angegebenen Prozentwert oder um Prozentwert der im Attribut hyperionDimStep eingestellt ist (Voreinstellung: 10)
  1519. </li>
  1520. <li>
  1521. <i>dimUp [delta]</i><br>
  1522. Aufhellen des RGB Lichts um angegebenen Prozentwert oder um Prozentwert der im Attribut hyperionDimStep eingestellt ist (Voreinstellung: 10)
  1523. </li>
  1524. <li>
  1525. <i>effect &lt;effect&gt; [Dauer] [Priorit&auml;t] [effectargs]</i><br>
  1526. Stellt gew&auml;hlten Effekt ein (ersetzte Leerzeichen mit Unterstrichen) mit optionaler Dauer in Sekunden und optionaler Priorit&auml;t<br>
  1527. effectargs k&ouml;nnen ebenfalls &uuml;bermittelt werden - muss ein JSON String ohne Leerzeichen sein
  1528. </li>
  1529. <li>
  1530. <i>gamma &lt;1.90,1.90,1.90&gt;</i><br>
  1531. Justiert Gamma von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1532. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1533. </li>
  1534. <li>
  1535. <i>luminanceGain &lt;1.00&gt;</i><br>
  1536. Justiert Helligkeit<br>
  1537. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1538. </li>
  1539. <li>
  1540. <i>luminanceMinimum &lt;0.00&gt;</i><br>
  1541. Justiert Hintergrundbeleuchtung<br>
  1542. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1543. </li>
  1544. <li>
  1545. <i>mode &lt;clearall|effect|off|rgb&gt;</i><br>
  1546. Setzt das Licht im gew&auml;hlten Modus mit dem zuletzt f&uuml;r diesen Modus eingestellten Wert
  1547. </li>
  1548. <li>
  1549. <i>off</i><br>
  1550. Schaltet aus mit Farbe schwarz
  1551. </li>
  1552. <li>
  1553. <i>on</i><br>
  1554. Schaltet mit letztem Modus und letztem Wert ein
  1555. </li>
  1556. <li>
  1557. <i>rgb &lt;RRGGBB&gt; [Dauer] [Priorit&auml;t]</i><br>
  1558. Setzt Farbe im RGB Hex Format mit optionaler Dauer in Sekunden und optionaler Priorit&auml;t
  1559. </li>
  1560. <li>
  1561. <i>saturationGain &lt;1.10&gt;</i><br>
  1562. Justiert S&auml;ttigung<br>
  1563. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1564. </li>
  1565. <li>
  1566. <i>saturationLGain &lt;1.00&gt;</i><br>
  1567. Justiert minimale S&auml;ttigung<br>
  1568. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1569. </li>
  1570. <li>
  1571. <i>threshold &lt;0.16,0.16,0.16&gt;</i><br>
  1572. Justiert den Schwellenwert von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1573. Werte von 0.00 bis 1.00 in Schritten von 0.01
  1574. </li>
  1575. <li>
  1576. <i>toggle</i><br>
  1577. Schaltet zwischen an und aus hin und her
  1578. </li>
  1579. <li>
  1580. <i>toggleMode</i><br>
  1581. Schaltet alle Modi durch
  1582. </li>
  1583. <li>
  1584. <i>valueGain &lt;1.70&gt;</i><br>
  1585. Justiert Helligkeit vom Ambilight<br>
  1586. Werte von 0.00 bis 5.00 in Schritten von 0.01
  1587. </li>
  1588. <li>
  1589. <i>whitelevel &lt;0.70,0.80,0.90&gt;</i><br>
  1590. Justiert den Wei&szlig;wert von jeder Farbe separat (Komma separiert) (R,G,B)<br>
  1591. Werte von 0.00 bis 1.00 in Schritten von 0.01
  1592. </li>
  1593. </ul>
  1594. <br>
  1595. <a name="Hyperion_get"></a>
  1596. <p><b>Get</b></p>
  1597. <ul>
  1598. <li>
  1599. <i>configFiles</i><br>
  1600. Holt die verf&uuml;gbaren Konfigurationsdateien aus dem Verzeichnis vom Attribut hyperionConfigDir<br>
  1601. Es m&uuml;ssen mindestens zwei Konfigurationsdateien im Verzeichnis vorhanden sein. Die Dateien d&uuml;rfen keine Leerzeichen enthalten und m&uuml;ssen mit .config.json enden!
  1602. </li>
  1603. <li>
  1604. <i>devStateIcon</i><br>
  1605. Zeigt den Wert des aktuellen devStateIcon
  1606. </li>
  1607. <li>
  1608. <i>statusRequest</i><br>
  1609. Holt den aktuellen Status vom Hyperion Server,<br>
  1610. holt auch die Internals vom Hyperion Server inklusive verf&uuml;gbarer Effekte
  1611. </li>
  1612. </ul>
  1613. <br>
  1614. <a name="Hyperion_attr"></a>
  1615. <p><b>Attribute</b></p>
  1616. <ul>
  1617. <li>
  1618. <i>disable</i><br>
  1619. Abfragen beenden und Verbindung trennen<br>
  1620. Voreinstellung: 0
  1621. </li>
  1622. <li>
  1623. <i>hyperionBin</i><br>
  1624. Pfad zum Hyperion Daemon<br>
  1625. OpenELEC Benutzer m&uuml;ssen eventuell hyperiond.sh als Daemon einstellen<br>
  1626. Voreinstellung: /usr/bin/hyperiond
  1627. </li>
  1628. <li>
  1629. <i>hyperionConfigDir</i><br>
  1630. Pfad zu den Hyperion Konfigurationsdateien<br>
  1631. Voreinstellung: /etc/hyperion/
  1632. </li>
  1633. <li>
  1634. <i>hyperionCustomEffects</i><br>
  1635. Leerzeichen separierte Liste von JSON Strings (ohne Leerzeichen - bitte Leerzeichen in Effektnamen durch Unterstriche ersetzen)<br>
  1636. muss name (als Anzeigename), oname (Name des basierenden Effekts) und args (die eigentlichen unterschiedlichen Effekt Argumente) beinhalten (auch genau in dieser Reihenfolge, sonst kommt beim &Uuml;bernehmen des Attributs ein Fehler und das Attribut wird nicht gespeichert)<br>
  1637. Beispiel: {"name":"Knight_Rider_speed_2","oname":"Knight_rider","args":{"color":[255,0,255],"speed":2}} {"name":"Knight_Rider_speed_4","oname":"Knight_rider","args":{"color":[0,0,255],"speed":4}}
  1638. </li>
  1639. <li>
  1640. <i>hyperionDefaultDuration</i><br>
  1641. Voreinstellung f&uuml;r Dauer<br>
  1642. Voreinstellung: 0 = unendlich
  1643. </li>
  1644. <li>
  1645. <i>hyperionDefaultPriority</i><br>
  1646. Voreinstellung f&uuml;r Priorit&auml;t<br>
  1647. Voreinstellung: 0 = h&ouml;chste Priorit&auml;t
  1648. </li>
  1649. <li>
  1650. <i>hyperionDimStep</i><br>
  1651. Dimmstufen f&uuml;r dimDown/dimUp<br>
  1652. Voreinstellung: 10 (Prozent)
  1653. </li>
  1654. <li>
  1655. <i>hyperionGainStep</i><br>
  1656. valueGain Dimmstufen f&uuml;r valueGainDown/valueGainUp<br>
  1657. Voreinstellung: 0.1
  1658. </li>
  1659. <li>
  1660. <i>hyperionNoSudo</i><br>
  1661. Deaktiviert sudo f&uuml;r nicht root SSH Benutzer<br>
  1662. Voreinstellung: 0
  1663. </li>
  1664. <li>
  1665. <i>hyperionSshUser</i><br>
  1666. Benutzername mit dem SSH Befehle ausgef&uuml;hrt werden sollen<br>
  1667. Voreinstellung: pi
  1668. </li>
  1669. <li>
  1670. <i>hyperionToggleModes</i><br>
  1671. Modi und Reihenfolge von toggleMode als kommaseparierte Liste (min. 2 Werte, max. 4 Werte, jeder Mode nur 1x)<br>
  1672. Voreinstellung: clearall,rgb,effect,off
  1673. </li>
  1674. <li>
  1675. <i>hyperionVersionCheck</i><br>
  1676. Deaktiviert Hyperion Version&uuml;berpr&uuml;fung um (eventuell) &auml;ltere Hyperion Versionen zu unterst&uuml;tzen<br>
  1677. DAS GESCHIEHT AUF EIGENE VERANTWORTUNG! FHEM K&Ouml;NNTE UNERWARTET ABST&Uuml;RTZEN!<br>
  1678. Voreinstellung: 1
  1679. </li>
  1680. <li>
  1681. <i>queryAfterSet</i><br>
  1682. Wenn gesetzt auf 0 wird der Status des Hyperion Server nach einem set Befehl nicht abgerufen, stattdessen wird der Status zum n&auml;chsten eingestellten Interval abgerufen.<br>
  1683. Das wird nur verwendet wenn das priodische Abfragen aktiviert ist, ohne dieses Abfragen wird der Status automatisch nach dem set Befehl abgerufen.<br>
  1684. Voreinstellung: 1
  1685. </li>
  1686. </ul>
  1687. <br>
  1688. <a name="Hyperion_read"></a>
  1689. <p><b>Readings</b></p>
  1690. <ul>
  1691. <li>
  1692. <i>adjustBlue</i><br>
  1693. jede Farbe von Blau separat (Komma separiert) (R,G,B)
  1694. </li>
  1695. <li>
  1696. <i>adjustGreen</i><br>
  1697. jede Farbe von Gr&uuml;n separat (Komma separiert) (R,G,B)
  1698. </li>
  1699. <li>
  1700. <i>adjustRed</i><br>
  1701. jede Farbe von Rot separat (Komma separiert) (R,G,B)
  1702. </li>
  1703. <li>
  1704. <i>blacklevel</i><br>
  1705. Schwarzwert von jeder Farbe separat (Komma separiert) (R,G,B)
  1706. </li>
  1707. <li>
  1708. <i>colorTemperature</i><br>
  1709. Temperatur von jeder Farbe separat (Komma separiert) (R,G,B)
  1710. </li>
  1711. <li>
  1712. <i>configFile</i><br>
  1713. aktive/zuletzt geladene Konfigurationsdatei, doppelte Endung (.config.json) wird weggelassen
  1714. </li>
  1715. <li>
  1716. <i>correction</i><br>
  1717. Korrektur von jeder Farbe separat (Komma separiert) (R,G,B)
  1718. </li>
  1719. <li>
  1720. <i>dim</i><br>
  1721. aktive/letzte Dimmstufe (RGB Licht)
  1722. </li>
  1723. <li>
  1724. <i>duration</i><br>
  1725. aktive/letzte/verbleibende prim&auml;re Dauer in Sekunden oder infinite f&uuml;r unendlich
  1726. </li>
  1727. <li>
  1728. <i>effect</i><br>
  1729. aktiver/letzter Effekt
  1730. </li>
  1731. <li>
  1732. <i>effectArgs</i><br>
  1733. aktive/letzte Effekt Argumente als JSON
  1734. </li>
  1735. <li>
  1736. <i>gamma</i><br>
  1737. Gamma von jeder Farbe separat (Komma separiert) (R,G,B)
  1738. </li>
  1739. <li>
  1740. <i>id</i><br>
  1741. ID vom Hyperion Server
  1742. </li>
  1743. <li>
  1744. <i>lastError</i><br>
  1745. letzter aufgetretener Fehler w&auml;hrend der Kommunikation mit dem Hyperion Server
  1746. </li>
  1747. <li>
  1748. <i>luminanceGain</i><br>
  1749. aktive Helligkeit
  1750. </li>
  1751. <li>
  1752. <i>luminanceMinimum</i><br>
  1753. aktive Hintergrundbeleuchtung
  1754. </li>
  1755. <li>
  1756. <i>mode</i><br>
  1757. aktiver Modus
  1758. </li>
  1759. <li>
  1760. <i>mode_before_off</i><br>
  1761. letzter Modus vor aus
  1762. </li>
  1763. <li>
  1764. <i>priority</i><br>
  1765. aktive/letzte Priorit&auml;t
  1766. </li>
  1767. <li>
  1768. <i>rgb</i><br>
  1769. aktive/letzte RGB Farbe
  1770. </li>
  1771. <li>
  1772. <i>saturationGain</i><br>
  1773. aktive S&auml;ttigung
  1774. </li>
  1775. <li>
  1776. <i>saturationLGain</i><br>
  1777. aktive minimale S&auml;ttigung
  1778. </li>
  1779. <li>
  1780. <i>serverResponse</i><br>
  1781. letzte Hyperion Server Antwort (success/ERROR)
  1782. </li>
  1783. <li>
  1784. <i>state</i><br>
  1785. aktiver Status
  1786. </li>
  1787. <li>
  1788. <i>threshold</i><br>
  1789. Schwellenwert von jeder Farbe separat (Komma separiert) (R,G,B)
  1790. </li>
  1791. <li>
  1792. <i>valueGain</i><br>
  1793. aktive Helligkeit vom Ambilight
  1794. </li>
  1795. <li>
  1796. <i>whitelevel</i><br>
  1797. Wei&szlig;wert von jeder Farbe separat (Komma separiert) (R,G,B)
  1798. </li>
  1799. </ul>
  1800. </ul>
  1801. =end html_DE
  1802. =cut