61_EMWZ.pm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. ##############################################
  2. # $Id: 61_EMWZ.pm 14888 2017-08-13 12:07:12Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use Time::HiRes qw(gettimeofday);
  7. sub EMWZ_Get($@);
  8. sub EMWZ_Set($@);
  9. sub EMWZ_Define($$);
  10. sub EMWZ_GetStatus($);
  11. ###################################
  12. sub
  13. EMWZ_Initialize($)
  14. {
  15. my ($hash) = @_;
  16. $hash->{GetFn} = "EMWZ_Get";
  17. $hash->{SetFn} = "EMWZ_Set";
  18. $hash->{DefFn} = "EMWZ_Define";
  19. $hash->{AttrList} = "IODev dummy:1,0 model:EM1000WZ";
  20. }
  21. ###################################
  22. sub
  23. EMWZ_GetStatus($)
  24. {
  25. my ($hash) = @_;
  26. if(!$hash->{LOCAL}) {
  27. InternalTimer(gettimeofday()+300, "EMWZ_GetStatus", $hash, 0);
  28. }
  29. my $dnr = $hash->{DEVNR};
  30. my $name = $hash->{NAME};
  31. return "Empty status: dummy IO device" if(IsIoDummy($name));
  32. my $d = IOWrite($hash, sprintf("7a%02x", $dnr-1));
  33. if(!defined($d)) {
  34. my $msg = "EMWZ $name read error (GetStatus 1)";
  35. Log3 $name, 2, $msg;
  36. return $msg;
  37. }
  38. if($d eq ((pack('H*',"00") x 45) . pack('H*',"FF") x 6)) {
  39. my $msg = "EMWZ no device no. $dnr present";
  40. Log3 $name, 2, $msg;
  41. return $msg;
  42. }
  43. my $pulses=w($d,13);
  44. my $ec=w($d,49) / 10;
  45. if($ec <= 0) {
  46. my $msg = "EMWZ read error (GetStatus 2)";
  47. Log3 $name, 2, $msg;
  48. return $msg;
  49. }
  50. my $cur_energy = $pulses / $ec; # ec = U/kWh
  51. my $cur_power = $cur_energy / 5 * 60; # 5minute interval scaled to 1h
  52. if($cur_power > 30) { # 20Amp x 3 Phase
  53. my $msg = "EMWZ Bogus reading: curr. power is reported to be $cur_power";
  54. Log3 $name, 2, $msg;
  55. return $msg;
  56. }
  57. my %vals;
  58. $vals{"5min_pulses"} = $pulses;
  59. $vals{"energy"} = sprintf("%0.3f", $cur_energy);
  60. $vals{"power"} = sprintf("%.3f", $cur_power);
  61. $vals{"alarm_PA"} = w($d,45) . " Watt";
  62. $vals{"price_CF"} = sprintf("%.3f", w($d,47)/10000);
  63. $vals{"RperKW_EC"} = $ec;
  64. $hash->{READINGS}{cum_kWh}{VAL} = 0 if(!$hash->{READINGS}{cum_kWh}{VAL});
  65. $vals{"cum_kWh"} = sprintf("%0.3f",
  66. $hash->{READINGS}{cum_kWh}{VAL} + $vals{"energy"});
  67. $vals{summary} = sprintf("Pulses: %s Energy: %s Power: %s Cum: %s",
  68. $vals{"5min_pulses"}, $vals{energy},
  69. $vals{power}, $vals{cum_kWh});
  70. my $tn = TimeNow();
  71. my $idx = 0;
  72. foreach my $k (keys %vals) {
  73. my $v = $vals{$k};
  74. $hash->{CHANGED}[$idx++] = "$k: $v";
  75. $hash->{READINGS}{$k}{TIME} = $tn;
  76. $hash->{READINGS}{$k}{VAL} = $v
  77. }
  78. if(!$hash->{LOCAL}) {
  79. DoTrigger($name, undef) if($init_done);
  80. }
  81. $hash->{STATE} = "$cur_power kW";
  82. Log3 $name, 4, "EMWZ $name: $cur_power kW / $vals{energy}";
  83. return $hash->{STATE};
  84. }
  85. ###################################
  86. sub
  87. EMWZ_Get($@)
  88. {
  89. my ($hash, @a) = @_;
  90. return "argument is missing" if(int(@a) != 2);
  91. my $d = $hash->{DEVNR};
  92. my $msg;
  93. if($a[1] ne "status") {
  94. return "unknown argument $a[1], choose one of status";
  95. }
  96. $hash->{LOCAL} = 1;
  97. my $v = EMWZ_GetStatus($hash);
  98. delete $hash->{LOCAL};
  99. return "$a[0] $a[1] => $v";
  100. }
  101. sub
  102. EMWZ_Set($@)
  103. {
  104. my ($hash, @a) = @_;
  105. my $name = $hash->{NAME};
  106. my $v = $a[2];
  107. my $d = $hash->{DEVNR};
  108. my $msg;
  109. if($a[1] eq "price" && int(@a) == 3) {
  110. $v *= 10000; # Make display and input the same
  111. $msg = sprintf("79%02x2f02%02x%02x", $d-1, $v%256, int($v/256));
  112. } elsif($a[1] eq "alarm" && int(@a) == 3) {
  113. $msg = sprintf("79%02x2d02%02x%02x", $d-1, $v%256, int($v/256));
  114. } elsif($a[1] eq "rperkw" && int(@a) == 3) {
  115. $v *= 10; # Make display and input the same
  116. $msg = sprintf("79%02x3102%02x%02x", $d-1, $v%256, int($v/256));
  117. } else {
  118. return "Unknown argument $a[1], choose one of price alarm rperkw";
  119. }
  120. return "" if(IsIoDummy($name));
  121. my $ret = IOWrite($hash, $msg);
  122. if(!defined($ret)) {
  123. my $msg = "EMWZ $name read error (Set)";
  124. Log3 $name, 2, $msg;
  125. return $msg;
  126. }
  127. if(ord(substr($ret,0,1)) != 6) {
  128. $ret = "EMWZ Error occured: " . unpack('H*', $ret);
  129. Log3 $name, 2, $ret;
  130. return $ret;
  131. }
  132. return undef;
  133. }
  134. #############################
  135. sub
  136. EMWZ_Define($$)
  137. {
  138. my ($hash, $def) = @_;
  139. my @a = split("[ \t][ \t]*", $def);
  140. return "syntax: define <name> EMWZ devicenumber"
  141. if(@a != 3 || $a[2] !~ m,^[1-4]$,);
  142. $hash->{DEVNR} = $a[2];
  143. AssignIoPort($hash);
  144. EMWZ_GetStatus($hash);
  145. return undef;
  146. }
  147. 1;
  148. =pod
  149. =item summary EM1000WZ devices communicating over the EM1010PC
  150. =item summary_DE EM1000WZ Ger&auml;te angebunden &uuml;ber ein EM1010PC
  151. =begin html
  152. <a name="EMWZ"></a>
  153. <h3>EMWZ</h3>
  154. <ul>
  155. <a name="EMWZdefine"></a>
  156. <b>Define</b>
  157. <ul>
  158. <code>define &lt;name&gt; EMWZ &lt;device-number&gt;</code>
  159. <br><br>
  160. Define up to 4 EM1000WZ attached to the EM1010PC. The device number must
  161. be between 1 and 4. Defining an EMWZ will schedule an internal task, which
  162. reads the status of the device every 5 minutes, and triggers notify/filelog
  163. commands. <br><br>
  164. Example:
  165. <ul>
  166. <code>define emwz EMWZ 1</code><br>
  167. </ul>
  168. </ul>
  169. <br>
  170. <a name="EMWZset"></a>
  171. <b>Set</b>
  172. <ul>
  173. <code>set EMWZdevice &lt;param&gt; &lt;value&gt;</code><br><br>
  174. where param is one of:
  175. <ul>
  176. <li>rperkw<br>
  177. Number of rotations for a KiloWatt of the EM1000WZ device (actually
  178. of the device where the EM1000WZ is attached to). Without setting
  179. this correctly, all other readings will be incorrect.</li>
  180. <li>alarm<br>
  181. Alarm in WATT. if you forget to set it, the default value is
  182. rediculously low (random), and if a value above this threshold is
  183. received, the EM1010PC will start beeping once every minute. It can
  184. be very annoying.</li>
  185. <li>price<br>
  186. The price of one KW in EURO (use e.g. 0.20 for 20 Cents). It is used
  187. only on the EM1010PC display, it is of no interest for FHEM.</li>
  188. </ul>
  189. </ul>
  190. <br>
  191. <a name="EMWZget"></a>
  192. <b>Get</b>
  193. <ul>
  194. <code>get EMWZ status</code>
  195. <br><br>
  196. This is the same command which is scheduled every 5 minutes internally.
  197. </ul>
  198. <br>
  199. <a name="EMWZattr"></a>
  200. <b>Attributes</b>
  201. <ul>
  202. <li><a href="#model">model</a> (EM1000WZ)</li>
  203. <li><a href="#attrdummy">dummy</a></li>
  204. <li><a href="#IODev">IODev</a></li><br>
  205. </ul>
  206. <br>
  207. </ul>
  208. =end html
  209. =cut