############################################################################# # # 20_N4HBUS.pm # # net4home Busconnector Device # # (c) 2014-2016 Oliver Koerber # # # 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 . # # $Id$ # ############################################################################## package main; use strict; use warnings; use POSIX; use Data::Dumper; my $n4hbus_Version = "1.0.1.2 - 27.10.2016"; sub N4HBUS_Read($@); sub N4HBUS_Write($$$$); sub N4HBUS_Ready($); sub N4HBUS_getDevList($$); sub N4HBUS_decompSection($$$); sub N4HBUS_CompressSection($$); sub N4HBUS_Initialize($) { my ($hash) = @_; require "$attr{global}{modpath}/FHEM/DevIo.pm"; # Provider $hash->{ReadFn} = "N4HBUS_Read"; $hash->{WriteFn} = "N4HBUS_Write"; $hash->{ReadyFn} = "N4HBUS_Ready"; # Normal devices $hash->{UndefFn} = "N4HBUS_Undef"; $hash->{DefFn} = "N4HBUS_Define"; $hash->{AttrList} = "dummy:1,0 ". "OBJADR ". "MI "; } ################################################################################# sub N4HBUS_Define($$) { ################################################################################# my ($hash, $def) = @_; my @a = split("[ \t]+", $def); if(@a != 3) { my $msg = "wrong syntax: define N4HBUS hostname:port"; Log3 $hash, 2, $msg; return $msg; } DevIo_CloseDev($hash); my $name = $a[0]; my $dev = $a[2]; $hash->{VERSION} = $n4hbus_Version; $hash->{DeviceName} = $dev; $hash->{Clients} = ":N4HMODULE:"; my %matchList = ( "1:N4HMODULE" => ".*" ); $hash->{MatchList} = \%matchList; Log3 $hash, 3, "N4HBUS_Define -> $name at $dev"; if($dev eq "none") { Log3 $hash, 1, "N4HBUS device is none, commands will be echoed only"; $attr{$name}{dummy} = 1; return undef; } my $ret = DevIo_OpenDev($hash, 0, "N4HBUS_DoInit"); return $ret; } ################################################################################# sub N4HBUS_DoInit($) { ################################################################################# my $hash = shift; my $name = $hash->{NAME}; delete $hash->{HANDLE}; # set OBJ and MI if not defined as attributes if (!defined($hash->{OBJADR}) ) { $attr{$name}{OBJADR} = 32700; } if (!defined($hash->{MI}) ) { $attr{$name}{MI} = 65281; } my $sendmsg = "190000000002ac0f400a000002bc02404600000487000000c000000200"; DevIo_SimpleWrite($hash, $sendmsg, 1); return undef; } ################################################################################# sub N4HBUS_Undef($@) { ################################################################################# my ( $hash, $arg ) = @_; my $name = $hash->{NAME}; Log3 $hash, 2, "close port for $name"; DevIo_CloseDev($hash); return undef; } ################################################################################## sub decode_d2b (@) { ################################################################################## my $w = sprintf("%04x\n", @_); my $ret = substr($w,2,2).substr($w,0,2); return $ret; } ################################################################################# sub N4HBUS_CompressSection($$) { ################################################################################# my ($hash, $pUnCompressed) = @_; my ($cs, $x) = 0; my $pCompressed = ""; my $sizeRaw = length($pUnCompressed)/2; for(my $i=0;$i < (length($pUnCompressed)/2); $i++) { $cs = $cs + hex(substr($pUnCompressed,$i*2,2)); } my $len = length($pUnCompressed)/2; my $hi = $len >> 8; my $lo = $len & 0b0000000011111111; $pCompressed = sprintf ("%02X%02X", $hi,$lo); my $p = 0; while ($len>0){ $pCompressed = $pCompressed.(substr($pUnCompressed,$p*2,2)); $len--; $p++; } $pCompressed = $pCompressed."C0"; $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>24) ); $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>16) ); $pCompressed = $pCompressed.sprintf ("%02X", ($cs>>8) ); $pCompressed = $pCompressed.sprintf ("%02X", ( ($cs>>0) & 0xff ) ); $pCompressed = sprintf ("%02X", (length($pCompressed)/2))."000000".$pCompressed; return $pCompressed; } ################################################################################# sub N4HBUS_decompSection($$$) { ################################################################################# my ($hash, $p2, $fs) = @_; my $ret = 0; my $inBlock; my $gPoutPos = 0; my $zaehler = 0; my $err = 0; my $ende = 0; my $gPout = ""; my $bb = 0; my $bc = 0; my $csCalc = 0; my $csRx; my $maxoutlen = 372; my @ar2k; my $decompressor_err = -4; my $decompressor_errAdr = 0; while (($zaehler<$fs) && ($gPoutPos < $maxoutlen) && ($ende != 1) && ($err != 1)) { $bb = substr($p2,$zaehler*2,2); my $bbout = hex($bb) & 192; if ( (hex($bb) & 192) == 192) { # Ende ist gefunden $ende = 1; } elsif ((hex($bb) & 192) == 0) { $bc = substr($p2,(($zaehler+1)*2),2); $inBlock = (hex(substr($p2,$zaehler*2,2))*256) + hex($bc); $zaehler = $zaehler+2; while ($inBlock > 0) { $inBlock--; $gPout = $gPout.substr($p2,$zaehler*2,2); $zaehler++; } } elsif ((hex($bb) & 192) == 64) { $bc = substr($p2,(($zaehler+1)*2),2); $inBlock = ((hex(substr($p2,$zaehler*2,2))*256) + hex($bc)) & 16383; $bb = substr($p2,($zaehler+2)*2,2); $zaehler = $zaehler+3; while ($inBlock > 0) { $inBlock--; $gPout = $gPout.$bb; } } elsif ($bb & 0xC0 == 0x80) { $err = 1; $decompressor_err = -2; $zaehler++; } $decompressor_errAdr = $zaehler; } if (($err != 1) and ($ende == 1)) { $ret = $gPout; } return $ret; } ################################################################################## sub N4HBUS_bin2text ($) { ################################################################################## # Umwandlung der empfangenen oder zu sendenden Daten in lesbares Format my ( $data ) = @_; my $ret = ""; my $sub; if (length($data)>60) { # Kenne ich noch nicht $ret = "(".substr($data,0,12).")\t"; # ptype $sub = hex(substr($data,14,2).substr($data,12,2)); $ret = $ret."ptype=$sub\t"; # payloadlen $sub = hex(substr($data,18,2).substr($data,16,2)); $ret = $ret."payloadlen=$sub\t"; # MMS oder BIN $sub = hex(substr($data,22,2).substr($data,20,2)); $ret = $ret."IP=$sub\t"; # Kenne ich noch nicht $sub = substr($data,24, 6); $ret = $ret."($sub)\t"; # type8 $sub = hex(substr($data,30,2)); $ret = $ret."type8=$sub\t"; # ipsrc $sub = (substr($data,34,2).substr($data,32,2)); $ret = $ret."MI=$sub\t"; # ipdst $ret = $ret."ipdst=".hex(substr($data,38,2).substr($data,36,2))."\t"; # objsrc $ret = $ret."objsrc=".hex(substr($data,42,2).substr($data,40,2))."\t"; # datalen my $datalen = hex((substr($data,44,2))); $ret = $ret."datalen=".$datalen."\t"; # ddata $ret = $ret."ddata=".substr($data,46, ($datalen*2))."\t"; my $pos = $datalen*2+46; my $csRX = hex(substr($data,$pos,2)); my $csCalc = hex(substr($data,$pos+2,2)); my $len = hex(substr($data,$pos+4,2)); my $posb = hex(substr($data,$pos+6,2)); $ret = $ret."($csRX/$csCalc/$len/$posb)" } return $ret; } ################################################################################## sub N4HBUS_Write($$$$) { ################################################################################## my ($hash,$ipdst,$ddata,$objsource) = @_; my $name = $hash->{NAME}; return if(!$hash || AttrVal($hash->{NAME}, "dummy", 0) != 0); my $sendmsg = ""; my $sendbus = ""; my $msg = ""; my $objsrc = AttrVal($name, "OBJADR", 32700); my $ipsrc = AttrVal($name, "MI", 65281); # A10F 0000 4E00 0000 00 - 00 5902 0D62 2D65 03 32 00 64 03D416070102201500003120736563742000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004A4A030000 # payload type $sendbus = "A10F0000"; # payload len0 $sendbus = $sendbus."4E000000"; #?? $sendbus = $sendbus."00"; # typ8 $sendbus = $sendbus."00"; $sendbus = $sendbus.decode_d2b($ipsrc); $sendbus = $sendbus.decode_d2b($ipdst); if ($objsource !=0 ) { $objsrc = $objsource; } $sendbus = $sendbus.decode_d2b($objsrc); # ddata while (length($ddata)<128) { $ddata = $ddata."00"; } $sendbus = $sendbus.$ddata; # csRx, csCalc, len, posb $sendbus = $sendbus."00000000"; $sendmsg = N4HBUS_CompressSection($hash, $sendbus); Log3 $hash, 5, "N4HBUS (+++): $sendmsg"; if(defined($hash)) { DevIo_SimpleWrite($hash, $sendmsg, 1); } } ################################################################################## sub N4HBUS_Read($@) { ################################################################################# my ($hash, $local, $regexp) = @_; my $buf = DevIo_SimpleRead($hash); return "" if(!defined($buf)); my $name = $hash->{NAME}; my $recdata = unpack('H*', $buf); my $data; my $len = 0; $len = substr($recdata,6,2); $len = $len.substr($recdata,4,2); $len = $len.substr($recdata,2,2); $len = $len.substr($recdata,0,2); $len =~ s/^0+//; my $test = ""; $recdata = substr($recdata,8,hex($len)*2); while (length($recdata) >= ( hex($len) *2)) { $data = substr($recdata,0, hex($len)*2); Log3 $hash, 5, "N4HBUS (DECOMP): Länge (".hex($len)." bytes)-$data"; # Log3 $hash, 1, "(DECOMP1): Länge (".hex($len)." bytes)-$data"; # 0005 a10f 0000 04 40 05 0000 1c 7302 ff7f a86a 05 65 09 05 01 c2 4d617263656c20476f6572747a6b6175403000c000000b24 # 0005 a10f 0000 04 40 06 0000 1b 01 bc7f 1127 04 41 00 01 04 624d617263656c20476f6572747a6b6175403000c000000904 # 1b 01 ffff 1127 03 ff ff ff 64b44d617263656c20476f6572747a6b6175403000c000000d33 # 0005 a10f 0000 04 40 05 0000 1f 2600 ffff 2c0a 03 ff ff ff 017f2127100320160100271003201601006f00a19c400aff402300c000001333 my $idx; $idx = index($data,"a10f"); if ($idx>=0) { $data = substr($data,$idx); # Cut off beginning - Der Anfang interessiert erst mal nicht... my $msg = substr($data,18,length($data)); my $type8 = hex(substr($msg,0,2)); # Es ist ein "normales" Status-Paket if ($type8>=0) { $hash->{"${name}_MSGCNT"}++; $hash->{"${name}_TIME"} = TimeNow(); $hash->{RAWMSG} = $msg; my %addvals = (RAWMSG => $data); Dispatch($hash, $msg, \%addvals) if($init_done); } } # a10f - Statuspaket $recdata = substr($recdata,( hex($len) *2)); } # while return undef; } ################################################################################# sub N4HBUS_Ready($) { ################################################################################# my ($hash) = @_; Log3 $hash, 1, "N4HBUS_Ready"; return DevIo_OpenDev($hash, 1, "N4HBUS_DoInit"); } # function decompSection(p2:pbyte; offset, fs:dword; p2out:pbyte; MaxOutLen:dword; useCS:boolean):dword; ################################################################################# 1; =pod =item device =item summary Connector to net4home bus via IP =item summary_DE Konnektor zum net4home Bus über IP =begin html

