32_TechemWZ.pm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. ###############################################################################
  2. # $Id: 32_TechemWZ.pm 10662 2016-01-30 10:22:50Z herrmannj $
  3. #
  4. # this module is part of fhem under the same license
  5. # copyright 2015, joerg herrmann
  6. #
  7. # history
  8. # initial checkin
  9. #
  10. ###############################################################################
  11. package main;
  12. use strict;
  13. use warnings;
  14. use Time::HiRes qw(time);
  15. my %typeText = (
  16. '62' => 'warm water', #
  17. '72' => 'cold water', #
  18. '43' => 'heat meter', # compact V
  19. );
  20. sub
  21. TechemWZ_Initialize(@) {
  22. my ($hash) = @_;
  23. # require "Broker.pm";
  24. $hash->{Match} = "^b..446850[\\d]{8}..(?:43|62|72).*";
  25. $hash->{DefFn} = "TechemWZ_Define";
  26. $hash->{UndefFn} = "TechemWZ_Undef";
  27. $hash->{SetFn} = "TechemWZ_Set";
  28. $hash->{GetFn} = "TechemWZ_Get";
  29. $hash->{NotifyFn} = "TechemWZ_Notify";
  30. $hash->{ParseFn} = "TechemWZ_Parse";
  31. $hash->{AttrList} = "".$readingFnAttributes;
  32. return undef;
  33. }
  34. sub
  35. TechemWZ_Define(@) {
  36. my ($hash, $def) = @_;
  37. my ($name, $t, $id);
  38. ($name, $t, $id, $def) = split(/ /, $def,4);
  39. return "ID must have 8 digits" if ($id !~ /^\d{8}$/);
  40. return "ID $id already defined" if exists($modules{TechemWZ}{defptr}{$id});
  41. # house keeping
  42. if (exists($hash->{OLDDEF}) && ($hash->{DEF} ne $hash->{OLDDEF}) ) {
  43. my @a = split(/ /, $hash->{OLDDEF});
  44. delete($hash->{VERSION});
  45. delete($hash->{METER});
  46. delete($hash->{READINGS});
  47. delete($modules{TechemWZ}{defptr}{$a[0]});
  48. delete($hash->{helper}->{list});
  49. }
  50. # create crc table if required
  51. $data{WMBUS}{crc_table_13757} = TechemWZ_createCrcTable() unless (exists($data{WMBUS}{crc_table_13757}));
  52. $hash->{helper}->{listmode} = ($id eq '00000000')?1:0;
  53. $hash->{ID} = $id;
  54. $modules{TechemWZ}{defptr}{$id} = $hash;
  55. $hash->{FRIENDLY} = $def if (defined($def));
  56. # subscribe broadcast channels
  57. # TechemWZ_subscribe($hash, 'foo');
  58. TechemWZ_Run($hash) if $init_done;
  59. return undef;
  60. }
  61. sub
  62. TechemWZ_Undef(@) {
  63. my ($hash) = @_;
  64. my $id = $hash->{ID};
  65. delete($modules{TechemWZ}{defptr}{$id});
  66. return undef;
  67. }
  68. sub
  69. TechemWZ_Set(@) {
  70. my ($hash, $name, $cmd, @args) = @_;
  71. my $cnt = @args;
  72. return undef;
  73. }
  74. sub
  75. TechemWZ_Get(@) {
  76. my ($hash, $name, $cmd, @args) = @_;
  77. return undef unless ($hash->{helper}->{listmode});
  78. return "unknown command ($cmd): choose one of list" if ($cmd eq "?");
  79. return "unknown command ($cmd): choose one of list" if ($cmd ne "list");
  80. my $result = "";
  81. my $l = $hash->{helper}->{list};
  82. foreach my $key (sort { $l->{$a}->{msg}->{meter} <=> $l->{$b}->{msg}->{meter} } keys %{$l} ) {
  83. $result .= "$l->{$key}->{msg}->{long}\t";
  84. $result .= $typeText{$l->{$key}->{msg}->{type}}."\t";
  85. $result .= "$l->{$key}->{msg}->{meter}\t";
  86. $result .= "$l->{$key}->{msg}->{rssi}\t\n";
  87. }
  88. return $result;
  89. }
  90. sub
  91. TechemWZ_Notify (@) {
  92. my ($hash, $ntfyDev) = @_;
  93. return unless (($ntfyDev->{TYPE} eq 'CUL') || ($ntfyDev->{TYPE} eq 'Global'));
  94. foreach my $event (@{$ntfyDev->{CHANGED}}) {
  95. my @e = split(' ', $event);
  96. next unless defined($e[0]);
  97. TechemWZ_Run($hash) if ($e[0] eq 'INITIALIZED');
  98. # patch CUL.pm
  99. TechemWZ_IOPatch($hash, $e[1]) if (($e[0] eq 'ATTR') && ($e[2] eq 'rfmode') && ($e[3] eq 'WMBus_T'));
  100. # disable receiver
  101. if (($e[0] eq 'ATTR') && ($e[2] eq 'rfmode') && ($e[3] ne 'WMBus_T')) {
  102. readingsBeginUpdate($hash);
  103. readingsBulkUpdate($hash, "state", "standby (IO missing)", 1);
  104. readingsEndUpdate($hash, 1);
  105. }
  106. }
  107. return undef;
  108. }
  109. sub
  110. TechemWZ_Receive(@) {
  111. my ($hash, $msg, $raw) = @_;
  112. my @t = localtime(time);
  113. my ($ats, $ts);
  114. $hash->{VERSION} = $msg->{version};
  115. $hash->{METER} = $typeText{$msg->{type}};
  116. delete $hash->{CHANGETIME}; # clean up, workaround for fhem prior http://forum.fhem.de/index.php/topic,47474.msg391964.html#msg391964
  117. # day period changed
  118. $ats = ReadingsTimestamp($hash->{NAME},"current_period", "0");
  119. $ts = sprintf ("%02d-%02d-%02d 00:00:00", $msg->{actual}->{year}, $msg->{actual}->{month}, $msg->{actual}->{day});
  120. if ($ats ne $ts) {
  121. my $i;
  122. readingsBeginUpdate($hash);
  123. $hash->{".updateTimestamp"} = $ts;
  124. $i = $#{ $hash->{CHANGED} };
  125. readingsBulkUpdate($hash, "meter", $msg->{meter});
  126. $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
  127. $i = $#{ $hash->{CHANGED} };
  128. readingsBulkUpdate($hash, "current_period", $msg->{actualVal});
  129. $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
  130. readingsEndUpdate($hash, 1);
  131. }
  132. # billing period changed
  133. $ats = ReadingsTimestamp($hash->{NAME},"previous_period", "0");
  134. $ts = sprintf ("20%02d-%02d-%02d 00:00:00", $msg->{last}->{year}, $msg->{last}->{month}, $msg->{last}->{day});
  135. if ($ats ne $ts) {
  136. my $i;
  137. readingsBeginUpdate($hash);
  138. $hash->{".updateTimestamp"} = $ts;
  139. $i = $#{ $hash->{CHANGED} };
  140. readingsBulkUpdate($hash, "previous_period", $msg->{lastVal});
  141. $hash->{CHANGETIME}->[$#{ $hash->{CHANGED} }] = $ts if ($#{ $hash->{CHANGED} } != $i ); # only add ts if there is a event to
  142. readingsEndUpdate($hash, 1);
  143. }
  144. return undef;
  145. }
  146. sub
  147. TechemWZ_Run(@) {
  148. my ($hash) = @_;
  149. # find a CUL
  150. foreach my $d (keys %defs) {
  151. # live patch CUL.pm
  152. TechemWZ_IOPatch($hash, $d) if ($defs{$d}{TYPE} eq "CUL");
  153. }
  154. return undef;
  155. }
  156. # live patch CUL.pm, aka THE HACK
  157. sub
  158. TechemWZ_IOPatch(@) {
  159. my ($hash, $iodev) = @_;
  160. return undef unless (AttrVal($iodev, 'rfmode', '') eq 'WMBus_T');
  161. # see if already patched
  162. readingsSingleUpdate($hash, 'state', 'listening', 1);
  163. return undef if ($defs{$iodev}{Clients} =~ /TechemWZ/ );
  164. $defs{$iodev}{Clients} = ':TechemWZ'.$defs{$iodev}{Clients};
  165. $defs{$iodev}{'.clientArray'} = undef;
  166. return undef;
  167. }
  168. sub
  169. TechemWZ_Parse(@) {
  170. my ($iohash, $msg) = @_;
  171. my ($message, $rssi);
  172. ($msg, $rssi) = split (/::/, $msg);
  173. $msg = TechemWZ_SanityCheck($msg);
  174. return '' unless $msg;
  175. my @m = ($msg =~ m/../g);
  176. my @d;
  177. # parse
  178. ($message->{long}, $message->{short}) = TechemWZ_ParseID(@m);
  179. $message->{type} = TechemWZ_ParseSubType(@m);
  180. $message->{version} = TechemWZ_ParseSubVersion(@m);
  181. $message->{rssi} = ($rssi)?$rssi:"?";
  182. # metertype specific adjustment
  183. if ($message->{type} =~ /62|72/) {
  184. $message->{lastVal} = TechemWZ_ParseLastPeriod(@m);
  185. $message->{actualVal} = TechemWZ_ParseActualPeriod(@m);
  186. ($message->{actual}->{year}, $message->{actual}->{month}, $message->{actual}->{day}) = TechemWZ_ParseActualDate(@m);
  187. ($message->{last}->{year}, $message->{last}->{month}, $message->{last}->{day}) = TechemWZ_ParseLastDate(@m);
  188. $message->{lastVal} /= 10;
  189. $message->{actualVal} /= 10;
  190. $message->{meter} = $message->{lastVal} + $message->{actualVal};
  191. } elsif ($message->{type} =~ /43/) {
  192. $message->{lastVal} = TechemWZ_WMZ_Type1_ParseLastPeriod(@m);
  193. $message->{actualVal} = TechemWZ_WMZ_Type1_ParseActualPeriod(@m);
  194. ($message->{actual}->{year}, $message->{actual}->{month}, $message->{actual}->{day}) = TechemWZ_WMZ_Type1_ParseActualDate(@m);
  195. ($message->{last}->{year}, $message->{last}->{month}, $message->{last}->{day}) = TechemWZ_ParseLastDate(@m);
  196. $message->{meter} = $message->{lastVal} + $message->{actualVal};
  197. }
  198. # list
  199. if (exists( $modules{TechemWZ}{defptr}{'00000000'} ) && defined( $defs{$modules{TechemWZ}{defptr}{'00000000'}->{NAME}} )) {
  200. my $listdev = $modules{TechemWZ}{defptr}{'00000000'};
  201. $listdev->{helper}->{list}->{$message->{long}}->{msg} = $message;
  202. push @d, $listdev->{NAME};
  203. }
  204. # dispatch
  205. if (exists( $modules{TechemWZ}{defptr}{$message->{long}})) {
  206. my $deviceHash = $modules{TechemWZ}{defptr}{$message->{long}};
  207. TechemWZ_Receive($deviceHash, $message);
  208. push @d, $deviceHash->{NAME};
  209. }
  210. if (defined($d[0])) {
  211. return (@d);
  212. } else {
  213. return (''); # discard neighbor devices
  214. }
  215. }
  216. sub
  217. TechemWZ_SanityCheck(@) {
  218. my ($msg) = @_;
  219. my $rssi;
  220. my $t;
  221. my $dbg = 4;
  222. #($msg, $rssi) = split (/::/, $msg);
  223. my @m = ((substr $msg,1) =~ m/../g);
  224. # at least 3 chars
  225. if (length($msg) < 3) {
  226. Log3 ("TechemWZ", $dbg, "msg incomplete $msg");
  227. return undef;
  228. }
  229. # msg length without crc blocks
  230. my $l = hex(substr $msg, 1, 2) + 1;
  231. # full crc payload blocks
  232. my $fb = int(($l - 10) / 16);
  233. # remaining bytes ?
  234. my $rb = ($l - 10) % 16;
  235. # required len
  236. my $rl = $l + 2 + ($fb * 2) + (($rb)?2:0);
  237. if (($rl * 2) > (length($msg) -1)) {
  238. Log3 ("TechemWZ", $dbg, "msg incomplete $msg");
  239. return undef;
  240. }
  241. # CRC first 10 byte, then chunks of 16 byte then remaining
  242. if ((substr $msg, 21, 4) ne TechemWZ_crc16_13757(substr $msg, 1, 20)) {
  243. Log3 ("TechemWZ", $dbg, "crc error $msg");
  244. return undef;
  245. } else {
  246. $t = substr $msg, 3, 18;
  247. }
  248. for (my $i = 0; $i<$fb; $i++) {
  249. if ((substr $msg, 57 + ($i * 36), 4) ne TechemWZ_crc16_13757(substr $msg, 25 + ($i * 36), 32)) {
  250. Log3 ("TechemWZ", $dbg, "crc error $msg");
  251. return undef;
  252. } else {
  253. $t .= substr $msg, 25 + ($i * 36), 32;
  254. }
  255. }
  256. if ($rb) {
  257. if ((substr $msg, 25 + ($fb * 36) + ($rb * 2), 4) ne TechemWZ_crc16_13757(substr $msg, 25 + ($fb * 36), $rb * 2)) {
  258. Log3 ("TechemWZ", $dbg, "crc error $msg");
  259. return undef;
  260. } else {
  261. $t .= substr $msg, 25 + ($fb * 36), ($rb * 2);
  262. }
  263. }
  264. return $t;
  265. }
  266. sub
  267. TechemWZ_ParseID(@) {
  268. my @m = @_;
  269. return ("$m[6]$m[5]$m[4]$m[3]", "$m[4]$m[3]");
  270. }
  271. sub
  272. TechemWZ_ParseSubType(@) {
  273. my @m = @_;
  274. return "$m[8]";
  275. }
  276. sub
  277. TechemWZ_ParseSubVersion(@) {
  278. my @m = @_;
  279. return "$m[7]";
  280. }
  281. sub
  282. TechemWZ_ParseLastPeriod(@) {
  283. my @m = @_;
  284. return hex("$m[14]$m[13]");
  285. }
  286. sub
  287. TechemWZ_ParseActualPeriod(@) {
  288. my @m = @_;
  289. return hex("$m[18]$m[17]");
  290. }
  291. sub
  292. TechemWZ_ParseActualDate(@) {
  293. my @m = @_;
  294. my @t = localtime(time);
  295. my $b = hex("$m[16]$m[15]");
  296. my $d = ($b >> 4) & 0x1F;
  297. my $m = ($b >> 9) & 0x0F;
  298. my $y = $t[5] + 1900;
  299. return ($y, $m, $d);
  300. }
  301. sub
  302. TechemWZ_ParseLastDate(@) {
  303. my @m = @_;
  304. my $b = hex("$m[12]$m[11]");
  305. my $d = ($b >> 0) & 0x1F;
  306. my $m = ($b >> 5) & 0x0F;
  307. my $y = ($b >> 9) & 0x3F;
  308. return ($y, $m, $d);
  309. }
  310. ###############################################################################
  311. #
  312. # Compact 5 heatmeter
  313. #
  314. ###############################################################################
  315. sub
  316. TechemWZ_WMZ_Type1_ParseLastPeriod(@) {
  317. my @m = @_;
  318. return hex("$m[15]$m[14]$m[13]");
  319. }
  320. sub
  321. TechemWZ_WMZ_Type1_ParseActualPeriod(@) {
  322. my @m = @_;
  323. return hex("$m[19]$m[18]$m[17]");
  324. }
  325. sub
  326. TechemWZ_WMZ_Type1_ParseActualDate(@) {
  327. my @m = @_;
  328. my @t = localtime(time);
  329. my $b = hex("$m[21]$m[20]");
  330. my $d = ($b >> 7) & 0x1F;
  331. my $m = (hex("$m[16]") >> 3) & 0x0F;
  332. my $y = $t[5] + 1900;
  333. return ($y, $m, $d);
  334. }
  335. sub
  336. TechemWZ_createCrcTable(@) {
  337. my $poly = 0x3D65;
  338. my $c;
  339. my @table;
  340. for (my $i=0; $i<256; $i++) {
  341. $c = ($i << 8);
  342. for (my $j=0; $j<8; $j++) {
  343. if (($c & 0x8000) != 0) {
  344. $c = 0xFFFF & (($c << 1) ^ $poly);
  345. } else {
  346. $c <<= 1;
  347. }
  348. }
  349. $table[$i] = $c;
  350. }
  351. return \@table;
  352. }
  353. sub
  354. TechemWZ_crc16_13757(@) {
  355. my ($msg) = @_;
  356. my @table = @{$data{WMBUS}{crc_table_13757}};
  357. my @in = split '', pack 'H*', $msg;
  358. my $crc = 0x0000;
  359. for (my $i=0; $i<int(@in); $i++) {
  360. $crc = 0xffff & ( ($crc << 8) ^ $table[(($crc >> 8) ^ ord($in[$i]))] );
  361. }
  362. return sprintf ("%04lX", $crc ^ 0xFFFF);
  363. }
  364. # message bus ahead
  365. # sub
  366. #TechemWZ_subscribe(@) {
  367. # my ($hash, $topic) = @_;
  368. # broker::subscribe ($topic, $hash->{NAME}, \&TechemWZ_rcvBCST);
  369. # return undef;
  370. #}
  371. #sub
  372. #TechemWZ_sendBCST(@) {
  373. # my ($hash, $topic, $msg) = @_;
  374. # broker::publish ($topic, $hash->{NAME}, $msg);
  375. # return undef;
  376. #}
  377. #sub
  378. #TechemWZ_rcvBCST(@) {
  379. # my ($name, $topic, $sender, $msg) = @_;
  380. # my $hash = $defs{$name};
  381. # return undef;
  382. #}
  383. 1;
  384. =pod
  385. =begin html
  386. <a name="TechemWZ"></a>
  387. <h3>TechemWZ</h3>
  388. <ul>
  389. This module reads the transmission of techem volume data meter. Currently supported device:
  390. <p>
  391. <ul>
  392. <li>Messkapsel-Wasserzähler radio 3 (cold, warm water)</li>
  393. <li>Messkapsel-Wärmemengenzähler compact V (heating energy)</li>
  394. </ul>
  395. <br>
  396. It will display
  397. <ul>
  398. <li>meter data for current billing period</li>
  399. <li>meter data for previous billing period including date of request</li>
  400. <li>cumulative meter data</li>
  401. </ul>
  402. <br>
  403. It will require a CUL in WMBUS_T mode, although the CUL may temporary set into that mode.
  404. The module keeps track of the CUL rfmode.
  405. <br>
  406. <br>
  407. <a name="TechemWZ_preliminary"></a>
  408. <b>preliminary</b>
  409. <p>
  410. Techem volume data meter does not transmit their printed meter ID. Instead they transmit the ID of the build in radio module.
  411. <p>
  412. Therefore a <b>"list-mode"</b> is available which collects all Techem meter device in range to help you find out the right one.
  413. That "list-mode" will be activated by defining a TechemWZ device with id "00000000". Let it run for a while and do a "get &lt;name&gt; list".
  414. You will see a list of available (received) Techem device with their ID and meter data. Choose the right one (keep in mind that the meter reading reflects last midnight), note down their ID and define the appropriate device. After done the device with ID "00000000" can be removed.
  415. <br>
  416. <br>
  417. <a name="TechemWZ_Define"></a>
  418. <b>Define</b>
  419. <br>
  420. <code>define &lt;name&gt; TechemWZ &lt;8 digit ID&gt; [&lt;speaking name&gt;]</code>
  421. <ul>
  422. <li>ID: 8 digit ID (see list mode above)</li>
  423. <li>speaking name: (optional) human readable identification</li>
  424. </ul>
  425. <br>
  426. <a name="TechemWZ_Readings"></a>
  427. <b>Readings</b>
  428. <ul>
  429. <li>current_period: meter data for current billing period
  430. <br><i>cumulated since the start of the current billing period. The reading will be updated once a day, after receiving the first update. Reading time will reflect the time of data (not the time where the data were received)</i></br>
  431. </li>
  432. <li>previous_period: meter data for last billing period
  433. <br><i>meter rading at the end of the last billing period. The reading will be updated if a new billing period starts. Reading time will reflect the last day of previous billing period (not the time where the data were received)</i></br>
  434. </li>
  435. <li>meter: cumulative meter data.
  436. <br><i>The same data that will be shown at the Techem (mechanical) display</i></br>
  437. </li>
  438. <br>
  439. </ul>
  440. <a name="TechemWZ_Get"></a>
  441. <b>Get</b>
  442. <ul>
  443. <li>list: print a list of available (received) Techem device with their ID and meter data
  444. <br><i><u>only available if device ID is "00000000" (list-mode)</u></i></br>
  445. </li>
  446. <br>
  447. </ul>
  448. <a name="TechemWZ_Internals"></a>
  449. <b>Internals</b>
  450. <ul>
  451. <li>friendly: human readable identification of meter as specified by define</li>
  452. <br>
  453. </ul>
  454. </ul>
  455. =end html
  456. =begin html_DE
  457. <a name="TechemWZ"></a>
  458. <h3>TechemWZ</h3>
  459. <ul>
  460. Das modul empfängt Daten von Techem Volumenzählern. Unterstützte Zählertypen sind
  461. <p>
  462. <ul>
  463. <li>Messkapsel-Wasserzähler radio 3 (Kalt-, Warmwasser)</li>
  464. <li>Messkapsel-Wärmemengenzähler compact V</li>
  465. </ul>
  466. <br>
  467. Empfangen werden:
  468. <ul>
  469. <li>Wert des aktuellen Abrechnungszeitraumes</li>
  470. <li>Wert des vorhergehenden Abrechnungszeitraumes einschließlich des Ablesedatums</li>
  471. <li>Gesamter aufgelaufener Verbrauchswert</li>
  472. </ul>
  473. <br>
  474. Zum Empfang wird ein CUL im WMBUS_T mode benötigt. Dabei ist es ausreichend ihn vorrübergehend in diesen Modus zu schalten. Das Modul überwacht den rfmode aller verfügbaren CUL
  475. <br>
  476. <br>
  477. <a name="TechemWZ_preliminary"></a>
  478. <b>Vorbereitung</b>
  479. <p>
  480. Leider übertragen die Techem Volumenzähler nicht die aufgedruckte Zählernummer. Übertragen wird nur die ID des eingebauten Funkmoduls.
  481. <p>
  482. Das Modul stellt daher einen <b>"list-mode"</b> zur Verfügung. Damit kann eine Liste aller empfangenen Techem Volumenzähler anzeigt werden. Der "list-mode" wird aktiviert indem ein TechemWZ device mit der ID "00000000" definiert wird.
  483. Lassen Sie dieses device einige Zeit laufen damit es Informationen über die verfügbaren Zähler sammeln kann. Rufen Sie dann "get &lt;name&gt; list" auf um eine Liste der empfangenen Techem Volumenzähler, ihrer ID sowie der dazugehörigen Zählerstände zu sehen. Denken Sie daran das dies die Werte des letzten Tageswechsels sind.
  484. Notieren Sie sich anhand dieser Angaben die ID der gesuchten Zähler und definieren sie damit die entsprechenden TechemWZ device. Das list-mode device mit der ID "00000000" kann danach gefahrlos gelöscht werden.
  485. <br>
  486. <br>
  487. <a name="TechemWZ_Define"></a>
  488. <b>Define</b>
  489. <br>
  490. <code>define &lt;name&gt; TechemWZ &lt;8 digit ID&gt; [&lt;speaking name&gt;]</code>
  491. <ul>
  492. <li>ID: 8 stellige ID des Funkmoduls(siehe "list-mode")</li>
  493. <li>speaking name: (optional) Bezeichnung</li>
  494. </ul>
  495. <br>
  496. <a name="TechemWZ_Readings"></a>
  497. <b>Readings</b>
  498. <ul>
  499. <li>current_period: Wert des aktuellen Abrechnungszeitraumes
  500. <br><i>Der kumulierte Verbrauch seid dem Start des aktuellen Abrechnungszeitraumes. Das reading wird einmal am Tag aktualisiert. Die Zeit kennzeichnet den Stand der Daten. (und nicht den Empfangszeitpunkt der Daten)</i></br>
  501. </li>
  502. <li>previous_period: Wert des letzten Ablesezeitpunktes
  503. <br><i>Zählerstand zum letzten Abrechnungszeitpunkt. Das reading wird zum Ablesezeitpunkt aktualisiert. Die Zeit kennzeichnet das Ablesedatum (und nicht den Empfangszeitpunkt der Daten)</i></br>
  504. </li>
  505. <li>meter: gesamter Verbrauch.
  506. <br><i>Der Zählerstand so wie er an der (mechanischen) Anzeige des Zählers abgelesen werden kann</i></br>
  507. </li>
  508. <br>
  509. </ul>
  510. <a name="TechemWZ_Get"></a>
  511. <b>Get</b>
  512. <ul>
  513. <li>list: gibt eine Liste der empfangenen Techem Volumenzähler, ihrer ID sowie der dazugehörigen Zählerstände aus.
  514. <br><i><u>nur im "list-mode" (ID "00000000") verfügbar</u></i></br>
  515. </li>
  516. <br>
  517. </ul>
  518. <a name="TechemWZ_Internals"></a>
  519. <b>Internals</b>
  520. <ul>
  521. <li>friendly: die beim define übergebene, zusätzliche Bezeichnung</li>
  522. <br>
  523. </ul>
  524. </ul>
  525. =end html_DE
  526. =cut