10_HXBDevice.pm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. # $Id: 10_HXBDevice.pm 16375 2018-03-10 15:40:02Z neubert $
  2. ##############################################################################
  3. #
  4. # 10_HXBDevice.pm
  5. # Copyright 2014 by Dr. Boris Neubert
  6. # e-mail: omega at online dot de
  7. #
  8. # This file is part of fhem.
  9. #
  10. # Fhem is free software: you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation, either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # Fhem is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  22. #
  23. ##############################################################################
  24. # Debian: libdigest-crc-perl
  25. package main;
  26. use strict;
  27. use warnings;
  28. use Digest::CRC;
  29. #############################
  30. my %HXB_PTYPES= (
  31. HXB_PTYPE_ERROR => 0x00, # An error occured -- check the error code field for more information
  32. HXB_PTYPE_INFO => 0x01, # Endpoint provides information
  33. HXB_PTYPE_QUERY => 0x02, # Endpoint is requested to provide information
  34. HXB_PTYPE_WRITE => 0x04, # Endpoint is requested to set its value
  35. HXB_PTYPE_EPINFO => 0x09, # Endpoint metadata
  36. HXB_PTYPE_EPQUERY => 0x0A, # Request endpoint metadata
  37. );
  38. #print Dumper \%HXB_PTYPES;
  39. my %HXB_PTYPES_r = reverse %HXB_PTYPES;
  40. my %HXB_DTYPES= (
  41. HXB_DTYPE_UNDEFINED => 0x00, # Undefined: Nonexistent data type
  42. HXB_DTYPE_BOOL => 0x01, # Boolean. Value still represented by 8 bits, but may only be HXB_TRUE or HXB_FALSE
  43. HXB_DTYPE_UINT8 => 0x02, # Unsigned 8 bit integer
  44. HXB_DTYPE_UINT32 => 0x03, # Unsigned 32 bit integer
  45. HXB_DTYPE_DATETIME => 0x04, # Date and time
  46. HXB_DTYPE_FLOAT => 0x05, # 32bit floating point
  47. HXB_DTYPE_128STRING => 0x06, # 128char fixed length string
  48. HXB_DTYPE_TIMESTAMP => 0x07, # timestamp - used for measuring durations, time differences and so on - uint32; seconds
  49. HXB_DTYPE_65BYTES => 0x08, # raw 65 byte array, e.g. state machine data.
  50. HXB_DTYPE_16BYTES => 0x09, # raw 16 byte array, e.g. state machine ID.
  51. );
  52. my %HXB_DTYPES_r = reverse %HXB_DTYPES;
  53. my %HXB_FLAGS= (
  54. HXB_FLAG_NONE => 0x00, # No flags set
  55. );
  56. my %HXB_FLAGS_r = reverse %HXB_FLAGS;
  57. my %EP= (
  58. EP_DEVICE_DESCRIPTOR => 0,
  59. EP_POWER_SWITCH => 1,
  60. EP_POWER_METER => 2,
  61. EP_TEMPERATURE => 3,
  62. EP_BUTTON => 4,
  63. EP_HUMIDITY => 5,
  64. EP_PRESSURE => 6,
  65. EP_ENERGY_METER_TOTAL => 7,
  66. EP_ENERGY_METER => 8,
  67. EP_SM_CONTROL => 9,
  68. EP_SM_UP_RECEIVER => 10,
  69. EP_SM_UP_ACKNAK => 11,
  70. EP_SM_RESET_ID => 12,
  71. EP_ANALOGREAD => 22,
  72. EP_SHUTTER => 23,
  73. EP_HEXAPUSH_PRESSED => 24,
  74. EP_HEXAPUSH_CLICKED => 25,
  75. EP_PRESENCE_DETECTOR => 26,
  76. EP_HEXONOFF_SET => 27,
  77. EP_HEXONOFF_TOGGLE => 28,
  78. EP_LIGHTSENSOR => 29,
  79. EP_IR_RECEIVER => 30,
  80. EP_LIVENESS => 31,
  81. EP_EXT_DEV_DESC_1 => 32,
  82. EP_GENERIC_DIAL_0 => 33,
  83. EP_GENERIC_DIAL_1 => 34,
  84. EP_GENERIC_DIAL_2 => 35,
  85. EP_GENERIC_DIAL_3 => 36,
  86. EP_GENERIC_DIAL_4 => 37,
  87. EP_GENERIC_DIAL_5 => 38,
  88. EP_GENERIC_DIAL_6 => 39,
  89. EP_GENERIC_DIAL_7 => 40,
  90. EP_PV_PRODUCTION => 41,
  91. EP_POWER_BALANCE => 42,
  92. EP_BATTERY_BALANCE => 43,
  93. EP_HEATER_HOT => 44,
  94. EP_HEATER_COLD => 45,
  95. EP_HEXASENSE_BUTTON_STATE => 46,
  96. EP_FLUKSO_L1 => 47,
  97. EP_FLUKSO_L2 => 48,
  98. EP_FLUKSO_L3 => 49,
  99. EP_FLUKSO_S01 => 50,
  100. EP_FLUKSO_S02 => 51,
  101. EP_GL_IMPORT_L1 => 52,
  102. EP_GL_IMPORT_L2 => 53,
  103. EP_GL_IMPORT_L3 => 54,
  104. EP_GL_EXPORT_POWER => 55,
  105. EP_GL_EXPORT_L1 => 56,
  106. EP_GL_EXPORT_L2 => 57,
  107. EP_GL_EXPORT_L3 => 58,
  108. EP_GL_IMPORT_ENERGY => 59,
  109. EP_GL_EXPORT_ENERGY => 60,
  110. EP_GL_FIRMWARE => 61,
  111. EP_GL_CURRENT_L1 => 62,
  112. EP_GL_CURRENT_L2 => 63,
  113. EP_GL_CURRENT_L3 => 65,
  114. EP_GL_VOLTAGE_L1 => 66,
  115. EP_GL_VOLTAGE_L2 => 67,
  116. EP_GL_VOLTAGE_L3 => 68,
  117. EP_GL_POWER_FACTOR_L1 => 69,
  118. EP_GL_POWER_FACTOR_L2 => 70,
  119. EP_GL_POWER_FACTOR_L3 => 71,
  120. EP_METERING_RMS_CURRENT => 72,
  121. EP_METERING_RMS_VOLTAGE => 73,
  122. EP_METERING_FREQUENCY => 74,
  123. EP_METERING_REACTIVE_POWER => 75,
  124. EP_METERING_POWER_FACTOR => 76,
  125. EP_METERING_APPARENT_POWER => 77,
  126. EP_METERING_FUNDAMENTAL_ACTIVE_POWER => 78,
  127. EP_METERING_FUNDAMENTAL_REACTIVE_POWER => 79,
  128. EP_DIMMER_MODE => 80,
  129. EP_DIMMER_BRIGHTNESS => 81,
  130. );
  131. my %EP_r= reverse %EP;
  132. #############################
  133. sub
  134. HXBDevice_Define($$)
  135. {
  136. my ($hash, $def) = @_;
  137. my @a = split("[ \t]+", $def);
  138. return "Usage: define <name> HXBDevice <ipv6>" if($#a != 2);
  139. my $name= $a[0];
  140. my $ipv6= $a[2];
  141. $hash->{fhem}{ipv6}= $ipv6;
  142. AssignIoPort($hash);
  143. my @devarray= ();
  144. my $devarrayref= $modules{$hash->{TYPE}}{defptr}{"$ipv6"};
  145. if(defined($devarrayref)) {
  146. @devarray= @{$devarrayref};
  147. }
  148. push @devarray, $hash;
  149. $modules{$hash->{TYPE}}{defptr}{"$ipv6"}= \@devarray;
  150. return undef;
  151. # Todo: HXBDevice_Undefine
  152. }
  153. ###################################
  154. sub
  155. HXBDevice_Initialize($)
  156. {
  157. my ($hash) = @_;
  158. $hash->{Match} = "HX0C.+";
  159. #$hash->{GetFn} = "HXBDevice_Get";
  160. #$hash->{SetFn} = "HXBDevice_Set";
  161. $hash->{DefFn} = "HXBDevice_Define";
  162. $hash->{ParseFn} = "HXBDevice_Parse";
  163. #$hash->{AttrFn} = "HXBDevice_Attr";
  164. $hash->{AttrList} = $readingFnAttributes;
  165. }
  166. #####################################
  167. sub
  168. crc16Kermit($) {
  169. my ($raw)= @_;
  170. my $ctx= Digest::CRC->new(width=>16, init=>0x0000, xorout=>0x0000,
  171. refout=>1, poly=>0x1021, refin=>1, cont=>1);
  172. $ctx->add($raw);
  173. return $ctx->digest;
  174. }
  175. #############################
  176. sub
  177. HXBDevice_Parse($$)
  178. {
  179. # we never come here if $msg does not match $IOhash->{MATCH} in the first place
  180. my ($IOhash, $data) = @_; # IOhash points to the HXB, not to the HXBDevice
  181. my $socket= $IOhash->{TCPDev};
  182. my $ipv6= $socket->peerhost;
  183. my $hash;
  184. # array of device hash with that IPv6 address
  185. my @devices= ();
  186. # matching devices
  187. my @devarray= ();
  188. my $devarrayref= $modules{"HXBDevice"}{defptr}{"$ipv6"};
  189. if(defined($devarrayref)) {
  190. @devarray= @{$devarrayref};
  191. }
  192. return "UNDEFINED HXB_$ipv6 HXBDevice $ipv6" if($#devarray< 0);
  193. foreach $hash (@devarray) {
  194. my $n= length($data);
  195. return undef if($n< 8);
  196. my ($magic, $ptype, $flags, $payload, $crc)= unpack("A4CCa" . ($n-8) . "n", $data);
  197. my $raw= unpack("a" . ($n-2), $data);
  198. return undef unless($crc = crc16Kermit($raw));
  199. my $hxb_ptype= $HXB_PTYPES_r{$ptype};
  200. my $hxb_flag= $HXB_FLAGS_r{$flags};
  201. if($hxb_ptype eq "HXB_PTYPE_INFO") {
  202. my ($eid, $dtype, $value)= unpack("NCa*", $payload);
  203. my $ep= $EP_r{$eid};
  204. my $hxb_dtype= $HXB_DTYPES_r{$dtype};
  205. my $v= "<unknown>";
  206. if($hxb_dtype eq "HXB_DTYPE_BOOL") {
  207. $v= unpack("b", $value);
  208. } elsif($hxb_dtype eq "HXB_DTYPE_UINT8") {
  209. $v= unpack("C", $value);
  210. } elsif($hxb_dtype eq "HXB_DTYPE_UINT32") {
  211. $v= unpack("N", $value);
  212. } elsif($hxb_dtype eq "HXB_DTYPE_DATETIME") {
  213. $v= "?";
  214. } elsif($hxb_dtype eq "HXB_DTYPE_FLOAT") {
  215. #Debug unpack "V", $value;
  216. $v= unpack "f", pack "N", unpack "V", $value; #unpack("f", $value);
  217. } elsif($hxb_dtype eq "HXB_DTYPE_128STRING") {
  218. $v= "?";
  219. } elsif($hxb_dtype eq "HXB_DTYPE_TIMESTAMP") {
  220. $v= "?";
  221. } elsif($hxb_dtype eq "HXB_DTYPE_65BYTES") {
  222. $v= "?";
  223. } elsif($hxb_dtype eq "HXB_DTYPE_16BYTES") {
  224. $v= "?";
  225. }
  226. Log3 $hash,5, sprintf("%s: %s %s %s %s %s= %s",
  227. $hash->{NAME}, $hxb_ptype, $hxb_flag,
  228. $ep, $hxb_dtype, unpack("H*", $value), $v);
  229. my $fmtDateTime= readingsBeginUpdate($hash);
  230. readingsBulkUpdate($hash, "state", $fmtDateTime, 1); # we do not want an extra event for state
  231. readingsBulkUpdate($hash, $ep, $v, 1);
  232. readingsEndUpdate($hash, 1);
  233. push @devices, $hash->{NAME};
  234. }
  235. }
  236. return @devices;
  237. }
  238. #############################
  239. 1;
  240. #############################
  241. =pod
  242. =item summary receive multicast messages from a Hexabus device
  243. =item summary_DE empfange Multicast-Nachrichten von einem Hexabus-Ger&auml;
  244. =begin html
  245. <a name="HXBDevice"></a>
  246. <h3>HXBDevice</h3>
  247. <ul>
  248. <br>
  249. <a name="HXB"></a>
  250. <b>Define</b>
  251. <ul>
  252. <code>define &lt;name&gt; HXB &lt;IPv6Address&gt;</code><br>
  253. <br>
  254. Defines a Hexabus device at the IPv6 address &lt;IPv6Address&gt;. You need one <a href="#HXB">Hexabus</a>
  255. to receive multicast messages from Hexabus devices.
  256. Have a look at the <a href="https://github.com/mysmartgrid/hexabus/wiki">Hexabus wiki</a> for more information on Hexabus.
  257. <br><br>
  258. Example:
  259. <code>define myPlug fd01:1::50:c4ff:fe04:81ad</code>
  260. </ul>
  261. </ul>
  262. =end html