36_EMT7110.pm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. # $Id: 36_EMT7110.pm 12157 2016-09-13 11:23:02Z hcs-svn $
  2. #
  3. # TODO:
  4. package main;
  5. use strict;
  6. use warnings;
  7. use SetExtensions;
  8. sub EMT7110_Parse($$);
  9. sub
  10. EMT7110_Initialize($)
  11. {
  12. my ($hash) = @_;
  13. $hash->{Match} = "^OK\\sEMT7110\\s";
  14. $hash->{SetFn} = "EMT7110_Set";
  15. #$hash->{GetFn} = "EMT7110_Get";
  16. $hash->{DefFn} = "EMT7110_Define";
  17. $hash->{UndefFn} = "EMT7110_Undef";
  18. $hash->{FingerprintFn} = "EMT7110_Fingerprint";
  19. $hash->{ParseFn} = "EMT7110_Parse";
  20. $hash->{AttrFn} = "EMT7110_Attr";
  21. $hash->{AttrList} = "IODev".
  22. " accumulatedPowerOffset".
  23. " pricePerKWH".
  24. " $readingFnAttributes";
  25. }
  26. sub
  27. EMT7110_Define($$)
  28. {
  29. my ($hash, $def) = @_;
  30. my @a = split("[ \t][ \t]*", $def);
  31. if(@a != 3 ) {
  32. my $msg = "wrong syntax: define <name> EMT7110 <addr>";
  33. Log3 undef, 2, $msg;
  34. return $msg;
  35. }
  36. $a[2] =~ m/(\d|[abcdef]|[ABCDEF]){4}/i;
  37. return "$a[2] is not a valid EMT7110 address" if( !defined($1) );
  38. my $name = $a[0];
  39. my $addr = $a[2];
  40. return "EMT7110 device $addr already used for $modules{EMT7110}{defptr}{$addr}->{NAME}." if( $modules{EMT7110}{defptr}{$addr}
  41. && $modules{EMT7110}{defptr}{$addr}->{NAME} ne $name );
  42. $hash->{addr} = $addr;
  43. $modules{EMT7110}{defptr}{$addr} = $hash;
  44. AssignIoPort($hash);
  45. if(defined($hash->{IODev}->{NAME})) {
  46. Log3 $name, 3, "$name: I/O device is " . $hash->{IODev}->{NAME};
  47. } else {
  48. Log3 $name, 1, "$name: no I/O device";
  49. }
  50. return undef;
  51. }
  52. #####################################
  53. sub
  54. EMT7110_Undef($$)
  55. {
  56. my ($hash, $arg) = @_;
  57. my $name = $hash->{NAME};
  58. my $addr = $hash->{addr};
  59. delete( $modules{EMT7110}{defptr}{$addr} );
  60. return undef;
  61. }
  62. #####################################
  63. sub
  64. EMT7110_Get($@)
  65. {
  66. my ($hash, $name, $cmd, @args) = @_;
  67. return "\"get $name\" needs at least one parameter" if(@_ < 3);
  68. my $list = "";
  69. return "Unknown argument $cmd, choose one of $list";
  70. }
  71. sub
  72. EMT7110_Fingerprint($$)
  73. {
  74. my ($name, $msg) = @_;
  75. return ( "", $msg );
  76. }
  77. # // Format
  78. # //
  79. # // OK EMT7110 84 81 8 237 0 13 0 2 1 6 1 -> ID 5451 228,5V 13mA 2W 2,62kWh
  80. # // OK EMT7110 84 81 8 247 1 12 0 56 1 13 1 -> ID 5451 229,5V 268mA 56W 2,69kWh
  81. # // OK EMT7110 ID ID VV VV AA AA WW WW KW KW Flags
  82. # // | | | | | | | | | | | `--- Bit0: Connected Bit1: Pairing
  83. # // | | | | | | | | | | `--- AccumulatedPower * 100 LSB
  84. # // | | | | | | | | | `------ AccumulatedPower * 100 MSB
  85. # // | | | | | | | | `--- Power (W) LSB
  86. # // | | | | | | | `------ Power (W) MSB
  87. # // | | | | | | `--- Current (mA) LSB
  88. # // | | | | | `------ Current (mA) MSB
  89. # // | | | | `--- Voltage (V) * 10 LSB
  90. # // | | | `----- Voltage (V) * 10 MSB
  91. # // | | `--- ID
  92. # // | `------- ID
  93. # // `--- fix "EMT7110"
  94. sub
  95. EMT7110_Parse($$)
  96. {
  97. my ($hash, $msg) = @_;
  98. my $name = $hash->{NAME};
  99. my( @bytes, $addr,$voltage,$current,$power,$accumulatedPower,$accumulatedPowerMeasured,$connected,$pairing );
  100. if( $msg =~ m/^OK EMT7110/ ) {
  101. @bytes = split( ' ', substr($msg, 11) );
  102. $addr = sprintf( "%02X%02X", $bytes[0], $bytes[1] );
  103. $voltage = ($bytes[2]*256 + $bytes[3] ) / 10.0;
  104. $current = $bytes[4]*256 + $bytes[5];
  105. $power = $bytes[6]*256 + $bytes[7];
  106. $accumulatedPowerMeasured = ($bytes[8]*256 + $bytes[9]) / 100.0;
  107. $connected = ($bytes[10] & 0x01);
  108. $pairing = ($bytes[10] & 0x02) >> 1;
  109. } else {
  110. DoTrigger($name, "UNKNOWNCODE $msg");
  111. Log3 $name, 3, "$name: Unknown code $msg, help me!";
  112. return undef;
  113. }
  114. if($pairing > 0) {
  115. return undef;
  116. }
  117. else {
  118. my $raddr = $addr;
  119. my $rhash = $modules{EMT7110}{defptr}{$raddr};
  120. my $rname = $rhash?$rhash->{NAME}:$raddr;
  121. my $accumulatedPowerOffset = AttrVal( $rname, "accumulatedPowerOffset", 0);
  122. $accumulatedPower = $accumulatedPowerMeasured - $accumulatedPowerOffset;
  123. my $costs = $accumulatedPower * AttrVal( $rname, "pricePerKWH", 0);
  124. if( !$modules{EMT7110}{defptr}{$raddr} ) {
  125. Log3 $name, 3, "EMT7110 Unknown device $rname, please define it";
  126. return "" if( !$hash->{LaCrossePair} );
  127. return "UNDEFINED EMT7110_$rname EMT7110 $raddr";
  128. }
  129. my @list;
  130. push(@list, $rname);
  131. $rhash->{lastReceiveTime} = TimeNow();
  132. readingsBeginUpdate($rhash);
  133. readingsBulkUpdate($rhash, "voltage", $voltage);
  134. readingsBulkUpdate($rhash, "current", $current);
  135. readingsBulkUpdate($rhash, "power", $power);
  136. readingsBulkUpdate($rhash, "accumulatedPowerMeasured", $accumulatedPowerMeasured);
  137. readingsBulkUpdate($rhash, "accumulatedPower", $accumulatedPower);
  138. readingsBulkUpdate($rhash, "costs", $costs);
  139. my $state = "V: $voltage";
  140. $state .= " C: $current";
  141. $state .= " P: $power";
  142. $state .= " A: $accumulatedPower";
  143. readingsBulkUpdate($rhash, "state", $state) if( Value($rname) ne $state );
  144. readingsEndUpdate($rhash,1);
  145. return @list;
  146. }
  147. }
  148. #####################################
  149. sub
  150. EMT7110_Set($@)
  151. {
  152. my ($hash, @a) = @_;
  153. my $name = shift @a;
  154. my $cmd = shift @a;
  155. my $arg = join(" ", @a);
  156. my $list = "resetAccumulatedPower";
  157. return $list if( $cmd eq '?' || $cmd eq '');
  158. if($cmd eq "resetAccumulatedPower") {
  159. CommandAttr(undef, "$name accumulatedPowerOffset " . $hash->{READINGS}{accumulatedPowerMeasured}{VAL});
  160. }
  161. else {
  162. return "Unknown argument $cmd, choose one of ".$list;
  163. }
  164. return undef;
  165. }
  166. sub
  167. EMT7110_Attr(@)
  168. {
  169. my ($cmd, $name, $attrName, $attrVal) = @_;
  170. return undef;
  171. }
  172. 1;
  173. =pod
  174. =item summary EMT7110 is a plug with integrated power meter functionality.
  175. =item summary_DE EMT7110 ist ein Zwischenstecker für die Energiemessung.
  176. =begin html
  177. <a name="EMT7110"></a>
  178. <h3>EMT7110</h3>
  179. <ul>
  180. The EMT7110 is a plug with integrated power meter functionality.<br>
  181. It can be integrated into FHEM via a <a href="#JeeLink">JeeLink</a> as the IODevice.<br><br>
  182. The EMT7110 sends with 9.579 kbit/s. Therefore it is necessary to set the JeeLink to a mode where it recieves this data rate.<br>
  183. This can be done using the initCommands attribute of the JeeLink.<br><br>
  184. If you have only 9.579 kbit/s sensors use this setting:<br>
  185. <code>attr myJeeLink initCommands 1r v</code><br><br>
  186. If you have also 17.241 kbit/s sensors (like TX29...) use this setting:<br>
  187. <code>attr myJeeLink initCommands 30t v</code><br>
  188. 30t means that the JeeLink toggles the data rate every 30 Seconds.<br>
  189. <br><a name="EMT7110_Define"></a>
  190. <b>Define</b>
  191. <code>define &lt;name&gt; EMT7110 &lt;addr&gt;</code> <br>
  192. addr is a 4 digit hex number to identify the EMT7110 device.<br>
  193. To enable autocreate for a certain time you must set LaCrossePairForSec in the <a href="#JeeLink">JeeLink</a> IODevice device.<br>
  194. <br>
  195. <a name="EMT7110_Set"></a>
  196. <b>Set</b>
  197. <ul>
  198. <li>
  199. resetAccumulatedPower<br>
  200. Sets the accumulatedPowerOffset attribute to the current value of accumulatedPowerMeasured.
  201. Don't forget to call save to write the new value to fhem.cfg
  202. </li>
  203. </ul><br>
  204. <a name="EMT7110_Get"></a>
  205. <b>Get</b>
  206. <ul>
  207. </ul><br>
  208. <a name="EMT7110_Readings"></a>
  209. <b>Readings</b>
  210. <ul>
  211. <li>accumulatedPowerMeasured<br>
  212. The accumulated power sent by the EMT7110. The EMT7110 accumulates the power even if it was removed and reconnected to the power outlet.
  213. The only way to reset it is to remove and reinsert the batteries in the EMT7110.
  214. </li><br>
  215. <li>accumulatedPower<br>
  216. Is accumulatedPowerMeasured minus the value of the accumulatedPowerOffset attribute value
  217. This reading is used for the A: part of state
  218. </li><br>
  219. <li>costs<br>
  220. Is accumulatedPower * pricePerKWH attribute value
  221. </li><br>
  222. <li>current<br>
  223. The measured current in mA
  224. </li><br>
  225. <li>power<br>
  226. The measured power in Watt
  227. </li><br>
  228. <li>voltage<br>
  229. The measured voltage in Volt
  230. </li><br>
  231. </ul>
  232. <a name="EMT7110_Attr"></a>
  233. <b>Attributes</b>
  234. <ul>
  235. <li>accumulatedPowerOffset<br>
  236. See accumulatedPower reading
  237. </li><br>
  238. <li>pricePerKWH<br>
  239. See costs reading
  240. </li><br>
  241. </ul><br>
  242. </ul>
  243. =end html
  244. =cut