98_UbiquitiMP.pm 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. ################################################################
  2. #
  3. # $Id: 98_UbiquitiMP.pm 8516 2015-05-02 17:14:24Z wzut $
  4. #
  5. # (c) 2015 Copyright: Wzut
  6. # forum : http://forum.fhem.de/index.php/topic,35722.0.html
  7. # All rights reserved
  8. #
  9. # This code is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. # The GNU General Public License can be found at
  14. # http://www.gnu.org/copyleft/gpl.html.
  15. # A copy is found in the textfile GPL.txt and important notices to the license
  16. # from the author is found in LICENSE.txt distributed with these scripts.
  17. # This script is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. ################################################################
  23. # Changelog:
  24. # 25.3.15 add force for set on and off
  25. # 10.04.15 add enable/disable
  26. # 18.04.15 add toggle
  27. # 20.04.15 add Groups
  28. # first svn Version
  29. # 23.04.15 add Set Extensions for 1 Port Ubi , change Client to UbiquitiOut,
  30. # 25.06.15 add german docu, fix some timing problems
  31. # 02.05.15 fix groupPorts change at runtime
  32. package main;
  33. use strict;
  34. use warnings;
  35. use Time::HiRes qw(gettimeofday);
  36. use Blocking; # http://www.fhemwiki.de/wiki/Blocking_Call
  37. use SetExtensions;
  38. use Net::Telnet;
  39. use JSON;
  40. my %sets = ();
  41. my $setcmds = "on,off,toggle,enable,disable,lock,unlock,reset";
  42. #########################################################################
  43. sub UbiquitiMP_Initialize($)
  44. {
  45. my ($hash) = @_;
  46. $hash->{DefFn} = "UbiquitiMP_Define";
  47. $hash->{UndefFn} = "UbiquitiMP_Undef";
  48. $hash->{SetFn} = "UbiquitiMP_Set";
  49. $hash->{GetFn} = "UbiquitiMP_Get";
  50. $hash->{AttrFn} = "UbiquitiMP_Attr";
  51. $hash->{FW_summaryFn} = "UbiquitiMP_summaryFn";
  52. $hash->{AttrList} = "interval timeout user password subDevices:0,1 ignoreList ledconnect:off,blue,yellow,both,alternate groupPorts ".$readingFnAttributes;
  53. }
  54. sub UbiquitiMP_updateConfig($)
  55. {
  56. # this routine is called 5 sec after the last define of a restart
  57. # this gives FHEM sufficient time to fill in attributes
  58. my ($hash) = @_;
  59. my $name = $hash->{NAME};
  60. if (!$init_done)
  61. {
  62. RemoveInternalTimer($hash);
  63. InternalTimer(gettimeofday()+5,"UbiquitiMP_updateConfig", $hash, 0);
  64. return;
  65. }
  66. $hash->{INTERVAL} = AttrVal($name, "interval", 300);
  67. $hash->{".led"} = AttrVal($name, "ledconnect", 0);
  68. if ($hash->{".led"}) # Farben nach Kommando
  69. {
  70. $hash->{".led"} = "0" if ($hash->{".led"} eq "off");
  71. $hash->{".led"} = "1" if ($hash->{".led"} eq "blue");
  72. $hash->{".led"} = "2" if ($hash->{".led"} eq "yellow");
  73. $hash->{".led"} = "3" if ($hash->{".led"} eq "both");
  74. $hash->{".led"} = "4" if ($hash->{".led"} eq "alternate");
  75. }
  76. $hash->{MAC} = "";
  77. $hash->{lastcmd} = "Init";
  78. $hash->{".init"} = 1;
  79. RemoveInternalTimer($hash);
  80. InternalTimer(gettimeofday()+5, "UbiquitiMP_GetStatus",$hash, 0);
  81. return undef;
  82. }
  83. ################################################################################
  84. sub UbiquitiMP_Define($$) {
  85. my ($hash, $def) = @_;
  86. my $name = $hash->{NAME};
  87. my @a = split("[ \t][ \t]*", $def);
  88. return "wrong syntax: define <name> UbiquitiMP <IP or FQDN>" if(int(@a) < 3);
  89. $hash->{".host"} = $a[2];
  90. if( !defined( $attr{$a[0]}{user} ) ) { $attr{$a[0]}{user} = "ubnt";}
  91. $hash->{".user"} = $attr{$a[0]}{user};
  92. if( !defined( $attr{$a[0]}{password} ) ) { $attr{$a[0]}{password} = "ubnt";}
  93. $hash->{".pwd"} = $attr{$a[0]}{password};
  94. if( !defined( $attr{$a[0]}{subDevices} ) ) { $attr{$a[0]}{subDevices} = "1";}
  95. if( !defined( $attr{$a[0]}{timeout} ) ) { $attr{$a[0]}{timeout} = "5"}
  96. $hash->{".timeout"} = (int($attr{$a[0]}{timeout}) > 1) ? $attr{$a[0]}{timeout} : "5";
  97. if( !defined( $attr{$a[0]}{subDevices} ) ) { $attr{$a[0]}{subDevices} = "1"}
  98. $hash->{".subdevices"} = $attr{$a[0]}{subDevices};
  99. $hash->{Clients} = ":UbiquitiOut:";
  100. $hash->{PORTS} = 0;
  101. $hash->{force} = 0;
  102. $hash->{ERRORCOUNT} = 0;
  103. $hash->{".grouplist"} = "";
  104. readingsSingleUpdate($hash, "state", "defined",0);
  105. RemoveInternalTimer($hash);
  106. InternalTimer(gettimeofday()+5, "UbiquitiMP_updateConfig",$hash,0); # in 5 Sekunden machen wir den Rest
  107. return undef;
  108. }
  109. ################################################################################
  110. sub UbiquitiMP_Undef($$)
  111. {
  112. my ($hash, $arg) = @_;
  113. RemoveInternalTimer($hash);
  114. if(defined($hash->{helper}{RUNNING_PID}))
  115. {
  116. BlockingKill($hash->{helper}{RUNNING_PID});
  117. }
  118. return undef;
  119. }
  120. ################################################################################
  121. sub UbiquitiMP_force($)
  122. {
  123. my ($hash) = @_;
  124. my $name = $hash->{NAME};
  125. my $cmdlist = $hash->{lastcmd};
  126. Log3 $name, 4, "$name, force called for $cmdlist";
  127. $hash->{helper}{RUNNING_PID} = BlockingCall("UbiquitiMP_BCStart", $cmdlist, "UbiquitiMP_BCDone",(int($hash->{".timeout"})*3),"UbiquitiMP_BCAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  128. RemoveInternalTimer($hash);
  129. if($hash->{helper}{RUNNING_PID})
  130. {
  131. Log3 $name, 5, "$name, BC force process started with PID(".$hash->{helper}{RUNNING_PID}{pid}.") cmd : $cmdlist";
  132. }
  133. else
  134. { # das war wohl schon wieder nix :(
  135. InternalTimer(gettimeofday()+(int($hash->{".timeout"})*3), "UbiquitiMP_force",$hash, 0);
  136. }
  137. return undef;
  138. }
  139. ################################################################################
  140. sub UbiquitiMP_Attr(@)
  141. {
  142. my ($cmd,$name, $attrName,$attrVal) = @_;
  143. my $hash = $defs{$name};
  144. if ($cmd eq "set")
  145. {
  146. if ($attrName eq "timeout")
  147. {
  148. if (int($attrVal) < 2) {$attrVal="5";}
  149. $hash->{".timeout"} = $attrVal;
  150. $attr{$name}{timeout} = $attrVal;
  151. }
  152. elsif ($attrName eq "user")
  153. {
  154. $hash->{".user"} = $attrVal;
  155. $attr{$name}{user} = $attrVal;
  156. }
  157. elsif ($attrName eq "password")
  158. {
  159. $hash->{".pwd"} = $attrVal;
  160. $attr{$name}{password} = $attrVal;
  161. }
  162. elsif ($attrName eq "interval")
  163. {
  164. $hash->{INTERVAL} = $attrVal;
  165. $attr{$name}{interval} = $attrVal;
  166. }
  167. elsif ($attrName eq "subDevices")
  168. {
  169. $hash->{".subdevices"} = $attrVal;
  170. $attr{$name}{subDevices} = $attrVal;
  171. }
  172. elsif ($attrName eq "ledconnect")
  173. {
  174. $hash->{".led"} = "0" if ($attrVal eq "off");
  175. $hash->{".led"} = "1" if ($attrVal eq "blue");
  176. $hash->{".led"} = "2" if ($attrVal eq "yellow");
  177. $hash->{".led"} = "3" if ($attrVal eq "both");
  178. $hash->{".led"} = "4" if ($attrVal eq "alternate");
  179. $attr{$name}{ledconnect} = $attrVal;
  180. }
  181. elsif ($attrName eq "groupPorts")
  182. {
  183. $attr{$name}{groupPorts} = $attrVal;
  184. UbiquitiMP_createSets($hash);
  185. }
  186. }
  187. elsif ($cmd eq "del")
  188. {
  189. if ($attrName eq "groupPorts")
  190. {
  191. $attr{$name}{groupPorts} = "";
  192. UbiquitiMP_createSets($hash);
  193. }
  194. }
  195. return undef;
  196. }
  197. ################################################################################
  198. sub UbiquitiMP_Get($@) {
  199. my ($hash, $name , @a) = @_;
  200. my $cmd = $a[0];
  201. return "get $name needs one argument" if (int(@a) != 1);
  202. return "Unknown argument $cmd, choose one of status:noArg info:noArg reboot:noArg" if($cmd !~ /^(status|info|reboot)$/);
  203. $hash->{force} = 0; # Get setzt IMMER force zurueck !
  204. if ($cmd eq "info")
  205. { $cmd = $name."#info#cat /etc/board.info | grep board;"; $hash->{lastcmd} ="GetInfo";}
  206. elsif ($cmd eq "status")
  207. { $cmd = $name."#status#/sbin/cgi /usr/www/mfi/sensors.cgi#awk '{print \"u=\"\$1}' < /proc/uptime#awk '{print \"l=\"\$1\" \"\$2\" \"\$3}' < /proc/loadavg#cat /proc/power/energy_sum* | tr '\\n' ' '"; $hash->{lastcmd} ="GetStatus";}
  208. elsif ($cmd eq "reboot")
  209. { $cmd = $name."#reboot#reboot"; $hash->{lastcmd} ="GetReboot";}
  210. else { return undef; } # sollte eigentlich nie vorkommen
  211. $hash->{helper}{RUNNING_PID} = BlockingCall("UbiquitiMP_BCStart", $cmd, "UbiquitiMP_BCDone",(int($hash->{".timeout"})*2),"UbiquitiMP_BCAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  212. if($hash->{helper}{RUNNING_PID})
  213. {
  214. RemoveInternalTimer($hash);
  215. Log3 $name, 5, "$name, BC process started with PID(".$hash->{helper}{RUNNING_PID}{pid}.") cmd : $cmd";
  216. }
  217. else
  218. { # das war wohl nix :(
  219. Log3 $name, 3, "$name, BC process start failed, cmd : $cmd ";
  220. return $name.", can't execute get command as NonBlockingCall";
  221. }
  222. return undef;
  223. }
  224. ################################################################################
  225. sub UbiquitiMP_Set($@) {
  226. my ($hash, @a) = @_;
  227. my $name = $hash->{NAME};
  228. my ($port,$cmd,$subcmd);
  229. return undef if (!$hash->{PORTS}); # ohne bekannte Ports geht hier nichts :)
  230. UbiquitiMP_createSets($hash) if(!defined($sets{Out1}) && $hash->{PORTS}); # neu aufbauen nach reload;
  231. if (int($hash->{PORTS}) > 1)
  232. {
  233. $port = (defined($a[1])) ? $a[1] : "?" ;
  234. $cmd = (defined($a[2])) ? $a[2] : "";
  235. $subcmd = (defined($a[3])) ? $a[3] : "";
  236. if(!defined($sets{$port}))
  237. {
  238. my @commands = ();
  239. foreach my $key (sort keys %sets)
  240. {
  241. push @commands, $sets{$key} ? $key.":".join(",",$sets{$key}) : $key;
  242. }
  243. return "Unknown port $port, choose one of " . join(" ", @commands);
  244. }
  245. return "$name wrong command, please use on of on,off,toggle,lock,unlock,enable,disable or reset" if($cmd !~ /^(on|off|lock|unlock|reset|enable|disable|toggle)$/);
  246. }
  247. else # die mPower mini
  248. {
  249. $port = "Out1";
  250. $cmd = (defined($a[1])) ? $a[1] : "";
  251. $subcmd = (defined($a[2])) ? $a[2] : "";
  252. $setcmds =~ s/\,/ /g;
  253. shift(@a);
  254. return SetExtensions($hash,$setcmds,$name,@a) if($cmd !~ /^(on|off|lock|unlock|reset|enable|disable|toggle)$/);
  255. }
  256. my $cmdlist = "$name#$cmd";
  257. if ($hash->{force})
  258. {
  259. my $ret = "a force command is already active -> PID ".$hash->{force}." cmd : ".$hash->{lastcmd};
  260. Log3 $name, 3, "$name, $ret";
  261. return $ret;
  262. }
  263. if ((substr($port,0,3) eq "Out") && (int(substr($port,3,1)) > 0) && (int(substr($port,3,1)) <= int($hash->{PORTS})))
  264. { $cmdlist .= "#".substr($port,3,1); } # normaler einzelner Port
  265. else # oder doch eine Port Gruppe ?
  266. {
  267. @a = split("," ,$hash->{"group_".$port});
  268. foreach (@a)
  269. {
  270. return "Unknown port $_ in group list $port !" if ((int($_) < 1) || (int($_) > int($hash->{PORTS})));
  271. $cmdlist .="#".$_;
  272. }
  273. }
  274. $hash->{lastcmd} = $cmdlist;
  275. $hash->{helper}{RUNNING_PID} = BlockingCall("UbiquitiMP_BCStart", $cmdlist, "UbiquitiMP_BCDone",(int($hash->{".timeout"})*3),"UbiquitiMP_BCAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  276. if($hash->{helper}{RUNNING_PID})
  277. {
  278. RemoveInternalTimer($hash);
  279. $hash->{force} = ($subcmd eq "force") ? $hash->{helper}{RUNNING_PID}{pid} : 0;
  280. Log3 $name, 5, "$name, BC process started with PID(".$hash->{helper}{RUNNING_PID}{pid}.") cmd : $cmdlist , subcmd : $subcmd";
  281. }
  282. else
  283. { # das war wohl nix :(
  284. Log3 $name, 3, "$name, BC process start failed , cmd : $cmdlist , subcmd : $subcmd";
  285. UbiquitiMP_force($hash) if ($hash->{force}) ; # muessen wir das wiederholen ?
  286. return $name.", can't execute set as NonBlockingCall";
  287. }
  288. return undef;
  289. }
  290. ################################################################################
  291. sub UbiquitiMP_BCStart($)
  292. {
  293. my ($string) = @_;
  294. return unless(defined($string));
  295. my (@ret, $c, $v);
  296. my @a = split("\#" ,$string);
  297. my $output = $a[0]; # Name
  298. shift(@a);
  299. my $cmd = $a[0];
  300. shift(@a);
  301. my $hash = $defs{$output};
  302. my $name = $hash->{NAME};
  303. my $onoff = (($cmd eq "on") || ($cmd eq "lock") || ($cmd eq "enable")) ? "1" : "0";
  304. Log3 $name, 5, "$name, BC cmd : $cmd -> ".join(" ",@a);
  305. my $sock = new Net::Telnet(Timeout => $hash->{".timeout"}, Errmode => 'return');
  306. $sock->open( Host => $hash->{".host"}, Port => 23 );
  307. if (!$sock->errmsg)
  308. {
  309. $sock->login( Name => $hash->{".user"}, Password => $hash->{".pwd"} );
  310. if (!$sock->errmsg)
  311. {
  312. $sock->cmd("echo '".$hash->{".led"}."' >/proc/led/status") if ($hash->{".led"} ne "0");
  313. if (($cmd eq "reset") || ($cmd eq "toggle") ||
  314. ($cmd eq "lock") || ($cmd eq "unlock") ||
  315. ($cmd eq "enable") || ($cmd eq "disable") ||
  316. ($cmd eq "on") || ($cmd eq "off"))
  317. {
  318. $output .= "|1|status|"; # Rueckgabe wie eine Statusabfrage
  319. foreach (@a)
  320. {
  321. if ($cmd eq "reset")
  322. {
  323. $sock->cmd("cat /proc/power/relay".$_." > /tmp/relay".$_.".tmp"); # Akt. Zustand retten
  324. $sock->cmd("echo 0 > /proc/power/reset".$_); # Messwerte Reset
  325. $sock->cmd("cat /tmp/relay".$_.".tmp > /proc/power/output".$_); # alter Zustand wiederherstellen
  326. }
  327. elsif ($cmd eq "toggle")
  328. {
  329. @ret = $sock->cmd("awk '{print \$1=!\$1}' < /proc/power/relay".$_); # Akt. Zustand invers
  330. $sock->cmd("echo '".$ret[0]."' > /proc/power/output".$_);
  331. # ToDo : wer weiss wie man es in nur einer Zeile macht ?
  332. # ala : awk '{print $1=!$1}' < /proc/power/relayX > /proc/power/outputX
  333. }
  334. elsif (($cmd eq "on") || ($cmd eq "off"))
  335. {
  336. $sock->cmd("echo $onoff > /proc/power/output".$_);
  337. }
  338. elsif (($cmd eq "lock") || ($cmd eq "unlock"))
  339. {
  340. $sock->cmd("echo $onoff > /proc/power/lock".$_);
  341. }
  342. elsif (($cmd eq "enable") || ($cmd eq "disable"))
  343. {
  344. $sock->cmd("echo $onoff > /proc/power/enabled".$_);
  345. }
  346. } # foreach
  347. select(undef, undef, undef, 0.25); # 250 ms warten !
  348. @ret = $sock->cmd("/sbin/cgi /usr/www/mfi/sensors.cgi"); # neue Statuswerte holen
  349. if($ret[2])
  350. {
  351. ($ret[2],undef) = split("MF",$ret[2]); $output .= $ret[2];
  352. }
  353. }
  354. else #
  355. {
  356. $output .= "|1|$cmd|";
  357. foreach(@a)
  358. {
  359. select(undef, undef, undef, 0.25);
  360. @ret = $sock->cmd($_);
  361. Log3 $name, 5, "$name, ret -> ".$ret[0] if ($ret[0]);
  362. if ($cmd eq "status") { if($ret[2]) { ($ret[2],undef) = split("MF",$ret[2]); $output .= $ret[2]; } else { if ($ret[0]) {$ret[0] =~s/^MF.*//g; $output .= "|".$ret[0];}}}
  363. if ($cmd eq "info") { $c = join(";",@ret); $c =~s/\$//g; $c =~s/\"//g; ($c,$v) = split("MF.v",$c); $output .= $c; $output .= "version=$v";}
  364. }
  365. }
  366. $sock->cmd("echo '0' >/proc/led/status") if ($hash->{".led"} ne "0");
  367. $sock->close;
  368. $output =~s/\n//g;
  369. return $output;
  370. } else { return $output."|0|$cmd|".$sock->errmsg; }
  371. } else { return $output."|0|$cmd|".$sock->errmsg; }
  372. }
  373. sub UbiquitiMP_BCDone($)
  374. {
  375. my ($string) = @_;
  376. return unless(defined($string));
  377. my ($h,$ret,$cmd,$msg,@a) = split("\\|",$string);
  378. my $hash = $defs{$h};
  379. $msg = "" if (!defined($msg)) ;
  380. if ($hash->{helper}{RUNNING_PID}{pid})
  381. {
  382. Log3 $h, 4, "$h, BCDone : PID ".$hash->{helper}{RUNNING_PID}{pid};
  383. delete($hash->{helper}{RUNNING_PID});
  384. }
  385. Log3 $h, 5, "$h, BCDone : $string";
  386. if ($ret eq "0")
  387. {
  388. $hash->{ERRORMSG} = $msg;
  389. $hash->{ERRORTIME} = TimeNow();
  390. $hash->{ERRORCOUNT}++;
  391. Log3 $h, 2, "$h, Error[".$hash->{ERRORCOUNT}."] cmd $cmd -> $msg";
  392. $hash->{INTERVAL} = 3600 if ($hash->{INTERVAL} && ($hash->{ERRORCOUNT}>9));
  393. readingsSingleUpdate($hash,"state","error",1);
  394. if ($hash->{force}) # muessen wir wiederholen ?
  395. {
  396. UbiquitiMP_force($hash);
  397. return;
  398. }
  399. }
  400. else # das ging ja schon mal gut
  401. {
  402. $hash->{INTERVAL} = AttrVal($h, "interval", 300) if ($hash->{ERRORCOUNT} >9);
  403. $hash->{ERRORCOUNT} = 0;
  404. $hash->{force} = 0;
  405. if ($cmd eq "info") { UbiquitiMP_Info($hash,$msg); }
  406. elsif ($cmd eq "status")
  407. {
  408. if($msg ne "") # haben wir wieder mal einen leeren Status bekommen ?
  409. {
  410. UbiquitiMP_Status($hash,$msg,@a) if($msg ne "") ;
  411. }
  412. else
  413. {
  414. # etwas warten und versuchen den Status doch noch abzuschliessen
  415. InternalTimer(gettimeofday()+$hash->{".timeout"}, "UbiquitiMP_GetStatus",$hash, 0);
  416. return ;
  417. }
  418. }
  419. }
  420. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "UbiquitiMP_GetStatus",$hash, 0) if ($hash->{INTERVAL});
  421. }
  422. ################################################################################
  423. sub UbiquitiMP_BCAborted($)
  424. {
  425. my ($hash) = @_;
  426. delete($hash->{helper}{RUNNING_PID});
  427. $hash->{ERRORCOUNT}++;
  428. $hash->{ERRORTIME} = TimeNow();
  429. Log3 $hash->{NAME}, 3, $hash->{NAME}.", BlockingCall for ".$hash->{NAME}." cmd ".$hash->{lastcmd}." aborted EC : ".$hash->{ERRORCOUNT};
  430. $hash->{INTERVAL} = 3600 if ($hash->{INTERVAL} && ($hash->{ERRORCOUNT}>9));
  431. if ($hash->{force}) # ein abgebrochenes force ?
  432. {
  433. UbiquitiMP_force($hash);
  434. }
  435. elsif ($hash->{lastcmd} eq "GetStatus") # war das ein erfolgloses auto status update ?
  436. {
  437. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "UbiquitiMP_GetStatus",$hash, 0) if($hash->{INTERVAL});
  438. }
  439. return;
  440. }
  441. ################################################################################
  442. sub UbiquitiMP_Status($$@)
  443. {
  444. my ($hash,$js,@a) = @_;
  445. my $name = $hash->{NAME};
  446. my $devstate;
  447. my $devname;
  448. my $state;
  449. my $sum_current;
  450. my $sum_power;
  451. my $sum_month;
  452. my $sum_prevmonth;
  453. my $sum_energy;
  454. my @ener;
  455. my $json = ();
  456. $json = JSON->new->utf8(0)->decode($js);
  457. my $sensors = scalar keys $json->{sensors};
  458. if ((!$hash->{PORTS}) && ($sensors > 0)) # nur einmal zu Begin bzw nach reload
  459. {
  460. $hash->{PORTS} = $sensors;
  461. UbiquitiMP_createSets($hash);
  462. }
  463. # bei der 1 Port Ubi default keine Subdevices , bei den anderen ja
  464. my $subdev = (int($hash->{PORTS}) >1) ? AttrVal($name, "subDevices", 1) : AttrVal($name, "subDevices", 0);
  465. @ener = split(" ",$a[2]) if (defined($a[2]));
  466. readingsBeginUpdate($hash);
  467. for (my $i=0; $i<$sensors; $i++)
  468. {
  469. if (index(AttrVal($name, "ignoreList", "") , $i+1) == -1) # welche Ports ignorieren ?
  470. {
  471. my $thismonth = ($json->{sensors}[$i]{thismonth}) ? sprintf("%.0f", $json->{sensors}[$i]{thismonth}*0.3125) : 0; # Verbrauch aktueller Monat
  472. my $prevmonth = ($json->{sensors}[$i]{prevmonth}) ? sprintf("%.0f", $json->{sensors}[$i]{prevmonth}*0.3125) : 0; # Verbrauch letzter Monat , in welcher Einheit ?
  473. my $powerfactor = sprintf("%.2f", $json->{sensors}[$i]{powerfactor}); $powerfactor +=0; # wer will 0.00 ?
  474. my $output = $json->{sensors}[$i]{output}; # 1/0 fuer on/off
  475. my $port = $json->{sensors}[$i]{port}; # Port Nr. 1- n
  476. my $voltage = sprintf("%.0f", $json->{sensors}[$i]{voltage}); # V
  477. my $power = sprintf("%.0f", $json->{sensors}[$i]{power}); # W
  478. my $current = sprintf("%.2f", $json->{sensors}[$i]{current}); $current +=0; # A
  479. my $lock = $json->{sensors}[$i]{lock};
  480. my $label = $json->{sensors}[$i]{label};
  481. my $enabled = $json->{sensors}[$i]{enabled}; # wann wird das angefasst ?
  482. my $energy = (defined($ener[$i])) ? sprintf("%.2f",$ener[$i]*0.3125) : 0;
  483. $energy += 0;
  484. my $eState ="E:$energy P:$power I:$current U:$voltage i:$powerfactor";
  485. $sum_current += (defined($json->{sensors}[$i]{current})) ? $json->{sensors}[$i]{current} : 0;
  486. $sum_month += (defined($json->{sensors}[$i]{thismonth})) ? $json->{sensors}[$i]{thismonth}*0.3125 : 0;
  487. $sum_prevmonth += (defined($json->{sensors}[$i]{prevmonth})) ? $json->{sensors}[$i]{prevmonth}*0.3125 : 0;
  488. $sum_power += (defined($json->{sensors}[$i]{power})) ? $json->{sensors}[$i]{power} : 0;
  489. $sum_energy += (defined($ener[$i])) ? $ener[$i]*0.3125 : 0;
  490. $devstate = ($output eq "0") ? "off" : "on";
  491. $state .= ($i == $sensors) ? $devstate : $devstate." ";
  492. $devname = "Out".$port; # Port kann eigenen Namen haben
  493. $hash->{helper}{$devname}{state} = $output;
  494. $hash->{helper}{$devname}{name} = $devname;
  495. $hash->{helper}{$devname}{lock} = $lock;
  496. if ($subdev) # aufteilen oder lieber alles am Stueck ?
  497. {
  498. my $defptr = $modules{UbiquitiOut}{defptr}{$name.$port};
  499. if (defined($defptr))
  500. {
  501. readingsBeginUpdate($defptr);
  502. readingsBulkUpdate($defptr, "state" , $devstate);
  503. readingsBulkUpdate($defptr, "eState" , $eState);
  504. readingsBulkUpdate($defptr, "power" , $power);
  505. readingsBulkUpdate($defptr, "voltage" , $voltage);
  506. readingsBulkUpdate($defptr, "current" , $current);
  507. readingsBulkUpdate($defptr, "pf" , $powerfactor);
  508. readingsBulkUpdate($defptr, "month" , $thismonth);
  509. readingsBulkUpdate($defptr, "prevmonth" , $prevmonth) if ($prevmonth);
  510. readingsBulkUpdate($defptr, "lock" , $lock);
  511. readingsBulkUpdate($defptr, "label" , $label) if ($label);
  512. readingsBulkUpdate($defptr, "enabled" , $enabled);
  513. readingsBulkUpdate($defptr, "energy" , $energy);
  514. readingsEndUpdate($defptr, 1 );
  515. }
  516. else
  517. {
  518. Log3 $name, 3, "$name, autocreate sub device for $devname Port $port";
  519. CommandDefine(undef, $name."_".$devname." UbiquitiOut $name $port");
  520. }
  521. }
  522. else # all in one
  523. {
  524. if (int($hash->{PORTS}) > 1)
  525. {
  526. readingsBulkUpdate($hash, $devname."_state" , $devstate);
  527. readingsBulkUpdate($hash, $devname."_eState" , $eState);
  528. readingsBulkUpdate($hash, $devname."_power" , $power);
  529. readingsBulkUpdate($hash, $devname."_voltage" , $voltage);
  530. readingsBulkUpdate($hash, $devname."_current" , $current);
  531. readingsBulkUpdate($hash, $devname."_pf" , $powerfactor);
  532. readingsBulkUpdate($hash, $devname."_month" , $thismonth);
  533. readingsBulkUpdate($hash, $devname."_prevmonth" , $prevmonth) if ($prevmonth);
  534. readingsBulkUpdate($hash, $devname."_lock" , $lock);
  535. readingsBulkUpdate($hash, $devname."_label" , $label) if ($label);
  536. readingsBulkUpdate($hash, $devname."_enabled" , $enabled);
  537. readingsBulkUpdate($hash, $devname."_energy" , $energy);
  538. }
  539. else # 1 Port Dose
  540. {
  541. readingsBulkUpdate($hash, "eState" , $eState);
  542. readingsBulkUpdate($hash, "power" , $power);
  543. readingsBulkUpdate($hash, "voltage" , $voltage);
  544. readingsBulkUpdate($hash, "current" , $current);
  545. readingsBulkUpdate($hash, "pf" , $powerfactor);
  546. readingsBulkUpdate($hash, "month" , $thismonth);
  547. readingsBulkUpdate($hash, "prevmonth" , $prevmonth) if ($prevmonth);
  548. readingsBulkUpdate($hash, "lock" , $lock);
  549. readingsBulkUpdate($hash, "label" , $label) if ($label);
  550. readingsBulkUpdate($hash, "enabled" , $enabled);
  551. readingsBulkUpdate($hash, "energy" , $energy);
  552. } # 1 Port
  553. } # all in one
  554. } # if
  555. } # for
  556. if(defined($a[0]) && (substr($a[0],0,2) eq "u=")) # uptime
  557. {
  558. my $sec;
  559. (undef,$sec) = split("=",$a[0]); # u=xxxx.yyy
  560. if (int($sec) > 0)
  561. {
  562. my ($seconds, $microseconds) = gettimeofday();
  563. my @t = localtime($seconds-int($sec));
  564. $hash->{powerd_on} = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1],$t[0]);
  565. my($d,$h,$m,$s,$up);
  566. $d=int($sec/(24*60*60));
  567. $h=($sec/(60*60))%24;
  568. $m=($sec/60)%60;
  569. $s=$sec%60;
  570. $up = "$d days, " if($d > 1);
  571. $up = "1 day, " if($d == 1);
  572. $up .= sprintf("%02s:%02s:%02s", $h, $m, $s);
  573. readingsBulkUpdate($hash, "uptime", $up);
  574. }
  575. }
  576. if (defined($a[1]) && (substr($a[1],0,2) eq "l=")) # load
  577. {
  578. my $load;
  579. (undef , $load) = split("=",$a[1]); # l=xxx yyy zzz
  580. $hash->{load} = $load if ($load);
  581. }
  582. if(int($hash->{PORTS}) > 1)
  583. {
  584. readingsBulkUpdate($hash, "all_current", sprintf("%.2f", $sum_current));
  585. readingsBulkUpdate($hash, "all_power", sprintf("%.2f", $sum_power));
  586. readingsBulkUpdate($hash, "all_month", sprintf("%.2f", $sum_month/1000));
  587. readingsBulkUpdate($hash, "all_prevmonth", sprintf("%.2f", $sum_prevmonth/1000));
  588. readingsBulkUpdate($hash, "all_energy", sprintf("%.2f", $sum_energy));
  589. }
  590. readingsBulkUpdate($hash, "state",$state);
  591. readingsEndUpdate($hash, 1 );
  592. return undef;
  593. }
  594. ################################################################################
  595. sub UbiquitiMP_Info($$)
  596. {
  597. my ($hash,$info) = @_;
  598. my $name = $hash->{NAME};
  599. my $var;
  600. my $val;
  601. my $ports;
  602. my $board_id;
  603. my @a = split(";" , $info);
  604. foreach (@a)
  605. {
  606. ($var,$val) = split("=" , $_);
  607. Log3 $name, 5, "$name, $var = $val";
  608. $board_id = $val if ($var eq "board.sysid");
  609. $hash->{BNAME} = $val if ($var eq "board.name");
  610. $hash->{SNAME} = $val if ($var eq "board.shortname");
  611. $hash->{VERSION} = $val if ($var eq "version");
  612. $hash->{MAC} = $val if ($var eq "board.hwaddr");
  613. }
  614. if (($board_id) && (!$hash->{PORTS}))
  615. {
  616. if ($board_id eq "0xe648") { $ports = 8; }
  617. elsif ($board_id eq "0xe656") { $ports = 6; }
  618. elsif (($board_id eq "0xe653") ||
  619. ($board_id eq "0xe643")){ $ports = 3; }
  620. elsif ($board_id eq "0xe642") { $ports = 2; }
  621. else { $ports = 1; }
  622. if ($ports > 0)
  623. {
  624. $hash->{PORTS} = $ports;
  625. UbiquitiMP_createSets($hash);
  626. }
  627. }
  628. if (defined($hash->{VERSION}))
  629. {
  630. my $v = $hash->{VERSION};
  631. my $msg = "Old version ".$hash->{VERSION}." found, please update to >= 2.1.8 !";
  632. $v =~s/\.//g;
  633. if (int($v) < 218)
  634. {
  635. $hash->{VERSION} = $msg;
  636. Log3 $name, 1, "$name, $msg";
  637. }
  638. }
  639. if ($hash->{".init"}) # kommen wir ueber einen Neustart ?
  640. {
  641. readingsSingleUpdate($hash,"state","Initialized",1);
  642. delete($hash->{".init"});
  643. InternalTimer(gettimeofday()+$hash->{".timeout"}, "UbiquitiMP_GetStatus",$hash, 0);
  644. }
  645. return undef;
  646. }
  647. ################################################################################
  648. sub UbiquitiMP_GetStatus($)
  649. {
  650. my ($hash) = @_;
  651. my $name = $hash->{NAME};
  652. my $cmd = $name;
  653. Log3 $name, 5, "$name, GetStatus Interval : ".$hash->{INTERVAL};
  654. if ($hash->{".init"}) # kommen wir ueber einen Neustart ?
  655. {
  656. $cmd .= "#info#cat /etc/board.info | grep board";
  657. }
  658. else
  659. {
  660. $cmd .= "#status#/sbin/cgi /usr/www/mfi/sensors.cgi";
  661. $cmd .= "#awk '{print\"u=\" \$1}' /proc/uptime";
  662. $cmd .= "#awk '{print \"l=\"\$1\" \"\$2\" \"\$3}' < /proc/loadavg";
  663. $cmd .= "#cat /proc/power/energy_sum* | tr '\\n' ' '";
  664. }
  665. $hash->{helper}{RUNNING_PID} = BlockingCall("UbiquitiMP_BCStart", $cmd, "UbiquitiMP_BCDone",(int($hash->{".timeout"})*2),"UbiquitiMP_BCAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  666. if($hash->{helper}{RUNNING_PID})
  667. {
  668. Log3 $name, 5, "$name, BC process started with PID(".$hash->{helper}{RUNNING_PID}{pid}.") cmd : $cmd";
  669. $hash->{lastcmd} = "GetStatus";
  670. }
  671. else
  672. { # das ging schief wiederholen nach doppelter timeout Wartezeit
  673. Log3 $name, 3, "$name, BC process GetStatus start failed !";
  674. InternalTimer(gettimeofday()+(int($hash->{".timeout"})*2), "UbiquitiMP_GetStatus",$hash, 0);
  675. }
  676. return;
  677. }
  678. ################################################################################
  679. sub UbiquitiMP_summaryFn($$$$) {
  680. my ($FW_wname, $hash, $room, $pageHash) = @_;
  681. $hash = $defs{$hash};
  682. my $state = $hash->{STATE};
  683. my $name = $hash->{NAME};
  684. return if ((AttrVal($name, "stateFormat", "")) || (int($hash->{PORTS}) < 2));
  685. my ($icon,$html,$cmd,$i,$title,$txt,$a,$b);
  686. $html ="<nobr>";
  687. if (($state ne "defined") && ($state ne "error") && ($state ne "Initialized"))
  688. {
  689. for ($i=1; $i<= $hash->{PORTS}; $i++)
  690. {
  691. if (defined($hash->{helper}{"Out".$i}{state}))
  692. {
  693. if ($hash->{helper}{"Out".$i}{state})
  694. {
  695. $cmd = "Out".$i." off";
  696. $title = $hash->{helper}{"Out".$i}{name}. " on";
  697. ($icon, undef, undef) = FW_dev2image($name,"on");
  698. ($a,$b) = split('title=\"on\"' , FW_makeImage($icon, "on"));
  699. $txt = $a."title=\"".$title."\"".$b;
  700. }
  701. else
  702. {
  703. $cmd = "Out".$i." on";
  704. $title = $hash->{helper}{"Out".$i}{name}. " off";
  705. ($icon, undef, undef) = FW_dev2image($name,"off");
  706. ($a,$b) = split('title=\"off\"' , FW_makeImage($icon, "off"));
  707. $txt = $a."title=\"".$title."\"".$b;
  708. }
  709. if (!$hash->{helper}{"Out".$i}{lock})
  710. {
  711. $html .= "<a href=\"/fhem?cmd.$name=set $name ".$cmd."&room=$room&amp;room=$room\">$txt</a>";
  712. }
  713. else { $html .= $txt; }
  714. $html .= "&nbsp;&nbsp;";
  715. }
  716. }
  717. } else { $html .= $state };
  718. $html .= "</nobr>";
  719. return $html;
  720. }
  721. ################################################################################
  722. sub UbiquitiMP_createSets($)
  723. {
  724. my ($hash) = @_;
  725. my $name = $hash->{NAME};
  726. my $list = AttrVal($name, "groupPorts", "");
  727. my (@a, @b);
  728. return if (!$hash->{PORTS});
  729. %sets = ();
  730. # bei nur einem Port macht eine Gruppe keinen Sinn
  731. if (int($hash->{PORTS}) == 1)
  732. {
  733. @a = split("," ,$setcmds);
  734. foreach (@a) { $sets{$_} = "noArg"; }
  735. #%sets = ($setcmds);
  736. return;
  737. }
  738. $hash->{group_ALL} = "";
  739. for (my $j=1; $j<= $hash->{PORTS}; $j++) { $sets{"Out".$j} = $setcmds; $hash->{group_ALL} .= "$j,"; }
  740. $sets{"ALL"} = $setcmds;
  741. chop($hash->{group_ALL}); # das letzte Komma weg
  742. if ($hash->{".grouplist"})
  743. {
  744. @a = split("," , $hash->{".grouplist"});
  745. foreach (@a) { delete $hash->{"group_".$_}; }
  746. $hash->{".grouplist"} = "";
  747. }
  748. if ($list)
  749. {
  750. @a = split(" " , $list);
  751. foreach (@a)
  752. {
  753. @b = split("=" , $_);
  754. if ($b[0] && (index($b[1],",") > 0))
  755. {
  756. $hash->{"group_".$b[0]} = $b[1];
  757. $sets{$b[0]} = $setcmds;
  758. $hash->{".grouplist"} .= $b[0].",";
  759. }
  760. }
  761. chop($hash->{".grouplist"});
  762. }
  763. return;
  764. }
  765. 1;
  766. =pod
  767. =begin html
  768. <a name="UbiquitiMP"></a>
  769. <h3>UbiquitiMP</h3>
  770. <ul>
  771. <table>
  772. <tr><td>
  773. FHEM module for the Ubiquiti mFi mPower modules<br>
  774. Please read also the <a href="http://www.fhemwiki.de/wiki/Ubiquit_mFi/mPower">Wiki</a> at http://www.fhemwiki.de/wiki/Ubiquit_mFi/mPower<br>
  775. FHEM Forum : http://forum.fhem.de/index.php/topic,35722.0.html
  776. </td></tr></table>
  777. <a name="UbiquitiMPdefine"></a>
  778. <b>Define</b>
  779. <ul>
  780. <code>define &lt;name&gt; UbiquitiMP &lt;IP or FQDN&gt;</code><br>
  781. example :<br>
  782. define myPM UbiquitiMP 192.168.0.100<br>
  783. define myPM UbiquitiMP myhost.dyndns.org<br>
  784. Perl Net::Telnet and JSON module are required. On a Raspberry you can install them with :<br>
  785. apt-get install libjson-perl<br>
  786. apt-get install libnet-telnet-perl
  787. </ul>
  788. <br>
  789. <a name="UbiquitiMPset"></a>
  790. <b>Set </b>
  791. <ul>
  792. <li>Outx on / off (force) -> turns Port x on or off</li>
  793. <li>Outx toggle -> toggle port </li>
  794. <li>Outx lock / unlock -> protects port to switch port on/off</li>
  795. <li>Outx reset -> reset power counter for this port</li>
  796. <li>Outx enable / disable -> power counting for this port</li>
  797. </ul>
  798. <a name="UbiquitiMPget"></a>
  799. <b>Get</b>
  800. <ul>
  801. <li>status -> returns the status of all Outs</li>
  802. <li>info -> returns some internal informations of the device</li>
  803. <li>reboot -> reboot the device</li><br>
  804. </ul>
  805. <a name="UbiquitiMPattr"></a>
  806. <b>Attributes</b>
  807. <ul>
  808. <li>ignoreList -> list of ignored ports<br> e.g. attr name ignoreList 456<br>ignores all values of ports 4,5 & 6<br></li>
  809. <li>groupPorts -> space separeted list to group ports so you can use them like a single device<br>
  810. e.g. attr name groupPorts TV=12 Media=4,5,6 (GroupName=Port numbers in the group)<br>
  811. set name TV on or set name Media toggle </li>
  812. <li>ledconnect -> led color since fhem connect</li>
  813. <li>subDevices -> use a single sub devices for each out port<br>
  814. (default 1 for the 3 and 6 port mPower, default 0 for the mPower mini) requires 98_UbiquitiOut.pm</li>
  815. <li>interval -> polling interval in seconds, set to 0 to disable polling (default 300)</li>
  816. <li>timeout -> seconds to wait for a answer from the Power Module (default 5 seconds)</li>
  817. <li>user -> defined user on the Power Module (default ubnt)</li>
  818. <li>password -> password for user (default ubnt)</li>
  819. </ul>
  820. <br>
  821. </ul>
  822. =end html
  823. =begin html_DE
  824. <a name="UbiquitiMP"></a>
  825. <h3>UbiquitiMP</h3>
  826. <ul>
  827. <table>
  828. <tr><td>
  829. FHEM Modul f&uuml;r die Ubiquiti mFi mPower Schaltsteckdosen<br>
  830. Mehr Informationen zu den verschiedenen mPower Modellen im <a href="http://www.fhemwiki.de/wiki/Ubiquit_mFi/mPower">Wiki</a> unter http://www.fhemwiki.de/wiki/Ubiquit_mFi/mPower<br>
  831. FHEM Forum : http://forum.fhem.de/index.php/topic,35722.0.html
  832. </td></tr></table>
  833. <a name="UbiquitiMPdefine"></a>
  834. <b>Define</b>
  835. <ul>
  836. <code>define &lt;name&gt; UbiquitiMP &lt;IP or FQDN&gt;</code><br>
  837. Beispiel :<br>
  838. define Ubi UbiquitiMP 192.168.0.100<br>
  839. define Ubi UbiquitiMP myhost.dyndns.org<br>
  840. Perl Net::Telnet und das Perl JSON Modul werden ben&ouml;tigt.
  841. Bei einem Raspberry Pi k&ouml;nnen diese leicht mit den folgenden beiden Befehlen installiert werden:<br>
  842. apt-get install libjson-perl<br>
  843. apt-get install libnet-telnet-perl
  844. </ul>
  845. <br>
  846. <a name="UbiquitiMPset"></a>
  847. <b>Set </b>
  848. <ul>
  849. <li>Outx on / off (force) -> schaltet den Port x an oder aus</li>
  850. <li>Outx toggle -> schaltet den Port aus wenn er an ist und umgekehrt</li>
  851. <li>Outx lock / unlock -> Ist lock bei einem Port gesetzt kann er nicht mehr an oder aus geschaltet werden</li>
  852. <li>Outx reset -> setzt den internen Verbrauchsz&auml;hler f&uuml;r diesen Port zur&uuml;ck</li>
  853. <li>Outx enable / disable -> interne Verbrauchsmessung f&uuml;r diesen Port ein / aus schalten</li>
  854. <br><b>Bei der mPower mini entf&auml;llt die Angabe von Outx !</b><br>
  855. Zus&auml;tzlich unterst&uuml;tzt die mini die <a href="#setExtensions">set Extensions</a> direkt
  856. </ul>
  857. <a name="UbiquitiMPget"></a>
  858. <b>Get</b>
  859. <ul>
  860. <li>status -> Gibt den aktuellen Status aller Ports zur&uuml;ck</li>
  861. <li>info -> liefert einige interne Parameter des Ger&auml;tes</li>
  862. <li>reboot -> Startet das Ger&auml;t neu</li><br>
  863. </ul>
  864. <a name="UbiquitiMPattr"></a>
  865. <b>Attributes</b>
  866. <ul>
  867. <li>ignoreList -> Liste der Ports die bei Abfragen ignoriert werden sollen, Bsp. <code>attr Ubi ignoreList 456</code><br>
  868. ignoriert alle Werte der Ports 4,5 und 6</li><br>
  869. <li>groupPorts -> Durch Kommatas getrennte Liste um Ports in Gruppen zusammen zu fassen.<br>
  870. Die Gruppen k&ouml;nnen danach wie win einzelner Port behandelt werden.<br>
  871. Bsp. <code>attr Ubi groupPorts TV=12 Media=4,5,6</code> (GruppenName=Port Nummer des Ports in der Gruppe)<br>
  872. <code>set Ubi TV on</code> oder <code>set Ubi Media toggle</code></li><br>
  873. <li>ledconnect -> Farbe der LED beim Zugriff mit fhem</li><br>
  874. <li>subDevices -> Legt f&uuml;r jeden Port ein eigenes Subdevice an<br>
  875. (Default 1 f&uuml;r die 3 and 6 Port mPower, Default 0 f&uuml;r die mPower 1 Port mini) ben&ouml;tigt zus&auml;tzlich das Modul 98_UbiquitiOut.pm</li><br>
  876. <li>interval -> Abfrage Interval in Sekunden, kann ausgeschaltet werden mit dem Wert 0 (Default ist 300)</li><br>
  877. <li>timeout -> Wartezeit in Sekunden bevor eine Abfrage mit einer Fehlermeldung abgebrochen wird (Default ist 5 Sekunden)<br>
  878. Werte unter zwei Sekunden werden vom Modul nicht angenommen !</li><br>
  879. <li>user -> Login Username (Default ubnt)</li><br>
  880. <li>password -> Login Passwort (Default ubnt)</li>
  881. </ul>
  882. <br>
  883. </ul>
  884. =end html_DE
  885. =cut