| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- # $Id: 10_HXBDevice.pm 16375 2018-03-10 15:40:02Z neubert $
- ##############################################################################
- #
- # 10_HXBDevice.pm
- # Copyright 2014 by Dr. Boris Neubert
- # e-mail: omega at online dot de
- #
- # This file is part of fhem.
- #
- # Fhem is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 2 of the License, or
- # (at your option) any later version.
- #
- # Fhem is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with fhem. If not, see <http://www.gnu.org/licenses/>.
- #
- ##############################################################################
- # Debian: libdigest-crc-perl
- package main;
- use strict;
- use warnings;
- use Digest::CRC;
- #############################
- my %HXB_PTYPES= (
- HXB_PTYPE_ERROR => 0x00, # An error occured -- check the error code field for more information
- HXB_PTYPE_INFO => 0x01, # Endpoint provides information
- HXB_PTYPE_QUERY => 0x02, # Endpoint is requested to provide information
- HXB_PTYPE_WRITE => 0x04, # Endpoint is requested to set its value
- HXB_PTYPE_EPINFO => 0x09, # Endpoint metadata
- HXB_PTYPE_EPQUERY => 0x0A, # Request endpoint metadata
- );
- #print Dumper \%HXB_PTYPES;
- my %HXB_PTYPES_r = reverse %HXB_PTYPES;
- my %HXB_DTYPES= (
- HXB_DTYPE_UNDEFINED => 0x00, # Undefined: Nonexistent data type
- HXB_DTYPE_BOOL => 0x01, # Boolean. Value still represented by 8 bits, but may only be HXB_TRUE or HXB_FALSE
- HXB_DTYPE_UINT8 => 0x02, # Unsigned 8 bit integer
- HXB_DTYPE_UINT32 => 0x03, # Unsigned 32 bit integer
- HXB_DTYPE_DATETIME => 0x04, # Date and time
- HXB_DTYPE_FLOAT => 0x05, # 32bit floating point
- HXB_DTYPE_128STRING => 0x06, # 128char fixed length string
- HXB_DTYPE_TIMESTAMP => 0x07, # timestamp - used for measuring durations, time differences and so on - uint32; seconds
- HXB_DTYPE_65BYTES => 0x08, # raw 65 byte array, e.g. state machine data.
- HXB_DTYPE_16BYTES => 0x09, # raw 16 byte array, e.g. state machine ID.
- );
- my %HXB_DTYPES_r = reverse %HXB_DTYPES;
- my %HXB_FLAGS= (
- HXB_FLAG_NONE => 0x00, # No flags set
- );
- my %HXB_FLAGS_r = reverse %HXB_FLAGS;
- my %EP= (
- EP_DEVICE_DESCRIPTOR => 0,
- EP_POWER_SWITCH => 1,
- EP_POWER_METER => 2,
- EP_TEMPERATURE => 3,
- EP_BUTTON => 4,
- EP_HUMIDITY => 5,
- EP_PRESSURE => 6,
- EP_ENERGY_METER_TOTAL => 7,
- EP_ENERGY_METER => 8,
- EP_SM_CONTROL => 9,
- EP_SM_UP_RECEIVER => 10,
- EP_SM_UP_ACKNAK => 11,
- EP_SM_RESET_ID => 12,
- EP_ANALOGREAD => 22,
- EP_SHUTTER => 23,
- EP_HEXAPUSH_PRESSED => 24,
- EP_HEXAPUSH_CLICKED => 25,
- EP_PRESENCE_DETECTOR => 26,
- EP_HEXONOFF_SET => 27,
- EP_HEXONOFF_TOGGLE => 28,
- EP_LIGHTSENSOR => 29,
- EP_IR_RECEIVER => 30,
- EP_LIVENESS => 31,
- EP_EXT_DEV_DESC_1 => 32,
- EP_GENERIC_DIAL_0 => 33,
- EP_GENERIC_DIAL_1 => 34,
- EP_GENERIC_DIAL_2 => 35,
- EP_GENERIC_DIAL_3 => 36,
- EP_GENERIC_DIAL_4 => 37,
- EP_GENERIC_DIAL_5 => 38,
- EP_GENERIC_DIAL_6 => 39,
- EP_GENERIC_DIAL_7 => 40,
- EP_PV_PRODUCTION => 41,
- EP_POWER_BALANCE => 42,
- EP_BATTERY_BALANCE => 43,
- EP_HEATER_HOT => 44,
- EP_HEATER_COLD => 45,
- EP_HEXASENSE_BUTTON_STATE => 46,
- EP_FLUKSO_L1 => 47,
- EP_FLUKSO_L2 => 48,
- EP_FLUKSO_L3 => 49,
- EP_FLUKSO_S01 => 50,
- EP_FLUKSO_S02 => 51,
- EP_GL_IMPORT_L1 => 52,
- EP_GL_IMPORT_L2 => 53,
- EP_GL_IMPORT_L3 => 54,
- EP_GL_EXPORT_POWER => 55,
- EP_GL_EXPORT_L1 => 56,
- EP_GL_EXPORT_L2 => 57,
- EP_GL_EXPORT_L3 => 58,
- EP_GL_IMPORT_ENERGY => 59,
- EP_GL_EXPORT_ENERGY => 60,
- EP_GL_FIRMWARE => 61,
- EP_GL_CURRENT_L1 => 62,
- EP_GL_CURRENT_L2 => 63,
- EP_GL_CURRENT_L3 => 65,
- EP_GL_VOLTAGE_L1 => 66,
- EP_GL_VOLTAGE_L2 => 67,
- EP_GL_VOLTAGE_L3 => 68,
- EP_GL_POWER_FACTOR_L1 => 69,
- EP_GL_POWER_FACTOR_L2 => 70,
- EP_GL_POWER_FACTOR_L3 => 71,
- EP_METERING_RMS_CURRENT => 72,
- EP_METERING_RMS_VOLTAGE => 73,
- EP_METERING_FREQUENCY => 74,
- EP_METERING_REACTIVE_POWER => 75,
- EP_METERING_POWER_FACTOR => 76,
- EP_METERING_APPARENT_POWER => 77,
- EP_METERING_FUNDAMENTAL_ACTIVE_POWER => 78,
- EP_METERING_FUNDAMENTAL_REACTIVE_POWER => 79,
- EP_DIMMER_MODE => 80,
- EP_DIMMER_BRIGHTNESS => 81,
- );
- my %EP_r= reverse %EP;
- #############################
- sub
- HXBDevice_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t]+", $def);
- return "Usage: define <name> HXBDevice <ipv6>" if($#a != 2);
- my $name= $a[0];
- my $ipv6= $a[2];
-
- $hash->{fhem}{ipv6}= $ipv6;
- AssignIoPort($hash);
-
- my @devarray= ();
- my $devarrayref= $modules{$hash->{TYPE}}{defptr}{"$ipv6"};
- if(defined($devarrayref)) {
- @devarray= @{$devarrayref};
- }
- push @devarray, $hash;
- $modules{$hash->{TYPE}}{defptr}{"$ipv6"}= \@devarray;
-
- return undef;
-
- # Todo: HXBDevice_Undefine
- }
- ###################################
- sub
- HXBDevice_Initialize($)
- {
- my ($hash) = @_;
- $hash->{Match} = "HX0C.+";
-
- #$hash->{GetFn} = "HXBDevice_Get";
- #$hash->{SetFn} = "HXBDevice_Set";
- $hash->{DefFn} = "HXBDevice_Define";
- $hash->{ParseFn} = "HXBDevice_Parse";
- #$hash->{AttrFn} = "HXBDevice_Attr";
- $hash->{AttrList} = $readingFnAttributes;
- }
- #####################################
- sub
- crc16Kermit($) {
- my ($raw)= @_;
- my $ctx= Digest::CRC->new(width=>16, init=>0x0000, xorout=>0x0000,
- refout=>1, poly=>0x1021, refin=>1, cont=>1);
- $ctx->add($raw);
- return $ctx->digest;
- }
- #############################
- sub
- HXBDevice_Parse($$)
- {
- # we never come here if $msg does not match $IOhash->{MATCH} in the first place
- my ($IOhash, $data) = @_; # IOhash points to the HXB, not to the HXBDevice
- my $socket= $IOhash->{TCPDev};
- my $ipv6= $socket->peerhost;
-
- my $hash;
-
- # array of device hash with that IPv6 address
- my @devices= ();
- # matching devices
- my @devarray= ();
- my $devarrayref= $modules{"HXBDevice"}{defptr}{"$ipv6"};
- if(defined($devarrayref)) {
- @devarray= @{$devarrayref};
- }
- return "UNDEFINED HXB_$ipv6 HXBDevice $ipv6" if($#devarray< 0);
-
- foreach $hash (@devarray) {
-
- my $n= length($data);
- return undef if($n< 8);
-
- my ($magic, $ptype, $flags, $payload, $crc)= unpack("A4CCa" . ($n-8) . "n", $data);
- my $raw= unpack("a" . ($n-2), $data);
- return undef unless($crc = crc16Kermit($raw));
- my $hxb_ptype= $HXB_PTYPES_r{$ptype};
- my $hxb_flag= $HXB_FLAGS_r{$flags};
- if($hxb_ptype eq "HXB_PTYPE_INFO") {
- my ($eid, $dtype, $value)= unpack("NCa*", $payload);
- my $ep= $EP_r{$eid};
- my $hxb_dtype= $HXB_DTYPES_r{$dtype};
- my $v= "<unknown>";
- if($hxb_dtype eq "HXB_DTYPE_BOOL") {
- $v= unpack("b", $value);
- } elsif($hxb_dtype eq "HXB_DTYPE_UINT8") {
- $v= unpack("C", $value);
- } elsif($hxb_dtype eq "HXB_DTYPE_UINT32") {
- $v= unpack("N", $value);
- } elsif($hxb_dtype eq "HXB_DTYPE_DATETIME") {
- $v= "?";
- } elsif($hxb_dtype eq "HXB_DTYPE_FLOAT") {
- #Debug unpack "V", $value;
- $v= unpack "f", pack "N", unpack "V", $value; #unpack("f", $value);
- } elsif($hxb_dtype eq "HXB_DTYPE_128STRING") {
- $v= "?";
- } elsif($hxb_dtype eq "HXB_DTYPE_TIMESTAMP") {
- $v= "?";
- } elsif($hxb_dtype eq "HXB_DTYPE_65BYTES") {
- $v= "?";
- } elsif($hxb_dtype eq "HXB_DTYPE_16BYTES") {
- $v= "?";
- }
- Log3 $hash,5, sprintf("%s: %s %s %s %s %s= %s",
- $hash->{NAME}, $hxb_ptype, $hxb_flag,
- $ep, $hxb_dtype, unpack("H*", $value), $v);
-
- my $fmtDateTime= readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "state", $fmtDateTime, 1); # we do not want an extra event for state
- readingsBulkUpdate($hash, $ep, $v, 1);
- readingsEndUpdate($hash, 1);
-
- push @devices, $hash->{NAME};
- }
-
- }
- return @devices;
-
- }
- #############################
- 1;
- #############################
- =pod
- =item summary receive multicast messages from a Hexabus device
- =item summary_DE empfange Multicast-Nachrichten von einem Hexabus-Gerä
- =begin html
- <a name="HXBDevice"></a>
- <h3>HXBDevice</h3>
- <ul>
- <br>
- <a name="HXB"></a>
- <b>Define</b>
- <ul>
- <code>define <name> HXB <IPv6Address></code><br>
- <br>
- Defines a Hexabus device at the IPv6 address <IPv6Address>. You need one <a href="#HXB">Hexabus</a>
- to receive multicast messages from Hexabus devices.
- Have a look at the <a href="https://github.com/mysmartgrid/hexabus/wiki">Hexabus wiki</a> for more information on Hexabus.
- <br><br>
- Example:
- <code>define myPlug fd01:1::50:c4ff:fe04:81ad</code>
- </ul>
- </ul>
- =end html
|