64_ESA.pm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. ##############################################
  2. # (c) by STefan Mayer (stefan(at)clumsy.ch) #
  3. # #
  4. # please feel free to contact me for any #
  5. # changes, improvments, suggestions, etc #
  6. # #
  7. ##############################################
  8. package main;
  9. use strict;
  10. use warnings;
  11. my %codes = (
  12. "19fa" => "ESA2000_LED",
  13. );
  14. #####################################
  15. sub
  16. ESA_Initialize($)
  17. {
  18. my ($hash) = @_;
  19. # S0119FA011E00007D6E003100000007C9 ESA2000_LED
  20. $hash->{Match} = "^S................................\$";
  21. $hash->{DefFn} = "ESA_Define";
  22. $hash->{UndefFn} = "ESA_Undef";
  23. $hash->{ParseFn} = "ESA_Parse";
  24. $hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model:esa2000-led loglevel:0,1,2,3,4,5,6 ignore:0,1";
  25. }
  26. #####################################
  27. sub
  28. ESA_Define($$)
  29. {
  30. my ($hash, $def) = @_;
  31. my @a = split("[ \t][ \t]*", $def);
  32. return "wrong syntax: define <name> ESA CODE" if(int(@a) != 3);
  33. $a[2] = lc($a[2]);
  34. return "Define $a[0]: wrong CODE format: specify a 4 digit hex value"
  35. if($a[2] !~ m/^[a-f0-9][a-f0-9][a-f0-9][a-f0-9]$/);
  36. $hash->{CODE} = $a[2];
  37. $modules{ESA}{defptr}{$a[2]} = $hash;
  38. AssignIoPort($hash);
  39. return undef;
  40. }
  41. #####################################
  42. sub
  43. ESA_Undef($$)
  44. {
  45. my ($hash, $name) = @_;
  46. delete($modules{ESA}{defptr}{$hash->{CODE}})
  47. if(defined($hash->{CODE}) &&
  48. defined($modules{ESA}{defptr}{$hash->{CODE}}));
  49. return undef;
  50. }
  51. #####################################
  52. sub
  53. ESA_Parse($$)
  54. {
  55. my ($hash, $msg) = @_;
  56. # 0123456789012345678901234567890123456789
  57. # S0119FA011E00007D6E003100000007C9F9 ESA2000_LED
  58. $msg = lc($msg);
  59. my $seq = substr($msg, 1, 2);
  60. my $cde = substr($msg, 3, 4);
  61. my $dev = substr($msg, 7, 4);
  62. my $val = substr($msg, 11, 22);
  63. Log 5, "ESA msg $msg";
  64. Log 5, "ESA seq $seq";
  65. Log 5, "ESA device $dev";
  66. Log 5, "ESA code $cde";
  67. my $type = "";
  68. foreach my $c (keys %codes) {
  69. $c = lc($c);
  70. if($cde =~ m/$c/) {
  71. $type = $codes{$c};
  72. last;
  73. }
  74. }
  75. if(!defined($modules{ESA}{defptr}{$dev})) {
  76. Log 3, "Unknown ESA device $dev, please define it";
  77. $type = "ESA" if(!$type);
  78. return "UNDEFINED ${type}_$dev ESA $dev";
  79. }
  80. my $def = $modules{ESA}{defptr}{$dev};
  81. my $name = $def->{NAME};
  82. return "" if(IsIgnored($name));
  83. my (@v, @txt);
  84. if($type eq "ESA2000_LED") {
  85. @txt = ( "repeat", "sequence", "total_ticks", "actual_ticks", "ticks_kwh", "raw", "total_kwh", "actual_kwh" );
  86. # Codierung Hex
  87. $v[0] = int(hex($seq) / 128) ? "+" : "-"; # repeated
  88. $v[1] = hex($seq) % 128;
  89. $v[2] = hex(substr($val,0,8));
  90. $v[3] = hex(substr($val,8,4));
  91. $v[4] = hex(substr($val,18,4)) ^ 25; # XOR 25, whyever bit 1,4,5 are swapped?!?!
  92. $v[5] = sprintf("CNT: %d%s CUM: %d CUR: %d TICKS: %d",
  93. $v[1], $v[0], $v[2], $v[3], $v[4]);
  94. $v[6] = $v[2]/$v[4]; # calculate kW
  95. $v[7] = $v[3]/$v[4]; # calculate kW
  96. $val = sprintf("CNT: %d%s CUM: %0.3f CUR: %0.3f TICKS: %d",
  97. $v[1], $v[0], $v[6], $v[7], $v[4]);
  98. # $v[0] = "$v[0] (Repeated)";
  99. # $v[1] = "$v[1] (Sequence)";
  100. # $v[2] = "$v[2] (Total)";
  101. # $v[3] = "$v[3] (Actual)";
  102. # $v[4] = "$v[4] (T/kWh)";
  103. } else {
  104. Log 3, "ESA Device $dev (Unknown type: $type)";
  105. return "";
  106. }
  107. my $now = TimeNow();
  108. my $max = int(@txt);
  109. if ( $def->{READINGS}{"sequence"}{VAL} ne $v[1] ) {
  110. Log GetLogLevel($name,4), "ESA $name: $val";
  111. for( my $i = 0; $i < $max; $i++) {
  112. $def->{READINGS}{$txt[$i]}{TIME} = $now;
  113. $def->{READINGS}{$txt[$i]}{VAL} = $v[$i];
  114. $def->{CHANGED}[$i] = "$txt[$i]: $v[$i]";
  115. }
  116. $def->{READINGS}{type}{TIME} = $now;
  117. $def->{READINGS}{type}{VAL} = $type;
  118. $def->{STATE} = $val;
  119. $def->{CHANGED}[$max++] = $val;
  120. } else {
  121. Log GetLogLevel($name,4), "(ESA/DISCARDED $name: $val)";
  122. return "($name)";
  123. }
  124. return $name;
  125. }
  126. 1;