mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 22:15:09 +00:00
508 lines
14 KiB
Perl
508 lines
14 KiB
Perl
#############################################################################
|
|
#
|
|
# 20_N4HBUS.pm
|
|
#
|
|
# net4home Busconnector Device
|
|
#
|
|
# (c) 2014-2023 Oliver Koerber <koerber@net4home.de>
|
|
#
|
|
# $Id$
|
|
#
|
|
##############################################################################
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use DevIo;
|
|
use POSIX;
|
|
use Data::Dumper;
|
|
|
|
my $n4hbus_Version = "1.0.4.0 - 07.11.2023";
|
|
|
|
sub N4HBUS_Read($@);
|
|
sub N4HBUS_Write($$$$);
|
|
sub N4HBUS_Ready($);
|
|
sub N4HBUS_getDevList($$);
|
|
sub N4HBUS_decompSection($$$);
|
|
sub N4HBUS_CompressSection($$);
|
|
sub N4HBUS_Initialize($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
# 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 <name> N4HBUS hostname/IP:port";
|
|
Log3 $hash, 1, $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" => "^[0-9A-Fa-f]" );
|
|
$hash->{MatchList} = \%matchList;
|
|
|
|
Log3 $hash, 3, "N4HBUS Define -> $name at $dev";
|
|
|
|
if($dev eq "none") {
|
|
Log3 $hash, 0, "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, 0, "N4HBUS 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);
|
|
Log3 $hash, 5, "N4HBUS (DECOMP) a10f: Dispatch $msg - ".$hash->{NAME};
|
|
Dispatch($hash, $msg, \%addvals, 1) if($init_done);
|
|
}
|
|
} # a10f - Statuspaket
|
|
|
|
$recdata = substr($recdata,( hex($len) *2));
|
|
} # while
|
|
return undef;
|
|
}
|
|
|
|
#################################################################################
|
|
sub N4HBUS_Ready($) {
|
|
#################################################################################
|
|
|
|
my ($hash) = @_;
|
|
|
|
Log3 $hash, 0, "N4HBUS Connected";
|
|
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
|
|
|
|
<a name="N4HBUS"></a>
|
|
<h3>N4HBUS</h3>
|
|
This module connects fhem to the net4home Bus. You need to define ojects with <a href="#N4MODULE">N4MODULE</a> to set or read
|
|
data of th net4home bus.
|
|
<br /><br />
|
|
Further technical information can be found at the <a href="http://www.net4home.de">net4home.de</a> Homepage
|
|
<br /><br />
|
|
<a name="N4HBUS_Define"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> N4HBUS <device></code>
|
|
<br /> <br />
|
|
<device> is a combination of <host>:<port>, where <host> is the IP address of the net4home Busconnector and <port> (default:3478).
|
|
<br /> <br />
|
|
Example:
|
|
<ul>
|
|
<code>define net4home N4HBUS 192.168.1.69:3478</code>
|
|
</ul>
|
|
<br />
|
|
The device can also be connected to the busconnector on the same machine. <br />
|
|
Default Port for communication is 3478. In case you need to change this please change also the Port in the conf of Busconnector service.
|
|
</ul>
|
|
<br />
|
|
<a name="N4HBUS_Readings"></a>
|
|
<b>Readings</b>
|
|
<ul>
|
|
<li>state - current state of the connection to net4home bus connector</li>
|
|
</ul><br />
|
|
|
|
<a name="N4HBUS_Attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>MI - a unique MI in the net4home environment (default:65281)</li>
|
|
<li>OBJADR - a unique OBJADR in the net4home environment (default:32700)</li>
|
|
</ul>
|
|
|
|
=end html
|
|
|
|
=begin html_DE
|
|
|
|
<a name="N4HBUS"></a>
|
|
<h3>N4HBUS</h3>
|
|
Dieses Modul verbindet fhem über IP mit dem net4home Bus. Zusätzlich müssen Objekte über den Typ
|
|
<a href="#N4MODULE">N4MODULE</a> definiert werden, um Daten an den net4home-Bus zu senden oder zu lesen.
|
|
<br /><br />
|
|
Weitere technische Informationen gibt es auf der Homepage unter <a href="http://www.net4home.de">net4home.de</a>
|
|
<br /><br />
|
|
<a name="N4HBUS_Define"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> N4HBUS <device></code>
|
|
<br /> <br />
|
|
<device> ist eine Kombination aus IP Adresse des net4home Busconnectors und dem Port (default:3478).
|
|
<br /> <br />
|
|
Beispiel:
|
|
<ul>
|
|
<code>define net4home N4HBUS 192.168.1.69:3478</code>
|
|
</ul>
|
|
<br />
|
|
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.<br />
|
|
</ul>
|
|
<br />
|
|
<a name="N4HBUS_Readings"></a>
|
|
<b>Readings</b>
|
|
<ul>
|
|
<li>state - aktueller Status der Verbindung zum net4home Busconnector</li>
|
|
</ul><br />
|
|
<a name="N4HBUS_Attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>MI - die eindeutige MI in der net4home Umgebung (default:65281)</li>
|
|
<li>OBJADR - die eindeutige OBJADR in der net4home Umgebung (default:32700)</li>
|
|
</ul>
|
|
|
|
=end html_DE
|
|
|
|
=cut
|
|
|