2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-06 00:26:35 +00:00
fhem-mirror/fhem/FHEM/00_HMLAN.pm
martinp876 dc80cf8706 update HMLAN description
git-svn-id: https://svn.fhem.de/fhem/trunk@3558 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2013-07-31 11:24:52 +00:00

662 lines
23 KiB
Perl
Executable File

##############################################
# $Id$
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday time);
sub HMLAN_Initialize($);
sub HMLAN_Define($$);
sub HMLAN_Undef($$);
sub HMLAN_RemoveHMPair($);
sub HMLAN_Attr(@);
sub HMLAN_Set($@);
sub HMLAN_ReadAnswer($$$);
sub HMLAN_Write($$$);
sub HMLAN_Read($);
sub HMLAN_uptime($@);
sub HMLAN_Parse($$);
sub HMLAN_Ready($);
sub HMLAN_SimpleWrite(@);
sub HMLAN_DoInit($);
sub HMLAN_KeepAlive($);
sub HMLAN_secSince2000();
sub HMLAN_relOvrLd($);
sub HMLAN_relOvrLd($);
sub HMLAN_condUpdate($$);
my $debug = 1; # set 1 for better log readability
my %sets = ( "hmPairForSec" => "HomeMatic"
,"hmPairSerial" => "HomeMatic"
);
my %HMcond = ( 0 =>'ok'
,2 =>'Warning-HighLoad'
,4 =>'ERROR-Overload'
,254=>'Overload-released'
,255=>'init');
my $HMOvLdRcvr = 6*60;# time HMLAN needs to recover from overload
sub HMLAN_Initialize($) {
my ($hash) = @_;
require "$attr{global}{modpath}/FHEM/DevIo.pm";
# Provider
$hash->{ReadFn} = "HMLAN_Read";
$hash->{WriteFn} = "HMLAN_Write";
$hash->{ReadyFn} = "HMLAN_Ready";
$hash->{SetFn} = "HMLAN_Set";
$hash->{AttrFn} = "HMLAN_Attr";
$hash->{Clients} = ":CUL_HM:";
my %mc = (
"1:CUL_HM" => "^A......................",
);
$hash->{MatchList} = \%mc;
# Normal devices
$hash->{DefFn} = "HMLAN_Define";
$hash->{UndefFn} = "HMLAN_Undef";
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 " .
"loglevel:0,1,2,3,4,5,6 addvaltrigger " .
"hmId hmKey " .
"respTime wdStrokeTime:5,10,15,20,25 " .
"hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger ".
"wdTimer ".
$readingFnAttributes;
}
sub HMLAN_Define($$) {#########################################################
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
if(@a != 3) {
my $msg = "wrong syntax: define <name> HMLAN ip[:port]";
Log 2, $msg;
return $msg;
}
DevIo_CloseDev($hash);
my $name = $a[0];
my $dev = $a[2];
$dev .= ":1000" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
if($dev eq "none") {
Log 1, "$name device is none, commands will be echoed only";
$attr{$name}{dummy} = 1;
return undef;
}
$attr{$name}{wdTimer} = 25;
$hash->{DeviceName} = $dev;
my $ret = DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
return $ret;
}
sub HMLAN_Undef($$) {##########################################################
my ($hash, $arg) = @_;
my $name = $hash->{NAME};
foreach my $d (sort keys %defs) {
if(defined($defs{$d}) &&
defined($defs{$d}{IODev}) &&
$defs{$d}{IODev} == $hash)
{
my $lev = ($reread_active ? 4 : 2);
Log GetLogLevel($name,$lev), "deleting port for $d";
delete $defs{$d}{IODev};
}
}
DevIo_CloseDev($hash);
return undef;
}
sub HMLAN_RemoveHMPair($) {####################################################
my($in ) = shift;
my(undef,$name) = split(':',$in);
my $hash = $defs{$name};
delete($hash->{hmPair});
}
sub HMLAN_Attr(@) {#################################
my ($cmd,$name, $attrName,$aVal) = @_;
if ($attrName eq "wdTimer"){#allow between 5 and 25 second
return "select wdTimer between 5 and 25 seconds" if ($aVal>25 || $aVal<5);
$attr{$name}{wdTimer} = $aVal;
}
return;
}
sub HMLAN_Set($@) {############################################################
my ($hash, @a) = @_;
return "\"set HMLAN\" needs at least one parameter" if(@a < 2);
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
if(!defined($sets{$a[1]}));
my $name = shift @a;
my $type = shift @a;
my $arg = join("", @a);
my $ll = GetLogLevel($name,3);
if($type eq "hmPairForSec") { ####################################
return "Usage: set $name hmPairForSec <seconds_active>"
if(!$arg || $arg !~ m/^\d+$/);
$hash->{hmPair} = 1;
InternalTimer(gettimeofday()+$arg, "HMLAN_RemoveHMPair", "hmPairForSec:".$hash, 1);
}
elsif($type eq "hmPairSerial") { ################################
return "Usage: set $name hmPairSerial <10-character-serialnumber>"
if(!$arg || $arg !~ m/^.{10}$/);
my $id = AttrVal($hash->{NAME}, "hmId", "123456");
$hash->{HM_CMDNR} = $hash->{HM_CMDNR} ? ($hash->{HM_CMDNR}+1)%256 : 1;
HMLAN_Write($hash, undef, sprintf("As15%02X8401%s000000010A%s",
$hash->{HM_CMDNR}, $id, unpack('H*', $arg)));
$hash->{hmPairSerial} = $arg;
}
return undef;
}
sub HMLAN_ReadAnswer($$$) {# This is a direct read for commands like get
my ($hash, $arg, $regexp) = @_;
my $type = $hash->{TYPE};
return ("No FD", undef)
if(!$hash && !defined($hash->{FD}));
my ($mdata, $rin) = ("", '');
my $buf;
my $to = 3; # 3 seconds timeout
$to = $hash->{RA_Timeout} if($hash->{RA_Timeout}); # ...or less
for(;;) {
return ("Device lost when reading answer for get $arg", undef)
if(!$hash->{FD});
vec($rin, $hash->{FD}, 1) = 1;
my $nfound = select($rin, undef, undef, $to);
if($nfound < 0) {
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
my $err = $!;
DevIo_Disconnected($hash);
return("HMLAN_ReadAnswer $arg: $err", undef);
}
return ("Timeout reading answer for get $arg", undef) if($nfound == 0);
$buf = DevIo_SimpleRead($hash);# and now read
return ("No data", undef) if(!defined($buf));
if($buf) {
Log 5, "HMLAN/RAW (ReadAnswer): $buf";
$mdata .= $buf;
}
if($mdata =~ m/\r\n/) {
if($regexp && $mdata !~ m/$regexp/) {
HMLAN_Parse($hash, $mdata);
}
else {
return (undef, $mdata);
}
}
}
}
my %lhash; # remember which ID is assigned to this HMLAN
sub HMLAN_Write($$$) {#########################################################
my ($hash,$fn,$msg) = @_;
if (length($msg)>22){
my ($mtype,$src,$dst) = (substr($msg, 8, 2),
substr($msg, 10, 6),
substr($msg, 16, 6));
my $ll5 = GetLogLevel($hash->{NAME},5);
if ($mtype eq "02" && $src eq $hash->{owner} && length($msg) == 24){
# Acks are generally send by HMLAN autonomously
# Special
Log $ll5, "HMLAN: Skip ACK" if (!$debug);
return;
}
# my $IDHM = '+'.$dst.',01,00,F1EF'; #used by HMconfig - meanning??
# my $IDadd = '+'.$dst; # guess: add ID?
# my $IDack = '+'.$dst.',02,00,'; # guess: ID acknowledge
# my $IDack = '+'.$dst.',FF,00,'; # guess: ID acknowledge
# my $IDsub = '-'.$dst; # guess: ID remove?
# my $IDnew = '+'.$dst.',00,01,'; # newChannel- trailing 01 to be sent if talk to neu channel
my $IDadd = '+'.$dst.',00,00,'; # guess: add ID?
if (!$lhash{$dst} && $dst ne "000000"){
HMLAN_SimpleWrite($hash, $IDadd);
delete $hash->{helper}{$dst};
my $dN = CUL_HM_id2Name($dst);
if (!($dN eq $dst) && # name not found
!(CUL_HM_Get(CUL_HM_id2Hash($dst),$dN,"param","rxType") & ~0x04)){#config only
$hash->{helper}{$dst}{newChn} = '+'.$dst.",01,01,FE1F";
}
else{
$hash->{helper}{$dst}{newChn} = '+'.$dst.',00,01,';
}
$hash->{helper}{$dst}{name} = CUL_HM_id2Name($dst);
$lhash{$dst} = 1;
$hash->{assignIDs}=join(',',keys %lhash);
$hash->{assignIDsCnt}=scalar(keys %lhash);
}
}
my $tm = int(gettimeofday()*1000) % 0xffffffff;
$msg = sprintf("S%08X,00,00000000,01,%08X,%s",$tm, $tm, substr($msg, 4));
HMLAN_SimpleWrite($hash, $msg);
}
sub HMLAN_Read($) {############################################################
# called from the global loop, when the select for hash->{FD} reports data
my ($hash) = @_;
my $buf = DevIo_SimpleRead($hash);
return "" if(!defined($buf));
my $name = $hash->{NAME};
my $ll5 = GetLogLevel($name,5);
my $hmdata = $hash->{PARTIAL};
Log $ll5, "HMLAN/RAW: $hmdata/$buf" if (!$debug);
$hmdata .= $buf;
while($hmdata =~ m/\n/) {
my $rmsg;
($rmsg,$hmdata) = split("\n", $hmdata, 2);
$rmsg =~ s/\r//;
HMLAN_Parse($hash, $rmsg) if($rmsg);
}
$hash->{PARTIAL} = $hmdata;
}
sub HMLAN_uptime($@) {#########################################################
my ($hmtC,$hash) = @_; # hmTime Current
$hmtC = hex($hmtC);
if ($hash && $hash->{helper}{ref}){ #will calculate new ref-time
my $ref = $hash->{helper}{ref};#shortcut
my $sysC = int(time()*1000); #current systime in ms
my $offC = $sysC - $hmtC; #offset calc between time and HM-stamp
if ($ref->{hmtL} && ($hmtC > $ref->{hmtL})){
if (($sysC - $ref->{kTs})<20){ #if delay is more then 20ms, we dont trust
if ($ref->{sysL}){
$ref->{drft} = ($offC - $ref->{offL})/($sysC - $ref->{sysL});
}
$ref->{sysL} = $sysC;
$ref->{offL} = $offC;
}
}
else{# hm had a skip in time, start over calculation
delete $hash->{helper}{ref};
}
$hash->{helper}{ref}{hmtL} = $hmtC;
$hash->{helper}{ref}{kTs} = 0;
}
my $sec = int($hmtC/1000);
return sprintf("%03d %02d:%02d:%02d.%03d",
int($hmtC/86400000), int($sec/3600),
int(($sec%3600)/60), $sec%60, $hmtC % 1000);
}
sub HMLAN_Parse($$) {##########################################################
my ($hash, $rmsg) = @_;
my $name = $hash->{NAME};
my $ll5 = GetLogLevel($name,5);
my @mFld = split(',', $rmsg);
my $letter = substr($mFld[0],0,1); # get leading char
if ($letter =~ m/^[ER]/){#@mFld=($src, $status, $msec, $d2, $rssi, $msg)
# max speed for devices is 100ms after receive - example:TC
my ($mNo,$flg,$type,$src,$dst,$p) = unpack('A2A2A2A6A6A*',$mFld[5]);
my $CULinfo = "";
Log $ll5, "HMLAN_Parse: $name R:".$mFld[0]
.(($mFld[0] =~ m/^E/)?' ':'')
.' stat:' .$mFld[1]
.' t:' .$mFld[2]
.' d:' .$mFld[3]
.' r:' .$mFld[4]
.' m:'.$mNo
.' '.$flg.$type
.' '.$src
.' '.$dst
.' '.$p;
# handle status.
#HMcond stat
# 00 00= msg without relation
# 00 01= ack that HMLAN waited for
# 00 02= msg send, no ack requested
# 00 08= nack - ack was requested, msg repeated 3 times, still no ack
# 00 21= ??(seen with 'R')
# 00 30= ??
# 00 41= ??(seen with 'R')
# 00 50= ??(seen with 'R')
# 00 81= ??
# 01 xx= ?? (seen with 'E')
# 02 xx= prestate to 04xx. Message is still sent. This is a warning
# 04 xx= nothing sent anymore. Any restart unsuccessful except power
#
# parameter 'cond'- condition of the IO device
# Cond text
# 0 ok
# 2 Warning-HighLoad
#
my $stat = hex($mFld[1]);
my $HMcnd =$stat >>8; #high = HMLAN cond
$stat &= 0xff; # low byte related to message format
if ($stat){# message with status information
HMLAN_condUpdate($hash,$HMcnd)if ($hash->{helper}{HMcnd} != $HMcnd);
$hash->{helper}{$dst}{flg} = 0;#got response => unblock sending
if ($stat & 0x0A){#08 and 02 dont need to go to CUL, internal ack only
Log $ll5, "HMLAN_Parse: $name no ACK from Device" if($stat & 0x08);
return;
}
}
my $rssi = hex($mFld[4])-65536;
#update some User information ------
$hash->{uptime} = HMLAN_uptime($mFld[2]);
$hash->{RSSI} = $rssi;
$hash->{RAWMSG} = $rmsg;
$hash->{"${name}_MSGCNT"}++;
$hash->{"${name}_TIME"} = TimeNow();
my $dly = 0;
if ($hash->{helper}{ref} && $hash->{helper}{ref}{drft}){
my $ref = $hash->{helper}{ref};#shortcut
my $sysC = int(time()*1000); #current systime in ms
$dly = int($sysC - (hex($mFld[2]) + $ref->{offL} + $ref->{drft}*($sysC - $ref->{sysL})));
$hash->{helper}{dly}{lst} = $dly;
my $dlyP = $hash->{helper}{dly};
$dlyP->{min} = $dly if (!$dlyP->{min} || $dlyP->{min}>$dly);
$dlyP->{max} = $dly if (!$dlyP->{max} || $dlyP->{max}<$dly);
if ($dlyP->{cnt}) {$dlyP->{cnt}++} else {$dlyP->{cnt} = 1} ;
$hash->{msgParseDly} = "min:" .$dlyP->{min}
." max:" .$dlyP->{max}
." last:".$dlyP->{lst}
." cnt:" .$dlyP->{cnt};
$dly = 0 if ($dly<0);
}
# HMLAN sends ACK for flag 'A0' but not for 'A4'(config mode)-
# we ack ourself an long as logic is uncertain - also possible is 'A6' for RHS
if (hex($flg)&0x4){#not sure: 4 oder 2 ?
my $wait = 0.100 - $dly/1000;
$hash->{helper}{nextSend}{$src} = gettimeofday() + $wait if ($wait > 0);
}
if (hex($flg)&0xA4 == 0xA4 && $hash->{owner} eq $dst){
Log $ll5, "HMLAN_Parse: $name ACK config";
HMLAN_Write($hash,undef, "As15".$mNo."8002".$dst.$src."00");
}
if ($letter eq 'R' && $hash->{helper}{$src}{flg}){
$hash->{helper}{$src}{flg} = 0; #release send-holdoff
if ($hash->{helper}{$src}{msg}){ #send delayed msg if any
Log $ll5,"HMLAN_SdDly: $name $src";
HMLAN_SimpleWrite($hash, $hash->{helper}{$src}{msg});
}
$hash->{helper}{$src}{msg} = ""; #clear message
}
# prepare dispatch-----------
# HM format A<len><msg>:<info>:<RSSI>:<IOname> Info is not used anymore
my $dmsg = sprintf("A%02X%s:$CULinfo:$rssi:$name",
length($mFld[5])/2, uc($mFld[5]));
my %addvals = (RAWMSG => $rmsg, RSSI => hex($mFld[4])-65536);
Dispatch($hash, $dmsg, \%addvals);
}
elsif($mFld[0] eq 'HHM-LAN-IF'){#HMLAN version info
$hash->{serialNr} = $mFld[2];
$hash->{firmware} = sprintf("%d.%d", (hex($mFld[1])>>12)&0xf, hex($mFld[1]) & 0xffff);
$hash->{owner} = $mFld[4];
$hash->{uptime} = HMLAN_uptime($mFld[5],$hash);
$hash->{assignIDsReport}=hex($mFld[6]);
$hash->{helper}{keepAliveRec} = 1;
$hash->{helper}{keepAliveRpt} = 0;
Log $ll5, 'HMLAN_Parse: '.$name. ' V:'.$mFld[1]
.' sNo:'.$mFld[2].' d:'.$mFld[3]
.' O:' .$mFld[4].' t:'.$mFld[5].' IDcnt:'.$mFld[6];
my $myId = AttrVal($name, "hmId", "");
$myId = $attr{$name}{hmId} = $mFld[4] if (!$myId);
if($mFld[4] ne $myId && !AttrVal($name, "dummy", 0)) {
Log 1, 'HMLAN setting owner to '.$myId.' from '.$mFld[4];
HMLAN_SimpleWrite($hash, "A$myId");
}
}
elsif($rmsg =~ m/^I00.*/) {;
# Ack from the HMLAN
}
else {
Log $ll5, "$name Unknown msg >$rmsg<";
}
}
sub HMLAN_Ready($) {###########################################################
my ($hash) = @_;
return DevIo_OpenDev($hash, 1, "HMLAN_DoInit");
}
sub HMLAN_SimpleWrite(@) {#####################################################
my ($hash, $msg, $nonl) = @_;
return if(!$hash || AttrVal($hash->{NAME}, "dummy", undef));
my $name = $hash->{NAME};
my $ll5 = GetLogLevel($name,5);
my $len = length($msg);
# It is not possible to answer befor 100ms
if ($len>51){
return if($hash->{helper}{HMcnd} && $hash->{helper}{HMcnd} == 4);#overload
my $dst = substr($msg,46,6);
if ($hash->{helper}{nextSend}{$dst}){
my $DevDelay = $hash->{helper}{nextSend}{$dst} - gettimeofday();
select(undef, undef, undef, (($DevDelay > 0.1)?0.1:$DevDelay))
if ($DevDelay > 0.01);
delete $hash->{helper}{nextSend}{$dst};
}
if ($dst ne $attr{$name}{hmId}){ #delay send if answer is pending
if ( $hash->{helper}{$dst}{flg} && #HMLAN's ack pending
($hash->{helper}{$dst}{to} > gettimeofday())){#won't wait forever!
$hash->{helper}{$dst}{msg} = $msg; #postpone message
Log $ll5,"HMLAN_Delay: $name $dst";
return;
}
my $flg = substr($msg,36,2);
$hash->{helper}{$dst}{flg} = (hex($flg)&0x20)?1:0;
$hash->{helper}{$dst}{to} = gettimeofday() + 2;# flag timeout after 2 sec
$hash->{helper}{$dst}{msg} = "";
}
if ($len > 52){#channel information included, send sone kind of clearance
my $chn = substr($msg,52,2);
if ($hash->{helper}{$dst}{chn} && $hash->{helper}{$dst}{chn} ne $chn){
my $updt = $hash->{helper}{$dst}{newChn};
Log $ll5, 'HMLAN_Send: '.$name.' S:'.$updt;
syswrite($hash->{TCPDev}, $updt."\r\n") if($hash->{TCPDev});
}
$hash->{helper}{$dst}{chn} = $chn;
}
$msg =~ m/(.{9}).(..).(.{8}).(..).(.{8}).(..)(....)(.{6})(.{6})(.*)/;
Log $ll5, 'HMLAN_Send: '.$name.' S:'.$1
.' stat: ' .$2
.' t:' .$3
.' d:' .$4
.' r:' .$5
.' m:' .$6
.' ' .$7
.' ' .$8
.' ' .$9
.' ' .$10;
}
else{
Log $ll5, 'HMLAN_Send: '.$name.' I:'.$msg;
}
$msg .= "\r\n" unless($nonl);
syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
}
sub HMLAN_DoInit($) {##########################################################
my ($hash) = @_;
my $name = $hash->{NAME};
my $id = AttrVal($name, "hmId", undef);
my $key = AttrVal($name, "hmKey", ""); # 36(!) hex digits
my $s2000 = sprintf("%02X", HMLAN_secSince2000());
HMLAN_SimpleWrite($hash, "A$id") if($id);
HMLAN_SimpleWrite($hash, "C");
HMLAN_SimpleWrite($hash, "Y01,01,$key");
HMLAN_SimpleWrite($hash, "Y02,00,");
HMLAN_SimpleWrite($hash, "Y03,00,");
HMLAN_SimpleWrite($hash, "Y03,00,");
HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
delete $hash->{helper}{ref};
$hash->{helper}{HMcnd} = 0xff; # init HMLAN xmit cond, will force reading
RemoveInternalTimer( "Overload:".$name);
foreach (keys %lhash){delete ($lhash{$_})};# clear IDs - HMLAN might have a reset
$hash->{helper}{keepAliveRec} = 1; # ok for first time
$hash->{helper}{keepAliveRpt} = 0; # ok for first time
RemoveInternalTimer( "keepAliveCk:".$name);# avoid duplicate timer
RemoveInternalTimer( "keepAlive:".$name);# avoid duplicate timer
InternalTimer(gettimeofday()+$attr{$name}{wdTimer}, "HMLAN_KeepAlive", "keepAlive:".$name, 0);
return undef;
}
sub HMLAN_KeepAlive($) {#######################################################
my($in ) = shift;
my(undef,$name) = split(':',$in);
my $hash = $defs{$name};
$hash->{helper}{keepAliveRec} = 0; # reset indicator
return if(!$hash->{FD});
HMLAN_SimpleWrite($hash, "K");
$hash->{helper}{ref}{kTs} = int(time()*1000);
RemoveInternalTimer( "keepAlive:".$name);# avoid duplicate timer
my $rt = AttrVal($name,"respTime",1);
InternalTimer(gettimeofday()+$rt,"HMLAN_KeepAliveCheck","keepAliveCk:".$name,1);
$attr{$name}{wdTimer} = 25 if (!$attr{$name}{wdTimer});
InternalTimer(gettimeofday()+$attr{$name}{wdTimer} ,"HMLAN_KeepAlive", "keepAlive:".$name, 1);
}
sub HMLAN_KeepAliveCheck($) {##################################################
my($in ) = shift;
my(undef,$name) = split(':',$in);
my $hash = $defs{$name};
if ($hash->{helper}{keepAliveRec} != 1){# no answer
if ($hash->{helper}{keepAliveRpt} >2){# give up here
DevIo_Disconnected($hash);
}
else{
$hash->{helper}{keepAliveRpt}++;
HMLAN_KeepAlive("keepAlive:".$name);#repeat
}
}
else{
$hash->{helper}{keepAliveRpt}=0;
}
}
sub HMLAN_secSince2000() {#####################################################
# Calculate the local time in seconds from 2000.
my $t = time();
my @l = localtime($t);
my @g = gmtime($t);
$t += 60*(($l[2]-$g[2] + ((($l[5]<<9)|$l[7]) <=> (($g[5]<<9)|$g[7])) * 24) * 60 + $l[1]-$g[1])
# timezone and daylight saving...
- 946684800 # seconds between 01.01.2000, 00:00 and THE EPOCH (1970)
- 7200; # HM Special
return $t;
}
sub HMLAN_relOvrLd($) {########################################################
my(undef,$name) = split(':',$_[0]);
HMLAN_condUpdate($defs{$name},0xFE);
}
sub HMLAN_condUpdate($$) {#####################################################
my($hash,$HMcnd) = @_;
my $name = $hash->{NAME};
$hash->{helper}{cnd}{$HMcnd} = 0 if (!$hash->{helper}{cnd}{$HMcnd});
$hash->{helper}{cnd}{$HMcnd}++;
InternalTimer(gettimeofday()+$HMOvLdRcvr,"HMLAN_relOvrLd","Overload:".$name,1)
if ($HMcnd == 4);
my $HMcndTxt = $HMcond{$HMcnd}?$HMcond{$HMcnd}:"Unknown:$HMcnd";
Log GetLogLevel($name,2), "HMLAN_Parse: $name new condition $HMcndTxt";
readingsSingleUpdate($hash,"cond",$HMcndTxt,1);
my $txt;
$txt .= $HMcond{$_}.":".$hash->{helper}{cnd}{$_}." "
foreach (keys%{$hash->{helper}{cnd}});
readingsSingleUpdate($hash,"Xmit-Events",$txt,1);
$hash->{helper}{HMcnd} = $HMcnd;
}
1;
=pod
=begin html
<a name="HMLAN"></a>
<h3>HMLAN</h3>
<ul>
The HMLAN is the fhem module for the eQ-3 HomeMatic LAN Configurator.<br>
A description on how to use <a href="https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb">hmCfgUsb</a> can be found follwing the link.<br/>
<br/>
The fhem module will emulate a CUL device, so the <a href="#CUL_HM">CUL_HM</a> module can be used to define HomeMatic devices.<br/>
<br>
In order to use it with fhem you <b>must</b> disable the encryption first with the "HomeMatic Lan Interface Configurator"<br>
(which is part of the supplied Windows software), by selecting the device, "Change IP Settings", and deselect "AES Encrypt Lan Communication".<br/>
<br/>
This device can be used in parallel with a CCU and (readonly) with fhem. To do this:
<ul>
<li>start the fhem/contrib/tcptee.pl program</li>
<li>redirect the CCU to the local host</li>
<li>disable the LAN-Encryption on the CCU for the Lan configurator</li>
<li>set the dummy attribute for the HMLAN device in fhem</li>
</ul>
<br/><br/>
<a name="HMLANdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; HMLAN &lt;ip-address&gt;[:port]</code><br>
<br>
port is 1000 by default.<br/>
If the ip-address is called none, then no device will be opened, so you can experiment without hardware attached.
</ul>
<br><br>
<a name="HMLANset"></a>
<b>Set</b>
<ul>
<li><a href="#hmPairForSec">hmPairForSec</a></li>
<li><a href="#hmPairSerial">hmPairSerial</a></li>
</ul>
<br><br>
<a name="HMLANget"></a>
<b>Get</b>
<ul>
N/A
</ul>
<br><br>
<a name="HMLANattr"></a>
<b>Attributes</b>
<ul>
<li><a href="#do_not_notify">do_not_notify</a></li><br>
<li><a href="#attrdummy">dummy</a></li><br>
<li><a href="#loglevel">loglevel</a></li><br>
<li><a href="#addvaltrigger">addvaltrigger</a></li><br>
<li><a href="#hmId">hmId</a></li><br>
<li><a href="#hmProtocolEvents">hmProtocolEvents</a></li><br>
<li><a href="#respTime">respTime</a><br>
Define max response time of the HMLAN adapter in seconds. Default is 1 sec.<br/>
Longer times may be used as workaround in slow/instable systems or LAN configurations.</li>
<li><a href="#wdTimer">wdTimer</a><br>
Time in sec to trigger HMLAN. Values between 5 and 25 are allowed, 25 is default.<br/>
It is <B>not recommended</B> to change this timer. If problems are detected with <br/>
HLMLAN disconnection it is advisable to resolve the root-cause of the problem and not symptoms.</li>
</ul>
</ul>
=end html
=cut