70_SML.pm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. ##############################################################################
  2. #
  3. # 70_SML.pm
  4. #
  5. # a module to show smartmeter data
  6. #
  7. # written 2012 by Gabriel Bentele <gabriel at bentele.de>>
  8. #
  9. # $Id: 70_SML.pm 10650 2016-01-28 14:47:44Z bentele $
  10. #
  11. # Version = 2.7
  12. #
  13. ##############################################################################
  14. #
  15. # define <name> SML <host> <port> [<interval> [<timeout>]]
  16. #
  17. # If <interval> is positive, new values are read every <interval> seconds.
  18. # If <interval> is 0, new values are read whenever a get request is called
  19. # on <name>. The default for <interval> is 60 (i.e. 1 minutes).
  20. #
  21. # get <name> <key>
  22. #
  23. # where <key> is one of minPower, maxPower, lastPower, avgPower, DAYPOWER, MONTHPOWER, YEARPOWER, TOTALPOWER
  24. ##############################################################################
  25. package main;
  26. use IO::Socket::INET;
  27. use Blocking;
  28. my @gets = ('minPower', # min value
  29. 'maxPower', # max value
  30. 'lastPower', # last value
  31. 'avgPower', # avagare value in interval
  32. 'DAYPOWER',
  33. 'MONTHPOWER',
  34. 'YEARPOWER',
  35. 'TOTALPOWER',
  36. 'NT',
  37. 'HT');
  38. sub
  39. SML_Initialize($)
  40. {
  41. my ($hash) = @_;
  42. $hash->{DefFn} = "energy_Define";
  43. $hash->{UndefFn} = "energy_Undef";
  44. $hash->{GetFn} = "energy_Get";
  45. $hash->{StateFn} = "energy_State";
  46. $hash->{SetFn} = "energy_Set";
  47. }
  48. sub
  49. energy_State($$$$)
  50. {
  51. my ($hash, $tim, $vt, $val) = @_;
  52. $hash->{READINGS}{$vt}{VAL} = $val;
  53. $hash->{READINGS}{$vt}{TIME} = TimeNow();
  54. Log3 $hash, 4, "$tim Readings: $vt Value: $val";
  55. return undef;
  56. }
  57. sub
  58. energy_Set($$$$)
  59. {
  60. my ($hash, $tim, $vt, $val) = @_;
  61. $hash->{READINGS}{$vt}{VAL} = $val;
  62. $hash->{READINGS}{$vt}{TIME} = TimeNow();
  63. Log3 $hash, 4, "$tim Readings: $vt Value: $val";
  64. if ( $vt eq "?"){
  65. return "Unknown argument ?, choose one of Interval DAYPOWER MONTHPOWER YEARPOWER TOTALPOWER";
  66. }
  67. if ( $vt eq "Interval"){
  68. $hash->{Interval} = $val;
  69. }
  70. return undef;
  71. }
  72. sub
  73. energy_Define($$)
  74. {
  75. my ($hash, $def) = @_;
  76. my @args = split("[ \t]+", $def);
  77. if (int(@args) < 4)
  78. {
  79. return "energy_Define: too few arguments. Usage:\n" .
  80. "define <name> SML <host> <port> [<interval> [<timeout>]]";
  81. }
  82. $hash->{Host} = $args[2];
  83. $hash->{Port} = $args[3];
  84. if ( int(@args) >= 5 ){
  85. if ( int($args[4]) >= 100 ){
  86. $hash->{Interval} = 100;
  87. }else{
  88. $hash->{Interval} = int($args[4]);
  89. }
  90. }
  91. $hash->{Timeout} = int(@args) >= 6 ? int($args[5]) : 4;
  92. #Log 4, "$hash->{NAME} will read from SML at $hash->{Host}:$hash->{Port} " ;
  93. Log3 $hash, 4, "$hash->{NAME} will read from SML at $hash->{Host}:$hash->{Port} " ;
  94. $hash->{Rereads} = 2; # number of retries when reading curPwr of 0
  95. $hash->{UseSVTime} = ''; # use the SV time as timestamp (else: TimeNow())
  96. $hash->{READINGS}{STATE}{VAL} = "Initializing";
  97. $hash->{READINGS}{STATE}{TIME} = $timenow;
  98. my $timenow = TimeNow();
  99. for my $get (@gets)
  100. {
  101. $hash->{READINGS}{$get}{VAL} = -1;
  102. $hash->{READINGS}{$get}{TIME} = $timenow;
  103. }
  104. RemoveInternalTimer($hash);
  105. InternalTimer(gettimeofday()+$hash->{Interval}, "sml_energy_Update", $hash, 0);
  106. #sml_energy_Update($hash);
  107. Log3 $hash, 3, "$hash->{NAME} will read from SML at $hash->{Host}:$hash->{Port} " ;
  108. return undef;
  109. }
  110. sub
  111. energy_Counter($)
  112. {
  113. my ($hash) = @_;
  114. my $ip = $hash->{Host};
  115. my $port = $hash->{Port};
  116. my $interval = $hash->{Interval};
  117. my $timeout = $hash->{Timeout};
  118. my $url = "/?action=20";
  119. my $socket ;
  120. my $buf ;
  121. my $message ;
  122. my @array ;
  123. my $counts = 0 ;
  124. my $HT = 0;
  125. my $NT = 0;
  126. Log3 $hash, 4, "$hash->{NAME} $ip : $port : $url";
  127. $socket = new IO::Socket::INET (
  128. PeerAddr => $ip,
  129. PeerPort => $port,
  130. Proto => 'tcp',
  131. Reuse => 0,
  132. Timeout => $timeout
  133. );
  134. Log3 $hash, 4, "$hash->{NAME} socket new";
  135. if (defined ($socket) and $socket and $socket->connected())
  136. {
  137. Log3 $hash, 4, "$hash->{NAME} Connected ...";
  138. print $socket "GET $url HTTP/1.0\r\n\r\n";
  139. $socket->autoflush(1);
  140. while ((read $socket, $buf, 1024) > 0)
  141. {
  142. Log 5,"buf: $buf";
  143. $message .= $buf;
  144. }
  145. }else{
  146. Log3 $hash, 3, "$hash->{NAME} Cannot open socket ...";
  147. $success = 1;
  148. return 0;
  149. }
  150. @array = split(/\n/,$message);
  151. foreach (@array){
  152. if ( $_ =~ /^<h3>(.*)HT:(.*)$/){
  153. $HT = 1;
  154. }
  155. if ( $HT == 1 ){
  156. if ( $_ =~ /^<h3>(.*) kWh<\/h3>(.*)$/){
  157. $HT = $1;
  158. $counts = 0;
  159. }
  160. }
  161. if ( $_ =~ /^<h3>(.*)NT:(.*)$/){
  162. $NT = 1;
  163. }
  164. if ( $NT == 1 ){
  165. if ( $_ =~ /^<h3>(.*) kWh<\/h3>(.*)$/){
  166. $NT = $1;
  167. $counts = 0;
  168. }
  169. }
  170. }
  171. $hash->{READINGS}{HT}{VAL} = $HT;
  172. $hash->{READINGS}{NT}{VAL} = $NT;
  173. my $gesammt = $HT + $NT;
  174. push @{$hash->{CHANGED}}, "HT: $HT kWh NT: $NT kWh Summe: $gesammt kWh";
  175. DoTrigger($hash->{NAME}, undef) if ($init_done);
  176. return "HT: $HT kWh NT: $NT kWh Summe: $gesammt kWh";
  177. }
  178. sub
  179. sml_energy_Update($)
  180. {
  181. my ($hash) = @_;
  182. my $name = $hash->{NAME};
  183. my $ip = $hash->{Host};
  184. my $port = $hash->{Port};
  185. my $interval = $hash->{Interval};
  186. #Log 4, "$hash->{NAME} tries to contact SML at $hash->{Host}:$hash->{Port}";
  187. Log3 $hash, 4, "$hash->{NAME} tries to contact SML at $hash->{Host}:$hash->{Port}";
  188. $hash->{helper}{RUNNING_PID} = BlockingCall("sml_energy_DoUpdate", $name."|".$ip."|".$port."|".$interval, "sml_energy_energyDone", 120, "sml_energy_energyAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
  189. }
  190. sub
  191. sml_energy_DoUpdate($)
  192. {
  193. my ($string) = @_;
  194. my ($name, $ip, $port,$interval) = split("\\|", $string);
  195. my $success = 0;
  196. my %readings = ();
  197. my $timenow = TimeNow();
  198. my $counts = 0 ;
  199. my $summary = 0 ;
  200. #my $url = "/InstantView/request/getPowerProfile.html?ts=0\&n=$interval\&param=Wirkleistung\&format=1";
  201. my $url = "/InstantView/request/getPowerProfile.html?ts=0\&n=$interval";
  202. my $socket ;
  203. my $buf ;
  204. my $message ;
  205. my @array;
  206. my $last;
  207. my $avg;
  208. my $min = 20000;
  209. my $max = 0;
  210. #Log 4, "$hash->{NAME} $url";
  211. Log3 $hash, 4, "$hash->{NAME} $url";
  212. $socket = new IO::Socket::INET (
  213. PeerAddr => $ip,
  214. PeerPort => $port,
  215. Proto => 'tcp',
  216. Reuse => 0,
  217. Timeout => 10
  218. );
  219. Log3 $hash, 4, "$name socket new";
  220. if (defined ($socket) and $socket and $socket->connected())
  221. {
  222. Log3 $name, 4, "$name Connected ...";
  223. print $socket "GET $url HTTP/1.0\r\n\r\n";
  224. $socket->autoflush(1);
  225. while ((read $socket, $buf, 1024) > 0)
  226. {
  227. Log 5,"buf: $buf";
  228. $message .= $buf;
  229. }
  230. $socket->close();
  231. Log3 $hash, 4, "$hash->{NAME} Socket closed";
  232. @array = split(/\n/,$message);
  233. foreach (@array){
  234. if ( $_ =~ /<v>(.*)<\/v>/ ){
  235. Log3 $hash, 5, "$hash->{NAME} got fresh values from $ip ($1)";
  236. if ( $1 eq "NaN" ){
  237. Log3 $hash, 5, "$hash->{NAME} NaN fehler ($1) summary: $summary";
  238. }else{
  239. $last = $1;
  240. $counts++ ;
  241. $summary += $1;
  242. if ($last < $min) {$min = $last};
  243. if ($last > $max) {$max = $last};
  244. }
  245. }
  246. if ( $_ =~ /<error>(.*)<\/error>/ )
  247. {
  248. if ( $1 eq "true" )
  249. {
  250. $success = 1;
  251. Log3 $name, 4, "$name error from the $ip ($1)";
  252. }
  253. }
  254. }
  255. }else{
  256. Log3 $hash, 3, "$hash->{NAME} Cannot open socket ...";
  257. $success = 1;
  258. # return 0;
  259. }
  260. if ( $success == 0 and $summary > 0 and $counts > 0){
  261. $avg = $summary/$counts;
  262. $avg =sprintf("%.2f",$avg);
  263. return "$name|$min|$max|$last|$avg|0" ;
  264. }else{
  265. return "$name|1|1|1|1|1";
  266. }
  267. } #sub ende
  268. sub
  269. sml_energy_energyDone($)
  270. {
  271. my ($string) = @_;
  272. return unless(defined($string));
  273. my (@a) = split("\\|", $string);
  274. my $hash = $defs{$a[0]};
  275. my ($min,$max,$last,$avg,$success) = ($a[1],$a[2],$a[3],$a[4],$a[5]);
  276. my $log = "";
  277. my $timenow = TimeNow();
  278. my $interval = $hash->{Interval};
  279. Log3 $hash, 4, "sml_energy_energyDone min: $min max: $max last: $last avg: $avg";
  280. delete($hash->{helper}{RUNNING_PID});
  281. # if ($hash->{Interval} > 0) {
  282. InternalTimer(gettimeofday() + $hash->{Interval}, "sml_energy_Update", $hash, 0);
  283. Log3 $hash, 4, "internalTimer funktion";
  284. # }
  285. if ( $success == 0){
  286. readingsBeginUpdate($hash);
  287. readingsBulkUpdate($hash, "minPower" , $min );
  288. readingsBulkUpdate($hash, "maxPower" , $max );
  289. readingsBulkUpdate($hash, "lastPower" , $last );
  290. readingsBulkUpdate($hash, "avgPower" , $avg );
  291. $log = "min: $min max: $max last: $last avg: $avg";
  292. $hash->{STATE} = "min: $min max: $max last: $last avg: $avg";
  293. my $newpower = $avg/(3600/$interval);
  294. $newpower = $newpower/1000;
  295. $newpower =sprintf("%.6f",$newpower);
  296. my ($date, $month, $day, $hour, $min, $sec) = $timenow =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
  297. # ######### DAYPOWER
  298. if ( $hash->{READINGS}{DAYPOWER}{VAL} eq "-1" ){
  299. $hash->{READINGS}{DAYPOWER}{VAL} = $newpower;
  300. }else{
  301. my ($dateLast, $monthLast, $dayLast, $hourLast, $minLast, $secLast) = $hash->{READINGS}{DAYPOWER}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
  302. my ($powLast) = $hash->{READINGS}{DAYPOWER}{VAL} =~ /^(.*)$/;
  303. Log3 $hash, 4, "$hash->{NAME} myhour: $dateLast $monthLast $dayLast $hourLast $minLast $secLast $powLast";
  304. $hash->{READINGS}{DAYPOWER}{TIME} = $timenow;
  305. if ( $dayLast eq $day ){ # es ist der gleiche Tag
  306. $powLast += $newpower ;
  307. #$hash->{READINGS}{DAYPOWER}{VAL} = $powLast;
  308. readingsBulkUpdate($hash, "DAYPOWER" , $powLast );
  309. Log3 $hash, 4, "$hash->{NAME} same day timenow: $timenow newpower $newpower powlast $powLast";
  310. $log .= " day: $powLast";
  311. }else{ # es ist eine Tag vergangen
  312. readingsBulkUpdate($hash, "DAYPOWER" , $newpower );
  313. #$hash->{READINGS}{DAYPOWER}{VAL} = $newpower;
  314. Log3 $hash, 4, "$hash->{NAME} new day timenow: $timenow newpower $newpower powlast $powLast";
  315. $log .= " day: $newpower";
  316. }
  317. }
  318. # ######### MONTH
  319. if ( $hash->{READINGS}{MONTHPOWER}{VAL} eq "-1" ){
  320. #$hash->{READINGS}{MONTHPOWER}{VAL} = $newpower;
  321. readingsBulkUpdate($hash, "MONTHPOWER" , $newpower );
  322. }else{
  323. my ($dateLast, $monthLast, $dayLast, $hourLast, $minLast, $secLast) = $hash->{READINGS}{MONTHPOWER}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
  324. my ($powLast) = $hash->{READINGS}{MONTHPOWER}{VAL} =~ /^(.*)$/;
  325. Log3 $hash, 4, "$hash->{NAME} month: $dateLast $monthLast $dayLast $hourLast $minLast $secLast $powLast";
  326. $hash->{READINGS}{MONTHPOWER}{TIME} = $timenow;
  327. if ( $monthLast eq $month ){ # es ist der gleiche Monat
  328. $powLast += $newpower ;
  329. #$hash->{READINGS}{MONTHPOWER}{VAL} = $powLast;
  330. readingsBulkUpdate($hash, "MONTHPOWER" , $powLast );
  331. Log3 $hash, 4, "$hash->{NAME} Gleicher Monat timenow: $timenow newpower $newpower powlast $powLast";
  332. $log .= " month: $powLast";
  333. }else{ # es ist eine Monat vergangen
  334. #$hash->{READINGS}{MONTHPOWER}{VAL} = $newpower;
  335. readingsBulkUpdate($hash, "MONTHPOWER" , $newpower );
  336. Log3 $hash, 4, "$hash->{NAME} Neuer Monat timenow: $timenow newpower $newpower powlast $powLast";
  337. $log .= " month: $newpower";
  338. }
  339. }
  340. # ######### YEARPOWER
  341. if ( $hash->{READINGS}{YEARPOWER}{VAL} eq "-1" ){
  342. readingsBulkUpdate($hash, "YEARPOWER" , $newpower );
  343. #$hash->{READINGS}{YEARPOWER}{VAL} = $newpower;
  344. }else{
  345. my ($dateLast, $monthLast, $dayLast, $hourLast, $minLast, $secLast) = $hash->{READINGS}{YEARPOWER}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
  346. my ($powLast) = $hash->{READINGS}{YEARPOWER}{VAL} =~ /^(.*)$/;
  347. Log3 $hash, 4, "$hash->{NAME} yearpower: $dateLast $monthLast $dayLast $hourLast $minLast $secLast $powLast";
  348. $hash->{READINGS}{YEARPOWER}{TIME} = $timenow;
  349. if ( $dateLast eq $date ){ # es ist das gleiche Jahr
  350. $powLast += $newpower ;
  351. readingsBulkUpdate($hash, "YEARPOWER" , $powLast );
  352. #$hash->{READINGS}{YEARPOWER}{VAL} = $powLast;
  353. Log3 $hash, 4, "$hash->{NAME} Gleiches Jahr timenow: $timenow newpower $newpower powlast $powLast";
  354. $log .= " year: $powLast";
  355. }else{ # es ist eine Jahr vergangen
  356. #$hash->{READINGS}{YEARPOWER}{VAL} = $newpower;
  357. readingsBulkUpdate($hash, "YEARPOWER" , $newpower );
  358. Log3 $hash, 4, "$hash->{NAME} Neues Jahr timenow: $timenow newpower $newpower powlast $powLast";
  359. $log .= " year: $newpower";
  360. }
  361. }
  362. # ######### TOTALPOWER
  363. $hash->{READINGS}{TOTALPOWER}{TIME} = $timenow;
  364. if ( $hash->{READINGS}{TOTALPOWER}{VAL} eq "-1" ){
  365. #$hash->{READINGS}{TOTALPOWER}{VAL} = $newpower;
  366. readingsBulkUpdate($hash, "TOTALPOWER" , $newpower );
  367. }else{
  368. my ($dateLast, $monthLast, $dayLast, $hourLast, $minLast, $secLast) = $hash->{READINGS}{TOTALPOWER}{TIME} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
  369. my ($powLast) = $hash->{READINGS}{TOTALPOWER}{VAL} =~ /^(.*)$/;
  370. Log3 $hash, 5, "$hash->{NAME} total: $dateLast $monthLast $dayLast $hourLast $minLast $secLast $powLast";
  371. $powLast += $newpower ;
  372. #$hash->{READINGS}{TOTALPOWER}{VAL} = $powLast;
  373. readingsBulkUpdate($hash, "TOTALPOWER" , $powLast );
  374. $log .= " total: $powLast";
  375. }
  376. $hash->{READINGS}{STATE}{VAL} = 'Connected';
  377. $hash->{READINGS}{STATE}{TIME} = $timenow;
  378. push @{$hash->{CHANGED}}, $log;
  379. DoTrigger($hash->{NAME}, undef) if ($init_done);
  380. Log3 $hash, 4, "$hash->{NAME} write log file: $log";
  381. Log3 $hash, 4, "$hash->{NAME} STATE: $hash->{READINGS}{STATE}{VAL} timenow: $timenow";
  382. readingsEndUpdate ($hash, 1 );
  383. }else{
  384. $hash->{STATE}{VAL} = 'disconnected';
  385. Log3 $hash, 3, "$hash->{NAME} can't update - device send a error";
  386. push @{$hash->{CHANGED}}, $log;
  387. DoTrigger($hash->{NAME}, undef) if ($init_done);
  388. Log3 $hash, 4, "$hash->{NAME} write log file: $log";
  389. Log3 $hash, 4, "$hash->{NAME} STATE: $hash->{READINGS}{STATE}{VAL} timenow: $timenow";
  390. }
  391. return undef;
  392. }
  393. sub
  394. sml_energy_energyAborted($)
  395. {
  396. my ($hash) = @_;
  397. Log3 $hash, 3, "$hash->{NAME} sml_energy_energyAborted";
  398. delete($hash->{helper}{RUNNING_PID});
  399. #new
  400. RemoveInternalTimer($hash);
  401. InternalTimer(gettimeofday()+$hash->{Interval}, "sml_energy_Update", $hash, 0);
  402. }
  403. sub
  404. energy_Get($@)
  405. {
  406. my ($hash, @args) = @_;
  407. return 'energy_Get needs two arguments' if (@args != 2);
  408. sml_energy_Update($hash) unless $hash->{Interval};
  409. my $get = $args[1];
  410. my $val = $hash->{Invalid};
  411. if ( $get eq "counter"){
  412. $val = energy_Counter($hash);
  413. }
  414. if (defined($hash->{READINGS}{$get})) {
  415. $val = $hash->{READINGS}{$get}{VAL};
  416. }
  417. if ( $get eq "?"){
  418. return "Unknown argument ?, choose one of counter minPower maxPower lastPower avgPower DAYPOWER MONTHPOWER YEARPOWER TOTALPOWER";
  419. }
  420. Log3 $hash, 3, "$args[0] $val";
  421. return $val;
  422. }
  423. sub
  424. energy_Undef($$)
  425. {
  426. my ($hash, $args) = @_;
  427. RemoveInternalTimer($hash) if $hash->{Interval};
  428. BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
  429. return undef;
  430. }
  431. 1;
  432. =pod
  433. =begin html
  434. <a name="SML"></a>
  435. <h3>SML</h3>
  436. <ul><p>
  437. This module supports "Intelligenter Strom Zhler"(ENBW) and "Sparzhler" (Yellow Strom).<br>
  438. The electricity meter will be polled in a defined interval (1-100) for new values.
  439. </p>
  440. <b>Define</b><br>
  441. <code>define &lt;name&gt; SML &lt;host&gt; &lt;port&gt; [&lt;interval&gt; &lt;timeout&gt;]</code><br>
  442. <p>
  443. Example:<br>
  444. define StromZ1 SML 192.168.178.20 <br>
  445. define StromZ2 SML 192.168.10.25 60 60 <br>
  446. </p>
  447. <b>Set</b><br>
  448. set &lt;name&gt; &lt;value&gt; &lt;nummber&gt;<br>where value is one of:<br><br>
  449. <ul>
  450. <li><code>TOTALPOWER</code> </li>
  451. <li><code>YEARPOWER </code> </li>
  452. <li><code>MONTHPOWER</code> </li>
  453. <li><code>DAYPOWER </code> </li>
  454. <li><code>Interval </code> </li>
  455. </ul>
  456. <br>Example:<br>
  457. set &lt;name&gt; TOTALPOWER 12345 <br><br>
  458. <b>Get</b><br>
  459. get &lt;name&gt; &lt;value&gt; <br>where value is one of:<br>
  460. <ul>
  461. <li><code>TOTALPOWER</code></li>
  462. <li><code>YEARPOWER </code></li>
  463. <li><code>MONTHPOWER</code></li>
  464. <li><code>DAYPOWER </code></li>
  465. <li><code>Interval </code> </li>
  466. </ul>
  467. <br>Example:<br>
  468. get &lt;name&gt; DAYPOWER<br>
  469. get &lt;name&gt; YEARPOWER<br><br>
  470. </ul>
  471. =end html
  472. =cut