00_HMLAN.pm 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460
  1. ##############################################
  2. # $Id: 00_HMLAN.pm 14073 2017-04-22 13:45:25Z martinp876 $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use Time::HiRes qw(gettimeofday time);
  7. use Digest::MD5 qw(md5);
  8. sub HMLAN_Initialize($);
  9. sub HMLAN_Define($$);
  10. sub HMLAN_Undef($$);
  11. sub HMLAN_RemoveHMPair($);
  12. sub HMLAN_Attr(@);
  13. sub HMLAN_Set($@);
  14. sub HMLAN_ReadAnswer($$$);
  15. sub HMLAN_Write($$$);
  16. sub HMLAN_Read($);
  17. sub HMLAN_uptime($@);
  18. sub HMLAN_Parse($$);
  19. sub HMLAN_Ready($);
  20. sub HMLAN_SimpleWrite(@);
  21. sub HMLAN_DoInit($);
  22. sub HMLAN_KeepAlive($);
  23. sub HMLAN_secSince2000();
  24. sub HMLAN_relOvrLd($);
  25. sub HMLAN_condUpdate($$);
  26. sub HMLAN_getVerbLvl ($$$$);
  27. my %sets = ( "open" => ""
  28. ,"close" => ""
  29. ,"reopen" => ""
  30. ,"restart" => ""
  31. ,"hmPairForSec" => "HomeMatic"
  32. ,"hmPairSerial" => "HomeMatic"
  33. ,"reassignIDs" => ""
  34. );
  35. my %gets = ( "assignIDs" => ""
  36. );
  37. my %HMcond = ( 0 =>'ok'
  38. ,2 =>'Warning-HighLoad'
  39. ,4 =>'ERROR-Overload'
  40. ,251=>'dummy'
  41. ,252=>'timeout'
  42. ,253=>'disconnected'
  43. ,254=>'Overload-released'
  44. ,255=>'init');
  45. my $HMmlSlice = 12; # number of messageload slices per hour (10 = 6min)
  46. sub HMLAN_Initialize($) {
  47. my ($hash) = @_;
  48. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  49. # Provider
  50. $hash->{ReadFn} = "HMLAN_Read";
  51. $hash->{WriteFn} = "HMLAN_Write";
  52. $hash->{ReadyFn} = "HMLAN_Ready";
  53. $hash->{SetFn} = "HMLAN_Set";
  54. $hash->{GetFn} = "HMLAN_Get";
  55. $hash->{NotifyFn}= "HMLAN_Notify";
  56. $hash->{AttrFn} = "HMLAN_Attr";
  57. $hash->{Clients} = ":CUL_HM:";
  58. my %mc = (
  59. "1:CUL_HM" => "^A......................",
  60. );
  61. $hash->{MatchList} = \%mc;
  62. # Normal devices
  63. $hash->{DefFn} = "HMLAN_Define";
  64. $hash->{UndefFn} = "HMLAN_Undef";
  65. $hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 " .
  66. "addvaltrigger " .
  67. "hmId hmKey hmKey2 hmKey3 ".#hmKey4 hmKey5 " .
  68. "respTime " .
  69. "hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger ".
  70. "hmMsgLowLimit ".
  71. "loadLevel ".
  72. "hmLanQlen:1_min,2_low,3_normal,4_high,5_critical ".
  73. "wdTimer:5,10,15,20,25 ".
  74. "logIDs:multiple,sys,all,broadcast ".
  75. $readingFnAttributes;
  76. }
  77. sub HMLAN_Define($$) {#########################################################
  78. my ($hash, $def) = @_;
  79. my @a = split("[ \t][ \t]*", $def);
  80. if(@a != 3) {
  81. my $msg = "wrong syntax: define <name> HMLAN ip[:port]";
  82. Log3 $hash, 2, $msg;
  83. return $msg;
  84. }
  85. DevIo_CloseDev($hash);
  86. my $name = $a[0];
  87. my $dev = $a[2];
  88. $dev .= ":1000" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
  89. if($dev eq "none") {
  90. Log3 $hash, 1, "$name device is none, commands will be echoed only";
  91. $attr{$name}{dummy} = 1;
  92. return undef;
  93. }
  94. $attr{$name}{hmLanQlen} = "1_min"; #max message queue length in HMLan
  95. no warnings 'numeric';
  96. $hash->{helper}{q}{hmLanQlen} = int($attr{$name}{hmLanQlen})+0;
  97. use warnings 'numeric';
  98. $hash->{DeviceName} = $dev;
  99. $hash->{msgKeepAlive} = ""; # delay of trigger Alive messages
  100. $hash->{helper}{k}{DlyMax} = 0;
  101. $hash->{helper}{k}{BufMin} = 30;
  102. $hash->{helper}{q}{answerPend} = 0;#pending answers from LANIf
  103. my @arr = ();
  104. @{$hash->{helper}{q}{apIDs}} = \@arr;
  105. $hash->{helper}{q}{scnt} = 0;
  106. $hash->{helper}{q}{loadNo} = 0;
  107. $hash->{helper}{q}{loadLastMax} = 0; # max load in last slice
  108. my @ald = ("0") x $HMmlSlice;
  109. $hash->{helper}{q}{ald} = \@ald; # array of load events
  110. $hash->{msgLoadCurrent} = 0;
  111. $defs{$name}{helper}{log}{all} = 0;# selective log support
  112. $defs{$name}{helper}{log}{sys} = 0;
  113. my @al = ();
  114. @{$hash->{helper}{log}{ids}} = \@al;
  115. $hash->{assignedIDsCnt} = 0;#define hash
  116. $hash->{helper}{assIdRep} = 0;
  117. $hash->{helper}{assIdCnt} = 0;
  118. HMLAN_condUpdate($hash,253);#set disconnected
  119. readingsSingleUpdate($hash,"state","disconnected",1);
  120. $hash->{owner} = "";
  121. HMLAN_Attr("delete",$name,"loadLevel");
  122. my $ret = DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
  123. return $ret;
  124. }
  125. sub HMLAN_Undef($$) {##########################################################
  126. my ($hash, $arg) = @_;
  127. my $name = $hash->{NAME};
  128. foreach my $d (sort keys %defs) {
  129. if(defined($defs{$d}) &&
  130. defined($defs{$d}{IODev}) &&
  131. $defs{$d}{IODev} == $hash){
  132. Log3 $hash, 2, "deleting port for $d";
  133. delete $defs{$d}{IODev};
  134. }
  135. }
  136. DevIo_CloseDev($hash);
  137. return undef;
  138. }
  139. sub HMLAN_RemoveHMPair($) {####################################################
  140. my($in ) = shift;
  141. my(undef,$name) = split(':',$in);
  142. my $hash = $defs{$name};
  143. RemoveInternalTimer("hmPairForSec:$name");
  144. delete($hash->{hmPair});
  145. delete($hash->{hmPairSerial});
  146. }
  147. sub HMLAN_Notify(@) {##########################################################
  148. my ($hash,$dev) = @_;
  149. if ($dev->{NAME} eq "global" && grep (m/^INITIALIZED$/,@{$dev->{CHANGED}})){
  150. if ($hash->{helper}{attrPend}){
  151. my $aVal = AttrVal($hash->{NAME},"logIDs","");
  152. HMLAN_Attr("set",$hash->{NAME},"logIDs",$aVal) if($aVal);
  153. delete $hash->{helper}{attrPend};
  154. }
  155. HMLAN_writeAesKey($hash->{NAME});
  156. }
  157. elsif ($dev->{NAME} eq $hash->{NAME}){
  158. foreach (grep (m/CONNECTED$/,@{$dev->{CHANGED}})) { # connect/disconnect
  159. if ($_ eq "DISCONNECTED") {HMLAN_condUpdate($hash,253);}
  160. # elsif ($_ eq "CONNECTED") {covered by init;}
  161. }
  162. }
  163. return;
  164. }
  165. sub HMLAN_Attr(@) {############################################################
  166. my ($cmd,$name, $aName,$aVal) = @_;
  167. if ($aName eq "wdTimer" && $cmd eq "set"){#allow between 5 and 25 second
  168. return "select wdTimer between 5 and 25 seconds" if ($aVal>30 || $aVal<5);
  169. $attr{$name}{wdTimer} = $aVal;
  170. $defs{$name}{helper}{k}{Start} = 0;
  171. }
  172. elsif($aName eq "hmLanQlen"){
  173. if ($cmd eq "set"){
  174. no warnings 'numeric';
  175. $defs{$name}{helper}{q}{hmLanQlen} = int($aVal)+0;
  176. use warnings 'numeric';
  177. }
  178. else{
  179. $defs{$name}{helper}{q}{hmLanQlen} = 1;
  180. }
  181. }
  182. elsif($aName =~ m /^hmKey/){
  183. my $retVal= "";
  184. if ($cmd eq "set"){
  185. # eQ3 default key A4E375C6B09FD185F27C4E96FC273AE4
  186. my $kno = ($aName eq "hmKey")?1:substr($aName,5,1);
  187. my ($no,$val) = (sprintf("%02X",$kno),$aVal);
  188. if ($aVal =~ m/:/){#number given
  189. ($no,$val) = split ":",$aVal;
  190. return "illegal number:$no" if (hex($no) < 1 || hex($no) > 255 || length($no) != 2);
  191. }
  192. $attr{$name}{$aName} = "$no:".
  193. (($val =~ m /^[0-9A-Fa-f]{32}$/ )
  194. ? $val
  195. : unpack('H*', md5($val)));
  196. $retVal = "$aName set to $attr{$name}{$aName}"
  197. if($aVal ne $attr{$name}{$aName});
  198. }
  199. else{
  200. delete $attr{$name}{$aName};
  201. }
  202. HMLAN_writeAesKey($name);
  203. return $retVal;
  204. }
  205. elsif($aName eq "hmMsgLowLimit"){
  206. if ($cmd eq "set"){
  207. return "hmMsgLowLimit:please add integer between 10 and 100"
  208. if ( $aVal !~ m/^(\d+)$/
  209. ||$aVal<10
  210. ||$aVal >100 );
  211. delete $defs{$name}{helper}{loadLvl}{h}{$aVal};
  212. my %lvlHr = reverse %{$defs{$name}{helper}{loadLvl}{h}};
  213. $lvlHr{batchLevel} = $aVal;
  214. my %lvlH = reverse %lvlHr;
  215. $defs{$name}{helper}{loadLvl}{h} = \%lvlH;
  216. my @a = sort { $b <=> $a } keys %lvlH;
  217. $defs{$name}{helper}{loadLvl}{a} = \@a;
  218. $attr{$name}{loadLevel} = join(",",map{"$_:$lvlH{$_}"}sort keys%lvlH);
  219. $defs{$name}{helper}{loadLvl}{bl} = $aVal;
  220. }
  221. if ($init_done){
  222. return "better use loadLevel batchLevel";
  223. }
  224. }
  225. elsif($aName eq "hmId"){
  226. if ($cmd eq "set"){
  227. my $owner_ccu = InternalVal($name,"owner_CCU",undef);
  228. return "device owned by $owner_ccu" if ($owner_ccu);
  229. return "wrong syntax: hmId must be 6-digit-hex-code (3 byte)"
  230. if ($aVal !~ m/^[A-F0-9]{6}$/i);
  231. }
  232. }
  233. elsif($aName eq "logIDs"){
  234. HMLAN_UpdtLogId();
  235. if ($cmd eq "set"){
  236. if ($init_done){
  237. if ($aVal){
  238. my @ids = split",",$aVal;
  239. my @idName;
  240. if (grep /sys/,@ids){
  241. push @idName,"sys";
  242. $defs{$name}{helper}{log}{sys}=1;
  243. }
  244. else{
  245. $defs{$name}{helper}{log}{sys}=0;
  246. }
  247. if (grep /all/,@ids){
  248. push @idName,"all";
  249. $defs{$name}{helper}{log}{all}=1;
  250. }
  251. else{
  252. $defs{$name}{helper}{log}{all}=0;
  253. for (@ids) {s/broadcast/000000/g};
  254. $_=substr(CUL_HM_name2Id($_),0,6) foreach(grep !/^$/,@ids);
  255. $_="" foreach(grep !/^[A-F0-9]{6}$/,@ids);
  256. @ids = HMLAN_noDup(@ids);
  257. push @idName,CUL_HM_id2Name($_) foreach(@ids);
  258. for (@idName) {s/000000/broadcast/g};
  259. }
  260. $attr{$name}{$aName} = join(",",@idName);
  261. @{$defs{$name}{helper}{log}{ids}}=grep !/^(sys|all)$/,@ids;
  262. }
  263. else{
  264. $attr{$name}{$aName} = "";
  265. @{$defs{$name}{helper}{log}{ids}}=();
  266. }
  267. }
  268. else{
  269. $defs{$name}{helper}{attrPend} = 1;
  270. return;
  271. }
  272. }
  273. else{
  274. my @ids = ();
  275. $defs{$name}{helper}{log}{sys}=0;
  276. $defs{$name}{helper}{log}{all}=0;
  277. @{$defs{$name}{helper}{log}{ids}}=grep !/^(sys|all)$/,@ids;
  278. }
  279. return "logging set to $attr{$name}{$aName}"
  280. if ($aVal && $attr{$name}{$aName} ne $aVal);
  281. }
  282. elsif($aName eq "loadLevel"){
  283. my %lvlH;
  284. my $batchLevel = 40;#defailt batch level
  285. if ($cmd eq "set"){
  286. foreach my $lvl(sort split(",",$aVal)){
  287. next if(!$lvl);
  288. my @lvlSp = split(":",$lvl);
  289. return "$lvl not parsed. Only one Level per Entry:".scalar @lvlSp if (scalar @lvlSp != 2);
  290. return "$lvlSp[0] must be between 0 and 100" if ( $lvlSp[0] !~ m/^(\d+)$/
  291. ||$lvlSp[0]<0
  292. ||$lvlSp[0] >100 );
  293. $lvlH{$lvlSp[0]+0} = $lvlSp[1];
  294. }
  295. my %lvlHr = reverse %lvlH;
  296. $lvlH{0} = "low" if (!defined $lvlH{0});
  297. if (!defined $lvlHr{batchLevel}){
  298. $lvlH{$batchLevel} = "batchLevel";
  299. }
  300. else{
  301. $batchLevel = $lvlHr{batchLevel};
  302. }
  303. }
  304. else{#delete
  305. $lvlH{0} = "low";
  306. $lvlH{$batchLevel} = "batchLevel";
  307. $lvlH{90} = "high";
  308. $lvlH{99} = "suspended";
  309. }
  310. $defs{$name}{helper}{loadLvl}{h} = \%lvlH;
  311. my @a = sort { $b <=> $a } keys %lvlH;
  312. $defs{$name}{helper}{loadLvl}{a} = \@a;
  313. $defs{$name}{helper}{loadLvl}{bl} = $batchLevel;
  314. $attr{$name}{loadLevel} = join(",",map{"$_:$lvlH{$_}"}sort keys%lvlH) if ($cmd ne "set");
  315. }
  316. elsif($aName eq "dummy"){
  317. if ($cmd eq "set" && $aVal != 0){
  318. RemoveInternalTimer( "keepAliveCk:".$name);
  319. RemoveInternalTimer( "keepAlive:".$name);
  320. DevIo_CloseDev($defs{$name});
  321. HMLAN_condUpdate($defs{$name},251);#state: dummy
  322. }
  323. else{
  324. if ($cmd eq "set"){
  325. $attr{$name}{$aName} = $aVal;
  326. }
  327. else{
  328. delete $attr{$name}{$aName};
  329. }
  330. DevIo_OpenDev($defs{$name}, 1, "HMLAN_DoInit");
  331. }
  332. }
  333. return;
  334. }
  335. sub HMLAN_UpdtLogId() {####################################################
  336. $modules{HMLAN}{AttrList} =~ s/logIDs:.*? //;
  337. $modules{HMLAN}{AttrList} =~ s/logIDs:.*?$//;
  338. $modules{HMLAN}{AttrList} .= " logIDs:multiple,sys,all,broadcast,"
  339. .join(",",(devspec2array("TYPE=CUL_HM:FILTER=DEF=......:FILTER=model!=ActionDetector")));
  340. return;
  341. }
  342. sub HMLAN_UpdtMsgLoad($$) {####################################################
  343. my($name,$val) = @_;
  344. my $hash = $defs{$name};
  345. my $hashQ = $defs{$name}{helper}{q};
  346. $hash->{msgLoadCurrent} = $val;
  347. my ($r) = grep { $_ <= $val } @{$hash->{helper}{loadLvl}{a}};
  348. readingsSingleUpdate($hash,"loadLvl",$hash->{helper}{loadLvl}{h}{$r},1);
  349. $hashQ->{loadLastMax} = $val if ($hashQ->{loadLastMax} < $val);
  350. my $t = int(gettimeofday()/(3600/$HMmlSlice))%$HMmlSlice;
  351. if ($hashQ->{loadNo} != $t){
  352. $hashQ->{loadNo} = $t;
  353. unshift @{$hashQ->{ald}},$hashQ->{loadLastMax};
  354. #relative history my @a = map{$hashQ->{ald}[$_] -
  355. #relative history $hashQ->{ald}[$_ + 1]} (0..($HMmlSlice-1));
  356. #relative history $hash->{msgLoadHistory} = (60/$HMmlSlice)."min steps: ".join("/",@a);
  357. pop @{$hashQ->{ald}};
  358. $hash->{msgLoadHistoryAbs} = (60/$HMmlSlice)."min steps: ".join("/",@{$hashQ->{ald}});
  359. # try to release high-load condition with a dummy message
  360. # one a while
  361. if (ReadingsVal($name,"cond","") =~ m /(Warning-HighLoad|ERROR-Overload)/){
  362. $hash->{helper}{recoverTest} = 1;
  363. HMLAN_Write($hash,"","As09998112"
  364. .AttrVal($name,"hmId","999999")
  365. ."000000");
  366. }
  367. $hashQ->{loadLastMax} = 0;
  368. }
  369. return;
  370. }
  371. sub HMLAN_Get($@) {############################################################
  372. my ($hash, @a) = @_;
  373. my $ret = "";
  374. return "\"get $hash->{NAME}\" no command given" if(@a < 2);
  375. return "Unknown argument $a[1], choose one of " . join(" ", sort keys %gets)
  376. if(!defined($gets{$a[1]}));
  377. my $name = shift @a;
  378. my $cmd = shift @a;
  379. my $arg = join("", @a);
  380. if($cmd eq "assignIDs") { #--------------------------------------
  381. return "set $name $cmd doesn't support parameter" if(scalar(@a));
  382. my @aIds = map{CUL_HM_id2Name($_)} keys %{$hash->{helper}{ids}};
  383. @aIds = map{CUL_HM_name2Id($_)." : $_"} sort @aIds;
  384. $ret = "assignedIDs: ".scalar(@aIds)."\n".join("\n", @aIds);
  385. }
  386. return ($ret);# no not generate trigger outof command
  387. }
  388. sub HMLAN_Set($@) {############################################################
  389. my ($hash, @a) = @_;
  390. return "\"set $hash->{NAME}\" no command given" if(@a < 2);
  391. return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
  392. if(!defined($sets{$a[1]}));
  393. my $name = shift @a;
  394. my $cmd = shift @a;
  395. my $arg = join("", @a);
  396. if ($cmd eq "hmPairForSec") { #################################
  397. $arg = 60 if(!$arg || $arg !~ m/^\d+$/);
  398. HMLAN_RemoveHMPair("hmPairForSec:$name");
  399. $hash->{hmPair} = 1;
  400. InternalTimer(gettimeofday()+$arg, "HMLAN_RemoveHMPair", "hmPairForSec:$name", 1);
  401. }
  402. elsif($cmd eq "hmPairSerial") { #################################
  403. return "Usage: set $name hmPairSerial <10-character-serialnumber>"
  404. if(!$arg || $arg !~ m/^.{10}$/);
  405. my $id = InternalVal($hash->{NAME}, "owner", "123456");
  406. $hash->{HM_CMDNR} = $hash->{HM_CMDNR} ? ($hash->{HM_CMDNR}+1)%256 : 1;
  407. HMLAN_Write($hash, undef, sprintf("As15%02X8401%s000000010A%s",
  408. $hash->{HM_CMDNR}, $id, unpack('H*', $arg)));
  409. HMLAN_RemoveHMPair("hmPairForSec:$name");
  410. $hash->{hmPair} = 1;
  411. $hash->{hmPairSerial} = $arg;
  412. InternalTimer(gettimeofday()+20, "HMLAN_RemoveHMPair", "hmPairForSec:".$name, 1);
  413. }
  414. elsif($cmd eq "reassignIDs") { #################################
  415. return "set $name $cmd doesn't support parameter" if(scalar(@a));
  416. HMLAN_assignIDs($hash);
  417. }
  418. elsif($cmd eq "reopen") { #################################
  419. DevIo_CloseDev($hash);
  420. HMLAN_condUpdate($hash,253);#set disconnected
  421. DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
  422. }
  423. elsif($cmd eq "restart") { #################################
  424. HMLAN_SimpleWrite($hash, "Y05,");
  425. HMLAN_condUpdate($hash,253);#set disconnected
  426. }
  427. elsif($cmd eq "close") { #################################
  428. DevIo_CloseDev($hash);
  429. HMLAN_condUpdate($hash,253);#set disconnected
  430. }
  431. elsif($cmd eq "open") { #################################
  432. DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
  433. }
  434. return ("",1);# no not generate trigger outof command
  435. }
  436. sub HMLAN_ReadAnswer($$$) {# This is a direct read for commands like get
  437. my ($hash, $arg, $regexp) = @_;
  438. my $type = $hash->{TYPE};
  439. return ("No FD", undef)
  440. if(!$hash && !defined($hash->{FD}));
  441. my ($mdata, $rin) = ("", '');
  442. my $buf;
  443. my $to = 3; # 3 seconds timeout
  444. $to = $hash->{RA_Timeout} if($hash->{RA_Timeout}); # ...or less
  445. for(;;) {
  446. return ("Device lost when reading answer for get $arg", undef)
  447. if(!$hash->{FD});
  448. vec($rin, $hash->{FD}, 1) = 1;
  449. my $nfound = select($rin, undef, undef, $to);
  450. if($nfound < 0) {
  451. next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
  452. my $err = $!;
  453. DevIo_Disconnected($hash);
  454. HMLAN_condUpdate($hash,253);
  455. return("HMLAN_ReadAnswer $arg: $err", undef);
  456. }
  457. return ("Timeout reading answer for get $arg", undef) if($nfound == 0);
  458. $buf = DevIo_SimpleRead($hash);# and now read
  459. return ("No data", undef) if(!defined($buf));
  460. if($buf) {
  461. Log3 $hash, 5, "HMLAN/RAW (ReadAnswer): $buf";
  462. $mdata .= $buf;
  463. }
  464. if($mdata =~ m/\r\n/) {
  465. if($regexp && $mdata !~ m/$regexp/) {
  466. HMLAN_Parse($hash, $mdata);
  467. }
  468. else {
  469. return (undef, $mdata);
  470. }
  471. }
  472. }
  473. }
  474. sub HMLAN_Write($$$) {#########################################################
  475. my ($hash,$fn,$msg) = @_;
  476. return if(!defined $msg);
  477. if (defined($fn) && $fn eq "cmd"){
  478. HMLAN_SimpleWrite($hash,$msg);
  479. return;
  480. }
  481. if (length($msg)>21){
  482. my ($mtype,$src,$dst) = (substr($msg, 8, 2),
  483. substr($msg, 10, 6),
  484. substr($msg, 16, 6));
  485. if ( $mtype eq "02" && $src eq $hash->{owner} && length($msg) == 24
  486. && defined $hash->{helper}{ids}{$dst}){
  487. # Acks are generally send by HMLAN autonomously
  488. # Special
  489. Log3 $hash, 5, "HMLAN: Skip ACK";
  490. return;
  491. }
  492. # my $IDHM = '+'.$dst.',01,00,F1EF'; # used by HMconfig - meaning??
  493. # my $IDadd = '+'.$dst; # guess: add ID?
  494. # my $IDack = '+'.$dst.',02,00,'; # guess: ID acknowledge
  495. # my $IDack = '+'.$dst.',FF,00,'; # guess: ID acknowledge
  496. # my $IDsub = '-'.$dst; # guess: ID remove?
  497. # my $IDnew = '+'.$dst.',00,01,'; # newChannel- trailing 01 to be sent if talk to neu channel
  498. my $IDadd = '+'.$dst.',00,00,'; # guess: add ID?
  499. if (!$hash->{helper}{ids}{$dst} && $dst ne "000000"){
  500. HMLAN_SimpleWrite($hash, $IDadd);
  501. $hash->{helper}{ids}{$dst}{name} = CUL_HM_id2Name($dst);
  502. $hash->{helper}{assIdCnt} = scalar(keys %{$hash->{helper}{ids}});
  503. $hash->{assignedIDsCnt} = $hash->{helper}{assIdCnt}
  504. .(($hash->{helper}{assIdCnt} eq $hash->{helper}{assIdRep})
  505. ?""
  506. :" report:$hash->{helper}{assIdRep}")
  507. ;
  508. }
  509. }
  510. elsif(length($msg)<5){
  511. Log3 $hash, 2, "HMLAN_Send: cmd too short:".($fn?$fn:"noFn").":".($msg?$msg:"no_msg");
  512. }
  513. elsif($msg =~ m /init:(......)/){
  514. my $dst = $1;
  515. if ($modules{CUL_HM}{defptr}{$dst} &&
  516. $modules{CUL_HM}{defptr}{$dst}{helper}{io}{newChn} ){
  517. HMLAN_SimpleWrite($hash,$modules{CUL_HM}{defptr}{$dst}{helper}{io}{newChn});
  518. $hash->{helper}{ids}{$dst}{cfg} = $modules{CUL_HM}{defptr}{$dst}{helper}{io}{newChn};
  519. $hash->{helper}{ids}{$dst}{name} = CUL_HM_id2Name($dst);
  520. $hash->{helper}{assIdCnt} = scalar(keys %{$hash->{helper}{ids}});
  521. $hash->{assignedIDsCnt} = $hash->{helper}{assIdCnt}
  522. .(($hash->{helper}{assIdCnt} eq $hash->{helper}{assIdRep})
  523. ?""
  524. :" report:$hash->{helper}{assIdRep}")
  525. ;
  526. }
  527. return;
  528. }
  529. elsif($msg =~ m /remove:(......)/){
  530. my $dst = $1;
  531. if ($modules{CUL_HM}{defptr}{$dst} &&
  532. $modules{CUL_HM}{defptr}{$dst}{helper}{io}{newChn} ){
  533. HMLAN_SimpleWrite($hash,"-$dst");
  534. delete $hash->{helper}{ids}{$dst};
  535. $hash->{helper}{assIdCnt} = scalar(keys %{$hash->{helper}{ids}});
  536. $hash->{assignedIDsCnt} = $hash->{helper}{assIdCnt}
  537. .(($hash->{helper}{assIdCnt} eq $hash->{helper}{assIdRep})
  538. ?""
  539. :" report:$hash->{helper}{assIdRep}")
  540. ;
  541. }
  542. return;
  543. }
  544. my $tm = int(gettimeofday()*1000) % 0xffffffff;
  545. $msg = sprintf("S%08X,00,00000000,01,%08X,%s",$tm, $tm, substr($msg, 4));
  546. HMLAN_SimpleWrite($hash, $msg);
  547. }
  548. sub HMLAN_Read($) {############################################################
  549. # called from the global loop, when the select for hash->{FD} reports data
  550. my ($hash) = @_;
  551. my $buf = DevIo_SimpleRead($hash);
  552. return "" if(!defined($buf));
  553. my $name = $hash->{NAME};
  554. my $hmdata = $hash->{PARTIAL};
  555. Log3 $hash, 5, "HMLAN/RAW: $hmdata/$buf";
  556. $hmdata .= $buf;
  557. while($hmdata =~ m/\n/) {
  558. my $rmsg;
  559. ($rmsg,$hmdata) = split("\n", $hmdata, 2);
  560. $rmsg =~ s/\r//;
  561. HMLAN_Parse($hash, $rmsg) if($rmsg);
  562. }
  563. $hash->{PARTIAL} = $hmdata;
  564. }
  565. sub HMLAN_uptime($@) {#########################################################
  566. my ($hmtC,$hash) = @_; # hmTime Current
  567. $hmtC = hex($hmtC);
  568. if ($hash && $hash->{helper}{ref}){ #will calculate new ref-time
  569. my $ref = $hash->{helper}{ref};#shortcut
  570. my $sysC = int(time()*1000); #current systime in ms
  571. my $offC = $sysC - $hmtC; #offset calc between time and HM-stamp
  572. if ($ref->{hmtL} && ($hmtC > $ref->{hmtL})){
  573. if (($sysC - $ref->{kTs})<20){ #if delay is more then 20ms, we dont trust
  574. if ($ref->{sysL}){
  575. $ref->{drft} = ($offC - $ref->{offL})/($sysC - $ref->{sysL});
  576. }
  577. $ref->{sysL} = $sysC;
  578. $ref->{offL} = $offC;
  579. }
  580. }
  581. else{# hm had a skip in time, start over calculation
  582. delete $hash->{helper}{ref};
  583. }
  584. $hash->{helper}{ref}{hmtL} = $hmtC;
  585. $hash->{helper}{ref}{kTs} = 0;
  586. }
  587. my $sec = int($hmtC/1000);
  588. return sprintf("%03d %02d:%02d:%02d.%03d",
  589. int($hmtC/86400000), int($sec/3600),
  590. int(($sec%3600)/60), $sec%60, $hmtC % 1000);
  591. }
  592. sub HMLAN_Parse($$) {##########################################################
  593. my ($hash, $rmsg) = @_;
  594. my $name = $hash->{NAME};
  595. my @mFld = split(',', $rmsg);
  596. my $letter = substr($mFld[0],0,1); # get leading char
  597. if ($letter =~ m/^[ER]/){#@mFld=($src, $status, $msec, $d2, $rssi, $msg)
  598. # max speed for devices is 100ms after receive - example:TC
  599. my ($mNo,$flg,$type,$src,$dst,$p) = unpack('A2A2A2A6A6A*',$mFld[5]);
  600. my $mLen = length($mFld[5])/2;
  601. my $CULinfo = "";
  602. Log3 $hash, HMLAN_getVerbLvl ($hash,$src,$dst,"5")
  603. , "HMLAN_Parse: $name R:".$mFld[0]
  604. .(($mFld[0] =~ m/^E/)?' ':'')
  605. .' stat:' .$mFld[1]
  606. .' t:' .$mFld[2]
  607. .' d:' .$mFld[3]
  608. .' r:' .$mFld[4]
  609. .' m:'.$mNo
  610. .' '.$flg.$type
  611. .' '.$src
  612. .' '.$dst
  613. .' '.$p;
  614. # handle status.
  615. #HMcnd stat
  616. # 00 00= msg without relation
  617. # 00 01= ack that HMLAN waited for
  618. # 00 02= msg send, no ack requested
  619. # 00 08= nack - ack was requested, msg repeated 3 times, still no ack
  620. # 00 21= ??(seen with 'R') - see below
  621. # 00 2x= should: AES was accepted, here is the response
  622. # 00 30= should: AES response failed
  623. # 00 4x= AES response accepted
  624. # 00 50= ??(seen with 'R')
  625. # 00 8x= response to a message send autonomous by HMLAN (e.g. A112 -> wakeup)
  626. # 01 xx= ?? 0100 AES response send (gen autoMsgSent)
  627. # 02 xx= prestate to 04xx. Message is still sent. This is a warning
  628. # 04 xx= nothing sent anymore. Any restart unsuccessful except power
  629. #
  630. # parameter 'cond'- condition of the IO device
  631. # Cond text
  632. # 0 ok
  633. # 1 AES request by HMLAN pending
  634. # 2 Warning-HighLoad
  635. # 4 Overload condition - no send anymore
  636. #
  637. my ($HMcnd,$stat) = map{hex($_)} unpack('A2A2',($mFld[1]));
  638. if ($HMcnd == 0x01){#HMLAN responded to AES request
  639. $CULinfo = ($mFld[3] eq "FF")?"AESpending"
  640. :"AESKey-".$mFld[3];
  641. }
  642. # config message: reset timer handling
  643. $hash->{helper}{ids}{$src}{flg} = 0 if ($type eq "00");
  644. if ($stat){# message with status information
  645. HMLAN_condUpdate($hash,$HMcnd) if ($hash->{helper}{q}{HMcndN} != $HMcnd);
  646. my $myId = $attr{$name}{hmId};
  647. if ($stat & 0x03 && $dst eq $myId){HMLAN_qResp($hash,$src,0);}
  648. elsif ($stat & 0x08 && $src eq $myId){HMLAN_qResp($hash,$dst,0);}
  649. $hash->{helper}{ids}{$dst}{flg} = 0 if(defined $hash->{helper}{ids}{$dst});
  650. #got response => unblock sending
  651. if ($stat & 0x0A){#08 and 02 dont need to go to CUL, internal ack only
  652. Log3 $hash, HMLAN_getVerbLvl ($hash,$src,$dst,"5")
  653. , "HMLAN_Parse: $name no ACK from $dst" if($stat & 0x08);
  654. return;
  655. }
  656. elsif (($stat & 0x70) == 0x30){Log3 $hash, HMLAN_getVerbLvl ($hash,$src,$dst,"5")
  657. , "HMLAN_Parse: $name AES code rejected for $dst $stat";
  658. $CULinfo = "AESerrReject";
  659. HMLAN_qResp($hash,$src,0);
  660. }
  661. elsif (($stat & 0x70) == 0x20){$CULinfo = "AESCom-ok"; }
  662. elsif ( $stat & 0x40) {$CULinfo = "AESCom-".($stat & 0x10?"fail":"ok");}
  663. }
  664. my $rssi = hex($mFld[4])-65536;
  665. #update some User information ------
  666. $hash->{uptime} = HMLAN_uptime($mFld[2]);
  667. $hash->{RSSI} = $rssi;
  668. $hash->{RAWMSG} = $rmsg;
  669. $hash->{"${name}_MSGCNT"}++;
  670. $hash->{"${name}_TIME"} = TimeNow();
  671. my $dly = 0; #--------- calc messageDelay ----------
  672. if ($hash->{helper}{ref} && $hash->{helper}{ref}{drft}){
  673. my $ref = $hash->{helper}{ref};#shortcut
  674. my $sysC = int(time()*1000); #current systime in ms
  675. $dly = int($sysC - (hex($mFld[2]) + $ref->{offL} + $ref->{drft}*($sysC - $ref->{sysL})));
  676. $hash->{helper}{dly}{lst} = $dly;
  677. my $dlyP = $hash->{helper}{dly};
  678. $dlyP->{min} = $dly if (!$dlyP->{min} || $dlyP->{min}>$dly);
  679. $dlyP->{max} = $dly if (!$dlyP->{max} || $dlyP->{max}<$dly);
  680. if ($dlyP->{cnt}) {$dlyP->{cnt}++} else {$dlyP->{cnt} = 1} ;
  681. $hash->{msgParseDly} = "min:" .$dlyP->{min}
  682. ." max:" .$dlyP->{max}
  683. ." last:".$dlyP->{lst}
  684. ." cnt:" .$dlyP->{cnt};
  685. ################# debugind help
  686. #my $st = $sysC - $dly;#time send
  687. #my $stms = sprintf("%03d",$st%1000);
  688. #my @slt = localtime(int($st/1000));
  689. #Log 1,"HMLAN dlyTime st:$slt[2]:$slt[1]:$slt[0].".$stms." dly:$dly";
  690. #################
  691. $dly = 0 if ($dly<0);
  692. }
  693. # HMLAN sends ACK for flag 'A0' but not for 'A4'(config mode)-
  694. # we ack ourself an long as logic is uncertain - also possible is 'A6' for RHS
  695. my $wait = 0.100 - $dly/1000;
  696. $modules{CUL_HM}{defptr}{$src}{helper}{io}{nextSend} = gettimeofday()+$wait
  697. if ($modules{CUL_HM}{defptr}{$src} && $wait > 0);
  698. if (hex($flg)&0xA4 == 0xA4 && $hash->{owner} eq $dst){
  699. Log3 $hash, HMLAN_getVerbLvl ($hash,$src,$dst,"5")
  700. , "HMLAN_Parse: $name ACK config";
  701. HMLAN_Write($hash,undef, "As15".$mNo."8002".$dst.$src."00");
  702. }
  703. if ($letter eq 'R' && $hash->{helper}{ids}{$src}{flg}){
  704. $hash->{helper}{ids}{$src}{flg} = 0 if($dst ne "000000"); #release send-holdoff
  705. if ($hash->{helper}{ids}{$src}{msg}){ #send delayed msg if any
  706. Log3 $hash, HMLAN_getVerbLvl ($hash,$src,$dst,"5")
  707. ,"HMLAN_SdDly: $name $src";
  708. HMLAN_SimpleWrite($hash, $hash->{helper}{ids}{$src}{msg});
  709. }
  710. $hash->{helper}{ids}{$src}{msg} = ""; #clear message
  711. }
  712. # prepare dispatch-----------
  713. # HM format A<len><msg>:<info>:<RSSI>:<IOname> Info is not used anymore
  714. my $dmsg = sprintf("A%02X%s:$CULinfo:$rssi:$name",
  715. $mLen, uc($mFld[5]));
  716. my %addvals = (RAWMSG => $rmsg, RSSI => hex($mFld[4])-65536);
  717. Dispatch($hash, $dmsg, \%addvals) if($mFld[5] !~ m/99.112999999000000/);#ignore overload test
  718. }
  719. elsif($mFld[0] =~ m /HHM-(LAN|USB)-IF/){#HMLAN version info
  720. $hash->{IFmodel} = $1;
  721. $hash->{uptime} = HMLAN_uptime($mFld[5],$hash);
  722. $hash->{helper}{assIdRep} = hex($mFld[6]);
  723. $hash->{assignedIDsCnt} = $hash->{helper}{assIdCnt}
  724. .(($hash->{helper}{assIdCnt} eq $hash->{helper}{assIdRep})
  725. ?""
  726. :" report:$hash->{helper}{assIdRep}")
  727. ;
  728. $hash->{helper}{q}{keepAliveRec} = 1;
  729. $hash->{helper}{q}{keepAliveRpt} = 0;
  730. my $load = defined $mFld[7] ? hex($mFld[7]):0;
  731. Log3 $hash, ($hash->{helper}{log}{sys}?0:5)
  732. , 'HMLAN_Parse: '.$name. " V:$mFld[1]"
  733. ." sNo:$mFld[2] d:$mFld[3]"
  734. ." O:$mFld[4] t:$mFld[5] IDcnt:$mFld[6] L:$load %";
  735. HMLAN_UpdtMsgLoad($name,$load);
  736. my $myId = AttrVal($name, "hmId", "");
  737. $myId = $attr{$name}{hmId} = $mFld[4] if (!$myId);
  738. my (undef,$info) = unpack('A11A29',$rmsg);
  739. if (!$hash->{helper}{info} || $hash->{helper}{info} ne $info){
  740. my $fwVer = hex($mFld[1]);
  741. $fwVer = sprintf("%d.%d", ($fwVer >> 12) & 0xf, $fwVer & 0xffff);
  742. $hash->{owner} = $mFld[4];
  743. readingsBeginUpdate($hash);
  744. readingsBulkUpdate($hash,"D-firmware" ,$fwVer);
  745. readingsBulkUpdate($hash,"D-serialNr" ,$mFld[2]);
  746. readingsBulkUpdate($hash,"D-HMIdOriginal",$mFld[3]);
  747. readingsBulkUpdate($hash,"D-HMIdAssigned",$mFld[4]);
  748. readingsEndUpdate($hash,1);
  749. $hash->{helper}{info} = $info;
  750. }
  751. if($mFld[4] ne $myId && !AttrVal($name, "dummy", 0)) {
  752. Log3 $hash, 1, 'HMLAN setting owner to '.$myId.' from '.$mFld[4];
  753. HMLAN_SimpleWrite($hash, "A$myId");
  754. }
  755. }
  756. elsif($rmsg =~ m/^I00.*/) {;
  757. # Ack from the HMLAN
  758. }
  759. else {
  760. Log3 $hash, 5, "$name Unknown msg >$rmsg<";
  761. }
  762. }
  763. sub HMLAN_Ready($) {###########################################################
  764. my ($hash) = @_;
  765. return DevIo_OpenDev($hash, 1, "HMLAN_DoInit");
  766. }
  767. sub HMLAN_SimpleWrite(@) {#####################################################
  768. my ($hash, $msg, $nonl) = @_;
  769. return if(!$hash || AttrVal($hash->{NAME}, "dummy", 0) != 0);
  770. my $name = $hash->{NAME};
  771. my $len = length($msg);
  772. # It is not possible to answer befor 100ms
  773. if ($len>51){
  774. if($hash->{helper}{q}{HMcndN}){
  775. my $HMcnd = $hash->{helper}{q}{HMcndN};
  776. return if ( ($HMcnd == 4 || $HMcnd == 253)
  777. && !$hash->{helper}{recoverTest});# no send if overload or disconnect
  778. delete $hash->{helper}{recoverTest}; # test done
  779. }
  780. my ($s,undef,$stat,undef,$t,undef,$d,undef,$r,undef,$no,$flg,$typ,$src,$dst,$p) =
  781. unpack('A9A1A2A1A8A1A2A1A8A1A2A2A2A6A6A*',$msg);
  782. my $hmId = AttrVal($name,"hmId","");
  783. my $hDst = $hash->{helper}{ids}{$dst};# shortcut
  784. my $tn = gettimeofday();
  785. if($modules{CUL_HM}{defptr}{$dst} &&
  786. $modules{CUL_HM}{defptr}{$dst}{helper}{io}
  787. ){
  788. if ($modules{CUL_HM}{defptr}{$dst}{helper}{io}{nextSend}){
  789. my $dDly = $modules{CUL_HM}{defptr}{$dst}{helper}{io}{nextSend} - $tn;
  790. #$dDly -= 0.05 if ($typ eq "02");# delay at least 50ms for ACK, but not 100
  791. select(undef, undef, undef, (($dDly > 0.1)?0.1:$dDly))
  792. if ($dDly > 0.01);
  793. }
  794. }
  795. if ($dst ne $hmId){ #delay send if answer is pending
  796. if ( $hDst->{flg} && #HMLAN's ack pending
  797. ($hDst->{to} > $tn)){#won't wait forever! check timeout
  798. $hDst->{msg} = $msg; #postpone message
  799. Log3 $hash, HMLAN_getVerbLvl($hash,$src,$dst,"5"),"HMLAN_Delay: $name $dst";
  800. return;
  801. }
  802. if ($src eq $hmId){
  803. $hDst->{flg} = (hex($flg)&0x20)?1:0;# answer expected?
  804. $hDst->{to} = $tn + 2;# flag timeout after 2 sec
  805. $hDst->{msg} = "";
  806. HMLAN_qResp($hash,$dst,1) if ($hDst->{flg} == 1);
  807. }
  808. }
  809. if ($len > 52){#channel information included, send sone kind of clearance
  810. my $chn = substr($msg,52,2);
  811. if (!$hDst->{chn} || $hDst->{chn} ne $chn){
  812. my $updt = $modules{CUL_HM}{defptr}{$dst}{helper}{io}{newChn};
  813. if ($updt && (!$hDst->{cfg} || $updt ne $hDst->{cfg})){
  814. Log3 $hash, HMLAN_getVerbLvl($hash,$src,$dst,"5")
  815. , 'HMLAN_Send: '.$name.' S:'.$updt;
  816. syswrite($hash->{TCPDev}, $updt."\r\n") if($hash->{TCPDev});
  817. $hDst->{cfg} = $updt;
  818. }
  819. }
  820. $hDst->{chn} = $chn;
  821. }
  822. Log3 $hash, HMLAN_getVerbLvl($hash,$src,$dst,"5")
  823. , 'HMLAN_Send: '.$name.' S:'.$s
  824. .' stat: ' .$stat
  825. .' t:' .$t
  826. .' d:' .$d
  827. .' r:' .$r
  828. .' m:' .$no
  829. .' ' .$flg.$typ
  830. .' ' .$src
  831. .' ' .$dst
  832. .' ' .$p;
  833. $hash->{helper}{q}{scnt}++;
  834. }
  835. else{
  836. Log3 $hash, ($hash->{helper}{log}{sys}?0:5), 'HMLAN_Send: '.$name.' I:'.$msg;
  837. }
  838. $msg .= "\r\n" unless($nonl);
  839. syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
  840. if ($hash->{helper}{q}{scnt} == 10){
  841. $hash->{helper}{q}{scnt} = 0;
  842. HMLAN_KeepAlive("x:$name") ;
  843. }
  844. }
  845. sub HMLAN_DoInit($) {##########################################################
  846. my ($hash) = @_;
  847. my $name = $hash->{NAME};
  848. my $id = AttrVal($name, "hmId", "999999");
  849. # readingsSingleUpdate($hash,"state","init",1);
  850. HMLAN_SimpleWrite($hash, "A$id") if($id ne "999999");
  851. HMLAN_assignIDs($hash);
  852. HMLAN_writeAesKey($name);
  853. my $s2000 = sprintf("%02X", HMLAN_secSince2000());
  854. HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
  855. $hash->{helper}{setTime} = int(gettimeofday())>>15;
  856. delete $hash->{helper}{ref};
  857. HMLAN_condUpdate($hash,255);
  858. $hash->{helper}{q}{keepAliveRec} = 1; # ok for first time
  859. $hash->{helper}{q}{keepAliveRpt} = 0; # ok for first time
  860. my $tn = gettimeofday();
  861. my $wdTimer = AttrVal($name,"wdTimer",25);
  862. $hash->{helper}{k}{Start} = $tn;
  863. $hash->{helper}{k}{Next} = $tn + $wdTimer;
  864. RemoveInternalTimer( "keepAliveCk:".$name);# avoid duplicate timer
  865. RemoveInternalTimer( "keepAlive:".$name);# avoid duplicate timer
  866. InternalTimer($tn+$wdTimer, "HMLAN_KeepAlive", "keepAlive:".$name, 0);
  867. # send first message to retrieve HMLAN condition
  868. HMLAN_Write($hash,"","As09998112".$id."000000");
  869. return undef;
  870. }
  871. sub HMLAN_assignIDs($){
  872. # remove all assigned IDs and assign the ones from list
  873. my ($hash) = @_;
  874. HMLAN_SimpleWrite($hash, "C"); #clear all assigned IDs
  875. HMLAN_Write($hash,"","init:$_") foreach(keys %{$hash->{helper}{ids}});
  876. }
  877. sub HMLAN_writeAesKey($) {#####################################################
  878. my ($name) = @_;
  879. return if (!$name || !$defs{$name} || $defs{$name}{TYPE} ne "HMLAN");
  880. my %keys = ();
  881. my $vccu = InternalVal($name,"owner_CCU",$name);
  882. $vccu = $name if(!AttrVal($vccu,"hmKey",""));
  883. foreach my $i (1..3){
  884. my ($kNo,$k) = split(":",AttrVal($vccu,"hmKey".($i== 1?"":$i),""));
  885. if (defined($kNo) && defined($k)) {
  886. $keys{$kNo} = $k;
  887. }
  888. }
  889. my @kNos = reverse(sort(keys(%keys)));
  890. foreach my $i (1..3){
  891. my $k;
  892. my $kNo;
  893. if (defined($kNos[$i-1])) {
  894. $kNo = $kNos[$i-1];
  895. $k = $keys{$kNo};
  896. }
  897. HMLAN_SimpleWrite($defs{$name}, "Y0$i,".($k?"$kNo,$k":"00,"));
  898. }
  899. }
  900. sub HMLAN_KeepAlive($) {#######################################################
  901. my($in ) = shift;
  902. my(undef,$name) = split(':',$in);
  903. my $hash = $defs{$name};
  904. $hash->{helper}{q}{keepAliveRec} = 0; # reset indicator
  905. return if(!$hash->{FD});
  906. my $tn = gettimeofday();
  907. my $wdTimer = AttrVal($name,"wdTimer",25);
  908. my $rht = int($tn)>>15 ;
  909. if( $rht != $hash->{helper}{setTime}){# reset HMLAN watch about each 10h
  910. $hash->{helper}{setTime} = $rht;
  911. my $s2000 = sprintf("%02X", HMLAN_secSince2000());
  912. HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
  913. }
  914. HMLAN_SimpleWrite($hash, "K");
  915. my $kDly = int(($tn - $hash->{helper}{k}{Next})*1000)/1000;
  916. $hash->{helper}{k}{DlyMax} = $kDly if($hash->{helper}{k}{DlyMax} < $kDly);
  917. if ($hash->{helper}{k}{Start}){
  918. my $kBuf = int($hash->{helper}{k}{Start} + 30 - $tn);
  919. $hash->{helper}{k}{BufMin} = $kBuf if($hash->{helper}{k}{BufMin} > $kBuf);
  920. }
  921. else{
  922. $hash->{helper}{k}{BufMin} = 30;
  923. }
  924. $hash->{msgKeepAlive} = "dlyMax:".$hash->{helper}{k}{DlyMax}
  925. ." bufferMin:". $hash->{helper}{k}{BufMin};
  926. $hash->{helper}{k}{Start} = $tn;
  927. $hash->{helper}{k}{Next} = $tn + $wdTimer;
  928. $hash->{helper}{ref}{kTs} = int($tn*1000);
  929. my $rt = AttrVal($name,"respTime",1);
  930. InternalTimer($tn+$rt,"HMLAN_KeepAliveCheck","keepAliveCk:".$name,1);
  931. RemoveInternalTimer( "keepAlive:".$name);# avoid duplicate timer
  932. InternalTimer($tn+$wdTimer,"HMLAN_KeepAlive", "keepAlive:".$name, 1);
  933. }
  934. sub HMLAN_KeepAliveCheck($) {##################################################
  935. my($in ) = shift;
  936. my(undef,$name) = split(':',$in);
  937. my $hash = $defs{$name};
  938. if ($hash->{helper}{q}{keepAliveRec} != 1){# no answer
  939. if ($hash->{helper}{q}{keepAliveRpt} >2){# give up here
  940. HMLAN_condUpdate($hash,253);# trigger timeout event
  941. DevIo_Disconnected($hash);
  942. }
  943. else{
  944. $hash->{helper}{q}{keepAliveRpt}++;
  945. HMLAN_KeepAlive("keepAlive:".$name);#repeat
  946. }
  947. }
  948. else{
  949. $hash->{helper}{q}{keepAliveRpt} = 0;
  950. HMLAN_condUpdate($hash,0) if ($hash->{helper}{q}{HMcndN} == 255);
  951. }
  952. }
  953. sub HMLAN_secSince2000() {#####################################################
  954. # Calculate the local time in seconds from 2000.
  955. my $t = time();
  956. my @l = localtime($t);
  957. my @g = gmtime($t);
  958. $t += 60*(($l[2]-$g[2] + ((($l[5]<<9)|$l[7]) <=> (($g[5]<<9)|$g[7])) * 24) * 60 + $l[1]-$g[1])
  959. # timezone and daylight saving...
  960. - 946684800 # seconds between 01.01.2000, 00:00 and THE EPOCH (1970)
  961. - 7200; # HM Special
  962. return $t;
  963. }
  964. sub HMLAN_qResp($$$) {#response-waiting queue##################################
  965. my($hash,$id,$cmd) = @_;
  966. my $hashQ = $hash->{helper}{q};
  967. if ($cmd){
  968. $hashQ->{answerPend} ++;
  969. push @{$hashQ->{apIDs}},$id;
  970. if ($hashQ->{answerPend} >= $hashQ->{hmLanQlen}){
  971. $hash->{XmitOpen} = 2;#delay further sending
  972. RemoveInternalTimer("hmClearQ:$hash->{NAME}");
  973. InternalTimer(gettimeofday()+10, "HMLAN_clearQ", "hmClearQ:$hash->{NAME}", 0);
  974. }
  975. }
  976. else{
  977. $hashQ->{answerPend}-- if ($hashQ->{answerPend}>0);
  978. @{$hashQ->{apIDs}}=grep !/$id/,@{$hashQ->{apIDs}};
  979. RemoveInternalTimer("hmClearQ:$hash->{NAME}")if ($hash->{XmitOpen} == 0);
  980. if ($hashQ->{HMcndN} == 4 ||
  981. $hashQ->{HMcndN} == 253){ $hash->{XmitOpen} = 0;}
  982. elsif($hashQ->{answerPend} >= $hashQ->{hmLanQlen}){$hash->{XmitOpen} = 2;}
  983. else{ $hash->{XmitOpen} = 1;}
  984. }
  985. }
  986. sub HMLAN_clearQ($) {#clear pending acks due to timeout########################
  987. my($in ) = shift;
  988. my(undef,$name) = split(':',$in);
  989. my $hash = $defs{$name};
  990. @{$hash->{helper}{q}{apIDs}} = (); #clear Q-status
  991. $hash->{helper}{q}{answerPend} = 0;
  992. Log3 $hash, 4, "HMLAN_ack: timeout - clear queue";
  993. my $HMcnd = $hash->{helper}{q}{HMcndN};
  994. if ($HMcnd == 4 || $HMcnd == 253) {$hash->{XmitOpen} = 0;
  995. }else{ $hash->{XmitOpen} = 1;}
  996. }
  997. sub HMLAN_condUpdate($$) {#####################################################
  998. my($hash,$HMcnd) = @_;
  999. my $name = $hash->{NAME};
  1000. if (AttrVal($name,"dummy",undef)){
  1001. readingsSingleUpdate($hash,"state","disconnected",1);
  1002. $hash->{XmitOpen} = 0;
  1003. return;
  1004. }
  1005. my $hashCnd = $hash->{helper}{cnd};#short to helper
  1006. my $hashQ = $hash->{helper}{q};#short to helper
  1007. $hash->{helper}{cnd}{$HMcnd} = 0 if (!$hash->{helper}{cnd} ||
  1008. !$hash->{helper}{cnd}{$HMcnd});
  1009. $hash->{helper}{cnd}{$HMcnd}++;
  1010. readingsBeginUpdate($hash);
  1011. if ($HMcnd == 4){#HMLAN needs a rest. Supress all sends exept keep alive
  1012. readingsBulkUpdate($hash,"state","overload");
  1013. }
  1014. elsif ($HMcnd == 251 || $HMcnd == 253){#HMLAN dummy/disconnected
  1015. readingsBulkUpdate($hash,"state","disconnected");
  1016. }
  1017. else{# revert from overload
  1018. readingsBulkUpdate($hash,"state","opened")
  1019. if (InternalVal($name,"STATE","") eq "overload");
  1020. }
  1021. my $HMcndTxt = $HMcond{$HMcnd} ? $HMcond{$HMcnd} : "Unknown:$HMcnd";
  1022. Log3 $hash, 1, "HMLAN_Parse: $name new condition $HMcndTxt";
  1023. my $txt;
  1024. $txt .= $HMcond{$_}.":".$hash->{helper}{cnd}{$_}." "
  1025. foreach (keys%{$hash->{helper}{cnd}});
  1026. readingsBulkUpdate($hash,"cond",$HMcndTxt);
  1027. readingsBulkUpdate($hash,"Xmit-Events",$txt);
  1028. readingsBulkUpdate($hash,"prot_".$HMcndTxt,"last");
  1029. $hashQ->{HMcndN} = $HMcnd;
  1030. if ($HMcnd == 4 || $HMcnd == 251|| $HMcnd == 253 || $HMcnd == 255) {#transmission down
  1031. $hashQ->{answerPend} = 0;
  1032. @{$hashQ->{apIDs}} = (); #clear Q-status
  1033. $hash->{XmitOpen} = 0; #deny transmit
  1034. readingsBulkUpdate($hash,"prot_keepAlive","last")
  1035. if ( $HMcnd == 253
  1036. && $hash->{helper}{k}{Start}
  1037. &&(gettimeofday() - 29) > $hash->{helper}{k}{Start});
  1038. }
  1039. else{
  1040. $hash->{XmitOpen} = ($hashQ->{answerPend} < $hashQ->{hmLanQlen})?"1":"2";#allow transmit
  1041. }
  1042. readingsEndUpdate($hash,1);
  1043. my $ccu = InternalVal($name,"owner_CCU","");
  1044. CUL_HM_UpdtCentralState($ccu) if ($ccu);
  1045. }
  1046. sub HMLAN_noDup(@) {#return list with no duplicates
  1047. my %all;
  1048. return "" if (scalar(@_) == 0);
  1049. $all{$_}=0 foreach (grep !/^$/,@_);
  1050. delete $all{""}; #remove empties if present
  1051. return (sort keys %all);
  1052. }
  1053. sub HMLAN_getVerbLvl ($$$$){#get verboseLevel for message
  1054. my ($hash,$src,$dst,$def) = @_;
  1055. return ($hash->{helper}{log}{all}||
  1056. (grep /($src|$dst)/,@{$hash->{helper}{log}{ids}}))?0:$def;
  1057. }
  1058. 1;
  1059. =pod
  1060. =item device
  1061. =item summary IO device for wireless homematic
  1062. =item summary_DE IO device für funkgesteuerte Homematic Devices
  1063. =begin html
  1064. <a name="HMLAN"></a>
  1065. <h3>HMLAN</h3>
  1066. <ul>
  1067. The HMLAN is the fhem module for the eQ-3 HomeMatic LAN Configurator.<br>
  1068. 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/>
  1069. <br/>
  1070. 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/>
  1071. <br>
  1072. In order to use it with fhem you <b>must</b> disable the encryption first with the "HomeMatic Lan Interface Configurator"<br>
  1073. (which is part of the supplied Windows software), by selecting the device, "Change IP Settings", and deselect "AES Encrypt Lan Communication".<br/>
  1074. <br/>
  1075. This device can be used in parallel with a CCU and (readonly) with fhem. To do this:
  1076. <ul>
  1077. <li>start the fhem/contrib/tcptee.pl program</li>
  1078. <li>redirect the CCU to the local host</li>
  1079. <li>disable the LAN-Encryption on the CCU for the Lan configurator</li>
  1080. <li>set the dummy attribute for the HMLAN device in fhem</li>
  1081. </ul>
  1082. <br/><br/>
  1083. <a name="HMLANdefine"><b>Define</b></a>
  1084. <ul>
  1085. <code>define &lt;name&gt; HMLAN &lt;ip-address&gt;[:port]</code><br>
  1086. <br>
  1087. port is 1000 by default.<br/>
  1088. If the ip-address is called none, then no device will be opened, so you can experiment without hardware attached.
  1089. </ul>
  1090. <br><br>
  1091. <a name="HMLANset"><b>Set</b></a>
  1092. <ul>
  1093. <li><a href="#hmPairForSec">hmPairForSec</a></li>
  1094. <li><a href="#hmPairSerial">hmPairSerial</a></li>
  1095. <li><a href="#hmreopen">reopen</a>
  1096. reconnect the device
  1097. </li>
  1098. <li><a href="#hmrestart">restart</a>
  1099. Restart the device
  1100. </li>
  1101. <li><a href="#HMLANset_reassignIDs">reassignIDs</a>
  1102. Syncs the IDs between HMLAN and the FHEM list.
  1103. Usually this is done automatically and only is recomended if there is a difference in counts.
  1104. </li>
  1105. <br><br>
  1106. </ul>
  1107. <a name="HMLANget"><b>Get</b></a>
  1108. <ul>
  1109. <li><a href="#HMLANgetassignIDs">assignIDs</a>
  1110. Gibt eine Liste aller diesem IO zugewiesenen IOs aus.
  1111. </li>
  1112. </ul>
  1113. <br><br>
  1114. <a name="HMLANattr"><b>Attributes</b></a>
  1115. <ul>
  1116. <li><a href="#addvaltrigger">addvaltrigger</a></li>
  1117. <li><a href="#do_not_notify">do_not_notify</a></li>
  1118. <li><a href="#attrdummy">dummy</a></li>
  1119. <li><a href="#HMLANlogIDs">logIDs</a><br>
  1120. enables selective logging of HMLAN messages. A list of HMIds or names can be
  1121. entered, comma separated, which shall be logged.<br>
  1122. The attribute only allows device-IDs, not channel IDs.
  1123. Channel-IDs will be modified to device-IDs automatically.
  1124. <b>all</b> will log raw messages for all HMIds<br>
  1125. <b>sys</b> will log system related messages like keep-alive<br>
  1126. in order to enable all messages set "<b>all,sys</b>"<br>
  1127. </li>
  1128. <li><a name="HMLANloadLevel">loadLevel</a><br>
  1129. loadlevel will be mapped to reading vaues. <br>
  1130. 0:low,30:mid,40:batchLevel,90:high,99:suspended<br>
  1131. the batchLevel value will be set to 40 if not entered. This is the level at which
  1132. background message generation e.g. for autoReadReg will be stopped<br>
  1133. </li>
  1134. <li><a href="#hmId">hmId</a></li>
  1135. <li><a name="HMLANhmKey">hmKey</a></li>
  1136. <li><a name="HMLANhmKey2">hmKey2</a></li>
  1137. <li><a name="HMLANhmKey3">hmKey3</a></li>
  1138. <li><a name="HMLANhmKey4">hmKey4</a></li>
  1139. <li><a name="HMLANhmKey5">hmKey5</a><br>
  1140. AES keys for the HMLAN adapter. <br>
  1141. The key is converted to a hash. If a hash is given directly it is not converted but taken directly.
  1142. Therefore the original key cannot be converted back<br>
  1143. </li>
  1144. <li><a href="#hmProtocolEvents">hmProtocolEvents</a></li><br>
  1145. <li><a name="HMLANrespTime">respTime</a><br>
  1146. Define max response time of the HMLAN adapter in seconds. Default is 1 sec.<br/>
  1147. Longer times may be used as workaround in slow/instable systems or LAN configurations.</li>
  1148. <li><a name="HMLAN#wdTimer">wdTimer</a><br>
  1149. Time in sec to trigger HMLAN. Values between 5 and 25 are allowed, 25 is default.<br>
  1150. It is <B>not recommended</B> to change this timer. If problems are detected with <br>
  1151. HLMLAN disconnection it is advisable to resolve the root-cause of the problem and not symptoms.</li>
  1152. <li><a name="HMLANhmLanQlen">hmLanQlen</a><br>
  1153. defines queuelength of HMLAN interface. This is therefore the number of
  1154. simultanously send messages. increasing values may cause higher transmission speed.
  1155. It may also cause retransmissions up to data loss.<br>
  1156. Effects can be observed by watching protocol events<br>
  1157. 1 - is a conservatibe value, and is default<br>
  1158. 5 - is critical length, likely cause message loss</li>
  1159. </ul><br>
  1160. <a name="HMLANparameter"><b>parameter</b></a>
  1161. <ul>
  1162. <li><B>assignedIDsCnt</B><br>
  1163. number of IDs that are assigned to HMLAN by FHEM.
  1164. If the number reported by HMLAN differ it will be reported as 'reported'.<br>
  1165. It is recommended to resync HMLAN using the command 'assignIDs'.
  1166. </li>
  1167. <li><B>msgKeepAlive</B><br>
  1168. performance of keep-alive messages. <br>
  1169. <B>dlyMax</B>: maximum delay of sheduled message-time to actual message send.<br>
  1170. <B>bufferMin</B>: minimal buffer left to before HMLAN would likely disconnect
  1171. due to missing keepAlive message. bufferMin will be reset to 30sec if
  1172. attribut wdTimer is changed.<br>
  1173. if dlyMax is high (several seconds) or bufferMin goes to "0" (normal is 4) the system
  1174. suffers on internal delays. Reasons for the delay might be explored. As a quick solution
  1175. wdTimer could be decreased to trigger HMLAN faster.</li>
  1176. <li><B>msgLoadCurrent</B><br>
  1177. Current transmit load of HMLAN. When capacity reaches 100% HMLAN stops sending and waits for
  1178. reduction. See also:
  1179. <a href="#HMLANloadLevel">loadLevel</a><br></li>
  1180. <li><B>msgLoadHistoryAbs</B><br>
  1181. Historical transmition load of IO.</li>
  1182. <li><B>msgParseDly</B><br>
  1183. calculates the delay of messages in ms from send in HMLAN until processing in FHEM.
  1184. It therefore gives an indication about FHEM system performance.
  1185. </li>
  1186. </ul><br>
  1187. <a name="HMLANreadings"><b>parameter and readings</b></a>
  1188. <ul>
  1189. <li><B>prot_disconnect</B> <br>recent HMLAN disconnect</li>
  1190. <li><B>prot_init</B> <br>recent HMLAN init</li>
  1191. <li><B>prot_keepAlive</B> <br>HMLAN disconnect likely do to slow keep-alive sending</li>
  1192. <li><B>prot_ok</B> <br>recent HMLAN ok condition</li>
  1193. <li><B>prot_timeout</B> <br>recent HMLAN timeout</li>
  1194. <li><B>prot_Warning-HighLoad</B> <br>high load condition entered - HMLAN has about 10% performance left</li>
  1195. <li><B>prot_ERROR-Overload</B> <br>overload condition - HMLAN will receive bu tno longer transmitt messages</li>
  1196. <li><B>prot_Overload-released</B><br>overload condition released - normal operation possible</li>
  1197. </ul>
  1198. </ul>
  1199. =end html
  1200. =begin html_DE
  1201. <a name="HMLAN"></a>
  1202. <h3>HMLAN</h3>
  1203. <ul>
  1204. Das HMLAN ist das fhem-Modul f&uuml;r den eQ-3 HomeMatic LAN Configurator welcher als IO
  1205. in FHEM fungiert. Siehe <a href="http://www.fhemwiki.de/wiki/HM-CFG-LAN_LAN_Konfigurations-Adapter">HM-CFG-LAN_LAN_Konfigurations-Adapter</a> zur Konfiguration.<br>
  1206. Eine weitere Beschreibung, wie der HomeMatic USB Konfigurations-Adapter
  1207. <a href="https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb">(HM-CFG-USB)</a>
  1208. verwendet werden kann, ist unter dem angegebenen Link zu finden.<br/>
  1209. <br>
  1210. Dieses Ger&auml;t kann gleichzeitig mit einer CCU und (nur lesend) mit FHEM verwendet werden.
  1211. Hierf&uuml;r ist wie folgt vorzugehen:
  1212. <ul>
  1213. <li>Starten des fhem/contrib/tcptee.pl Programms</li>
  1214. <li>Umleiten der CCU zum local host</li>
  1215. <li>Ausschalten der LAN-Encryption auf der CCU f&uuml;r den LAN-Configurator</li>
  1216. <li>Setzen des dummy Attributes f&uuml;r das HMLAN Ger&auml;t in FHEM</li>
  1217. </ul>
  1218. <br><br>
  1219. <a name="HMLANdefine"><b>Define</b></a>
  1220. <ul>
  1221. <code>define &lt;name&gt; HMLAN &lt;ip-address&gt;[:port]</code><br>
  1222. <br>
  1223. Der Standard-Port lautet: 1000.<br/>
  1224. Wenn keine IP-Adresse angegeben wird, wird auch kein Ger&auml;t ge&ouml;ffnet; man kann
  1225. also auch ohne angeschlossene Hardware experimentieren.
  1226. </ul>
  1227. <br><br>
  1228. <a name="HMLANset"><b>Set</b></a>
  1229. <ul>
  1230. <li><a href="#hmPairForSec">hmPairForSec</a></li>
  1231. <li><a href="#hmPairSerial">hmPairSerial</a></li>
  1232. <li><a href="#hmreopen">reopen</a>
  1233. Connection zum IO device neu starten</li>
  1234. <li><a href="#hmrestart">restart</a>
  1235. Neustart des IOdevice
  1236. </li>
  1237. <li><a href="#HMLANset_reassignIDs">reassignIDs</a>
  1238. Synchronisiert die im HMLAN eingetragenen IDs mit der von FHEM verwalteten Liste.
  1239. I.a. findet dies automatisch statt, koennte aber in reset Fällen abweichen.
  1240. </li>
  1241. </ul>
  1242. <br><br>
  1243. <a name="HMLANget"><b>Get</b></a>
  1244. <ul>
  1245. <li><a href="#HMLANgetassignIDs">assignIDs</a>
  1246. Gibt eine Liste aller diesem IO zugewiesenen IOs aus.
  1247. </li>
  1248. </ul>
  1249. <br><br>
  1250. <a name="HMLANattr"><b>Attributes</b></a>
  1251. <ul>
  1252. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  1253. <li><a href="#attrdummy">dummy</a></li><br>
  1254. <li><a href="#addvaltrigger">addvaltrigger</a></li><br>
  1255. <li><a href="#HMLANlogIDs">logIDs</a><br>
  1256. Schaltet selektives Aufzeichnen der HMLAN Meldungen ein. Eine Liste der
  1257. HMIds oder Namen, die aufgezeichnet werden sollen, k&ouml;nnen - getrennt durch
  1258. Kommata - eingegeben werden.<br>
  1259. Die Attribute erlauben ausschließlich die Angabe von Device-IDs und keine Kanal-IDs.
  1260. Die Kanal-IDs werden automatisch in Device-IDs umgewandelt.<br>
  1261. <b>all</b> zeichnet die Original-Meldungen f&uuml;r alle HMIds auf.<br>
  1262. <b>sys</b> zeichnet alle systemrelevanten Meldungen wie keep-alive auf.<br>
  1263. <b>all,sys</b> damit wird die Aufzeichnung aller Meldungen eingeschaltet<br>
  1264. </li>
  1265. <li><a name="HMLANloadLevel">loadLevel</a><br>
  1266. loadlevel mapped den Auslastungslevel auf die Namen in ein Reading. <br>
  1267. 0:low,30:mid,40:batchLevel,90:high,99:suspended<br>
  1268. Der batchLevel Wert wird auf 40 gesetzt., sollte er fehlen.
  1269. Das ist der Levelbei dem die Hintergrundnachrichten z.B. durch autoReadReg gestoppt werden<br>
  1270. </li><br>
  1271. <li><a href="#hmId">hmId</a></li><br>
  1272. <li><a name="HMLANhmKey">hmKey</a></li><br>
  1273. <li><a name="HMLANhmKey2">hmKey2</a></li><br>
  1274. <li><a name="HMLANhmKey3">hmKey3</a></li><br>
  1275. <li><a name="HMLANhmKey4">hmKey4</a></li><br>
  1276. <li><a name="HMLANhmKey5">hmKey5</a><br>
  1277. AES Schl&uuml;ssel f&uuml;r den HMLAN Adapter. <br>
  1278. Der Schl&uuml;ssel wird in eine hash-Zeichenfolge umgewandelt. Wenn eine Hash-Folge unmittelbar
  1279. eingegeben wird, erfolgt keine Umwandlung, sondern eine eine direkte Benutzung der Hash-Folge.
  1280. Deshalb kann der Originalschl&uuml;ssel auch nicht entschl&uuml;sselt werden.<br>
  1281. </li>
  1282. <li><a href="#hmProtocolEvents">hmProtocolEvents</a></li><br>
  1283. <li><a name="HMLANrespTime">respTime</a><br>
  1284. Definiert die maximale Antwortzeit des HMLAN-Adapters in Sekunden. Standardwert ist 1 Sekunde.<br/>
  1285. L&auml;ngere Zeiten k&ouml;nnen &uuml;bergangsweise in langsamen und instabilen Systemen oder in
  1286. LAN-Konfigurationen verwendet werden.</li>
  1287. <li><a name="HMLAN#wdTimer">wdTimer</a><br>
  1288. Zeit in Sekunden, um den HMLAN zu triggern. Werte zwischen 5 und 25 sind zul&auml;ssig.
  1289. Standardwert ist 25 Sekunden.<br>
  1290. Es wird <B>davon abgeraten</B> diesen Timer zu ver&auml;ndern. Wenn Probleme mit
  1291. HMLAN-Abbr&uuml;chen bestehen wird empfohlen die Ursache des Problems zu finden
  1292. und zu beheben und nicht die Symptom.</li>
  1293. <li><a name="HMLANhmLanQlen">hmLanQlen</a><br>
  1294. Definiert die L&auml;nge der Warteschlange des HMLAN Interfaces. Es ist deshalb die Anzahl
  1295. der gleichzeitig zu sendenden Meldungen. Erh&ouml;hung des Wertes kann eine Steigerung der
  1296. &Uuml;bertragungsgeschwindigkeit verursachen, ebenso k&ouml;nnen wiederholte Aussendungen
  1297. Datenverlust bewirken.<br>
  1298. Die Auswirkungen werden durch die Ereignisse im Protokoll sichtbar.<br>
  1299. 1 - ist ein Wert auf der sicheren Seite und deshalb der Standardwert<br>
  1300. 5 - ist eine kritische L&auml;nge und verursacht wahrscheinlich Meldungsverluste</li>
  1301. </ul>
  1302. <a name="HMLANparameter"><b>parameter</b></a>
  1303. <ul>
  1304. <li><B>assignedIDsCnt</B><br>
  1305. Anzahl der IDs, die von FHEM einem HMLAN zugeordnet sind.
  1306. Sollte die Anzahl von der im HMLAN abweichen wird dies als 'reported' gemeldet.<br>
  1307. Wird eine Abweichung festgestellt kann man mit dem Kommando assignIDs das HMLAN synchronisieren.
  1308. </li>
  1309. <li><B>msgKeepAlive</B><br>
  1310. G&uuml;te der keep-alive Meldungen. <br>
  1311. <B>dlyMax</B>: maximale Verz&ouml;gerungsdauer zwischen dem geplanten Meldungszeitpunkt
  1312. und der tats&auml;chlich gesendeten Meldung.<br>
  1313. <B>bufferMin</B>: minimal verf&uuml;gbarer Speicher bevor HMLAN voraussichtlich
  1314. unterbrochen wird bedingt durch die fehlende keepAlive Meldung. bufferMin
  1315. wird auf 30 Sekunden zur&uuml;ckgesetzt wenn das Attribut wdTimer ver&auml;ndert wird.<br>
  1316. Wenn dlyMax hoch ist (mehrere Sekunden) oder bufferMin geht gegen "0" (normal ist 4)
  1317. leidet das System unter den internen Verz&ouml;gerungen. Den Gr&uuml;nden hierf&uuml;r muss
  1318. nachgegangen werdensystem. Als schnelle L&ouml;sung kann der Wert f&uuml;r wdTimer
  1319. verkleinert werden, um HMLAN schneller zu triggern.</li>
  1320. <li><B>msgLoadCurrent</B><br>
  1321. Aktuelle Funklast des HMLAN. Da HMLAN nur eine begrenzte Kapzit&auml;t je Stunde hat
  1322. Telegramme abzusetzen stellt es bei 100% das Senden ein. Siehe auch
  1323. <a href="#loadLevel">loadLevel</a><br></li>
  1324. <li><B>msgLoadHistoryAbs</B><br>
  1325. IO Funkbelastung vergangener Zeitabschnitte.</li>
  1326. <li><B>msgParseDly</B><br>
  1327. Kalkuliert die Verz&ouml;gerungen einer Meldung vom Zeitpunkt des Abschickens im HMLAN
  1328. bis zu Verarbeitung in FHEM. Deshalb ist dies ein Indikator f&uuml;r die Leistungsf&auml;higkeit
  1329. des Systems von FHEM.
  1330. </li>
  1331. </ul>
  1332. <a name="HMLANreadings"><b>Parameter und Readings</b></a>
  1333. <ul>
  1334. <li><B>prot_disconnect</B> <br>letzter HMLAN disconnect</li>
  1335. <li><B>prot_init</B> <br>letzter HMLAN init</li>
  1336. <li><B>prot_keepAlive</B> <br>HMLAN unterbrochen, wahrscheinlich um langsame
  1337. keep-alive Meldungen zu senden.</li>
  1338. <li><B>prot_ok</B> <br>letzte HMLAN ok Bedingung</li>
  1339. <li><B>prot_timeout</B> <br>letzter HMLAN Timeout</li>
  1340. <li><B>prot_Warning-HighLoad</B> <br>hohe Auslastung erreicht -
  1341. HMLAN hat nur noch 10% seiner Leistungsf&auml;higkeit &uuml;brig</li>
  1342. <li><B>prot_ERROR-Overload</B> <br>&Uuml;berlastung -
  1343. HMLAN wird zwar Meldungen empfangen aber keine Meldungen mehr absenden</li>
  1344. <li><B>prot_Overload-released</B><br>&Uuml;berlastung beendet - normale Arbeitsweise ist m&ouml;glich</li>
  1345. </ul>
  1346. </ul>
  1347. =end html_DE
  1348. =cut