N4HBUS

This module connects fhem to the net4home Bus. You need to define ojects with N4MODULE to set or read data of th net4home bus.

Further technical information can be found at the net4home.de Homepage

Define
    define <name> N4HBUS <device>

    <device> is a combination of <host>:<port>, where <host> is the IP address of the net4home Busconnector and <port> (default:3478).

    Example:
      define net4home N4HBUS 192.168.1.69:3478

    The device can also be connected to the busconnector on the same machine.
    Default Port for communication is 3478. In case you need to change this please change also the Port in the conf of busconnector service.

Readings
  • state - current state of the Bus connection

Attributes
  • MI - a unique MI in the net4home environment (default:65281)
  • OBJADR - a unique OBJADR in the net4home environment (default:32700)
=end html =begin html_DE

N4HBUS

Dieses Modul verbindet fhem über IP mit dem net4home Bus. Zusätzlich müssen Objekte über den Typ N4MODULE definiert werden, um Daten an den net4home-Bus zu senden oder zu lesen.

Weitere technische Informationen gibt es auf der Homepage unter net4home.de

Define
    define <name> N4HBUS <device>

    <device> ist eine Kombination aus IP Adresse des net4home Busconnectors und dem Port (default:3478).

    Beispiel:
      define net4home N4HBUS 192.168.1.69:3478

    Das Device kann sich auch mit dem Busconnector auf dem selben System verbinden. Der Default-Port für die Kommunikation ist 3478. Sollte es nötig sein den Port zu verändern, so muss dies ebenfalls in der Konfiguration des Services durchgeführt werden.

Readings
  • state - aktueller Status der Verbindung zum net4home Busconnector

Attributes
  • MI - die eindeutige MI in der net4home Umgebung (default:65281)
  • OBJADR - die eindeutige OBJADR in der net4home Umgebung (default:32700)
=end html_DE =cut