km271.pl 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Time::HiRes qw(gettimeofday);
  5. sub kmcrc($);
  6. sub fmt_now();
  7. my $stx = pack('H*', "02");
  8. my $dle = pack('H*', "10");
  9. my $etx = pack('H*', "03");
  10. my $nak = pack('H*', "15");
  11. my $logmode = pack('H*', "EE00001003FD");
  12. # Thx to Himtronics
  13. # http://www.mikrocontroller.net/topic/141831
  14. # http://www.mikrocontroller.net/attachment/63563/km271-protokoll.txt
  15. # Buderus documents: 63011376, 63011377, 63011378
  16. # http://www.buderus.de/pdf/unterlagen/0063061377.pdf
  17. my %trhash =
  18. (
  19. "8000" => 'Betriebswerte_1_HK1', # 76, 4 [repeat]
  20. "8001" => 'Betriebswerte_2_HK1', # 0 (22:33), 2 (7:33)
  21. "8002" => 'Vorlaufsolltemperatur_HK1', # 50-65
  22. "8003" => 'Vorlaufisttemperatur_HK1', # Schwingt um soll herum
  23. "8004" => 'Raumsolltemperatur_HK1', # 34 (22:33) 42 (7:33)
  24. "8005" => 'Raumisttemperatur_HK1',
  25. "8006" => 'Einschaltoptimierungszeit_HK1',
  26. "8007" => 'Ausschaltoptimierungszeit_HK1',
  27. "8008" => 'Pumpenleistung_HK1', # 0/100 == Ladepumpe
  28. "8009" => 'Mischerstellung_HK1',
  29. "800a" => 'nicht_belegt',
  30. "800b" => 'nicht_belegt',
  31. "800c" => 'Heizkennlinie_HK1_bei_+_10_Grad', # bei Umschaltung tag/nacht
  32. "800d" => 'Heizkennlinie_HK1_bei_0_Grad', # bei Umschaltung tag/nacht
  33. "800e" => 'Heizkennlinie_HK1_bei_-_10_Grad', # bei Umschaltung tag/nacht
  34. "800f" => 'nicht_belegt',
  35. "8010" => 'nicht_belegt',
  36. "8011" => 'nicht_belegt',
  37. "8112" => 'Betriebswerte_1_HK2',
  38. "8113" => 'Betriebswerte_1_HK2',
  39. "8114" => 'Vorlaufsolltemperatur_HK2',
  40. "8115" => 'Vorlaufisttemperatur_HK2',
  41. "8116" => 'Raumsolltemperatur_HK2',
  42. "8117" => 'Raumisttemperatur_HK2',
  43. "8118" => 'Einschaltoptimierungszeit_HK2',
  44. "8119" => 'Ausschaltoptimierungszeit_HK2',
  45. "811a" => 'Pumpenleistung_HK2',
  46. "811b" => 'Mischerstellung_HK2',
  47. "811c" => 'nicht_belegt',
  48. "811d" => 'nicht_belegt',
  49. "811e" => 'Heizkennlinie_HK2_bei_+_10_Grad', # == HK1 - (1 bis 3)
  50. "811f" => 'Heizkennlinie_HK2_bei_0_Grad', # == HK1 - (1 bis 3)
  51. "8120" => 'Heizkennlinie_HK2_bei_-_10_Grad', # == HK1 - (1 bis 3)
  52. "8121" => 'nicht_belegt',
  53. "8122" => 'nicht_belegt',
  54. "8123" => 'nicht_belegt',
  55. "8424" => 'Betriebswerte_1_WW',
  56. "8425" => 'Betriebswerte_2_WW', # 0 64 96 104 225 228
  57. "8426" => 'Warmwassersolltemperatur', # 10/55
  58. "8427" => 'Warmwasseristtemperatur', # 32-55
  59. "8428" => 'Warmwasseroptimierungszeit',
  60. "8429" => 'Ladepumpe', # 0 1 (an/aus?)
  61. # 1377, page 13
  62. "882a" => 'Kesselvorlaufsolltemperatur',
  63. "882b" => 'Kesselvorlaufisttemperatur', # == Vorlaufisttemperatur_HK1
  64. "882c" => 'Brennereinschalttemperatur', # 5-81
  65. "882d" => 'Brennerausschalttemperatur', # 19-85
  66. "882e" => 'Kesselintegral_1', # 0-23
  67. "882f" => 'Kesselintegral_2', # 0-255
  68. "8830" => 'Kesselfehler',
  69. "8831" => 'Kesselbetrieb', # 0 2 32 34
  70. "8832" => 'Brenneransteuerung', # 0 1 (an/aus?)
  71. "8833" => 'Abgastemperatur',
  72. "8834" => 'modulare_Brenner_Stellwert',
  73. "8835" => 'nicht_belegt',
  74. "8836" => 'Brennerlaufzeit_1_Stunden_2',
  75. "8837" => 'Brennerlaufzeit_1_Stunden_1', # 176
  76. "8838" => 'Brennerlaufzeit_1_Stunden_0', # 0-255 (Minuten)
  77. "8839" => 'Brennerlaufzeit_2_Stunden_2',
  78. "883a" => 'Brennerlaufzeit_2_Stunden_1',
  79. "883b" => 'Brennerlaufzeit_2_Stunden_0',
  80. # 1377, page 16
  81. "893c" => 'Aussentemperatur', # 0 1 254 255
  82. "893d" => 'gedaempfte_Aussentemperatur', # 0 1 2
  83. "893e" => 'Versionsnummer_VK',
  84. "893f" => 'Versionsnummer_NK',
  85. "8940" => 'Modulkennung',
  86. "8941" => 'nicht_belegt',
  87. );
  88. die("Usage: km271.pl <device>\n") if(int(@ARGV) != 1);
  89. require Device::SerialPort;
  90. my $po = new Device::SerialPort($ARGV[0]);
  91. die("Can't open $ARGV[0]: $!\n") if(!$po);
  92. $po->reset_error();
  93. $po->baudrate(2400);
  94. $po->databits(8);
  95. $po->parity('none');
  96. $po->stopbits(1);
  97. $po->handshake('none');
  98. my $fdin = $po->FILENO;
  99. printf("Setting device into logmode\n");
  100. $po->write($logmode);
  101. $| = 1;
  102. my $tbuf = "";
  103. for(;;) {
  104. my ($rout, $rin) = ('', '');
  105. vec($rin, $fdin, 1) = 1;
  106. my $nfound = select($rout=$rin, undef, undef, undef);
  107. die("Select error: $!\n") if(!defined($nfound) || $nfound < 0);
  108. if(vec($rout, $fdin, 1)) {
  109. my $buf = $po->input();
  110. if(!defined($buf)) {
  111. printf("EOF on dev\n");
  112. exit(1);
  113. }
  114. $buf = unpack('H*', $buf);
  115. #printf("%s DEV %s\n", fmt_now(), $buf);
  116. if($buf eq "02") {
  117. $tbuf = "";
  118. $po->write($dle);
  119. next;
  120. }
  121. $tbuf .= $buf;
  122. my $len = length($tbuf);
  123. next if($tbuf !~ m/^(.*)1003(..)$/);
  124. my ($data, $crc) = ($1, $2);
  125. if(kmcrc($data) ne $crc) {
  126. printf("Wrong CRC in $tbuf ($crc vs. %s)\n", kmcrc($data));
  127. $tbuf = "";
  128. $po->write($nak);
  129. next;
  130. }
  131. $po->write($dle);
  132. $data =~ s/1010/10/g;
  133. if($data =~ m/^(8...)(..)/) {
  134. my ($fn, $arg) = ($1, $2);
  135. printf("%s %s %d\n", fmt_now(), $trhash{$fn}, hex($arg));
  136. } elsif($data eq "04000701c4024192") {
  137. # No data message
  138. } else {
  139. printf("%s UNKNOWN %s\n", fmt_now(), $data);
  140. }
  141. $tbuf = "";
  142. }
  143. }
  144. sub
  145. kmcrc($)
  146. {
  147. my $in = shift;
  148. my $x = 0;
  149. foreach my $a (split("", pack('H*', $in))) {
  150. $x ^= ord($a);
  151. }
  152. $x ^= 0x10;
  153. $x ^= 0x03;
  154. return sprintf("%02x", $x);
  155. }
  156. sub
  157. fmt_now()
  158. {
  159. my $now = gettimeofday()+0.0;
  160. my @t = localtime($now);
  161. my $t = sprintf("%04d-%02d-%02d_%02d:%02d:%02d.%03d",
  162. $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0],
  163. ($now-int($now)) * 1000);
  164. return $t;
  165. }