98_EDIPLUG.pm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. ################################################################
  2. #
  3. # $Id: 98_EDIPLUG.pm 12458 2016-10-28 18:00:25Z wzut $
  4. #
  5. # (c) 2014 Copyright: Wzut based on 98_EDIPLUG.pm tre (ternst)
  6. # All rights reserved
  7. #
  8. # This code is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. # The GNU General Public License can be found at
  13. # http://www.gnu.org/copyleft/gpl.html.
  14. # A copy is found in the textfile GPL.txt and important notices to the license
  15. # from the author is found in LICENSE.txt distributed with these scripts.
  16. # This script is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU General Public License for more details.
  20. #
  21. ################################################################
  22. # Changelog:
  23. #
  24. # 2014-11-28 Initialversion by tre
  25. # 2014-12-05 edit (Wzut)
  26. # 2014-12-08 add schedule and list (Wzut)
  27. # 2014-12-09 add dellist (Wzut)
  28. # 2015-02-21 V1.00 first svn version (Wzut)
  29. # 2015-02-22 V1.01 add attr read-only, fix attr interval, update command.ref
  30. # 2015-03-07 V1.02 fix schedule
  31. # 2015-09-12 V1.03 fix errorcount and interval
  32. # 2016-01-20 V1.04 add Reading onoff for SP2101W
  33. # 2016-10-28 V1.05 fix wrong user on first start
  34. #
  35. ################################################################
  36. package main;
  37. use strict;
  38. use warnings;
  39. use Time::HiRes qw(gettimeofday);
  40. use HttpUtils;
  41. use SetExtensions;
  42. use XML::Simple qw(:strict);
  43. sub EDIPLUG_Initialize($);
  44. sub EDIPLUG_Define($$);
  45. sub EDIPLUG_Undef($$);
  46. sub EDIPLUG_Set($@);
  47. sub EDIPLUG_Get($@);
  48. sub EDIPLUG_GetUpdate($);
  49. sub EDIPLUG_Read($$$);
  50. my %gets = (
  51. "status:noArg" => "",
  52. "info:noArg" => "",
  53. "power:noArg" => "",
  54. "schedule:noArg" => ""
  55. );
  56. my %sets = (
  57. "on:noArg" => "",
  58. "off:noArg" => "",
  59. "list" => "",
  60. "addlist" => "",
  61. "dellist" => "",
  62. "delete:0,1,2,3,4,5,6" => "",
  63. "day" => "",
  64. "clear_error" => ""
  65. );
  66. my $data_s = "\'<?xml version=\"1.0\" encoding=\"UTF8\"?><SMARTPLUG id=\"edimax\"><CMD id=\"";
  67. my $data_e = "></CMD></SMARTPLUG>\'";
  68. my %datas = (
  69. "status" => $data_s."get\"><Device.System.Power.State/".$data_e,
  70. "info" => $data_s."get\"><SYSTEM_INFO/".$data_e,
  71. "power" => $data_s."get\"><NOW_POWER/".$data_e,
  72. "on" => $data_s."setup\"><Device.System.Power.State>ON</Device.System.Power.State".$data_e,
  73. "off" => $data_s."setup\"><Device.System.Power.State>OFF</Device.System.Power.State".$data_e,
  74. "schedule" => $data_s."get\"><SCHEDULE/".$data_e
  75. );
  76. #########################################################################
  77. sub EDIPLUG_Initialize($)
  78. {
  79. my ($hash) = @_;
  80. $hash->{DefFn} = "EDIPLUG_Define";
  81. $hash->{UndefFn} = "EDIPLUG_Undef";
  82. $hash->{SetFn} = "EDIPLUG_Set";
  83. $hash->{GetFn} = "EDIPLUG_Get";
  84. $hash->{AttrFn} = "EDIPLUG_Attr";
  85. $hash->{AttrList} = "interval timeout disable:0,1 model:SP1101W,SP2101W,unknow read-only:0,1 user password ".$readingFnAttributes;
  86. }
  87. ################################################################################
  88. sub EDIPLUG_Define($$) {
  89. my ($hash, $def) = @_;
  90. my @a = split("[ \t][ \t]*", $def);
  91. return "wrong syntax: define <name> EDIPLUG <IP or FQDN>" if(int(@a) != 3);
  92. $hash->{NAME} = $a[0];
  93. $hash->{host} = $a[2];
  94. if( !defined( $attr{$a[0]}{interval} ) ) { $attr{$a[0]}{interval} = "60"}
  95. $hash->{INTERVAL} = $attr{$a[0]}{interval};
  96. if( !defined( $attr{$a[0]}{user} ) ) { $attr{$a[0]}{user} = "admin"}
  97. $hash->{user} = $attr{$a[0]}{user};
  98. if( !defined( $attr{$a[0]}{password} ) ) { $attr{$a[0]}{password} = "1234"}
  99. $hash->{pwd} = $attr{$a[0]}{password};
  100. if( !defined( $attr{$a[0]}{model} ) ) { $attr{$a[0]}{model} = "unknow"}
  101. $hash->{MODEL} = $attr{$a[0]}{model};
  102. if( !defined($attr{$a[0]}{'read-only'} ) ) { $attr{$a[0]}{'read-only'} = "0"}
  103. $hash->{POWER} = "?";
  104. $hash->{LASTCMD} = "";
  105. $hash->{helper}{current} = "";
  106. $hash->{helper}{power} = "";
  107. # for non blocking HTTP Get
  108. $hash->{port} = "10000";
  109. $hash->{url} = "http://$hash->{user}:$hash->{pwd}\@$hash->{host}:$hash->{port}/smartplug.cgi";
  110. $hash->{callback} = \&EDIPLUG_Read;
  111. $hash->{timeout} = 2;
  112. $hash->{code} = "";
  113. $hash->{httpheader} = "";
  114. $hash->{conn} = "";
  115. $hash->{data} = "";
  116. $hash->{".firststart"} = 1;
  117. readingsSingleUpdate($hash, "state", "defined",0);
  118. for (my $i=0; $i<8; $i++) { $hash->{helper}{"list"}[$i] = ""; } # einer mehr als Tage :)
  119. RemoveInternalTimer($hash);
  120. InternalTimer(gettimeofday()+5, "EDIPLUG_GetUpdate", $hash, 0);
  121. #EDIPLUG_Get($hash,$hash->{NAME},"info");
  122. return undef;
  123. }
  124. ################################################################################
  125. sub EDIPLUG_Undef($$) {
  126. my ($hash, $arg) = @_;
  127. RemoveInternalTimer($hash);
  128. return undef;
  129. }
  130. ################################################################################
  131. sub EDIPLUG_GetUpdate($) {
  132. my ($hash) = @_;
  133. my $name = $hash->{NAME};
  134. if (!$init_done)
  135. {
  136. RemoveInternalTimer($hash);
  137. InternalTimer(gettimeofday()+5,"EDIPLUG_GetUpdate", $hash, 0);
  138. return;
  139. }
  140. $hash->{INTERVAL} = AttrVal($name, "interval", $hash->{INTERVAL}) if ($hash->{INTERVAL} != 3600);
  141. if (($hash->{".firststart"}) && !IsDisabled($name))
  142. {
  143. Log3 $name, 5, $name.", GetUpdate (firststart)";
  144. $hash->{".firststart"} = 0;
  145. EDIPLUG_Get($hash,$name,"info");
  146. InternalTimer(gettimeofday()+$hash->{timeout}+2, "EDIPLUG_GetUpdate", $hash, 1) if ($hash->{INTERVAL});
  147. return;
  148. }
  149. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "EDIPLUG_GetUpdate", $hash, 1) if ($hash->{INTERVAL});
  150. return if(IsDisabled($name));
  151. Log3 $name, 5, $name.", GetUpdate";
  152. EDIPLUG_Get($hash,$name,"status") if ($hash->{INTERVAL});
  153. return ;
  154. }
  155. ################################################################################
  156. sub EDIPLUG_Read($$$)
  157. {
  158. my ($hash, $err, $buffer) = @_;
  159. my $name = $hash->{NAME};
  160. my $state;
  161. Log3 $name, 5, $name.", Read : $hash , $buffer\r\n";
  162. if ($err)
  163. {
  164. my $error = "error";
  165. $error .= " ".$hash->{code} if ($hash->{code} && ($hash->{code} ne ""));
  166. $hash->{ERROR} = $err;
  167. $hash->{ERRORTIME} = TimeNow();
  168. $hash->{ERRORCOUNT}++;
  169. Log3 $name, 3, "$name, return ".$error."[".$hash->{ERRORCOUNT}."] -> ".$err;
  170. if ($hash->{ERRORCOUNT} > 5)
  171. {
  172. Log3 $name, 3, "$name, too many errors, setting interval from ".$hash->{INTERVAL}." to 3600 seconds" if($hash->{INTERVAL} != 3600);
  173. $hash->{INTERVAL} = 3600;
  174. }
  175. readingsSingleUpdate($hash, "state", $error, 0);
  176. return;
  177. }
  178. if ($hash->{INTERVAL} == 3600)
  179. {
  180. my $interval = AttrVal($name, "interval", 60);
  181. Log3 $name, 3, "$name, set interval back to $interval seconds";
  182. $hash->{INTERVAL} = $interval;
  183. }
  184. # auswerten der Rueckgabe
  185. if (!$buffer)
  186. {
  187. # sollte eigentlich gar nicht vorkommen bzw. nur bei fehlerhaften uebergebenen XML String
  188. $hash->{ERRORCOUNT}++;
  189. Log3 $name, 3, "$name, empty return buffer [".$hash->{ERRORCOUNT}."]";
  190. $hash->{ERROR} = "empty return buffer";
  191. $hash->{ERRORTIME} = TimeNow();
  192. return;
  193. }
  194. $hash->{ERRORCOUNT} = 0;
  195. readingsBeginUpdate($hash);
  196. # EDIPLUGs geben ein nicht gueltigen Zeichensatz zurueck ( UTF8 instead utf-8 )
  197. $buffer =~s/UTF8/utf-8/g;
  198. my $xml = XML::Simple->new(ForceArray => ['entry', 'link'], KeyAttr => []);
  199. my $xmlres = $xml->XMLin($buffer);
  200. # Device.System.Power.State (Status der Steckdose)
  201. if (exists $xmlres->{CMD}->{'Device.System.Power.State'})
  202. {
  203. if ($hash->{MODEL} eq "SP2101W")
  204. {
  205. $hash->{POWER} = uc($xmlres->{CMD}->{'Device.System.Power.State'});
  206. readingsBulkUpdate($hash, "onoff", lc($hash->{POWER}));
  207. $state = ($hash->{POWER} ne "OFF") ? $hash->{POWER}." / ".$hash->{helper}{power}. " W / ".$hash->{helper}{current}." A" : $hash->{POWER};
  208. }
  209. else
  210. {
  211. $state = lc($xmlres->{CMD}->{'Device.System.Power.State'});
  212. }
  213. }
  214. # SYSTEM_INFO
  215. if (exists $xmlres->{CMD}->{SYSTEM_INFO})
  216. {
  217. $hash->{'MODEL'} = $xmlres->{CMD}->{SYSTEM_INFO}->{'Run.Model'};
  218. $hash->{'VERSION'} = $xmlres->{CMD}->{SYSTEM_INFO}->{'Run.FW.Version'};
  219. $hash->{'MAC'} = $xmlres->{CMD}->{SYSTEM_INFO}->{'Run.LAN.Client.MAC.Address'};
  220. $hash->{'PName'} = $xmlres->{CMD}->{SYSTEM_INFO}->{'Device.System.Name'};
  221. }
  222. if ((exists $xmlres->{CMD}->{NOW_POWER}) && ($hash->{MODEL} eq "SP2101W"))
  223. {
  224. # POWER_NOW
  225. my $ltt = $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.LastToggleTime'};
  226. my $ltt_s = substr($ltt,8,2).":".substr($ltt,10,2).":".substr($ltt,12,2) ." ".substr($ltt,6,2).".".substr($ltt,4,2).".".substr($ltt,0,4);
  227. readingsBulkUpdate($hash, "last_Toggle_Time", $ltt_s) if ($ltt ne "0");
  228. $hash->{helper}{current} = $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowCurrent'};
  229. readingsBulkUpdate($hash, "current", $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowCurrent'}." A");
  230. $hash->{helper}{power} = $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowPower'};
  231. readingsBulkUpdate($hash, "power_now", $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowPower'}." W");
  232. readingsBulkUpdate($hash, "power_day", $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowEnergy.Day'}." kWh");
  233. readingsBulkUpdate($hash, "power_week", $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowEnergy.Week'}." kWh");
  234. readingsBulkUpdate($hash, "power_month", $xmlres->{CMD}->{NOW_POWER}->{'Device.System.Power.NowEnergy.Month'}." kWh");
  235. $state = ($hash->{POWER} ne "OFF") ? $hash->{POWER}." / ".$hash->{helper}{power}. " W / ".$hash->{helper}{current}." A" : $hash->{POWER};
  236. }
  237. my @days=("0.So","1.Mo","2.Di","3.Mi","4.Do","5.Fr","6.Sa");
  238. for (my $i=0; $i<7; $i++)
  239. {
  240. if (exists $xmlres->{CMD}{SCHEDULE}{'Device.System.Power.Schedule.'.$i.'.List'})
  241. {
  242. $hash->{helper}{"list"}[$i] = $xmlres->{CMD}{SCHEDULE}{'Device.System.Power.Schedule.'.$i.'.List'}; # die heben wir auf
  243. $hash->{helper}{"list"}[7] = "1"; # es ist eine aktuelle Liste vorhanden
  244. my $zeit = decode_list($hash->{helper}{"list"}[$i]);
  245. readingsBulkUpdate($hash, $days[$i] , lc($xmlres->{CMD}{SCHEDULE}{'Device.System.Power.Schedule.'.$i}{value}));
  246. if ($zeit ne "") { readingsBulkUpdate($hash, $days[$i].".list" , $zeit); }
  247. else { readingsBulkUpdate($hash, $days[$i].".list" , "no list on device");}
  248. }
  249. }
  250. readingsBulkUpdate($hash,"state",$state) if ($state);
  251. readingsEndUpdate($hash, 1 );
  252. # nach set on/off oder erstem Durchlauf sofort neuen Status holen
  253. if (($hash->{LASTCMD} eq "on") ||
  254. ($hash->{LASTCMD} eq "off") ||
  255. ($hash->{STATE} eq "defined"))
  256. {
  257. $hash->{LASTCMD} = "";
  258. select(undef, undef, undef, 1); # TODO , sehr hässlich - aber irgend eine Wartezeit muss sein
  259. EDIPLUG_Get($hash,$name,"status");
  260. }
  261. # und nach dem Status noch fuer die 2101 die aktuellen Power Werte
  262. elsif (($hash->{LASTCMD} eq "status") && ($hash->{MODEL} eq "SP2101W"))
  263. {
  264. EDIPLUG_Get($hash,$name,"power");
  265. }
  266. elsif (($hash->{LASTCMD} eq "addlist") ||
  267. ($hash->{LASTCMD} eq "list") ||
  268. ($hash->{LASTCMD} eq "dellist") ||
  269. ($hash->{LASTCMD} eq "delete") ||
  270. ($hash->{LASTCMD} eq "day"))
  271. {
  272. select(undef, undef, undef, 2); # TODO , sehr hässlich - aber irgend eine Wartezeit muss sein
  273. EDIPLUG_Get($hash,$name,"schedule"); # geaenderte Liste holen
  274. }
  275. return;
  276. }
  277. ################################################################################
  278. sub EDIPLUG_Attr(@)
  279. {
  280. my ($cmd,$name, $attrName,$attrVal) = @_;
  281. my $hash = $defs{$name};
  282. if ($cmd eq "set")
  283. {
  284. if ($attrName eq "disable")
  285. {
  286. RemoveInternalTimer($hash);
  287. $hash->{INTERVAL} = 0 if $attrVal;
  288. readingsSingleUpdate($hash, "state", "disabled",0) if (!$hash->{INTERVAL});
  289. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "EDIPLUG_GetUpdate", $hash, 1) if ($hash->{INTERVAL}>0);
  290. }
  291. elsif ($attrName eq "timeout")
  292. {
  293. $hash->{timeout} = $attrVal;
  294. $attr{$name}{timeout} = $attrVal;
  295. }
  296. elsif ($attrName eq "interval")
  297. {
  298. $hash->{INTERVAL} = $attrVal;
  299. $attr{$name}{interval} = $attrVal;
  300. }
  301. elsif ($attrName eq "model")
  302. {
  303. $hash->{MODEL} = $attrVal;
  304. $attr{$name}{model} = $attrVal;
  305. }
  306. elsif ($attrName eq "user")
  307. {
  308. $hash->{user} = $attrVal;
  309. $attr{$name}{user} = $attrVal;
  310. $hash->{url} = "http://$hash->{user}:$hash->{pwd}\@$hash->{host}:$hash->{port}/smartplug.cgi";
  311. }
  312. elsif ($attrName eq "password")
  313. {
  314. $hash->{pwd} = $attrVal;
  315. $attr{$name}{password} = $attrVal;
  316. $hash->{url} = "http://$hash->{user}:$hash->{pwd}\@$hash->{host}:$hash->{port}/smartplug.cgi";
  317. }
  318. }
  319. elsif ($cmd eq "del")
  320. {
  321. if ($attrName eq "disable")
  322. {
  323. RemoveInternalTimer($hash);
  324. readingsSingleUpdate($hash, "state", "???",0) if (!$hash->{INTERVAL});
  325. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "EDIPLUG_GetUpdate", $hash, 1) if ($hash->{INTERVAL});
  326. }
  327. elsif ($attrName eq "interval")
  328. {
  329. $hash->{INTERVAL} = 60;
  330. }
  331. }
  332. return undef;
  333. }
  334. ################################################################################
  335. sub EDIPLUG_Set($@) {
  336. my ($hash, $name , @a) = @_;
  337. my $cmd = $a[0];
  338. return "set $name needs at least one argument" if(int(@a) < 1);
  339. return ($cmd eq "?") ? undef : "no set commands are allowed on a read-only device !" if ($attr{$name}{'read-only'} eq "1");
  340. return ($cmd eq "?") ? undef : "no set commands are allowed on a disabled device!" if(IsDisabled($name));
  341. my $list = "on off list addlist delete:0,1,2,3,4,5,6 dellist day clear_error";
  342. return SetExtensions($hash, $list, $name, @a) if( $cmd eq "?" );
  343. return SetExtensions($hash, $list, $name, @a) if( !grep( $_ =~ /^$cmd($|:)/, split( ' ', $list)));
  344. $hash->{timeout} = AttrVal($name, "timeout", 2);
  345. my $oldcmd = $hash->{LASTCMD}; $hash->{LASTCMD}="";
  346. if($cmd eq "clear_error")
  347. {
  348. $hash->{ERROR} = undef;
  349. $hash->{ERRORCOUNT} = 0;
  350. $hash->{LASTCMD} = $cmd;
  351. return undef;
  352. }
  353. if(($cmd eq "on") || ($cmd eq "off"))
  354. {
  355. $hash->{LASTCMD} = $cmd;
  356. $hash->{data} = $datas{$cmd};
  357. }
  358. elsif(($cmd eq "list") || ($cmd eq "addlist") || ($cmd eq "dellist"))
  359. {
  360. return "set $name $cmd : DayOfWeek(0-6) Starttime(hh:mm) Endtime(hh:mm) Command(on/off) e.g. 1 10:00 11:30 on" if(int(@a) < 4);
  361. shift @a;
  362. my $day = $a[0];
  363. shift @a;
  364. return "set $name $cmd : wrong day $day, please use 0-6" if (($day >6) || ($day <0));
  365. return "set $name $cmd : wrong start time,missing : !" if (index($a[0],":") < 0);
  366. return "set $name $cmd : wrong end time, missing : !" if (index($a[1],":") < 0);
  367. return "set $name $cmd : don't use the same start and end time !" if ($a[0] eq $a[1]);
  368. return "set $name $cmd : wrong on/off command, use on or off" if (($a[2] ne "on") && ($a[2] ne "off") && ($cmd ne "dellist")) ;
  369. my $ret = encode_list(@a);
  370. return "set $name $cmd is to short ($ret)" if (length($ret) != 5);
  371. if ($cmd eq "addlist")
  372. {
  373. return "set $name $cmd : internal schedule list is empty, please use 'get $name schedule' first" if($hash->{helper}{"list"}[7] eq "");
  374. return "set $name $cmd : start and end time block already exist !" if (index($hash->{helper}{"list"}[$day],$ret) > -1) ;
  375. # Time Block schon vorhanden , aber jetzt on/off Umschaltung ?
  376. my $reverse_cmd = substr($ret,0,4);
  377. $reverse_cmd .= ($a[2] eq "on") ? "0" : "1";
  378. $hash->{helper}{"list"}[$day] =~ s/$reverse_cmd/$ret/g; # alt gegen neu tauschen
  379. # Block hinzufügen oder fertig ?
  380. if (index($hash->{helper}{"list"}[$day],$ret) > -1)
  381. { $ret = $hash->{helper}{"list"}[$day]; }
  382. else
  383. { $ret = $hash->{helper}{"list"}[$day]."-".$ret; }
  384. }
  385. elsif ($cmd eq "dellist")
  386. {
  387. $ret = substr($ret,0,4)."0"; # ist er als off definert ?
  388. my $pos = index($hash->{helper}{"list"}[$day],$ret);
  389. if ($pos<0) # oder doch als on ?
  390. {
  391. $ret = substr($ret,0,4)."1";
  392. $pos = index($hash->{helper}{"list"}[$day],$ret);
  393. }
  394. return "set $name $cmd : day $day, start and end time block do not exist" if ($pos<0);
  395. $hash->{helper}{"list"}[$day] =~ s/$ret//g; # raus aus der Liste
  396. $hash->{helper}{"list"}[$day] =~ s/\--/\-/g; # eventuelle jetzt noch vorhandene doppelte Minuszeichen bereinigen
  397. # war das erste von mehr als einem ?
  398. if (index($hash->{helper}{"list"}[$day], "-") == 0) { $hash->{helper}{"list"}[$day] = substr($hash->{helper}{"list"}[$day],1); }
  399. # oder der letzte von mehr als einem ?
  400. if (rindex($hash->{helper}{"list"}[$day], "-") == length($hash->{helper}{"list"}[$day])-1) { chop($hash->{helper}{"list"}[$day]); }
  401. $ret = $hash->{helper}{"list"}[$day];
  402. }
  403. $hash->{LASTCMD} = $cmd; # merken und später Liste neu holen
  404. $hash->{data} = $data_s."setup\"><SCHEDULE><Device.System.Power.Schedule.".$day.".List>".$ret;
  405. $hash->{data} .= "</Device.System.Power.Schedule.".$day.".List></SCHEDULE".$data_e;
  406. }
  407. elsif($cmd eq "day")
  408. {
  409. return "set $name $cmd : DayOfWeek(0-6) Command(on/off) e.g. 1 on" if(int(@a) < 3);
  410. shift @a;
  411. my $day = $a[0];
  412. my $oocmd = $a[1];
  413. return "set $name $cmd : wrong day $day, use 0-6" if (($day >6) || ($day <0));
  414. return "set $name $cmd : wrong on/off command, please use on or off" if (($oocmd ne "on") && ($oocmd ne "off"));
  415. return "set $name $cmd : schedule list is empty, please use 'get $name schedule' first" if($hash->{helper}{"list"}[7] eq "");
  416. $hash->{LASTCMD} = $cmd;
  417. $hash->{data} = $data_s."setup\"><SCHEDULE><Device.System.Power.Schedule.".$day." value=\"".uc($oocmd)."\"></Device.System.Power.Schedule.".$day."></SCHEDULE".$data_e;
  418. }
  419. elsif($cmd eq "delete")
  420. {
  421. return "set $name $cmd : DayOfWeek(0-6)" if(int(@a) < 2);
  422. shift @a;
  423. my $day = $a[0];
  424. return "set $name $cmd : wrong day $day, please use 0-6" if (($day >6) || ($day <0));
  425. $hash->{LASTCMD} = $cmd;
  426. $hash->{data} = $data_s."setup\"><SCHEDULE><Device.System.Power.Schedule.".$day.".List /".$data_e;
  427. }
  428. # Haben wir jetzt ein neues Set Kommando ?
  429. if ($hash->{LASTCMD})
  430. {
  431. #return $hash->{data}; # Debug nur anzeigem
  432. $hash->{code} = "";
  433. HttpUtils_NonblockingGet($hash);
  434. return undef;
  435. }
  436. # Hier sollten wir eigentlich nie hinkommen ..
  437. $hash->{LASTCMD} = $oldcmd;
  438. return "$name set with unknown argument $cmd, choose one of " . join(" ", sort keys %sets);
  439. }
  440. ################################################################################
  441. sub EDIPLUG_Get($@) {
  442. my ($hash, @a) = @_;
  443. my $name= $hash->{NAME};
  444. return "get $name needs at least one argument" if(int(@a) < 2);
  445. return "no get commands are allowed on a disabled device !" if(IsDisabled($name));
  446. my $cmd = $a[1];
  447. return "$name get power is not supported by this model !" if (($cmd eq "power") && ($hash->{MODEL} ne "SP2101W"));
  448. $hash->{data} = $datas{$cmd};
  449. if($hash->{data})
  450. {
  451. $hash->{LASTCMD} = $cmd;
  452. $hash->{timeout} = AttrVal($name, "timeout", 2);
  453. #$hash->{buf} = "";
  454. $hash->{code} = "";
  455. #$hash->{httpheader} = "";
  456. #$hash->{conn} = "";
  457. #$hash->{data} = "";
  458. HttpUtils_NonblockingGet($hash);
  459. return ;
  460. }
  461. return "$name get with unknown argument $cmd, choose one of " . join(" ", sort keys %gets);
  462. }
  463. ################################################################################
  464. sub decode_list($)
  465. {
  466. # Bsp : 10111-01020-nX001
  467. my ($string) = @_ ;
  468. return "" if (length($string)<5); # zu kurz
  469. # die beiden Sonderfaelle - ganzer Tag an oder aus
  470. return "00:00-24:00 on" if ($string eq "00001");
  471. return "00:00-24:00 off" if ($string eq "00000");
  472. my @a = split("-",$string);
  473. my @sorted = sort @a;
  474. my $s="";
  475. my $timetab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; # nur 0 - 59 wird gebraucht
  476. foreach(@sorted)
  477. {
  478. my $cmd = $_;
  479. return "" if (index($timetab, substr($cmd,0,1)) > 23); #TODO den HASH besser erkennen
  480. $s .= (length($s)) ? " / " : "";
  481. # Begin Stunde
  482. $s .= sprintf("%02d:",index($timetab, substr($cmd,0,1)));
  483. # Begin Minute
  484. $s .= sprintf("%02d-",index($timetab, substr($cmd,1,1)));
  485. # Ende Stunde
  486. $s .= sprintf("%02d:", index($timetab, substr($cmd,2,1)));
  487. # Ende Minute
  488. $s .= sprintf("%02d", index($timetab, substr($cmd,3,1)));
  489. # ON or OFF ?
  490. $s .= (substr($cmd,4,1) eq "0") ? " off" : " on";
  491. }
  492. return $s;
  493. }
  494. ################################################################################
  495. sub encode_list(@)
  496. {
  497. my ($start,$end,$cmd) = @_;
  498. my $ret;
  499. my $timetab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX"; # 0 - 59
  500. my ($sh,$sm) = split(":",$start);
  501. $sh++; $sh--; $sm++; $sm--; # fuuehrende Nullen weg
  502. return "wrong start hour !" if ($sh > 23);
  503. return "wrong start minute !" if ($sm > 59);
  504. $ret = substr($timetab,$sh,1);
  505. $ret .= substr($timetab,$sm,1);
  506. my ($eh, $em) = split(":",$end);
  507. $eh++; $eh--; $em++; $em--;
  508. $eh = 0 if (($eh == 24) && ($em == 0)); # den Sonderfall 24:00 Uhr zulassen !
  509. return "wrong end hour !" if ($eh > 23);
  510. return "wrong end minute !" if ($em > 59);
  511. return "starttime is after endtime !" if ($sh > $eh);
  512. return "starttime is after endtime !" if (($sh == $eh) && ($sm > $em));
  513. $ret .= substr($timetab,$eh,1);
  514. $ret .= substr($timetab,$em,1);
  515. return "don't use the same start and end time !" if (substr($ret,0,2) eq substr($ret,2,2)) && (($eh != 0) && ($em != 0));
  516. $ret .= ($cmd eq "on") ? "1" : "0";
  517. return $ret;
  518. }
  519. ################################################################################
  520. 1;
  521. =pod
  522. =item device
  523. =item summary controls EDIPLUG SP2101W / SP1101W WLAN switches
  524. =item summary_DE steuert EDIPLUG SP2101W / SP1101W WLAN Schaltsteckdosen
  525. =begin html
  526. <a name="EDIPLUG"></a>
  527. <h3>EDIPLUG</h3>
  528. FHEM module to control the Edimax Smart Plug Switches SP-2101W and SP-1101W (http://www.edimax.com)<br>
  529. FHEM Forum : <a href="http://forum.fhem.de/index.php/topic,29541.0.html">http://forum.fhem.de/index.php/topic,29541.0.html</a><br>
  530. SP-2101W - Edimax Smart Plug Switch with Power Meter<br>
  531. SP-1101W - Edimax Smart Plug Switch<br>
  532. requires XML:Simple -> sudo apt-get install libxml-simple-perl<br>
  533. <br>
  534. <ul>
  535. <a name="EDIPLUGdefine"></a>
  536. <b>Define</b>
  537. <ul>
  538. define &lt;name&gt; EDIPLUG &lt; IP_EDIMAX_Device (or FQDN) &gt;<br>
  539. Example:<br>
  540. <li>define myediplug EDIPLUG 192.168.0.99</li>
  541. <li>define myediplug EDIPLUG ediplug.myhome.net</li>
  542. </ul>
  543. <a name="EDIPLUGset"></a>
  544. <b>Set</b>
  545. <ul>
  546. <li>on => switch power on</li>
  547. <li>off => switch power off</li>
  548. <li>list => set a new list for one day with one entry : DayOfWeek(0-6) Starttime(hh:mm) Endtime(hh:mm) Command(on/off) e.g. 1 10:00 11:30 on<br>
  549. use (DayOfWeek) 00:00 24:00 on to switch the complete day on</li>
  550. <li>addlist => add a new on/off time : DayOfWeek(0-6) Starttime(hh:mm) Endtime(hh:mm) Command(on/off) e.g. 1 10:00 11:30 on</li>
  551. <li>dellist => remove a existing on/off time : DayOfWeek(0-6) Starttime(hh:mm) Endtime(hh:mm) e.g. 1 10:00 11:30</li>
  552. <li>delete => delete timelist of one day : DayOfWeek(0-6)</li>
  553. <li>day => enable/disable timeschedule for one day : DayOfWeek(0-6) on/off</li>
  554. </ul>
  555. <a name="EDIPLUGget"></a>
  556. <b>Get</b><ul>
  557. <li>info => shows MAC , Firmware Version , Model , Name</li>
  558. <li>power => shows all Power informations ( model SP-2101W only)</li>
  559. <li>schedule => show all internal on/off timetables</li>
  560. <li>status => show on/off state</li>
  561. </ul>
  562. <a name="EDIPLUGattr"></a>
  563. <b>Attributes</b>
  564. <ul>
  565. <li>interval => polling interval (default 60)</li>
  566. <li>timeout => max. time to wait in seconds (default 2)</li>
  567. <li>read-only => only read (Get) from device (default 0)</li>
  568. <li>user => username (default admin)</li>
  569. <li>password => password (default 1234)</li>
  570. </ul>
  571. <br>
  572. <b>Readings</b>
  573. <ul>
  574. <li>0.So -> switching times Sunday</li>
  575. <li>0.So.state -> Sunday switching on/off</li>
  576. <li>.</li>
  577. <li>.</li>
  578. <li>.</li>
  579. <li>6.Sa -> switching times Saturday</li>
  580. <li>6.Sa.state -> Saturday switching on/off ( model SP-2101W only )</li>
  581. <li>last_Toggle_Time ( model SP-2101W only )</li>
  582. <li>current ( model SP-2101W only )</li>
  583. <li>power_now ( model SP-2101W only )</li>
  584. <li>power_day ( model SP-2101W only )</li>
  585. <li>power_week ( model SP-2101W only )</li>
  586. <li>power_month ( model SP-2101W only )</li>
  587. </ul>
  588. </ul>
  589. =end html
  590. =begin html_DE
  591. <a name="EDIPLUG"></a>
  592. <h3>EDIPLUG</h3>
  593. FHEM Module f&uuml;r die Edimax Smart Plug Switches SP-2101W und SP-1101W (http://www.edimax.com)<br>
  594. FHEM Forum : <a href="http://forum.fhem.de/index.php/topic,29541.0.html">http://forum.fhem.de/index.php/topic,29541.0.html</a><br>
  595. SP-2101W - Edimax Smart Plug Switch mit Strom Verbrauchsmessung<br>
  596. SP-1101W - Edimax Smart Plug Switch<br>
  597. ben&oml;ntigt XML:Simple -> sudo apt-get install libxml-simple-perl
  598. <br>
  599. <ul>
  600. <a name="EDIPLUGdefine"></a>
  601. <b>Define</b>
  602. <ul>
  603. define &lt;name&gt; EDIPLUG IP_des_EDIPlug (oder FQDN Name)<br>
  604. Beispiel:<br>
  605. <li>define myediplug EDIPLUG 192.168.0.99</li>
  606. <li>define myediplug EDIPLUG ediplug.fritz.box</li>
  607. </ul>
  608. <br>
  609. <a name="EDIPLUGset"></a>
  610. <b>Set</b>
  611. <ul>
  612. <li>on => schalte an</li>
  613. <li>off => schalte aus</li>
  614. <li>list => erzeugt eine neue Zeitplan Liste mit einem Eintrag : Wochentag(0-6) Startzeit(hh:mm) Endezeit(hh:mm) Kommando(on/off) Bsp. 1 10:00 11:30 on<br>
  615. mit Wochentag 00:00 24:00 on kann man den kompletten Tag einschalten</li>
  616. <li>addlist => f&uuml;gt eine neue Schaltzeit einer bestehenden Zeitplan Liste hinzu : Wochentag(0-6) Startzeit(hh:mm) Endtezeit(hh:mm) Kommando(on/off) Bsp. 1 10:00 11:30 on</li>
  617. <li>dellist => l&ouml;scht eine bestimmte Schaltzeit eines Tages : Wochentag(0-6) Startzeit(hh:mm) Endezeit(hh:mm) Bsp. 1 10:00 11:30</li>
  618. <li>delete => l&ouml;scht die Liste eines ganzen Tages : Wochentag(0-6)</li>
  619. <li>day => schaltet die Zeitplanung eines Tages ein oder aus : Wochentag(0-6) on/off Bsp. 5 on</li>
  620. </ul>
  621. <br>
  622. <a name="EDIPLUGget"></a>
  623. <b>Get</b>
  624. <ul>
  625. <li>info => Anzeige von MAC , Firmware Version , Modell , Name</li>
  626. <li>power => zeigt alle Stromverbrauchswerte ( nur Modell SP-2101W )</li>
  627. <li>schedule => zeigt alle internen Schaltzeiten (ACHTUNG : Firmware Version beachten !)</li>
  628. <li>status => zeigt an/aus Status der Schaltdose</li>
  629. </ul>
  630. <br>
  631. <a name="EDIPLUGattr"></a>
  632. <b>Attributes</b>
  633. <ul>
  634. <li>interval => polling interval (default 60)</li>
  635. <li>timeout => max. Wartezeit in Sekunden (default 2)</li>
  636. <li>read-only => es ist nur lesen (Get) erlaubt (default 0)</li>
  637. <li>user => Username (default admin)</li>
  638. <li>password => Passwort (default 1234)</li>
  639. </ul>
  640. <br>
  641. <b>Readings</b>
  642. <ul>
  643. <li>0.So -> Schaltzeiten Sonntag</li>
  644. <li>0.So.state -> Sonntag an/aus</li>
  645. <li>.</li>
  646. <li>.</li>
  647. <li>.</li>
  648. <li>6.Sa -> Schaltzeiten Samstag</li>
  649. <li>6.Sa.state -> Samstag an/aus</li>
  650. <li>last_Toggle_Time ( nur Modell SP-2101W)</li>
  651. <li>current (nur Modell SP-2101W)</li>
  652. <li>power_now (nur Modell SP-2101W)</li>
  653. <li>power_day (nur Modell SP-2101W)</li>
  654. <li>power_week (nur Modell SP-2101W)</li>
  655. <li>power_month (nur Modell SP-2101W)</li>
  656. </ul>
  657. </ul>
  658. =end html_DE
  659. =cut