| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517 |
- ##############################################
- # $Id: 98_HMinfo.pm 13168 2017-01-21 11:57:16Z martinp876 $
- package main;
- use strict;
- use warnings;
- sub HMinfo_Initialize($$);
- sub HMinfo_Define($$);
- sub HMinfo_getParam(@);
- sub HMinfo_regCheck(@);
- sub HMinfo_peerCheck(@);
- sub HMinfo_getEntities(@);
- sub HMinfo_SetFn($@);
- sub HMinfo_SetFnDly($);
- sub HMinfo_noDup(@);
- sub HMinfo_register ($);
- use Blocking;
- use HMConfig;
- my $doAli = 0;#display alias names as well (filter option 2)
- my $tmplDefChange = 0;
- my $tmplUsgChange = 0;
- sub HMinfo_Initialize($$) {####################################################
- my ($hash) = @_;
- $hash->{DefFn} = "HMinfo_Define";
- $hash->{UndefFn} = "HMinfo_Undef";
- $hash->{SetFn} = "HMinfo_SetFn";
- $hash->{GetFn} = "HMinfo_GetFn";
- $hash->{AttrFn} = "HMinfo_Attr";
- $hash->{NotifyFn} = "HMinfo_Notify";
- $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 "
- ."sumStatus sumERROR "
- ."autoUpdate autoArchive "
- ."autoLoadArchive:0_no,1_load "
- # ."autoLoadArchive:0_no,1_template,2_register,3_templ+reg "
- ."hmAutoReadScan hmIoMaxDly "
- ."hmManualOper:0_auto,1_manual "
- ."configDir configFilename configTempFile "
- ."hmDefaults "
- .$readingFnAttributes;
- $hash->{NOTIFYDEV} = "global";
- }
- sub HMinfo_Define($$){#########################################################
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- my ($n) = devspec2array("TYPE=HMinfo");
- return "only one instance of HMInfo allowed, $n already instantiated"
- if ($n && $hash->{NAME} ne $n);
- my $name = $hash->{NAME};
- $hash->{Version} = "01";
- $attr{$name}{webCmd} = "update:protoEvents short:rssi:peerXref:configCheck:models";
- $attr{$name}{sumStatus} = "battery"
- .",sabotageError"
- .",powerError"
- .",motor";
- $attr{$name}{sumERROR} = "battery:ok"
- .",sabotageError:off"
- .",powerError:ok"
- .",overload:off"
- .",overheat:off"
- .",reduced:off"
- .",motorErr:ok"
- .",error:none"
- .",uncertain:[no|yes]"
- .",smoke_detect:none"
- .",cover:closed"
- ;
- $hash->{nb}{cnt} = 0;
- return;
- }
- sub HMinfo_Undef($$){##########################################################
- my ($hash, $name) = @_;
- return undef;
- }
- sub HMinfo_Attr(@) {###########################################################
- my ($cmd,$name, $attrName,$attrVal) = @_;
- my @hashL;
- my $hash = $defs{$name};
- if ($attrName eq "autoUpdate"){# 00:00 hh:mm
- delete $hash->{helper}{autoUpdate};
- return if ($cmd eq "del");
- my ($h,$m) = split":",$attrVal;
- return "please enter time [hh:mm]" if (!defined $h||!defined $m);
- my $sec = $h*3600+$m*60;
- return "give at least one minute" if ($sec < 60);
- $hash->{helper}{autoUpdate} = $sec;
- InternalTimer(gettimeofday()+$sec,"HMinfo_autoUpdate","sUpdt:".$name,0);
- }
- elsif($attrName eq "hmAutoReadScan"){# 00:00 hh:mm
- if ($cmd eq "del"){
- $modules{CUL_HM}{hmAutoReadScan} = 4;# return to default
- }
- else{
- return "please add plain integer between 1 and 300"
- if ( $attrVal !~ m/^(\d+)$/
- ||$attrVal<0
- ||$attrVal >300 );
- ## implement new timer to CUL_HM
- $modules{CUL_HM}{hmAutoReadScan}=$attrVal;
- CUL_HM_procQs("");
- }
- }
- elsif($attrName eq "hmIoMaxDly"){#
- if ($cmd eq "del"){
- $modules{CUL_HM}{hmIoMaxDly} = 60;# return to default
- }
- else{
- return "please add plain integer between 0 and 3600"
- if ( $attrVal !~ m/^(\d+)$/
- ||$attrVal<0
- ||$attrVal >3600 );
- ## implement new timer to CUL_HM
- $modules{CUL_HM}{hmIoMaxDly}=$attrVal;
- }
- }
- elsif($attrName eq "hmManualOper"){# 00:00 hh:mm
- if ($cmd eq "del"){
- $modules{CUL_HM}{helper}{hmManualOper} = 0;# default automode
- }
- else{
- return "please set 0 or 1" if ($attrVal !~ m/^(0|1)/);
- ## implement new timer to CUL_HM
- $modules{CUL_HM}{helper}{hmManualOper} = substr($attrVal,0,1);
- }
- }
- elsif($attrName eq "sumERROR"){
- if ($cmd eq "set"){
- foreach (split ",",$attrVal){ #prepare reading filter for error counts
- my ($p,@a) = split ":",$_;
- return "parameter illegal - "
- if(!$p || !$a[0]);
- }
- }
- }
- elsif($attrName eq "configDir"){
- if ($cmd eq "set"){
- $attr{$name}{configDir}=$attrVal;
- }
- else{
- delete $attr{$name}{configDir};
- }
- HMinfo_listOfTempTemplates();
- }
- elsif($attrName eq "configTempFile"){
- if ($cmd eq "set"){
- $attr{$name}{configTempFile}=$attrVal;
- }
- else{
- delete $attr{$name}{configTempFile};
- }
- HMinfo_listOfTempTemplates();
- }
- elsif($attrName eq "hmDefaults"){
- if ($cmd eq "set"){
- delete $modules{CUL_HM}{AttrListDef};
- my @defpara = ( "hmProtocolEvents"
- ,"rssiLog"
- ,"autoReadReg"
- ,"msgRepeat"
- ,"expert"
- ,"actAutoTry"
- );
- my %culAH;
- foreach (split" ",$modules{CUL_HM}{AttrList}){
- my ($p,$v) = split(":",$_);
- $culAH{$p} = $v?",$v,":"";
- }
-
- foreach (split(",",$attrVal)){
- my ($para,$val) = split(":",$_,2);
- return "no value defined for $para" if (!defined "val");
- return "param $para not allowed" if (!grep /$para/,@defpara);
- return "param $para :$val not allowed, use $culAH{$para}" if ($culAH{$para} && $culAH{$para} !~ m/,$val,/);
- $modules{CUL_HM}{AttrListDef}{$para} = $val;
- }
- }
- else{
- delete $modules{CUL_HM}{AttrListDef};
- }
- }
- elsif($attrName eq "autoLoadArchive"){
- if ($cmd eq "set"){
- }
- }
- return;
- }
- sub HMinfo_Notify(@){##########################################################
- my ($hash, $dev) = @_;
- my $name = $hash->{NAME};
- return "" if ($dev->{NAME} ne "global");
- my $events = deviceEvents($dev, AttrVal($name, "addStateEvent", 0));
- return undef if(!$events); # Some previous notify deleted the array.
- #we need to init the templist if HMInfo is in use
- my $cfgFn = AttrVal($name,"configTempFile","tempList.cfg");
- HMinfo_listOfTempTemplates() if (grep /(FILEWRITE.*$cfgFn|INITIALIZED)/,@{$events});
- if (grep /(SAVE|SHUTDOWN)/,@{$events}){# also save configuration
- HMinfo_archConfig($hash,$name,"","");
- }
- if (grep /INITIALIZED/,@{$events}){
- HMinfo_SetFn($hash,$name,"loadConfig")
- if ( grep (/INITIALIZED/,@{$events})
- && (substr(AttrVal($name, "autoLoadArchive", 0),0,1) ne 0));
-
- }
- return undef;
- }
- sub HMinfo_status($){##########################################################
- # - count defined HM entities, selected readings, errors on filtered readings
- # - display Assigned IO devices
- # - show ActionDetector status
- # - prot events if error
- # - rssi - eval minimum values
- my $hash = shift;
- my $name = $hash->{NAME};
- my ($nbrE,$nbrD,$nbrC,$nbrV) = (0,0,0,0);# count entities and types
- #--- used for status
- my @info = split ",",$attr{$name}{sumStatus};#prepare event
- my %sum;
- #--- used for error counts
- my @erro = split ",",$attr{$name}{sumERROR};
-
- my %errFlt;
- my %err;
- my @errNames;
- foreach (@erro){ #prepare reading filter for error counts
- my ($p,@a) = split ":",$_;
- $errFlt{$p}{x}=1; # add at least one reading
- $errFlt{$p}{$_}=1 foreach (@a);
- }
- #--- used for IO, protocol and communication (e.g. rssi)
- my @IOdev;
- my %IOccu;
- my %protC = (ErrIoId_ =>0,ErrIoAttack =>0);
- my %protE = (NACK =>0,IOerr =>0,ResndFail =>0,CmdDel =>0);
- my %protW = (Resnd =>0,CmdPend =>0);
- my @protNamesC; # devices with current protocol Critical
- my @protNamesE; # devices with current protocol Errors
- my @protNamesW; # devices with current protocol Warnings
- my @Anames; # devices with ActionDetector events
- my %rssiMin;
- my %rssiMinCnt = ("99>"=>0,"80>"=>0,"60>"=>0,"59<"=>0);
- my @rssiNames; #entities with ciritcal RSSI
- my @shdwNames; #entites with shadowRegs, i.e. unconfirmed register ->W_unconfRegs
- foreach my $id (keys%{$modules{CUL_HM}{defptr}}){#search/count for parameter
- my $ehash = $modules{CUL_HM}{defptr}{$id};
- my $eName = $ehash->{NAME};
- $nbrE++;
- $nbrC++ if ($ehash->{helper}{role}{chn});
- $nbrV++ if ($ehash->{helper}{role}{vrt});
- push @shdwNames,$eName if (CUL_HM_cleanShadowReg($eName)); # are shadowRegs active?
-
-
- foreach my $read (grep {$ehash->{READINGS}{$_}} @info){ #---- count critical readings
- my $val = $ehash->{READINGS}{$read}{VAL};
- $sum{$read}{$val} =0 if (!$sum{$read}{$val});
- $sum{$read}{$val}++;
- }
- foreach my $read (grep {$ehash->{READINGS}{$_}} keys %errFlt){#---- count error readings
- my $val = $ehash->{READINGS}{$read}{VAL};
- next if (grep (/$val/,(keys%{$errFlt{$read}})));# filter non-Error
- $err{$read}{$val} =0 if (!$err{$read}{$val});
- $err{$read}{$val}++;
- push @errNames,$eName;
- }
- if ($ehash->{helper}{role}{dev}){#---restrict to devices
- $nbrD++;
- push @IOdev,$ehash->{IODev}{NAME} if($ehash->{IODev} && $ehash->{IODev}{NAME});
- $IOccu{(split ":",AttrVal($eName,"IOgrp","no"))[0]}=1;
- push @Anames,$eName if ($attr{$eName}{actStatus} && $attr{$eName}{actStatus} eq "dead");
- foreach (grep /ErrIoId_/, keys %{$ehash}){# detect addtional critical entries
- my $k = $_;
- $k =~ s/^prot//;
- $protC{$k} = 0 if(!defined $protC{$_});
- }
- foreach (grep {$ehash->{"prot".$_}} keys %protC){ $protC{$_}++; push @protNamesC,$eName;}#protocol critical alarms
- foreach (grep {$ehash->{"prot".$_}} keys %protE){ $protE{$_}++; push @protNamesE,$eName;}#protocol errors
- foreach (grep {$ehash->{"prot".$_}} keys %protW){ $protW{$_}++; push @protNamesW,$eName;}#protocol events reported
- $rssiMin{$eName} = 0;
- foreach (keys %{$ehash->{helper}{rssi}}){
- next if($_ !~ m /at_.*$ehash->{IODev}->{NAME}/ );#ignore unused IODev
- $rssiMin{$eName} = $ehash->{helper}{rssi}{$_}{min}
- if ($rssiMin{$eName} > $ehash->{helper}{rssi}{$_}{min});
- }
- }
- }
- #====== collection finished - start data preparation======
- my @updates;
- foreach my $read(grep {defined $sum{$_}} @info){ #--- disp crt count
- my $d;
- $d .= "$_:$sum{$read}{$_},"foreach(sort keys %{$sum{$read}});
- push @updates,"I_sum_$read:".$d;
- }
- foreach my $read(keys %errFlt) {
- if (defined $err{$read}) {
- my $d;
- $d .= "$_:$err{$read}{$_},"foreach(keys %{$err{$read}});
- push @updates,"ERR_$read:".$d;
- }
- elsif (defined $hash->{READINGS}{"ERR_$read"}) {
- if ($hash->{READINGS}{"ERR_$read"}{VAL} ne '-') {
- # Error condition has been resolved, push empty update
- push @updates,"ERR_$read:";
- }
- else {
- # Delete reading again if it was already empty
- delete $hash->{READINGS}{"ERR_$read"};
- }
- }
- }
- @errNames = grep !/^$/,HMinfo_noDup(@errNames);
- $hash->{ERR_names} = join",",@errNames if(@errNames);# and name entities
- push @updates,"C_sumDefined:"."entities:$nbrE,device:$nbrD,channel:$nbrC,virtual:$nbrV";
- # ------- display status of action detector ------
- push @updates,"I_actTotal:".join",",(split" ",$modules{CUL_HM}{defptr}{"000000"}{STATE});
- if (@Anames){$hash->{ERRactNames} = join",",@Anames}
- else{ delete $hash->{ERRactNames}};
- # ------- what about IO devices??? ------
- push @IOdev,split ",",AttrVal($_,"IOList","")foreach (keys %IOccu);
- my %tmp; # remove duplicates
- $hash->{I_HM_IOdevices} = "";
- $tmp{ReadingsVal($_,"cond",
- InternalVal($_,"STATE","unknown"))}{$_} = 1 foreach( @IOdev);
- foreach my $IOstat (sort keys %tmp){
- $hash->{I_HM_IOdevices} .= "$IOstat: ".join(",",sort keys %{$tmp{$IOstat}}).";";
- }
- # ------- what about protocol events ------
- # Current Events are Rcv,NACK,IOerr,Resend,ResendFail,Snd
- # additional variables are protCmdDel,protCmdPend,protState,protLastRcv
- push @updates,"CRIT__protocol:" .join(",",map {"$_:$protC{$_}"} grep {$protC{$_}} sort keys(%protC));
- push @updates,"ERR__protocol:" .join(",",map {"$_:$protE{$_}"} grep {$protE{$_}} sort keys(%protE));
- push @updates,"W__protocol:" .join(",",map {"$_:$protW{$_}"} grep {$protW{$_}} sort keys(%protW));
- my @tpu = devspec2array("TYPE=CUL_HM:FILTER=state=unreachable");
- push @updates,"ERR__unreachable:".scalar(@tpu);
- push @updates,"I_autoReadPend:". scalar @{$modules{CUL_HM}{helper}{qReqConf}};
- $hash->{W__unreachNames} = join(",",@tpu);
- $hash->{CRI__protoNames} = join(",",grep !/^$/,HMinfo_noDup(@protNamesC));
- $hash->{ERR__protoNames} = join(",",grep !/^$/,HMinfo_noDup(@protNamesE));
- $hash->{W__protoNames} = join(",",grep !/^$/,HMinfo_noDup(@protNamesW));
- $hash->{I_autoReadPend} = join(",",@{$modules{CUL_HM}{helper}{qReqConf}});
- $hash->{W_unConfRegs} = join(",",@shdwNames);
-
- # ------- what about rssi low readings ------
- foreach (grep {$rssiMin{$_} != 0}keys %rssiMin){
- if ($rssiMin{$_}> -60) {$rssiMinCnt{"59<"}++;}
- elsif ($rssiMin{$_}> -80) {$rssiMinCnt{"60>"}++;}
- elsif ($rssiMin{$_}< -99) {$rssiMinCnt{"99>"}++;
- push @rssiNames,$_ ;}
- else {$rssiMinCnt{"80>"}++;}
- }
- my $d ="";
- $d .= "$_:$rssiMinCnt{$_} " foreach (sort keys %rssiMinCnt);
- push @updates,"I_rssiMinLevel:".$d;
- $hash->{ERR___rssiCrit} = join(",",@rssiNames);
- # ------- update own status ------
- $hash->{STATE} = "updated:".TimeNow();
-
- foreach (grep(/^(ERR|W_|I_|C_|CRI_)/,keys%{$hash})){# remove empty entries
- delete $hash->{$_} if(!$hash->{$_});
- # delete $hash->{READINGS}{$_};
- }
-
- readingsBeginUpdate($hash);
- foreach my $rd (@updates){
- next if (!$rd);
- my ($rdName, $rdVal) = split(":",$rd, 2);
- next if (defined $hash->{READINGS}{$rdName} &&
- $hash->{READINGS}{$rdName}{VAL} eq $rdVal);
- readingsBulkUpdate($hash,$rdName,
- ((defined($rdVal) && $rdVal ne "")?$rdVal:"-"));
- }
- readingsEndUpdate($hash,1);
- return;
- }
- sub HMinfo_autoUpdate($){#in:name, send status-request#########################
- my $name = shift;
- (undef,$name)=split":",$name,2;
- HMinfo_SetFn($defs{$name},$name,"update") if ($name);
- if (AttrVal($name,"autoArchive",undef) &&
- scalar(@{$modules{CUL_HM}{helper}{confUpdt}})){
- my $fN = AttrVal($name,"configFilename","regSave.cfg");
- $fN = AttrVal($name,"configDir",".")."\/".$fN if ($fN !~ m/\//);
- HMinfo_archConfig($defs{$name},$name,"",$fN);
- }
- InternalTimer(gettimeofday()+$defs{$name}{helper}{autoUpdate},
- "HMinfo_autoUpdate","sUpdt:".$name,0)
- if (defined $defs{$name}{helper}{autoUpdate});
- }
- sub HMinfo_getParam(@) { ######################################################
- my ($id,@param) = @_;
- my @paramList;
- my $ehash = $modules{CUL_HM}{defptr}{$id};
- my $eName = $ehash->{NAME};
- my $found = 0;
- foreach (@param){
- my $para = CUL_HM_Get($ehash,$eName,"param",$_);
- $para =~ s/,/ ,/g;
- push @paramList,sprintf("%-15s",($para eq "undefined"?" -":$para));
- $found = 1 if ($para ne "undefined") ;
- }
- return $found,sprintf("%-20s\t: %s",$eName,join "\t| ",@paramList);
- }
- sub HMinfo_regCheck(@) { ######################################################
- my @entities = @_;
- my @regIncompl;
- my @regMissing;
- my @regChPend;
- foreach my $eName (@entities){
- my $ehash = $defs{$eName};
- next if (!$ehash);
- my @lsNo = CUL_HM_reglUsed($eName);
- my @mReg = ();
- my @iReg = ();
- foreach my $rNm (@lsNo){# check non-peer lists
- next if (!$rNm || $rNm eq "");
- if ( !$ehash->{READINGS}{$rNm}
- || !$ehash->{READINGS}{$rNm}{VAL}) {push @mReg, $rNm;}
- elsif ( $ehash->{READINGS}{$rNm}{VAL} !~ m/00:00/){push @iReg, $rNm;}
- }
- if ($ehash->{helper}{shadowReg} && ref($ehash->{helper}{shadowReg}) eq 'HASH'){
- foreach my $rl (keys %{$ehash->{helper}{shadowReg}}){
- my $pre = (CUL_HM_getAttrInt($eName,"expert") & 0x02)?"":".";#raw register on
- delete $ehash->{helper}{shadowReg}{$rl}
- if ( ( $ehash->{READINGS}{$pre.$rl}
- && $ehash->{READINGS}{$pre.$rl}{VAL} eq $ehash->{helper}{shadowReg}{$rl}
- ) # content is already displayed
- ||(!$ehash->{helper}{shadowReg}{$rl}) # content is missing
- );
- }
- push @regChPend,$eName if (keys %{$ehash->{helper}{shadowReg}});
- }
-
- push @regMissing,$eName.":\t".join(",",@mReg) if (scalar @mReg);
- push @regIncompl,$eName.":\t".join(",",@iReg) if (scalar @iReg);
- }
- my $ret = "";
- $ret .="\n\n missing register list\n " .(join "\n ",sort @regMissing) if(@regMissing);
- $ret .="\n\n incomplete register list\n ".(join "\n ",sort @regIncompl) if(@regIncompl);
- $ret .="\n\n Register changes pending\n ".(join "\n ",sort @regChPend) if(@regChPend);
- return $ret;
- }
- sub HMinfo_peerCheck(@) { #####################################################
- my @entities = @_;
- my @peerIDsFail;
- my @peerIDnotDef;
- my @peerIDsNoPeer;
- my @peerIDsTrigUnp;
- my @peerIDsTrigUnd;
- my @peerIDsTeamRT;
- my @peeringStrange; # devices likely should not be peered
- my @peerIDsAES;
- foreach my $eName (@entities){
- next if (!$defs{$eName}{helper}{role}{chn});#device has no channels
- my $peersUsed = CUL_HM_peerUsed($eName);#
- next if ($peersUsed == 0);# no peers expected
-
- my $peerIDs = AttrVal($eName,"peerIDs","");
- $peerIDs =~ s/00000000,//;
- foreach (grep /^......$/, HMinfo_noDup(map {CUL_HM_name2Id(substr($_,8))}
- grep /^trigDst_/,
- keys %{$defs{$eName}{READINGS}})){
- push @peerIDsTrigUnp,"triggerUnpeered: ".$eName.":".$_
- if( ($peerIDs && $peerIDs !~ m/$_/)
- &&("CCU-FHEM" ne AttrVal(CUL_HM_id2Name($_),"model","")));
- push @peerIDsTrigUnd,"triggerUndefined: ".$eName.":".$_
- if(!$modules{CUL_HM}{defptr}{$_});
- }
-
- if($peersUsed == 2){#peerList incomplete
- push @peerIDsFail,"incomplete: ".$eName.":".$peerIDs;
- }
- else{# work on a valid list
- my $id = $defs{$eName}{DEF};
- my ($devId,$chn) = unpack 'A6A2',$id;
- my $devN = CUL_HM_id2Name($devId);
- my $st = AttrVal($devN,"subType","");# from Device
- my $md = AttrVal($devN,"model","");
- next if ($st eq "repeater");
- if ($st eq 'smokeDetector'){
- push @peeringStrange,$eName." not peered!! add SD to any team !!"
- if(!$peerIDs);
- }
- foreach my $pId (split",",$peerIDs){
- next if ($pId =~m /$devId/);
- if (length($pId) != 8){
- push @peerIDnotDef,$eName." id:$pId invalid format";
- next;
- }
- my ($pDid,$pChn) = unpack'A6A2',$pId;
- if (!$modules{CUL_HM}{defptr}{$pId} &&
- (!$pDid || !$modules{CUL_HM}{defptr}{$pDid})){
- next if($pDid && CUL_HM_id2IoId($id) eq $pDid);
- push @peerIDnotDef,"$eName id:$pId";
- next;
- }
- my $pName = CUL_HM_id2Name($pId);
- $pName =~s/_chn-0[10]//; #chan 01 could be covered by device
- my $pPlist = AttrVal($pName,"peerIDs","");
- my $pDName = CUL_HM_id2Name($pDid);
- my $pSt = AttrVal($pDName,"subType","");
- my $pMd = AttrVal($pDName,"model","");
- my $idc = $id;
- if($st =~ m/(pushButton|remote)/){ # type of primary device
- $idc = $devId;
- if($pChn eq "00"){
- foreach (CUL_HM_getAssChnNames($pDName)){
- $pPlist .= AttrVal($_,"peerIDs","");
- }
- }
- }
- push @peerIDsNoPeer,"$eName p:$pName"
- if ( (!$pPlist || $pPlist !~ m/$devId/)
- && $st ne 'smokeDetector'
- && $pChn !~ m/0[x0]/
- );
- if ($pSt eq "virtual"){
- if (AttrVal($devN,"aesCommReq",0) != 0){
- push @peerIDsAES,$eName." p:".$pName
- if ($pMd ne "CCU-FHEM");
- }
- }
- elsif ($md eq "HM-CC-RT-DN"){
- if ($chn =~ m/(0[45])$/){ # special RT climate
- my $c = $1 eq "04"?"05":"04";
- push @peerIDsNoPeer,$eName." pID:".$pId if ($pId !~ m/$c$/);
- if ($pMd !~ m/HM-CC-RT-DN/ ||$pChn !~ m/(0[45])$/ ){
- push @peeringStrange,$eName." pID: Model $pMd should be HM-CC-RT-DN ClimatTeam Channel";
- }
- elsif($chn eq "04"){
- # compare templist template are identical and boost is same
- my $rtCn = CUL_HM_id2Name(substr($pId,0,6)."04");
- my $ob = CUL_HM_Get($defs{$eName},$eName,"regVal","boostPeriod");
- my $pb = CUL_HM_Get($defs{$rtCn} ,$rtCn ,"regVal","boostPeriod");
- my $ot = AttrVal($eName,"tempListTmpl","--");
- my $pt = AttrVal($rtCn ,"tempListTmpl","--");
- push @peerIDsTeamRT,$eName." team:$rtCn boost differ $ob / $pb" if ($ob ne $pb);
- push @peerIDsTeamRT,$eName." team:$rtCn tempListTmpl differ $ot / $pt" if ($ot ne $pt);
- }
- }
- elsif($chn eq "02"){
- if($pChn ne "02" ||$pMd ne "HM-TC-IT-WM-W-EU" ){
- push @peeringStrange,$eName." pID: Model $pMd should be HM-TC-IT-WM-W-EU Climate Channel";
- }
- }
- }
- elsif ($md eq "HM-TC-IT-WM-W-EU"){
- if($chn eq "02"){
- if($pChn ne "02" ||$pMd ne "HM-CC-RT-DN" ){
- push @peeringStrange,$eName." pID: Model $pMd should be HM-TC-IT-WM-W-EU Climate Channel";
- }
- else{
- # compare templist template are identical and boost is same
- my $rtCn = CUL_HM_id2Name(substr($pId,0,6)."04");
- my $ob = CUL_HM_Get($defs{$eName},$eName,"regVal","boostPeriod");
- my $pb = CUL_HM_Get($defs{$rtCn} ,$rtCn ,"regVal","boostPeriod");
- my $ot = AttrVal($eName,"tempListTmpl","--");
- my $pt = AttrVal($rtCn ,"tempListTmpl","--");
- push @peerIDsTeamRT,$eName." team:$rtCn boost differ $ob / $pb" if ($ob ne $pb);
- # if templates differ AND RT template is not static then notify a difference
- push @peerIDsTeamRT,$eName." team:$rtCn tempListTmpl differ $ot / $pt" if ($ot ne $pt && $pt ne "defaultWeekplan");
- }
- }
- }
- }
- }
- }
- my $ret = "";
- $ret .="\n\n peer list incomplete. Use getConfig to read it." ."\n ".(join "\n ",sort @peerIDsFail )if(@peerIDsFail);
- $ret .="\n\n peer not defined" ."\n ".(join "\n ",sort @peerIDnotDef )if(@peerIDnotDef);
- $ret .="\n\n peer not verified. Check that peer is set on both sides"."\n ".(join "\n ",sort @peerIDsNoPeer )if(@peerIDsNoPeer);
- $ret .="\n\n peering strange - likely not suitable" ."\n ".(join "\n ",sort @peeringStrange)if(@peeringStrange);
- $ret .="\n\n trigger sent to unpeered device" ."\n ".(join "\n ",sort @peerIDsTrigUnp)if(@peerIDsTrigUnp);
- $ret .="\n\n trigger sent to undefined device" ."\n ".(join "\n ",sort @peerIDsTrigUnd)if(@peerIDsTrigUnd);
- $ret .="\n\n aesComReq set but virtual peer is not vccu - won't work"."\n ".(join "\n ",sort @peerIDsAES )if(@peerIDsAES);
- $ret .="\n\n boost or template differ in team" ."\n ".(join "\n ",sort @peerIDsTeamRT )if(@peerIDsTeamRT);
-
- return $ret;
- }
- sub HMinfo_burstCheck(@) { ####################################################
- my @entities = @_;
- my @needBurstMiss;
- my @needBurstFail;
- my @peerIDsCond;
- foreach my $eName (@entities){
- next if (!$defs{$eName}{helper}{role}{chn} #entity has no channels
- || CUL_HM_peerUsed($eName) != 1 #entity not peered or list incomplete
- || CUL_HM_Get($defs{$eName},$eName,"regList")#option not supported
- !~ m/peerNeedsBurst/);
- my $peerIDs = AttrVal($eName,"peerIDs",undef);
- next if(!$peerIDs); # no peers assigned
- my $devId = substr($defs{$eName}{DEF},0,6);
- foreach (split",",$peerIDs){
- next if ($_ eq "00000000" ||$_ =~m /$devId/);
- my $pn = CUL_HM_id2Name($_);
- $pn =~ s/_chn:/_chn-/;
- my $prxt = CUL_HM_getRxType($defs{$pn});
-
- next if (!($prxt & 0x82)); # not a burst peer
- my $pnb = ReadingsVal($eName,"R-$pn-peerNeedsBurst",ReadingsVal($eName,".R-$pn-peerNeedsBurst",undef));
- if (!$pnb) {push @needBurstMiss, "$eName:$pn";}
- elsif($pnb !~ m /on/){push @needBurstFail, "$eName:$pn";}
- if ($prxt & 0x80){# conditional burst - is it on?
- my $pDevN = CUL_HM_getDeviceName($pn);
- push @peerIDsCond," $pDevN for remote $eName" if (ReadingsVal($pDevN,"R-burstRx",ReadingsVal($pDevN,".R-burstRx","")) !~ m /on/);
- }
- }
- }
- my $ret = "";
- $ret .="\n\n peerNeedsBurst cannot be determined" ."\n ".(join "\n ",sort @needBurstMiss) if(@needBurstMiss);
- $ret .="\n\n peerNeedsBurst not set" ."\n ".(join "\n ",sort @needBurstFail) if(@needBurstFail);
- $ret .="\n\n conditionalBurst not set" ."\n ".(join "\n ",sort @peerIDsCond) if(@peerIDsCond);
- return $ret;
- }
- sub HMinfo_paramCheck(@) { ####################################################
- my @entities = @_;
- my @noIoDev;
- my @noID;
- my @idMismatch;
- my @ccuUndef;
- my @perfIoUndef;
- my @aesInval;
- foreach my $eName (@entities){
- if ($defs{$eName}{helper}{role}{dev}){
- my $ehash = $defs{$eName};
- my $pairId = ReadingsVal($eName,"R-pairCentral", ReadingsVal($eName,".R-pairCentral","undefined"));
- my $IoDev = $ehash->{IODev} if ($ehash->{IODev});
- my $ioHmId = AttrVal($IoDev->{NAME},"hmId","-");
- my ($ioCCU,$prefIO) = split":",AttrVal($eName,"IOgrp","");
- if ($ioCCU){
- if( !$defs{$ioCCU}
- || AttrVal($ioCCU,"model","") ne "CCU-FHEM"
- || !$defs{$ioCCU}{helper}{role}{dev}){
- push @ccuUndef,"$eName ->$ioCCU";
- }
- else{
- $ioHmId = $defs{$ioCCU}{DEF};
- if ($prefIO){
- my @pIOa = split(",",$prefIO);
- push @perfIoUndef,"$eName ->$_" foreach ( grep {!$defs{$_}} @pIOa);
- }
- }
- }
- if (!$IoDev) { push @noIoDev,$eName;}
- elsif (AttrVal($eName,"aesCommReq",0) && $IoDev->{TYPE} ne "HMLAN")
- { push @aesInval,"$eName ";}
-
- if ( !$defs{$eName}{helper}{role}{vrt}
- && AttrVal($eName,"model","") ne "CCU-FHEM"){
- if ($pairId eq "undefined") { push @noID,$eName;}
- elsif ($pairId !~ m /$ioHmId/
- && $IoDev ) { push @idMismatch,"$eName paired:$pairId IO attr: ${ioHmId}.";}
- }
- }
- }
- my $ret = "";
- $ret .="\n\n no IO device assigned" ."\n ".(join "\n ",sort @noIoDev) if (@noIoDev);
- $ret .="\n\n PairedTo missing/unknown" ."\n ".(join "\n ",sort @noID) if (@noID);
- $ret .="\n\n PairedTo mismatch to IODev" ."\n ".(join "\n ",sort @idMismatch) if (@idMismatch);
- $ret .="\n\n aesCommReq set, IO not compatibel" ."\n ".(join "\n ",sort @aesInval) if (@aesInval);
- $ret .="\n\n IOgrp: CCU not found" ."\n ".(join "\n ",sort @ccuUndef) if (@ccuUndef);
- $ret .="\n\n IOgrp: prefered IO undefined" ."\n ".(join "\n ",sort @perfIoUndef)if (@perfIoUndef);
- return $ret;
- }
- sub HMinfo_tempList(@) { ######################################################
- my ($hiN,$filter,$action,$fName)=@_;
- $filter = "." if (!$filter);
- $action = "" if (!$action);
- my %dl =("Sat"=>0,"Sun"=>1,"Mon"=>2,"Tue"=>3,"Wed"=>4,"Thu"=>5,"Fri"=>6);
- my $ret;
- if ($action eq "save"){
- # foreach my $eN(HMinfo_getEntities("d")){#search and select channel
- # my $md = AttrVal($eN,"model","");
- # my $chN; #tempList channel name
- # if ($md =~ m/(HM-CC-RT-DN-BoM|HM-CC-RT-DN)/){
- # $chN = $defs{$eN}{channel_04};
- # }
- # elsif ($md =~ m/(ROTO_ZEL-STG-RM-FWT|HM-CC-TC|HM-TC-IT-WM-W-EU)/){
- # $chN = $defs{$eN}{channel_02};
- # }
- # next if (!$chN || !$defs{$chN} || $chN !~ m/$filter/);
- # print aSave "\nentities:$chN";
- # my @tl = sort grep /tempList(P[123])?[SMFWT]/,keys %{$defs{$chN}{READINGS}};
- # if (scalar @tl != 7 && scalar @tl != 21){
- # print aSave "\nincomplete:$chN only data for ".join(",",@tl);
- # push @incmpl,$chN;
- # next;
- # }
- # foreach my $rd (@tl){
- # print aSave "\n$rd>$defs{$chN}{READINGS}{$rd}{VAL}";
- # }
- # }
- my @chList;
- my @storeList;
- my @incmpl;
- foreach my $eN(HMinfo_getEntities("d")){#search and select channel
- my $md = AttrVal($eN,"model","");
- my $chN; #tempList channel name
- if ($md =~ m/(HM-CC-RT-DN-BoM|HM-CC-RT-DN)/){
- $chN = $defs{$eN}{channel_04};
- }
- elsif ($md =~ m/(ROTO_ZEL-STG-RM-FWT|HM-CC-TC|HM-TC-IT-WM-W-EU)/){
- $chN = $defs{$eN}{channel_02};
- }
- if ($chN && $defs{$chN} && $chN =~ m/$filter/){
- my @tl = sort grep /tempList(P[123])?[SMFWT]/,keys %{$defs{$chN}{READINGS}};
- if (scalar @tl != 7 && scalar @tl != 21){
- push @incmpl,$chN;
- next;
- }
- else{
- push @chList,$chN;
- push @storeList,"entities:$chN";
- foreach my $rd (@tl){
- #print aSave "\n$rd>$defs{$chN}{READINGS}{$rd}{VAL}";
- push @storeList,"$rd>$defs{$chN}{READINGS}{$rd}{VAL}";
- }
- }
- }
- }
- my @oldList;
- if (-f $fName ){
- open(aRead, "$fName") || return("Can't open $fName: $!");
- my $skip = 0;
- while(<aRead>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- if ($line =~ m/entities:(.*)/){
- my $eFound = $1;
- if (grep /\b$eFound\b/,@chList){
- # renew this entry
- $skip = 1;
- }
- else{
- $skip = 0;
- }
- }
- push @oldList,$line if (!$skip);
- }
- close(aRead);
- }
- open(aSave, ">$fName") || return("Can't open $fName: $!");
- foreach my $line (@oldList,@storeList){
- print aSave "\n$line";
- # my @tl = sort grep /tempList(P[123])?[SMFWT]/,keys %{$defs{$chN}{READINGS}};
- # if (scalar @tl != 7 && scalar @tl != 21){
- # print aSave "\nincomplete:$chN only data for ".join(",",@tl);
- # push @incmpl,$chN;
- # next;
- # }
- # foreach my $rd (@tl){
- # print aSave "\n$rd>$defs{$chN}{READINGS}{$rd}{VAL}";
- # }
- }
- close(aSave);
- $ret = "incomplete data for ".join("\n ",@incmpl) if (scalar@incmpl);
- }
- elsif ($action =~ m/(verify|restore)/){
- $ret = HMinfo_tempListTmpl($hiN,$filter,"",$action,$fName);
- }
- else{
- $ret = "$action unknown option - please use save, verify or restore";
- }
- return $ret;
- }
- sub HMinfo_tempListTmpl(@) { ##################################################
- my ($hiN,$filter,$tmpl,$action,$fName)=@_;
- $filter = "." if (!$filter);
- my %dl =("Sat"=>0,"Sun"=>1,"Mon"=>2,"Tue"=>3,"Wed"=>4,"Thu"=>5,"Fri"=>6);
- my $ret = "";
- my @el ;
- foreach my $eN(HMinfo_getEntities("d")){#search for devices and select correct channel
- next if (!$eN);
- my $md = AttrVal($eN,"model","");
- my $chN; #tempList channel name
- if ($md =~ m/(HM-CC-RT-DN-BoM|HM-CC-RT-DN)/){$chN = $defs{$eN}{channel_04};}
- elsif ($md =~ m/(ROTO_ZEL-STG-RM-FWT|-TC)/) {$chN = $defs{$eN}{channel_02};}
- next if (!$chN || !$defs{$chN} || $chN !~ m/$filter/);
- push @el,$chN;
- }
- return "no entities selected" if (!scalar @el);
- $fName = HMinfo_tempListDefFn($fName);
- $tmpl = $fName.":".$tmpl if($tmpl);
- my @rs;
- foreach my $name (@el){
- my $tmplDev = $tmpl ? $tmpl
- : AttrVal($name,"tempListTmpl",$fName.":$name");
- $tmplDev = $fName.":$tmplDev" if ($tmplDev !~ m/:/);
-
- my $r = CUL_HM_tempListTmpl($name,$action,$tmplDev);
- HMinfo_regCheck($name);#clean helper data (shadowReg) after restore
- if($action eq "restore"){
- push @rs, (keys %{$defs{$name}{helper}{shadowReg}}? "restore: $tmplDev for $name"
- : "passed : $tmplDev for $name")
- ."\n";
- }
- else{
- push @rs, ($r ? "fail : $tmplDev for $name: $r"
- : "passed: $tmplDev for $name")
- ."\n";
- }
- }
- $ret .= join "",sort @rs;
- return $ret;
- }
- sub HMinfo_tempListTmplView() { ###############################################
- my %tlEntitys;
- $tlEntitys{$_}{v} = 1 foreach ((devspec2array("TYPE=CUL_HM:FILTER=model=HM-CC-RT.*:FILTER=chanNo=04")
- ,devspec2array("TYPE=CUL_HM:FILTER=model=.*-TC.*:FILTER=chanNo=02")));
- my $defFn = HMinfo_tempListDefFn();
- my @tlFiles = $defFn;
-
-
- my @tlFileMiss;
- my @tNfound;# templates found in files
- my @dWoTmpl;# Device not using templates
- foreach my $d (keys %tlEntitys){
- my ($tf,$tn) = split(":",AttrVal($d,"tempListTmpl","empty"));
- ($tf,$tn) = ($defFn,$tf) if (!defined $tn); # no file given, switch parameter
- if($tn =~ m/^(none|0) *$/){
- push @dWoTmpl,$d;
- delete $tlEntitys{$d};
- }
- else{
- push @tlFiles,$tf;
- $tlEntitys{$d}{t} = ("$tf:".($tn eq "empty"?$d:$tn));
- }
- }
- @tlFiles = HMinfo_noDup(@tlFiles);
- foreach my $fn (@tlFiles){#################################
- if (!(-r $fn)){
- push @tlFileMiss,$fn;
- next;
- }
- open(aSave, "$fn") || return("Can't open $fn: $!");
- push @tNfound,"$fn:";
- my $l = length($fn)+3;
- my $spc = sprintf("%${l}s"," ");
- while(<aSave>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- next if($line =~ m/#/);
- if($line =~ m/^entities:/){
- $line =~s/.*://;
- foreach my $eN (split(",",$line)){
- $eN =~ s/ //g;
- push @tNfound,$spc."$eN";
- }
- }
- }
- close (aSave);
- }
- foreach my $d (keys %tlEntitys){
- $tlEntitys{$d}{c} = CUL_HM_tempListTmpl($d,"verify",$tlEntitys{$d}{t});
- if ($tlEntitys{$d}{c}){
- $tlEntitys{$d}{c} =~ s/\n//g;
- }
- else{
- $tlEntitys{$d}{c} = "ok" if !($tlEntitys{$d}{c});
- }
- }
- ####################################################
- my $ret = "";
- $ret .= "\nfiles referenced but not found:\n " .join("\n => ",@tlFileMiss) if (@tlFileMiss);
- $ret .= "\navailable templates\n " .join("\n " ,@tNfound) if (@tNfound);
- $ret .= "\n\n ---------components-----------\n template : device : state\n";
- $ret .= "\n " .join("\n " ,(sort map{"$tlEntitys{$_}{t} : $_ : $tlEntitys{$_}{c}" } keys %tlEntitys));
- $ret .= "\ndevices not using tempList templates:\n => " .join("\n => ",@dWoTmpl) if (@dWoTmpl);
- return $ret;
- }
- sub HMinfo_tempListDefFn(@) { #################################################
- #return Default filename for tempList
- my ($fn) = shift;
- $fn = "" if (!defined $fn);
- my $ret = "";
- my ($n) =devspec2array("TYPE=HMinfo");
- $ret .= "$attr{global}{modpath}/" if (!$fn || $fn !~ m/^\//); #no path? add modpath
- $ret .= AttrVal($n,"configDir",".")."/" if (!$fn || $fn !~ m/..*\//);#no dir? add defDir
- if (!$fn){ #set filename
- my ($f) = split(",",AttrVal($n,"configTempFile","tempList.cfg"));
- $ret .= $f;
- }
- return $ret.$fn;
- }
- sub HMinfo_listOfTempTemplates() { ############################################
- # search all entries in tempListFile
- my ($n) =devspec2array("TYPE=HMinfo");
- my $dir = AttrVal($n,"configDir","$attr{global}{modpath}/")."/"; #no dir? add defDir
- $dir = "./".$dir if ($dir !~ m/^(\.|\/)/);
- my @tFiles = split(";",AttrVal($n,"configTempFile","tempList.cfg"));
- my $tDefault = $dir.$tFiles[0].":";
- my @tmpl;
- foreach my $fn (map{$dir.$_}@tFiles){
- next if (!(-r $fn));
- open(aSave, "$fn") || return("Can't open $fn: $!");
- while(<aSave>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- if($line =~ m/^entities:(.*)/){
- my $l =$1;
- $l =~s/.*://;
- push @tmpl,map{"$fn:$_"}split(",",$l);
- }
- }
- close (aSave);
- }
- @tmpl = map{s/$tDefault//;$_} @tmpl;
- $defs{$n}{helper}{weekplanList} = \@tmpl;
- my $at=$modules{CUL_HM};
- if ($modules{CUL_HM}{AttrList}){
- my $l = "none,defaultWeekplan,".join(",",@tmpl);
- $modules{CUL_HM}{AttrList} =~ s/ tempListTmpl(.*? )/ tempListTmpl:$l /;
- }
- return ;
- }
- sub HMinfo_tempListTmplGenLog($$) { ###########################################
- my ($hiN,$fN) = @_;
- $fN = HMinfo_tempListDefFn($fN);
- open(fnRead, $fN) || return("Can't open file: $!");
- my @eNl = ();
- my %wdl = ( tempListSun =>"02"
- ,tempListMon =>"03"
- ,tempListTue =>"04"
- ,tempListWed =>"05"
- ,tempListThu =>"06"
- ,tempListFri =>"07"
- ,tempListSat =>"08");
- my @plotL;
- while(<fnRead>){
- chomp;
- my $line = $_;
- next if($line =~ m/#/);
- if($line =~ m/^entities:/){
- @eNl = ();
- my $eN = $line;
- $line =~s/.*://;
- foreach my $eN (split(",",$line)){
- $eN =~ s/ //g;
- push @eNl,$eN;
- }
- }
- elsif($line =~ m/(R_)?(P[123])?(_?._)?(tempList[SMFWT]..)(.*)\>/){
- my ($p,$wd,$lst) = ($2,$4,$line);
- $lst =~s/.*>//;
- $lst =~ tr/ +/ /;
- $lst =~ s/^ //;
- $lst =~ s/ $//;
- my @tLst = split(" ","00:00 00.0 ".$lst);
- $p = "" if (!defined $p);
- for (my $cnt = 0;$cnt < scalar(@tLst);$cnt+=2){
- last if ($tLst[$cnt] eq "24:00");
- foreach my $e (@eNl){
- push @plotL,"2000-01-$wdl{$wd}_$tLst[$cnt]:00 $e$p $tLst[$cnt+3]";
- }
- }
- }
- }
- close (fnRead);
- open(fnSave, ">${fN}.log") || return("Can't openfile for write: $!");
- my %eNh;
- foreach (sort @plotL){
- print fnSave "\n$_";
- my (undef,$eN) = split " ",$_;
- $eNh{$eN} = 1;
- }
- close (fnSave);
- HMinfo_tempListTmplGenGplot($fN,keys %eNh);
- }
- sub HMinfo_tempListTmplGenGplot(@) { ##########################################
- my ($fN,@eN) = @_;
- my $fNfull = $fN;
- $fN =~ s/.cfg$//; # remove extention
- $fN =~ s/.*\///; # remove directory
- #define weekLogF FileLog ./setup/tempList.cfg.log none
- #define wp SVG weekLogF:tempList:CURRENT
- #attr wp fixedrange week
- #attr wp startDate 2000-01-02
- if (!defined($defs{"${fN}_Log"})){
- CommandDefine(undef,"${fN}_Log FileLog ${fNfull}.log none");
- }
- if (!defined($defs{"${fN}_SVG"})){
- CommandDefine(undef,"${fN}_SVG SVG ${fN}_Log:${fN}:CURRENT");
- CommandAttr(undef, "${fN}_SVG fixedrange week");
- CommandAttr(undef, "${fN}_SVG startDate 2000-01-02");
- }
- $fN = "./www/gplot/$fN.gplot";
- open(bSave, ">$fN") || return("Can't open $fN for write: $!");
- print bSave "\n# Created by FHEM/98_HMInfo.pm, "
- ."\nset terminal png transparent size <SIZE> crop"
- ."\nset output '<OUT>.png'"
- ."\nset xdata time"
- ."\nset timefmt \"%Y-%m-%d_%H:%M:%S\""
- ."\nset xlabel \" \""
- ."\nset title 'weekplan'"
- ."\nset ytics "
- ."\nset grid ytics"
- ."\nset ylabel \"Temperature\""
- ."\nset y2tics "
- ."\nset y2label \"invisib\""
- ."\nset y2range [99:99]"
- ."\n";
- my $cnt = 0;
- my ($func,$plot) = ("","\n\nplot");
- foreach my $e (sort @eN){
- $func .= "\n#FileLog 3:$e\.\*::";
- if ($cnt++ < 8){
- $plot .= (($cnt ==0)?"":",")
- ."\\\n \"<IN>\" using 1:2 axes x1y1 title '$e' ls l$cnt lw 0.5 with steps";
- }
- }
-
- print bSave $func.$plot;
- close (bSave);
- }
- sub HMinfo_getEntities(@) { ###################################################
- my ($filter,$re) = @_;
- my @names;
- my ($doDev,$doChn,$doEmp)= (1,1,1,1,1,1,1,1);
- my ($doIgn,$noVrt,$noPhy,$noAct,$noSen) = (0,0,0,0,0,0,0,0,0,0);
- $filter .= "dc" if ($filter !~ m/d/ && $filter !~ m/c/); # add default
- $re = '.' if (!$re);
- if ($filter){# options provided
- $doDev=$doChn=$doEmp= 0;#change default
- no warnings;
- my @pl = split undef,$filter;
- use warnings;
- foreach (@pl){
- $doDev = 1 if($_ eq 'd');
- $doChn = 1 if($_ eq 'c');
- $doIgn = 1 if($_ eq 'i');
- $noVrt = 1 if($_ eq 'v');
- $noPhy = 1 if($_ eq 'p');
- $noAct = 1 if($_ eq 'a');
- $noSen = 1 if($_ eq 's');
- $doEmp = 1 if($_ eq 'e');
- $doAli = 1 if($_ eq '2');
- }
- }
- # generate entity list
- foreach my $id (sort(keys%{$modules{CUL_HM}{defptr}})){
- next if ($id eq "000000");
- my $eHash = $modules{CUL_HM}{defptr}{$id};
- my $eName = $eHash->{NAME};
- next if ( !$eName || $eName !~ m/$re/);
- my $eIg = CUL_HM_Get($eHash,$eName,"param","ignore");
- $eIg = "" if ($eIg eq "undefined");
- next if (!$doIgn && $eIg);
- next if (!(($doDev && $eHash->{helper}{role}{dev}) ||
- ($doChn && $eHash->{helper}{role}{chn})));
- next if ( $noVrt && $eHash->{helper}{role}{vrt});
- next if ( $noPhy && !$eHash->{helper}{role}{vrt});
- my $eSt = CUL_HM_Get($eHash,$eName,"param","subType");
- next if ( $noSen && $eSt =~ m/^(THSensor|remote|pushButton|threeStateSensor|sensor|motionDetector|swi)$/);
- next if ( $noAct && $eSt =~ m/^(switch|blindActuator|dimmer|thermostat|smokeDetector|KFM100|outputUnit)$/);
- push @names,$eName;
- }
- return sort(@names);
- }
- sub HMinfo_getMsgStat() { #####################################################
- my ($hr,$dr,$hs,$ds);
- $hr = sprintf("\n %-14s:","receive hour");
- $hs = sprintf("\n %-14s:","send hour");
- $dr = sprintf("\n %-14s:","receive day");
- $ds = sprintf("\n %-14s:","send day");
- $hr .= sprintf("| %02d",$_) foreach (0..23);
- $hs .= sprintf("| %02d",$_) foreach (0..23);
- $dr .= sprintf("|%4s",$_) foreach ("Mon","Tue","Wed","Thu","Fri","Sat","Sun","# 24h");
- $ds .= sprintf("|%4s",$_) foreach ("Mon","Tue","Wed","Thu","Fri","Sat","Sun","# 24h");
- foreach my $ioD(keys %{$modules{CUL_HM}{stat}{r}}){
- next if ($ioD eq "dummy");
- $hr .= sprintf("\n %-10s:",$ioD);
- $hs .= sprintf("\n %-10s:",$ioD);
- $dr .= sprintf("\n %-10s:",$ioD);
- $ds .= sprintf("\n %-10s:",$ioD);
- $hr .= sprintf("|%3d",$modules{CUL_HM}{stat}{r}{$ioD}{h}{$_}) foreach (0..23);
- $hs .= sprintf("|%3d",$modules{CUL_HM}{stat}{s}{$ioD}{h}{$_}) foreach (0..23);
- $dr .= sprintf("|%4d",$modules{CUL_HM}{stat}{r}{$ioD}{d}{$_}) foreach (0..6);
- $ds .= sprintf("|%4d",$modules{CUL_HM}{stat}{s}{$ioD}{d}{$_}) foreach (0..6);
-
- my ($tdr,$tds);
- $tdr += $modules{CUL_HM}{stat}{r}{$ioD}{h}{$_} foreach (0..23);
- $tds += $modules{CUL_HM}{stat}{s}{$ioD}{h}{$_} foreach (0..23);
- $dr .= sprintf("|#%4d",$tdr);
- $ds .= sprintf("|#%4d",$tds);
- }
- my @l = localtime(gettimeofday());
- my $tsts = "\n |";
- $tsts .= "----" foreach (1..$l[2]);
- $tsts .= ">*" ;
- return "msg statistics\n"
- .$tsts
- .$hr.$hs
- .$tsts
- .$dr.$ds
- ;
- }
- sub HMinfo_GetFn($@) {#########################################################
- my ($hash,$name,$cmd,@a) = @_;
- my ($opt,$optEmpty,$filter) = ("",1,"");
- my $ret;
- $doAli = 0;#set default
-
- if (@a && ($a[0] =~ m/^-/) && ($a[0] !~ m/^-f$/)){# options provided
- $opt = $a[0];
- $optEmpty = ($opt =~ m/e/)?1:0;
- shift @a; #remove
- }
- if (@a && $a[0] =~ m/^-f$/){# options provided
- shift @a; #remove
- $filter = shift @a;
- }
- $cmd = "?" if(!$cmd);# by default print options
- #------------ statistics ---------------
- if ($cmd eq "protoEvents"){##print protocol-events-------------------------
- my ($type) = @a;
- $type = "short" if(!$type);
- my @paramList2;
- my @IOlist;
- my @plSum; push @plSum,0 for (0..9);#prefill
- my $maxNlen = 3;
- foreach my $dName (HMinfo_getEntities($opt."dv",$filter)){
- my $id = $defs{$dName}{DEF};
- my $nl = length($dName);
- $maxNlen = $nl if($nl > $maxNlen);
- my ($found,$para) = HMinfo_getParam($id,
- ,"protState","protCmdPend"
- ,"protSnd","protLastRcv","protResnd"
- ,"protCmdDel","protResndFail","protNack","protIOerr");
- $para =~ s/( last_at|20..-|\|)//g;
- my @pl = split "\t",$para;
- foreach (@pl){
- $_ =~ s/\s+$|//g ;
- $_ =~ s/CMDs_//;
- $_ =~ s/..-.. ..:..:..//g if ($type eq "short");
- $_ =~ s/CMDs // if ($type eq "short");
- }
- for (1..9){
- my ($x) = $pl[$_] =~ /(\d+)/;
- $plSum[$_] += $x if ($x);
- }
- push @paramList2,[@pl];
- push @IOlist,$defs{$pl[0]}{IODev}->{NAME};
- }
- $maxNlen ++;
- my ($hdr,$ftr);
- my @paramList;
- if ($type eq "short"){
- push @paramList, sprintf("%-${maxNlen}s%-17s|%-10s|%-10s|%-10s#%-10s|%-10s|%-10s|%-10s",
- @{$_}[0..3],@{$_}[5..9]) foreach(@paramList2);
- $hdr = sprintf("%-${maxNlen}s:%-16s|%-10s|%-10s|%-10s#%-10s|%-10s|%-10s|%-10s",
- ,"name"
- ,"State","CmdPend"
- ,"Snd","Resnd"
- ,"CmdDel","ResndFail","Nack","IOerr");
- $ftr = sprintf("%-${maxNlen}s%-17s|%-10s|%-10s|%-10s#%-10s|%-10s|%-10s|%-10s","sum",@plSum[1..3],@plSum[5..9]);
- }
- else{
- push @paramList, sprintf("%-${maxNlen}s%-17s|%-18s|%-18s|%-14s|%-18s#%-18s|%-18s|%-18s|%-18s",
- @{$_}[0..9]) foreach(@paramList2);
- $hdr = sprintf("%-${maxNlen}s:%-16s|%-18s|%-18s|%-14s|%-18s#%-18s|%-18s|%-18s|%-18s",
- ,"name"
- ,"State","CmdPend"
- ,"Snd","LastRcv","Resnd"
- ,"CmdDel","ResndFail","Nack","IOerr");
- $ftr = sprintf("%-${maxNlen}20s%-17s|%-18s|%-18s|%-14s|%-18s#%-18s|%-18s|%-18s|%-18s","sum",@plSum[1..9]);
- }
-
- $ret = $cmd." done:"
- ."\n ".$hdr
- ."\n ".(join "\n ",sort @paramList)
- ."\n================================================================================================================"
- ."\n ".$ftr
- ."\n"
- ."\n CUL_HM queue length:$modules{CUL_HM}{prot}{rspPend}"
- ."\n"
- ."\n requests pending"
- ."\n ----------------"
- ."\n autoReadReg : ".join(" ",@{$modules{CUL_HM}{helper}{qReqConf}})
- ."\n recent : ".($modules{CUL_HM}{helper}{autoRdActive}?$modules{CUL_HM}{helper}{autoRdActive}:"none")
- ."\n status request : ".join(" ",@{$modules{CUL_HM}{helper}{qReqStat}})
- ."\n autoReadReg wakeup : ".join(" ",@{$modules{CUL_HM}{helper}{qReqConfWu}})
- ."\n status request wakeup: ".join(" ",@{$modules{CUL_HM}{helper}{qReqStatWu}})
- ."\n autoReadTest : ".join(" ",@{$modules{CUL_HM}{helper}{confCheckArr}})
- ."\n"
- ;
- @IOlist = HMinfo_noDup(@IOlist);
- foreach(@IOlist){
- $_ .= ":".$defs{$_}{STATE}
- .(defined $defs{$_}{helper}{q}
- ? " pending=".$defs{$_}{helper}{q}{answerPend}
- : ""
- )
- ." condition:".ReadingsVal($_,"cond","-")
- .(defined $defs{$_}{msgLoadEst}
- ? "\n msgLoadEst: ".$defs{$_}{msgLoadEst}
- : ""
- )
- ;
- }
- $ret .= "\n IODevs:".(join"\n ",HMinfo_noDup(@IOlist));
- }
- elsif($cmd eq "msgStat") {##print message statistics----------------------
- $ret = HMinfo_getMsgStat();
- }
- elsif($cmd =~ m/^(rssi|rssiG)$/){##print RSSI protocol-events----------------
- my ($type) = (@a,"full");# ugly way to set "full" as default
- my @rssiList = ();
- my %rssiH;
- my @io;
- foreach my $dName (HMinfo_getEntities($opt."dv",$filter)){
- foreach my $dest (keys %{$defs{$dName}{helper}{rssi}}){
- my $dispName = $dName;
- my $dispDest = $dest;
- if ($dest =~ m/^at_(.*)/){
- $dispName = $1;
- $dispDest = (($dest =~ m/^to_rpt_/)?"rep_":"").$dName;
- }
- if (AttrVal($dName,"subType","") eq "virtual"){
- my $h = InternalVal($dName,"IODev","");
- $dispDest .= "/$h->{NAME}";
- }
- if ($type eq "full"){
- push @rssiList,sprintf("%-15s ",$dName)
- .($doAli ? sprintf("%-15s ",AttrVal($dName,"alias","-")):"")
- .sprintf("%-15s %-15s %6.1f %6.1f %6.1f<%6.1f %5s"
- ,$dispName,$dispDest
- ,$defs{$dName}{helper}{rssi}{$dest}{lst}
- ,$defs{$dName}{helper}{rssi}{$dest}{avg}
- ,$defs{$dName}{helper}{rssi}{$dest}{min}
- ,$defs{$dName}{helper}{rssi}{$dest}{max}
- ,$defs{$dName}{helper}{rssi}{$dest}{cnt}
- );
- }
- else{
- my $dir = ($dName eq $dispName)?$dispDest." >":$dispName." <";
- push @io,$dir;
- $rssiH{$dName}{$dir}{min} = $defs{$dName}{helper}{rssi}{$dest}{min};
- $rssiH{$dName}{$dir}{avg} = $defs{$dName}{helper}{rssi}{$dest}{avg};
- $rssiH{$dName}{$dir}{max} = $defs{$dName}{helper}{rssi}{$dest}{max};
- }
- }
- }
- if ($type eq "reduced"){
- @io = HMinfo_noDup(@io);
- my $s = sprintf(" %15s "," ");
- $s .= sprintf(" %12s",$_)foreach (@io);
- push @rssiList, $s;
-
- foreach my $d(keys %rssiH){
- my $str = sprintf("%-15s ",$d);
- $str .= sprintf("%-15s ",AttrVal($d,"alias","-"))if ($doAli);
- foreach my $i(@io){
- $str .= sprintf(" %12.1f"
- # ,($rssiH{$d}{$i}{min} ? $rssiH{$d}{$i}{min} : 0)
- ,($rssiH{$d}{$i}{avg} ? $rssiH{$d}{$i}{avg} : 0)
- # ,($rssiH{$d}{$i}{max} ? $rssiH{$d}{$i}{max} : 0)
- );
- }
- push @rssiList, $str;
- }
- $ret = "\n rssi average \n"
- .(join "\n ",sort @rssiList);
- }
- elsif($type eq "full"){
- $ret = $cmd." done:"."\n "."Device ".($doAli?"Alias ":"")."receive from last avg min_max count"
- ."\n ".(join "\n ",sort @rssiList)
- ;
- }
- }
- #------------ checks ---------------
- elsif($cmd eq "regCheck") {##check register--------------------------------
- my @entities = HMinfo_getEntities($opt."v",$filter);
- $ret = $cmd." done:" .HMinfo_regCheck(@entities);
- }
- elsif($cmd eq "peerCheck") {##check peers-----------------------------------
- my @entities = HMinfo_getEntities($opt,$filter);
- $ret = $cmd." done:" .HMinfo_peerCheck(@entities);
- }
- elsif($cmd eq "configCheck"){##check peers and register----------------------
- if ($hash->{CL}){
- my $id = ++$hash->{nb}{cnt};
- my $bl = BlockingCall("HMinfo_configCheck", join(",",("$name;$id;$hash->{CL}{NAME}",$opt,$filter)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:0");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = "";
- }
- else{
- (undef,undef,undef,$ret) = split(";",HMinfo_configCheck (join(",",("$name;;",$opt,$filter))),4);
- $ret =~s/-ret-/\n/g;
- }
- }
- elsif($cmd eq "templateChk"){##template: see if it applies ------------------
- my $id = ++$hash->{nb}{cnt};
- my $bl = BlockingCall("HMinfo_templateChk_Get", join(",",("$name;$id;$hash->{CL}{NAME}",$opt,$filter,@a)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:0");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = "";
- }
- elsif($cmd eq "templateUsg"){##template: see if it applies ------------------
- return HMinfo_templateUsg($opt,$filter,@a);
- }
- #------------ print tables ---------------
- elsif($cmd eq "peerXref") {##print cross-references------------------------
- my @peerPairs;
- my @peerFhem;
- my @peerUndef;
- my @fheml = ();
- foreach my $dName (HMinfo_getEntities($opt,$filter)){
- # search for irregular trigger
- my $peerIDs = AttrVal($dName,"peerIDs","");
- $peerIDs =~ s/00000000,//;
- foreach (grep /^......$/, HMinfo_noDup(map {CUL_HM_name2Id(substr($_,8))}
- grep /^trigDst_/,
- keys %{$defs{$dName}{READINGS}})){
- push @peerUndef,"$dName triggers $_"
- if( ($peerIDs && $peerIDs !~ m/$_/)
- &&("CCU-FHEM" ne AttrVal(CUL_HM_id2Name($_),"model","")));
- }
- #--- check regular references
- next if(!$peerIDs);
- my $dId = unpack 'A6',CUL_HM_name2Id($dName);
- my @pl = ();
- foreach (split",",$peerIDs){
- my $pn = CUL_HM_peerChName($_,$dId);
- $pn =~ s/_chn-01//;
- push @pl,$pn;
- push @fheml,"$_$dName" if ($pn =~ m/^fhem..$/);
- }
- push @peerPairs,$dName." => ".join(" ",(sort @pl)) if (@pl);
- }
- #--- calculate peerings to Central ---
- my %fChn;
- foreach (@fheml){
- my ($fhId,$fhCh,$p)= unpack 'A6A2A*',$_;
- my $fhemCh = "fhem_io_${fhId}_$fhCh";
- $fChn{$fhemCh} = ($fChn{$fhemCh}?$fChn{$fhemCh}.", ":"").$p;
- }
- push @peerFhem,map {"$_ => $fChn{$_}"} keys %fChn;
- $ret = $cmd." done:" ."\n x-ref list"."\n ".(join "\n ",sort @peerPairs)
- ."\n ".(join "\n ",sort @peerFhem)
- ;
- $ret .= "\n warning: sensor triggers but no config found"
- ."\n ".(join "\n ",sort @peerUndef)
- if(@peerUndef)
- ;
- }
- elsif($cmd eq "templateList"){##template: list templates --------------------
- return HMinfo_templateList($a[0]);
- }
- elsif($cmd eq "register") {##print register--------------------------------
- my $id = ++$hash->{nb}{cnt};
- my $bl = BlockingCall("HMinfo_register", join(",",("$name;$id;$hash->{CL}{NAME}",$name,$opt,$filter)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:0");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = "";
- }
- elsif($cmd eq "param") {##print param ----------------------------------
- my @paramList;
- foreach my $dName (HMinfo_getEntities($opt,$filter)){
- my $id = $defs{$dName}{DEF};
- my ($found,$para) = HMinfo_getParam($id,@a);
- push @paramList,$para if($found || $optEmpty);
- }
- my $prtHdr = "entity \t: ";
- $prtHdr .= sprintf("%-20s \t| ",$_)foreach (@a);
- $ret = $cmd." done:"
- ."\n param list" ."\n "
- .$prtHdr ."\n "
- .(join "\n ",sort @paramList)
- ;
- }
- elsif($cmd eq "models") {##print capability, models----------------------
- my $th = \%HMConfig::culHmModel;
- my @model;
- foreach (keys %{$th}){
- my $mode = $th->{$_}{rxt};
- $mode =~ s/\bc\b/config/;
- $mode =~ s/\bw\b/wakeup/;
- $mode =~ s/\bb\b/burst/;
- $mode =~ s/\b3\b/3Burst/;
- $mode =~ s/\bl\b/lazyConf/;
- $mode =~ s/\bf\b/burstCond/;
- $mode =~ s/:/,/g;
- $mode = "normal" if (!$mode);
- my $list = $th->{$_}{lst};
- $list =~ s/.://g;
- $list =~ s/p//;
- my $chan = "";
- foreach (split",",$th->{$_}{chn}){
- my ($n,$s,$e) = split(":",$_);
- $chan .= $s.(($s eq $e)?"":("-".$e))." ".$n.", ";
- }
- push @model,sprintf("%-16s %-24s %4s %-24s %-5s %-5s %s"
- ,$th->{$_}{st}
- ,$th->{$_}{name}
- ,$_
- ,$mode
- ,$th->{$_}{cyc}
- ,$list
- ,$chan
- );
- }
- @model = grep /$filter/,sort @model if($filter);
- $ret = $cmd.($filter?" filtered":"").":$filter\n "
- .sprintf("%-16s %-24s %4s %-24s %-5s %-5s %s\n "
- ,"subType"
- ,"name"
- ,"ID"
- ,"supportedMode"
- ,"Info"
- ,"List"
- ,"channels"
- )
- .join"\n ", @model;
- }
- # elsif($cmd eq "overview") {
- # my @entities = HMinfo_getEntities($opt."d",$filter);
- # return HMI_overview(\@entities,\@a);
- # }
-
- elsif($cmd eq "help") {
- $ret = HMInfo_help();
- }
- else{
- my @cmdLst =
- ( "help"
- ,"configCheck","param","peerCheck","peerXref"
- ,"protoEvents","msgStat"
- ,"rssi rssiG:full,reduced"
- ,"models"
- # ,"overview"
- ,"regCheck","register"
- ,"templateList:".join(",",("all",sort keys%HMConfig::culHmTpl))
- ,"templateChk","templateUsg"
- );
-
- $ret = "Unknown argument $cmd, choose one of ".join (" ",sort @cmdLst);
- }
- return $ret;
- }
- sub HMinfo_SetFn($@) {#########################################################
- my ($hash,$name,$cmd,@a) = @_;
- my @in = @a;
- my ($opt,$optEmpty,$filter) = ("",1,"");
- my $ret;
- $doAli = 0;#set default
- if (@a && ($a[0] =~ m/^-/) && ($a[0] !~ m/^-f$/)){# options provided
- $opt = $a[0];
- $optEmpty = ($opt =~ m/e/)?1:0;
- shift @a; #remove
- }
- if (@a && $a[0] =~ m/^-f$/){# options provided
- shift @a; #remove
- $filter = shift @a;
- }
- $cmd = "?" if(!$cmd);# by default print options
- if ($cmd =~ m/^clear[G]?/ ) {##actionImmediate: clear parameter--------------
- my ($type) = @a;
- return "please enter what to clear" if (! $type);
- if ($type eq "msgStat" || $type eq "all" ){
- foreach (keys %{$modules{CUL_HM}{stat}{r}}){
- next if ($_ eq "dummy");
- delete $modules{CUL_HM}{stat}{$_};
- delete $modules{CUL_HM}{stat}{r}{$_};
- delete $modules{CUL_HM}{stat}{s}{$_};
- }
- }
- if ($type ne "msgStat"){
- return "unknown parameter - use msgEvents, readings, msgStat, register, rssi, attack or all"
- if ($type !~ m/^(msgEvents|readings|register|oldRegs|rssi|all|attack|trigger)$/);
- $opt .= "d" if ($type =~ m/(msgEvents|rssi)/);# readings apply to all, others device only
- my @entities;
- foreach my $dName (HMinfo_getEntities($opt,$filter)){
- push @entities,$dName;
- CUL_HM_Set($defs{$dName},$dName,"clear",$type);
- }
- $ret = $cmd.$type." done:"
- ."\n cleared"
- ."\n ".(join "\n ",sort @entities)
- if($filter);# no return if no filter
- }
- HMinfo_status($hash);
- }
- elsif($cmd eq "autoReadReg"){##actionImmediate: re-issue register Read-------
- my @entities;
- foreach my $dName (HMinfo_getEntities($opt."dv",$filter)){
- next if (!substr(AttrVal($dName,"autoReadReg","0"),0,1));
- CUL_HM_qAutoRead($dName,1);
- push @entities,$dName;
- }
- return $cmd." done:" ."\n triggered:" ."\n ".(join "\n ",sort @entities)
- ;
- }
- elsif($cmd eq "templateSet"){##template: set of register --------------------
- return HMinfo_templateSet(@a);
- }
- elsif($cmd eq "templateDel"){##template: set of register --------------------
- return HMinfo_templateDel(@a);
- }
- elsif($cmd eq "templateDef"){##template: define one -------------------------
- return HMinfo_templateDef(@a);
- }
- elsif($cmd eq "cpRegs") {##copy register --------------------
- return HMinfo_cpRegs(@a);
- }
- elsif($cmd eq "update") {##update hm counts -----------------------------
- $ret = HMinfo_status($hash);
- }
- elsif($cmd =~ m/tempList[G]?/){##handle thermostat templist from file -------
- my $action = $a[0]?$a[0]:"";
- if ( $action eq "genPlot"){#generatelog and gplot file
- $ret = HMinfo_tempListTmplGenLog($name,$a[1]);
- }
- elsif ($action eq "status"){
- $ret = HMinfo_tempListTmplView();
- }
- else{
- my $fn = HMinfo_tempListDefFn($a[1]);
- $ret = HMinfo_tempList($name,$filter,$action,$fn);
- }
- HMinfo_listOfTempTemplates(); # execute post command - maybe there are new entries in the files.
- }
- elsif($cmd eq "templateExe"){##template: see if it applies ------------------
- return HMinfo_templateExe($opt,$filter,@a);
- }
- elsif($cmd eq "loadConfig") {##action: loadConfig----------------------------
- my $fn = $a[0]?$a[0]:AttrVal($name,"configFilename","regSave.cfg");
- $fn = "$attr{global}{modpath}/".AttrVal($name,"configDir",".")."\/".$fn if ($fn !~ m/\//);
- $ret = HMinfo_loadConfig($filter,$fn);
- }
- elsif($cmd eq "verifyConfig"){##action: verifyConfig-------------------------
- my $fn = $a[0]?$a[0]:AttrVal($name,"configFilename","regSave.cfg");
- $fn = "$attr{global}{modpath}/".AttrVal($name,"configDir",".")."\/".$fn
- if ($fn !~ m/\//);
- if ($hash->{CL}){
- my $id = ++$hash->{nb}{cnt};
- my $bl = BlockingCall("HMinfo_verifyConfig", join(",",("$name;$id;$hash->{CL}{NAME}",$fn)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:$id");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = "";
- }
- else{
- $ret = HMinfo_verifyConfig("$name;0;none,$fn");
- }
- }
- elsif($cmd eq "purgeConfig"){##action: purgeConfig---------------------------
- my $id = ++$hash->{nb}{cnt};
- my $fn = $a[0]?$a[0]:AttrVal($name,"configFilename","regSave.cfg");
- $fn = "$attr{global}{modpath}/".AttrVal($name,"configDir",".")."\/".$fn
- if ($fn !~ m/\//);
- my $bl = BlockingCall("HMinfo_purgeConfig", join(",",("$name;$id;none",$fn)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:$id");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = "";
- }
- elsif($cmd eq "saveConfig") {##action: saveConfig----------------------------
- my $id = ++$hash->{nb}{cnt};
- my $fn = $a[0]?$a[0]:AttrVal($name,"configFilename","regSave.cfg");
- $fn = "$attr{global}{modpath}/".AttrVal($name,"configDir",".")."\/".$fn
- if ($fn !~ m/\//);
- my $bl = BlockingCall("HMinfo_saveConfig", join(",",("$name;$id;none",$fn,$opt,$filter)),
- "HMinfo_bpPost", 30,
- "HMinfo_bpAbort", "$name:$id");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- $ret = $cmd." done:" ."\n saved";
- }
- elsif($cmd eq "archConfig") {##action: archiveConfig-------------------------
- # save config only if register are complete
- $ret = HMinfo_archConfig($hash,$name,$opt,($a[0]?$a[0]:""));
- }
- ### redirect set commands to get - thus the command also work in webCmd
- elsif($cmd ne '?' && HMinfo_GetFn($hash,$name,"?") =~ m/\b$cmd\b/){##----------------
- unshift @a,"-f",$filter if ($filter);
- unshift @a,"-".$opt if ($opt);
- $ret = HMinfo_GetFn($hash,$name,$cmd,@a);
- }
- else{
- my @cmdLst =
- ( "autoReadReg"
- ,"clear" #:msgStat,msgEvents,all,rssi,register,trigger,readings"
- ,"clearG:msgEvents,readings,register,oldRegs,rssi,msgStat,trigger,attack,all"
- ,"archConfig:-0,-a","saveConfig","verifyConfig","loadConfig","purgeConfig"
- ,"update"
- ,"cpRegs"
- ,"tempList"
- ,"tempListG:verify,status,save,restore,genPlot"
- ,"templateDef","templateSet","templateDel","templateExe"
- );
- $ret = "Unknown argument $cmd, choose one of ".join (" ",sort @cmdLst);
- }
- return $ret;
- }
- sub HMInfo_help(){ ############################################################
- return " Unknown argument choose one of "
- ."\n ---checks---"
- ."\n get configCheck [-typeFilter-] # perform regCheck and regCheck"
- ."\n get regCheck [-typeFilter-] # find incomplete or inconsistant register readings"
- ."\n get peerCheck [-typeFilter-] # find incomplete or inconsistant peer lists"
- ."\n ---actions---"
- ."\n set saveConfig [-typeFilter-] [-file-] # stores peers and register with saveConfig"
- ."\n set archConfig [-a] [-file-] # as saveConfig but only if data of entity is complete"
- ."\n set purgeConfig [-file-] # purge content of saved configfile "
- ."\n set loadConfig [-typeFilter-] -file- # restores register and peer readings if missing"
- ."\n set verifyConfig [-typeFilter-] -file- # compare curent date with configfile,report differences"
- ."\n set autoReadReg [-typeFilter-] # trigger update readings if attr autoReadReg is set"
- ."\n set tempList [-typeFilter-][save|restore|verify|status|genPlot][-filename-]# handle tempList of thermostat devices"
- ."\n ---infos---"
- ."\n set update # update HMindfo counts"
- ."\n get register [-typeFilter-] # devicefilter parse devicename. Partial strings supported"
- ."\n get peerXref [-typeFilter-] # peer cross-reference"
- ."\n get models [-typeFilter-] # list of models incl native parameter"
- ."\n get protoEvents [-typeFilter-] [short|long] # protocol status - names can be filtered"
- ."\n get msgStat # view message statistic"
- ."\n get param [-typeFilter-] [-param1-] [-param2-] ... # displays params for all entities as table"
- ."\n get rssi [-typeFilter-] # displays receive level of the HM devices"
- ."\n last: most recent"
- ."\n avg: average overall"
- ."\n range: min to max value"
- ."\n count: number of events in calculation"
- ."\n ---clear status---"
- ."\n set clear[G] [-typeFilter-] [msgEvents|readings|msgStat|register|rssi]"
- ."\n # delete readings selective"
- ."\n msgEvents # delete all protocol-events , msg events"
- ."\n readings # all readings"
- ."\n register # all register-readings"
- ."\n oldRegs # outdated register (cleanup) "
- ."\n rssi # all rssi data "
- ."\n msgStat # message statistics"
- ."\n trigger # trigger readings"
- ."\n attack # attack related readings"
- ."\n all # all of the above"
- ."\n ---help---"
- ."\n get help #"
- ."\n ***footnote***"
- ."\n [-nameFilter-] : only matiching names are processed - partial names are possible"
- ."\n [-modelsFilter-] : any match in the output are searched. "
- ."\n"
- ."\n set cpRegs -src:peer- -dst:peer-"
- ."\n copy register for a channel or behavior of channel/peer"
- ."\n set templateDef -templateName- -param1[:-param2-...] -description- -reg1-:-val1- [-reg2-:-val2-] ... "
- ."\n define a template"
- ."\n set templateSet -entity- -templateName- -peer:[long|short]- [-param1- ...] "
- ."\n write register according to a given template"
- ."\n set templateDel -entity- -templateName- -peer:[long|short]- "
- ."\n remove a template set"
- ."\n set templateExe -templateName-"
- ."\n write all assigned templates to the file"
- ."\n get templateUsg -templateName-[sortPeer|sortTemplate]"
- ."\n show template usage"
- ."\n get templateChk [-typeFilter-] -templateName- -peer:[long|short]- [-param1- ...] "
- ."\n compare whether register match the template values"
- ."\n get templateList [-templateName-] # gives a list of templates or a description of the named template"
- ."\n list all currently defined templates or the structure of a given template"
- ."\n ======= typeFilter options: supress class of devices ===="
- ."\n set -name- -cmd- [-dcasev] [-f -filter-] [params]"
- ."\n entities according to list will be processed"
- ."\n d - device :include devices"
- ."\n c - channels :include channels"
- ."\n i - ignore :include devices marked as ignore"
- ."\n v - virtual :supress fhem virtual"
- ."\n p - physical :supress physical"
- ."\n a - aktor :supress actor"
- ."\n s - sensor :supress sensor"
- ."\n e - empty :include results even if requested fields are empty"
- ."\n "
- ."\n -f - filter :regexp to filter entity names "
- ."\n "
- ;
- }
- sub HMinfo_verifyConfig($) {###################################################
- my ($param) = @_;
- my ($id,$fName) = split ",",$param;
- HMinfo_purgeConfig($param);
- open(aSave, "$fName") || return("$id;Can't open $fName: $!");
- my @elPeer = ();
- my @elReg = ();
- my @entryNF = ();
- my @elOk = ();
- my %nh;
- while(<aSave>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- next if ( $line !~ m/set .* (peerBulk|regBulk) .*/);
- $line =~ s/#.*//;
- my ($cmd1,$eN,$cmd,$param) = split(" ",$line,4);
- if (!$eN || !$defs{$eN}){
- push @entryNF,"$eN deleted";
- next;
- }
- $nh{$eN} = 1 if (!defined $nh{$eN});#
- if($cmd eq "peerBulk"){
- my $ePeer = AttrVal($eN,"peerIDs","");
- if ($param ne $ePeer){
- my @fPeers = grep !/00000000/,split(",",$param);#filepeers
- my @ePeers = grep !/00000000/,split(",",$ePeer);#entitypeers
- my %fp = map {$_=>1} @ePeers;
- my @onlyFile = grep { !$fp{$_} } @fPeers;
- my %ep = map {$_=>1} @fPeers;
- my @onlyEnt = grep { !$ep{$_} } @ePeers;
- push @elPeer,"$eN peer deleted: $_" foreach(@onlyFile);
- push @elPeer,"$eN peer added : $_" foreach(@onlyEnt);
- $nh{$eN} = 0 if(scalar@onlyFile || scalar @onlyEnt);
- }
- }
- elsif($cmd eq "regBulk"){
- next if($param !~ m/RegL_0[0-9][:\.]/);#allow . and : for the time to convert to . only
- $param =~ s/\.RegL/RegL/;
- my ($reg,$data) = split(" ",$param,2);
- my $eReg = ReadingsVal($eN,($defs{$eN}{helper}{expert}{raw}?"":".").$reg,"");
- my ($ensp,$dnsp) = ($eReg,$data);
- $ensp =~ s/ //g;
- $dnsp =~ s/ //g;
- if ($ensp ne $dnsp){
- my %r; # generate struct with changes addresses
- foreach my $rg(grep /..:../, split(" ",$eReg)){
- my ($a,$d) = split(":",$rg);
- $r{$a}{c} = $d;
- }
- foreach my $rg(grep !/00:00/,grep /..:../, split(" ",$data)){
- my ($a,$d) = split(":",$rg);
- next if (!$a || $a eq "00");
- if (!defined $r{$a}){$r{$a}{f} = $d;$r{$a}{c} = "";}
- elsif($r{$a}{c} ne $d){$r{$a}{f} = $d;}
- else {delete $r{$a};}
- }
- $r{$_}{f} = "" foreach (grep {!defined $r{$_}{f}} grep !/00/,keys %r);
- my @aCh = map {hex($_)} keys %r;#list of changed addresses
-
- # search register valid for thie entity
- my $dN = CUL_HM_getDeviceName($eN);
- my $chn = CUL_HM_name2Id($eN);
- my (undef,$listNo,undef,$peer) = unpack('A6A1A1A*',$reg);
- $chn = (length($chn) == 8)?substr($chn,6,2):"";
- my $culHmRegDefine =\%HMConfig::culHmRegDefine;
- my @regArr = grep{$culHmRegDefine->{$_}->{l} eq $listNo}
- CUL_HM_getRegN(AttrVal($dN,"subType","")
- ,AttrVal($dN,"model","")
- ,$chn);
- # now identify which register belongs to suspect address.
- foreach my $rgN (@regArr){
- next if ($culHmRegDefine->{$rgN}{l} ne $listNo);
- my $a = $culHmRegDefine->{$rgN}{a};
- next if (!grep {$a == int($_)} @aCh);
- $a = sprintf("%02X",$a);
- push @elReg,"$eN "
- .($peer?": peer:$peer ":"")
- ."addr:$a changed from $r{$a}{f} to $r{$a}{c} - effected RegName:$rgN";
- $nh{$eN} = 0;
- }
-
- }
- }
- }
- close(aSave);
- @elReg = HMinfo_noDup(@elReg);
- foreach (sort keys(%nh)){
- push @elOk,"$_" if($nh{$_});
- }
- my $ret;
- $ret .= "\npeer mismatch:\n " .join("\n ",sort(@elPeer)) if (scalar @elPeer);
- $ret .= "\nreg mismatch:\n " .join("\n ",sort(@elReg )) if (scalar @elReg);
- $ret .= "\nmissing devices:\n " .join("\n ",sort(@entryNF)) if (scalar @entryNF);
- # $ret .= "\nverified:\n " .join("\n ",sort(@elOk)) if (scalar @elOk);
- $ret =~ s/\n/-ret-/g;
- return "$id;$ret";
- }
- sub HMinfo_loadConfig($@) {####################################################
- my ($filter,$fName)=@_;
- $filter = "." if (!$filter);
- my $ret;
- open(rFile, "$fName") || return("Can't open $fName: $!");
- my @el = ();
- my @elincmpl = ();
- my @entryNF = ();
- my %changes;
- my @rUpdate;
- my @tmplList = (); #collect templates
- while(<rFile>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- next if ( $line !~ m/set .* (peerBulk|regBulk) .*/
- && $line !~ m/(setreading|template.e.) .*/);
- my ($command,$timeStamp) = split("#",$line,2);
- $timeStamp = "1900-01-01 00:00:01" if (!$timeStamp || $timeStamp !~ m /^20..-..-.. /);
- my ($cmd1,$eN,$cmd,$param) = split(" ",$command,4);
- next if ($eN !~ m/$filter/);
- if ($cmd1 !~ m /^template(Def|Set)$/ && (!$eN || !$defs{$eN})){
- push @entryNF,$eN;
- next;
- }
- if ($cmd1 eq "setreading"){
- if (!$defs{$eN}{READINGS}{$cmd}){
- $changes{$eN}{$cmd}{d}=$param ;
- $changes{$eN}{$cmd}{t}=$timeStamp ;
- }
- $defs{$eN}{READINGS}{$cmd}{VAL} = $param;
- $defs{$eN}{READINGS}{$cmd}{TIME} = "from archivexx";
- }
- elsif($cmd1 eq "templateDef"){
- if ($eN eq "templateStart"){#if new block we remove all old templates
- @tmplList = ();
- }
- push @tmplList,$line;
- }
- elsif($cmd1 eq "templateSet"){
- my (undef,$eNt,$tpl,$param) = split("=>",$line);
- if (defined($defs{$eNt})){
- if($tpl eq "start"){
- delete $defs{$eNt}{helper}{tmpl};
- }
- else{
- $defs{$eNt}{helper}{tmpl}{$tpl} = $param;
- }
- }
- }
- elsif($cmd eq "peerBulk"){
- next if(!$param);
- $param =~ s/ //g;
- if ($param !~ m/00000000/){
- push @elincmpl,"$eN peerList";
- next;
- }
- if ( $timeStamp
- && $timeStamp gt ReadingsTimestamp($eN,".peerListRDate","1900-01-01 00:00:01")){
- CUL_HM_ID2PeerList($eN,$_,1) foreach (grep /[0-9A-F]{8}/,split(",",$param));
- push @el,"$eN peerIDs";
- $defs{$eN}{READINGS}{".peerListRDate"}{VAL} = $defs{$eN}{READINGS}{".peerListRDate"}{TIME} = $timeStamp;
- }
- }
- elsif($cmd eq "regBulk"){
- next if($param !~ m/RegL_0[0-9][:\.]/);#allow . and : for the time to convert to . only
- $param =~ s/\.RegL/RegL/;
- $param = ".".$param if (!$defs{$eN}{helper}{expert}{raw});
- my ($reg,$data) = split(" ",$param,2);
- my @rla = CUL_HM_reglUsed($eN);
- next if (!$rla[0]);
- my $rl = join",",@rla;
- $reg =~ s/(RegL_0.):/$1\./;# conversion - : not allowed anymore. Update old versions
- $reg =~ s/_chn-00//; # special:
- my $r2 = $reg;
- $r2 =~ s/^\.//;
- next if ($rl !~ m/$r2/);
- if ($data !~ m/00:00/){
- push @elincmpl,"$eN reg list:$reg";
- next;
- }
- my $ts = ReadingsTimestamp($eN,$reg,"1900-01-01 00:00:01");
- $ts = "1900-01-01 00:00:00" if ($ts !~ m /^20..-..-.. /);
- if ( !$defs{$eN}{READINGS}{$reg}
- || $defs{$eN}{READINGS}{$reg}{VAL} !~ m/00:00/
- || ( ( $timeStamp gt $ts
- ||( $changes{$eN}
- && $changes{$eN}{$reg}
- && $timeStamp gt $changes{$eN}{$reg}{t})
- ))){
- $data =~ s/ //g;
- $changes{$eN}{$reg}{d}=$data;
- $changes{$eN}{$reg}{t}=$timeStamp;
- }
- }
- }
- close(rFile);
- foreach my $eN (keys %changes){
- foreach my $reg (keys %{$changes{$eN}}){
- $defs{$eN}{READINGS}{$reg}{VAL} = $changes{$eN}{$reg}{d};
- $defs{$eN}{READINGS}{$reg}{TIME} = $changes{$eN}{$reg}{t};
- my ($list,$pN) = ($1,$2) if ($reg =~ m/RegL_(..)\.(.*)/);
- next if (!$list);
- my $pId = CUL_HM_name2Id($pN);# allow devices also as peer. Regfile is korrekt
- # my $pId = CUL_HM_peerChId($pN,substr($defs{$eN}{DEF},0,6));#old - removed
- CUL_HM_updtRegDisp($defs{$eN},$list,$pId);
- push @el,"$eN reg list:$reg";
- }
- }
- $ret .= "\nadded data:\n " .join("\n ",@el) if (scalar@el);
- $ret .= "\nfile data incomplete:\n ".join("\n ",@elincmpl) if (scalar@elincmpl);
- $ret .= "\nentries not defind:\n " .join("\n ",@entryNF) if (scalar@entryNF);
- foreach ( @tmplList){
- my @tmplCmd = split("=>",$_);
- next if (!defined $tmplCmd[4]);
- delete $HMConfig::culHmTpl{$tmplCmd[1]};
- my $r = HMinfo_templateDef($tmplCmd[1],$tmplCmd[2],$tmplCmd[3],split(" ",$tmplCmd[4]));
- }
- $tmplDefChange = 0;# all changes are obsolete
- $tmplUsgChange = 0;# all changes are obsolete
- foreach my $tmpN(devspec2array("TYPE=CUL_HM")){
- $defs{$tmpN}{helper}{tmplChg} = 0 if(!$defs{$tmpN}{helper}{role}{vrt});
- CUL_HM_setTmplDisp($defs{$tmpN});#set readings if desired
- }
- return $ret;
- }
- sub HMinfo_purgeConfig($) {####################################################
- my ($param) = @_;
- my ($id,$fName) = split ",",$param;
- $fName = "regSave.cfg" if (!$fName);
- open(aSave, "$fName") || return("$id;Can't open $fName: $!");
- my %purgeH;
- while(<aSave>){
- chomp;
- my $line = $_;
- $line =~ s/\r//g;
- if($line =~ m/entity:/){#remove an old entry. Last entry is the final.
- my $name = $line;
- $name =~ s/.*entity://;
- $name =~ s/ .*//;
- delete $purgeH{$name};
- }
- next if ( $line !~ m/set (.*) (peerBulk|regBulk) (.*)/
- && $line !~ m/(setreading) .*/);
- my ($command,$timeStamp) = split("#",$line,2);
- my ($cmd,$eN,$typ,$p1,$p2) = split(" ",$command,5);
- if ($cmd eq "set" && $typ eq "regBulk"){
- $p1 =~ s/\.RegL_/RegL_/;
- $p1 =~ s/(RegL_0.):/$1\./;#replace old : with .
- $typ .= " $p1";
- $p1 = $p2;
- }
- elsif ($cmd eq "set" && $typ eq "peerBulk"){
- delete $purgeH{$eN}{$cmd}{regBulk};# regBulk needs to be rewritten
- }
- $purgeH{$eN}{$cmd}{$typ} = $p1.($timeStamp?"#$timeStamp":"");
- }
- close(aSave);
- open(aSave, ">$fName") || return("$id;Can't open $fName: $!");
- print aSave "\n\n#============data purged: ".TimeNow();
- foreach my $eN(sort keys %purgeH){
- next if (!defined $defs{$eN}); # remove deleted devices
- print aSave "\n\n#-------------- entity:".$eN." ------------";
- foreach my $cmd (sort keys %{$purgeH{$eN}}){
- my @peers = ();
- foreach my $typ (sort keys %{$purgeH{$eN}{$cmd}}){
- if ($typ eq "peerBulk"){# need peers to identify valid register
- @peers = map {CUL_HM_id2Name($_)}
- grep !/(00000000|peerBulk)/,
- split",",$purgeH{$eN}{$cmd}{$typ};
- }
- elsif($typ =~ m/^regBulk/){#
- if ($typ !~ m/regBulk RegL_..\.(self..)?$/){# only if peer is mentioned
- my $found = 0;
- foreach my $p (@peers){
- if ($typ =~ m/regBulk RegL_..\.$p/){
- $found = 1;
- last;
- }
- }
- next if (!$found);
- }
- }
- print aSave "\n$cmd $eN $typ ".$purgeH{$eN}{$cmd}{$typ};
- }
- }
- }
- print aSave "\n\n";
- print aSave "\n======= finished ===\n";
- close(aSave);
-
- HMinfo_templateWriteDef($fName);
- foreach my $eNt(devspec2array("TYPE=CUL_HM")){
- $defs{$eNt}{helper}{tmplChg} = 1 if(!$defs{$eNt}{helper}{role}{vrt});
- }
- HMinfo_templateWriteUsg($fName);
-
- return "$id;";
- }
- sub HMinfo_saveConfig($) {#####################################################
- my ($param) = @_;
- my ($id,$fN,$opt,$filter,$strict) = split ",",$param;
- $strict = "" if (!defined $strict);
- foreach my $dName (HMinfo_getEntities($opt."dv",$filter)){
- CUL_HM_Get($defs{$dName},$dName,"saveConfig",$fN,$strict);
- }
- HMinfo_templateWrite($fN);
- HMinfo_purgeConfig($param) if (-e $fN && 1000000 < -s $fN);# auto purge if file to big
- return $id;
- }
- sub HMinfo_archConfig($$$$) {##################################################
- # save config only if register are complete
- my ($hash,$name,$opt,$fN) = @_;
- $fN = $fN?$fN:AttrVal($name,"configFilename","regSave.cfg");
- $fN = "$attr{global}{modpath}/".AttrVal($name,"configDir",".")."\/".$fN
- if ($fN !~ m/\//);
- my $id = ++$hash->{nb}{cnt};
- my $bl = BlockingCall("HMinfo_archConfigExec", join(",",("$name;$id;none"
- ,$fN
- ,$opt)),
- "HMinfo_archConfigPost", 30,
- "HMinfo_bpAbort", "$name:$id");
- $hash->{nb}{$id}{$_} = $bl->{$_} foreach (keys %{$bl});
- @{$modules{CUL_HM}{helper}{confUpdt}} = ();
- return ;
- }
- sub HMinfo_archConfigExec($) {################################################
- # save config only if register are complete
- my ($id,$fN,$opt) = split ",",shift;
- my @eN;
- if ($opt eq "-a"){@eN = HMinfo_getEntities("d","");}
- else {@eN = @{$modules{CUL_HM}{helper}{confUpdt}}}
- my @names;
- push @names,(CUL_HM_getAssChnNames($_),$_) foreach(@eN);
- @{$modules{CUL_HM}{helper}{confUpdt}} = ();
- my @archs;
- @eN = ();
- foreach(HMinfo_noDup(@names)){
- if (CUL_HM_peerUsed($_) ==2 ||HMinfo_regCheck($_)){
- push @eN,$_;
- }
- else{
- push @archs,$_;
- }
- }
- HMinfo_saveConfig(join(",",( $id
- ,$fN
- ,"c"
- ,"\^(".join("|",@archs).")\$")
- ,"strict"));
- return "$id,".(@eN ? join(",",@eN) : "");
- }
- sub HMinfo_archConfigPost($) {################################################
- my @arr = split(",",shift);
- my ($name,$id,$cl) = split(";",$arr[0]);
- shift @arr;
- push @{$modules{CUL_HM}{helper}{confUpdt}},@arr;
- delete $defs{$name}{nb}{$id};
- return ;
- }
- sub HMinfo_configCheck ($){ ###################################################
- my ($param) = shift;
- my ($id,$opt,$filter) = split ",",$param;
-
- my @entities = HMinfo_getEntities($opt,$filter);
- my $ret = "configCheck done:" .HMinfo_regCheck (@entities)
- .HMinfo_peerCheck (@entities)
- .HMinfo_burstCheck(@entities)
- .HMinfo_paramCheck(@entities);
- my @td = (devspec2array("model=HM-CC-RT-DN.*:FILTER=chanNo=04"),
- devspec2array("model=HM.*-TC.*:FILTER=chanNo=02"));
- my @tlr;
- foreach my $e (@td){
- next if(!grep /$e/,@entities );
- my $tr = CUL_HM_tempListTmpl($e,"verify",AttrVal($e,"tempListTmpl"
- ,HMinfo_tempListDefFn().":$e"));
-
- next if ($tr eq "unused");
- push @tlr,"$e: $tr" if($tr);
- }
- $ret .= "\n\n templist mismatch \n ".join("\n ",sort @tlr) if (@tlr);
- @tlr = ();
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- next if (!defined $defs{$dName}{helper}{tmpl});
- foreach (keys %{$defs{$dName}{helper}{tmpl}}){
- my ($p,$t)=split(">",$_);
- my $tck = HMinfo_templateChk($dName,$t,$p,split(" ",$defs{$dName}{helper}{tmpl}{$_}));
- push @tlr,$tck if ($tck);
- }
- }
- $ret .= "\n\n template mismatch \n ".join("\n ",sort @tlr) if (@tlr);
- $ret =~ s/\n/-ret-/g; # replace return with a placeholder - we cannot transfere direct
- return "$id;$ret";
- }
- sub HMinfo_register ($){ ######################################################
- my ($param) = shift;
- my ($id,$name,$opt,$filter) = split ",",$param;
- my $hash = $defs{$name};
- my $RegReply = "";
- my @noReg;
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- my $regs = CUL_HM_Get(CUL_HM_name2Hash($dName),$dName,"reg","all");
- if ($regs !~ m/[0-6]:/){
- push @noReg,$dName;
- next;
- }
- my ($peerOld,$ptOld,$ptLine,$peerLine) = ("","",pack('A23',""),pack('A23',""));
- foreach my $reg (split("\n",$regs)){
- my ($peer,$h1) = split ("\t",$reg);
- $peer =~s/ //g;
- if ($peer !~ m/3:/){
- $RegReply .= $reg."\n";
- next;
- }
- next if (!$h1);
- $peer =~s/3://;
- my ($regN,$h2) = split (":",$h1);
- my ($pt,$rN) = unpack 'A2A*',$regN;
- if (!defined($hash->{helper}{r}{$rN})){
- $hash->{helper}{r}{$rN}{v} = "";
- $hash->{helper}{r}{$rN}{u} = pack('A5',"");
- }
- my ($val,$unit) = split (" ",$h2);
- $hash->{helper}{r}{$rN}{v} .= pack('A16',$val);
- $hash->{helper}{r}{$rN}{u} = pack('A5',"[".$unit."]") if ($unit);
- if ($pt ne $ptOld){
- $ptLine .= pack('A16',$pt);
- $ptOld = $pt;
- }
- if ($peer ne $peerOld){
- $peerLine .= pack('A32',$peer);
- $peerOld = $peer;
- }
- }
- $RegReply .= $peerLine."\n".$ptLine."\n";
- foreach my $rN (sort keys %{$hash->{helper}{r}}){
- $hash->{helper}{r}{$rN} =~ s/( o..)/$1 /g
- if($rN =~ m/^MultiExec /); #shift thhis reading since it does not appear for short
- $RegReply .= pack ('A18',$rN)
- .$hash->{helper}{r}{$rN}{u}
- .$hash->{helper}{r}{$rN}{v}
- ."\n";
- }
- delete $hash->{helper}{r};
- }
- my $ret = "No regs found for:".join(",",sort @noReg)."\n\n".$RegReply;
- $ret =~ s/\n/-ret-/g; # replace return with a placeholder - we cannot transfere direct
- return "$id;$ret";
- }
- sub HMinfo_bpPost($) {#bp finished ############################################
- my ($rep) = @_;
- my ($name,$id,$cl,$ret) = split(";",$rep,4);
- if ($rep =~ m/Can't open/){
- asyncOutput($defs{$cl},$ret);
- }
- else{
- if ($ret && defined $defs{$cl}){
- $ret =~s/-ret-/\n/g; # re-insert new-line
- asyncOutput($defs{$cl},$ret);
- }
- }
- delete $defs{$name}{nb}{$id};
- return;
- }
- sub HMinfo_bpAbort($) {#bp timeout ############################################
- my ($rep) = @_;
- my ($name,$id) = split(":",$rep);
- delete $defs{$name}{nb}{$id};
- return;
- }
- sub HMinfo_templateChk_Get ($){ ###############################################
- my ($param) = shift;
- my ($id,$opt,$filter,@a) = split ",",$param;
- $opt = "" if(!defined $opt);
- my $ret;
- if(@a){
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- unshift @a, $dName;
- $ret .= HMinfo_templateChk(@a);
- shift @a;
- }
- }
- else{
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- next if (!defined $defs{$dName}{helper}{tmpl});
- foreach (keys %{$defs{$dName}{helper}{tmpl}}){
- my ($p,$t)=split(">",$_);
- $ret .= HMinfo_templateChk($dName,$t,$p,split(" ",$defs{$dName}{helper}{tmpl}{$_}));
- }
- }
- }
- $ret = $ret ? $ret
- :"templateChk: passed";
- $ret =~ s/\n/-ret-/g; # replace return with a placeholder - we cannot transfere direct
- return "$id;$ret";
- }
- sub HMinfo_templateDef(@){#####################################################
- my ($name,$param,$desc,@regs) = @_;
- return "insufficient parameter, no param" if(!defined $param);
- $tmplDefChange = 1;# signal we have a change!
- if ($param eq "del"){
- delete $HMConfig::culHmTpl{$name};
- return;
- }
- return "$name already defined, delete it first" if($HMConfig::culHmTpl{$name});
- if ($param eq "fromMaster"){#set hm templateDef <tmplName> fromMaster <master> <(peer:long|0)> <descr>
- my ($master,$pl) = ($desc,@regs);
- return "master $master not defined" if(!$defs{$master});
- @regs = ();
- if ($pl eq "0"){
- foreach my $rdN (grep !/^\.?R-.*-(sh|lg)/,grep /^\.?R-/,keys %{$defs{$master}{READINGS}}){
- my $rdP = $rdN;
- $rdP =~ s/^\.?R-//;
- my ($val) = map{s/ .*//;$_;}$defs{$master}{READINGS}{$rdN}{VAL};
- push @regs,"$rdP:$val";
- }
- }
- else{
- my ($peer,$shlg) = split(":",$pl,2);
- return "peersegment not allowed. use <peer>:(both|short|long)" if($shlg != m/(short|long|both)/);
- $shlg = ($shlg eq "short"?"sh"
- :($shlg eq "long" ?"lg"
- :""));
- foreach my $rdN (grep /^\.?R-$peer-$shlg/,keys %{$defs{$master}{READINGS}}){
- my $rdP = $rdN;
- $rdP =~ s/^\.?R-$peer-$shlg//;
- my ($val) = map{s/ .*//;$_;}$defs{$master}{READINGS}{$rdN}{VAL};
- push @regs,"$rdP:$val";
- }
- }
- $param = "0";
- $desc = "from Master $name > $pl";
- }
- # get description if marked wir ""
- if ($desc =~ m/^"/ && $desc !~ m/^".*"/ ){ # parse "" - search for close and remove regs inbetween
- my $cnt = 0;
- foreach (@regs){
- $desc .= " ".$_;
- $cnt++;
- last if ($desc =~ m/"$/);
- }
- splice @regs,0,$cnt;
- }
- $desc =~ s/"//g;#reduce " to a single pair
- # $desc = "\"".$desc."\"";
- return "insufficient parameter, regs missing" if(@regs < 1);
-
- my $paramNo;
- if($param ne "0"){
- my @p = split(":",$param);
- $HMConfig::culHmTpl{$name}{p} = join(" ",@p) ;
- $paramNo = scalar (@p);
- }
- else{
- $HMConfig::culHmTpl{$name}{p} = "";
- $paramNo = 0;
- }
-
- $HMConfig::culHmTpl{$name}{t} = $desc;
-
- foreach (@regs){
- my ($r,$v)=split(":",$_,2);
- if (!defined $v){
- delete $HMConfig::culHmTpl{$name};
- return " empty reg value for $r";
- }
- elsif($v =~ m/^p(\d)/){
- if (($1+1)>$paramNo){
- delete $HMConfig::culHmTpl{$name};
- return ($1+1)." params are necessary, only $paramNo given";
- }
- }
- $HMConfig::culHmTpl{$name}{reg}{$r} = $v;
- }
- }
- sub HMinfo_templateSet(@){#####################################################
- my ($aName,$tmpl,$pSet,@p) = @_;
- return "aktor $aName unknown" if(!$defs{$aName});
- return "template undefined $tmpl" if(!$HMConfig::culHmTpl{$tmpl});
- return "exec set $aName getConfig first" if(!(grep /RegL_/,keys%{$defs{$aName}{READINGS}}));
- my $tmplID = "$pSet>$tmpl";
- $pSet = ":" if (!$pSet || $pSet eq "none");
- my ($pName,$pTyp) = split(":",$pSet);
- return "give <peer>:[short|long|both] with peer, not $pSet $pName,$pTyp" if($pName && $pTyp !~ m/(short|long|both)/);
- $pSet = $pTyp ? ($pTyp eq "long" ?"lg"
- :($pTyp eq "short"?"sh"
- :"")) # could be "both"
- :"";
- my $aHash = $defs{$aName};
- #blindActuator - confBtnTime range:1 to 255min special:permanent : 255=permanent
- #blindActuator - intKeyVisib literal:visib,invisib : visibility of internal channel
- my @regCh;
- foreach (keys%{$HMConfig::culHmTpl{$tmpl}{reg}}){
- my $regN = $pSet.$_;
- my $regV = $HMConfig::culHmTpl{$tmpl}{reg}{$_};
- if ($regV =~m /^p(.)$/) {#replace with User parameter
- return "insufficient values - at least ".$HMConfig::culHmTpl{p}." are $1 necessary" if (@p < ($1+1));
- $regV = $p[$1];
- }
- my ($ret,undef) = CUL_HM_Set($aHash,$aName,"regSet",$regN,"?",$pName);
- return "Device doesn't support $regN - template $tmpl not applicable" if ($ret =~ m/failed:/);
- return "peer necessary for template" if ($ret =~ m/peer required/ && !$pName);
- return "Device doesn't support literal $regV for reg $regN" if ($ret =~ m/literal:/ && $ret !~ m/\b$regV\b/);
-
- if ($ret =~ m/special:/ && $ret !~ m/\b$regV\b/){# if covered by "special" we are good
- my ($min,$max) = ($1,$2) if ($ret =~ m/range:(.*) to (.*) :/);
- $max = 0 if (!$max);
- $max =~ s/([0-9\.]+).*/$1/;
- return "$regV out of range: $min to $max" if ($min && ($regV < $min || ($max && $regV > $max)));
- }
- push @regCh,"$regN,$regV";
- }
- foreach (@regCh){#Finally write to shadow register.
- my ($ret,undef) = CUL_HM_Set($aHash,$aName,"regSet","prep",split(",",$_),$pName);
- return $ret if ($ret);
- }
- my ($ret,undef) = CUL_HM_Set($aHash,$aName,"regSet","exec",split(",",$regCh[0]),$pName);
- HMinfo_templateMark($aHash,$tmplID,@p);
- return $ret;
- }
- sub HMinfo_templateMark(@){####################################################
- my ($aHash,$tmplID,@p) = @_;
- $aHash->{helper}{tmpl}{$tmplID} = join(" ",@p);
- $tmplUsgChange = 1; # mark change
- $aHash->{helper}{tmplChg} = 1;
- CUL_HM_setTmplDisp($aHash);#set readings if desired
- return;
- }
- sub HMinfo_templateDel(@){#####################################################
- my ($aName,$tmpl,$pSet) = @_;
- return if (!defined $defs{$aName});
- delete $defs{$aName}{helper}{tmpl}{"$pSet>$tmpl"};
- $tmplUsgChange = 1; # mark change
- $defs{$aName}{helper}{tmplChg} = 1;
- CUL_HM_setTmplDisp($defs{$aName});#set readings if desired
- return;
- }
- sub HMinfo_templateExe(@){#####################################################
- my ($opt,$filter,$tFilter) = @_;
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- next if(!defined $defs{$dName}{helper}{tmpl});
- foreach my $tid(keys %{$defs{$dName}{helper}{tmpl}}){
- my ($p,$t) = split(">",$tid);
- next if($tFilter && $tFilter ne $t);
- HMinfo_templateSet($dName,$t,$p,split(" ",$defs{$dName}{helper}{tmpl}{$tid}));
- }
- }
- return;
- }
- sub HMinfo_templateUsg(@){#####################################################
- my ($opt,$filter,$tFilter) = @_;
- my @ul;
- foreach my $dName (HMinfo_getEntities($opt."v",$filter)){
- next if(!defined $defs{$dName}{helper}{tmpl});
- foreach my $tid(keys %{$defs{$dName}{helper}{tmpl}}){
- my ($p,$t) = split(">",$tid);
- if($tFilter && $tFilter =~ m/^sort.*/){
- if($tFilter eq "sortTemplate"){
- push @ul,sprintf("%-20s|%-15s|%s|%s",$t,$dName,$p,$defs{$dName}{helper}{tmpl}{$tid});
- }
- if($tFilter eq "sortPeer"){
- my ($pn,$ls) = split(":",$p);
- push @ul,sprintf("%-20s|%-15s|%5s:%-20s|%s",$pn,$t,$ls,$dName,$defs{$dName}{helper}{tmpl}{$tid});
- }
- # elsif($tFilter ne $t){
- # next;
- # }
- }
- else{
- my @param;
- my $para = "";
- if($defs{$dName}{helper}{tmpl}{$tid}){
- @param = split(" ",$HMConfig::culHmTpl{$t}{p});
- my @value = split(" ",$defs{$dName}{helper}{tmpl}{$tid});
- for (my $i = 0; $i<scalar(@value); $i++){
- $param[$i] .= ":".$value[$i];
- }
- $para = join(" ",@param);
- }
- push @ul,sprintf("%-20s|%-15s|%s|%s",$dName,$p,$t,$para) if(!$tFilter || $tFilter eq $t);
-
- }
- }
- }
- return join("\n",sort(@ul));
- }
- sub HMinfo_templateChk(@){#####################################################
- my ($aName,$tmpl,$pSet,@p) = @_;
- # pset: 0 = template w/o peers
- # peer / peer:both = template for peer, not extending Long/short
- # peer:short|long = template for peerlong or short
- return "template undefined $tmpl\n" if(!$HMConfig::culHmTpl{$tmpl});
- return "aktor $aName unknown\n" if(!$defs{$aName});
- return "give <peer>:[short|long|both] wrong:$pSet\n" if($pSet && $pSet !~ m/:(short|long|both)$/);
- $pSet = "0:0" if (!$pSet);
-
- my $repl = "";
- my($pName,$pTyp) = split(":",$pSet);
- if($pName && (grep !/$pName/,ReadingsVal($aName,"peerList" ,""))){
- $repl = " no peer:$pName\n";
- }
- else{
- my $pRnm = $pName ? $pName."-" : "";
- if ($pName){
- $pRnm = $pName.(($defs{$pName}{helper}{role}{dev})?"_chn-01-":"-");
- }
- my $pRnmLS = $pTyp eq "long"?"lg":($pTyp eq "short"?"sh":"");
- foreach my $rn (keys%{$HMConfig::culHmTpl{$tmpl}{reg}}){
- my $regV;
- my $pRnmChk = $pRnm.($rn !~ m/^(lg|sh)/ ? $pRnmLS :"");
- if ($pRnm){
- $regV = ReadingsVal($aName,"R-$pRnmChk$rn" ,ReadingsVal($aName,".R-$pRnmChk$rn",undef));
- }
- $regV = ReadingsVal($aName,"R-".$rn ,ReadingsVal($aName,".R-".$rn ,undef)) if (!defined $regV);
- if (defined $regV){
- $regV =~s/ .*//;#strip unit
- my $tplV = $HMConfig::culHmTpl{$tmpl}{reg}{$rn};
- if ($tplV =~m /^p(.)$/) {#replace with User parameter
- return "insufficient data - at least ".$HMConfig::culHmTpl{p}." are $1 necessary"
- if (@p < ($1+1));
- $tplV = $p[$1];
- }
- $repl .= " $rn :$regV should $tplV \n" if ($regV ne $tplV);
- }
- else{
- $repl .= " reg not found: $rn :$pRnm\n";
- }
- }
- }
- $repl = "$aName $pSet-> failed\n$repl" if($repl);
- return $repl;
- }
- sub HMinfo_templateList($){####################################################
- my $templ = shift;
- my $reply = "defined tempates:\n";
- if(!$templ || $templ eq "all"){# list all templates
- foreach (sort keys%HMConfig::culHmTpl){
- next if ($_ =~ m/^tmpl...Change$/); #ignore control
- $reply .= sprintf("%-16s params:%-24s Info:%s\n"
- ,$_
- ,$HMConfig::culHmTpl{$_}{p}
- ,$HMConfig::culHmTpl{$_}{t}
- );
- }
- }
- elsif( grep /$templ/,keys%HMConfig::culHmTpl ){#details about one template
- $reply = sprintf("%-16s params:%-24s Info:%s\n",$templ,$HMConfig::culHmTpl{$templ}{p},$HMConfig::culHmTpl{$templ}{t});
- foreach (sort keys %{$HMConfig::culHmTpl{$templ}{reg}}){
- my $val = $HMConfig::culHmTpl{$templ}{reg}{$_};
- if ($val =~m /^p(.)$/){
- my @a = split(" ",$HMConfig::culHmTpl{$templ}{p});
- $val = $a[$1];
- }
- $reply .= sprintf(" %-16s :%s\n",$_,$val);
- }
- }
- return $reply;
- }
- sub HMinfo_templateWrite($){###################################################
- my $fName = shift;
- HMinfo_templateWriteDef($fName) if ($tmplDefChange);
- HMinfo_templateWriteUsg($fName) if ($tmplUsgChange);
- return;
- }
- sub HMinfo_templateWriteDef($){################################################
- my $fName = shift;
- $tmplDefChange = 0; # reset changed bits
- my @tmpl =();
- #set templateDef <templateName> <param1[:<param2>...] <description> <reg1>:<val1> [<reg2>:<val2>] ...
- foreach my $tpl(sort keys%HMConfig::culHmTpl){
- next if ($tpl =~ m/^tmpl...Change$/ ||!defined$HMConfig::culHmTpl{$tpl}{reg});
- my @reg =();
- foreach (keys%{$HMConfig::culHmTpl{$tpl}{reg}}){
- push @reg,$_.":".$HMConfig::culHmTpl{$tpl}{reg}{$_};
- }
- push @tmpl,sprintf("templateDef =>%s=>%s=>\"%s\"=>%s"
- ,$tpl
- ,($HMConfig::culHmTpl{$tpl}{p}?join(":",split(" ",$HMConfig::culHmTpl{$tpl}{p})):"0")
- ,$HMConfig::culHmTpl{$tpl}{t}
- ,join(" ",@reg)
- );
- }
- open(aSave, ">>$fName") || return("Can't open $fName: $!");
- #important - this is the header - prior entires in the file will be ignored
- print aSave "\n\ntemplateDef templateStart Block stored:".TimeNow()."*******************\n\n";
- print aSave "\n".$_ foreach(sort @tmpl);
- print aSave "\n======= finished templates ===\n";
- close(aSave);
- return;
- }
- sub HMinfo_templateWriteUsg($){################################################
- my $fName = shift;
- $tmplUsgChange = 0; # reset changed bits
- my @tmpl =();
- foreach my $eN(sort (devspec2array("TYPE=CUL_HM"))){
- next if($defs{$eN}{helper}{role}{vrt} || !$defs{$eN}{helper}{tmplChg});
- push @tmpl,sprintf("templateSet =>%s=>start",$eN);# indicates: all entries before are obsolete
- $defs{$eN}{helper}{tmplChg} = 0;
- if (defined $defs{$eN}{helper}{tmpl}){
- foreach my $tid(keys %{$defs{$eN}{helper}{tmpl}}){
- my ($p,$t) = split(">",$tid);
- next if (!defined$HMConfig::culHmTpl{$t});
- push @tmpl,sprintf("templateSet =>%s=>%s=>%s"
- ,$eN
- ,$tid
- ,$defs{$eN}{helper}{tmpl}{$tid}
- );
- }
- }
- }
- if (@tmpl){
- open(aSave, ">>$fName") || return("Can't open $fName: $!");
- #important - this is the header - prior entires in the file will be ignored
- print aSave "\n".$_ foreach(@tmpl);
- print aSave "\n======= finished templates ===\n";
- close(aSave);
- }
- return;
- }
- sub HMinfo_cpRegs(@){##########################################################
- my ($srcCh,$dstCh) = @_;
- my ($srcP,$dstP,$srcPid,$dstPid,$srcRegLn,$dstRegLn);
- ($srcCh,$srcP) = split(":",$srcCh,2);
- ($dstCh,$dstP) = split(":",$dstCh,2);
- return "source channel $srcCh undefined" if (!$defs{$srcCh});
- return "destination channel $srcCh undefined" if (!$defs{$dstCh});
- #compare source and destination attributes
- # return "model not compatible" if (CUL_HM_Get($ehash,$eName,"param","model") ne
- # CUL_HM_Get($ehash,$eName,"param","model"));
- if ($srcP){# will be peer related copy
- if ($srcP =~ m/self(.*)/) {$srcPid = substr($defs{$srcCh}{DEF},0,6).sprintf("%02X",$1)}
- elsif($srcP =~ m/^[A-F0-9]{8}$/i){$srcPid = $srcP;}
- elsif($srcP =~ m/(.*)_chn-(..)/) {$srcPid = $defs{$1}->{DEF}.$2;}
- elsif($defs{$srcP}) {$srcPid = $defs{$srcP}{DEF}.$2;}
- if ($dstP =~ m/self(.*)/) {$dstPid = substr($defs{$dstCh}{DEF},0,6).sprintf("%02X",$1)}
- elsif($dstP =~ m/^[A-F0-9]{8}$/i){$dstPid = $dstP;}
- elsif($dstP =~ m/(.*)_chn-(..)/) {$dstPid = $defs{$1}->{DEF}.$2;}
- elsif($defs{$dstP}) {$dstPid = $defs{$dstP}{DEF}.$2;}
- return "invalid peers src:$srcP dst:$dstP" if(!$srcPid || !$dstPid);
- return "source peer not in peerlist" if ($attr{$srcCh}{peerIDs} !~ m/$srcPid/);
- return "destination peer not in peerlist" if ($attr{$dstCh}{peerIDs} !~ m/$dstPid/);
- if ($defs{$srcCh}{READINGS}{"RegL_03.".$srcP}) {$srcRegLn = "RegL_03.".$srcP}
- elsif($defs{$srcCh}{READINGS}{".RegL_03.".$srcP}) {$srcRegLn = ".RegL_03.".$srcP}
- elsif($defs{$srcCh}{READINGS}{"RegL_04.".$srcP}) {$srcRegLn = "RegL_04.".$srcP}
- elsif($defs{$srcCh}{READINGS}{".RegL_04.".$srcP}) {$srcRegLn = ".RegL_04.".$srcP}
- $dstRegLn = $srcRegLn;
- $dstRegLn =~ s/:.*/:/;
- $dstRegLn .= $dstP;
- }
- else{
- if ($defs{$srcCh}{READINGS}{"RegL_01."}) {$srcRegLn = "RegL_01."}
- elsif($defs{$srcCh}{READINGS}{".RegL_01."}) {$srcRegLn = ".RegL_01."}
- $dstRegLn = $srcRegLn;
- }
- return "source register not available" if (!$srcRegLn);
- return "regList incomplete" if ($defs{$srcCh}{READINGS}{$srcRegLn}{VAL} !~ m/00:00/);
- # we habe a reglist with termination, source and destination peer is checked. Go copy
- my $srcData = $defs{$srcCh}{READINGS}{$srcRegLn}{VAL};
- $srcData =~ s/00:00//; # remove termination
- my ($ret,undef) = CUL_HM_Set($defs{$dstCh},$dstCh,"regBulk",$srcRegLn,split(" ",$srcData));
- return $ret;
- }
- sub HMinfo_noDup(@) {#return list with no duplicates###########################
- my %all;
- return "" if (scalar(@_) == 0);
- $all{$_}=0 foreach (grep {defined($_)} @_);
- delete $all{""}; #remove empties if present
- return (sort keys %all);
- }
- 1;
- =pod
- =item command
- =item summary support and control instance for wireless homematic devices and IOs
- =item summary_DE Unterstützung und Ueberwachung von Homematic funk devices und IOs
- =begin html
- <a name="HMinfo"></a>
- <h3>HMinfo</h3>
- <ul>
- HMinfo is a module to support getting an overview of
- eQ-3 HomeMatic devices as defines in <a href="#CUL_HM">CUL_HM</a>. <br><br>
- <B>Status information and counter</B><br>
- HMinfo gives an overview on the CUL_HM installed base including current conditions.
- Readings and counter will not be updated automatically due to performance issues. <br>
- Command <a href="#HMinfoupdate">update</a> must be used to refresh the values.
- <ul><code><br>
- set hm update<br>
- </code></ul><br>
- Webview of HMinfo providee details, basically counter about how
- many CUL_HM entities experience exceptional conditions. It contains
- <ul>
- <li>Action Detector status</li>
- <li>CUL_HM related IO devices and condition</li>
- <li>Device protocol events which are related to communication errors</li>
- <li>count of certain readings (e.g. batterie) and conditions - <a href="#HMinfoattr">attribut controlled</a></li>
- <li>count of error condition in readings (e.g. overheat, motorErr) - <a href="#HMinfoattr">attribut controlled</a></li>
- </ul>
- <br>
- It also allows some HM wide commands such
- as store all collected register settings.<br><br>
- Commands are executed on all HM entities.
- If applicable and evident execution is restricted to related entities.
- e.g. rssi is executed on devices only since channels do not support rssi values.<br><br>
- <a name="HMinfoFilter"><b>Filter</b></a>
- <ul> can be applied as following:<br><br>
- <code>set <name> <cmd> <filter> [<param>]</code><br>
- whereby filter has two segments, typefilter and name filter<br>
- [-dcasev] [-f <filter>]<br><br>
- filter for <b>types</b> <br>
- <ul>
- <li>d - device :include devices</li>
- <li>c - channels :include channels</li>
- <li>v - virtual :supress fhem virtual</li>
- <li>p - physical :supress physical</li>
- <li>a - aktor :supress actor</li>
- <li>s - sensor :supress sensor</li>
- <li>e - empty :include results even if requested fields are empty</li>
- <li>2 - alias :display second name alias</li>
- </ul>
- and/or filter for <b>names</b>:<br>
- <ul>
- <li>-f <filter> :regexp to filter entity names </li>
- </ul>
- Example:<br>
- <ul><code>
- set hm param -d -f dim state # display param 'state' for all devices whos name contains dim<br>
- set hm param -c -f ^dimUG$ peerList # display param 'peerList' for all channels whos name is dimUG<br>
- set hm param -dcv expert # get attribut expert for all channels,devices or virtuals<br>
- </code></ul>
- </ul>
- <br>
- <a name="HMinfodefine"><b>Define</b></a>
- <ul>
- <code>define <name> HMinfo</code><br>
- Just one entity needs to be defined without any parameter.<br>
- </ul>
- <br>
- <a name="HMinfoget"><b>Get</b></a>
- <ul>
- <li><a name="#HMinfomodels">models</a><br>
- list all HM models that are supported in FHEM
- </li>
- <li><a name="#HMinfoparam">param</a> <a href="#HMinfoFilter">[filter]</a> <name> <name>...<br>
- returns a table of parameter values (attribute, readings,...)
- for all entities as a table
- </li>
- <li><a name="#HMinforegister">register</a> <a href="#HMinfoFilter">[filter]</a><br>
- provides a tableview of register of an entity
- </li>
- <li><a name="#HMinforegCheck">regCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- performs a consistency check on register readings for completeness
- </li>
- <li><a name="#HMinfopeerCheck">peerCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- performs a consistency check on peers. If a peer is set in a channel
- it will check wether the peer also exist on the opposit side.
- </li>
- <li><a name="#HMinfopeerXref">peerXref</a> <a href="#HMinfoFilter">[filter]</a><br>
- provides a cross-reference on peerings, a kind of who-with-who summary over HM
- </li>
- <li><a name="#HMinfoconfigCheck">configCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- performs a consistency check of HM settings. It includes regCheck and peerCheck
- </li>
- <li><a name="#HMinfotemplateList">templateList [<name>]</a><br>
- list defined templates. If no name is given all templates will be listed<br>
- </li>
- <li><a name="#HMinfotemplateUsg">templateUsg</a> <template> [sortPeer|sortTemplate]<br>
- templare usage<br>
- template filters the output
- </li>
- <li><a name="#HMinfomsgStat">msgStat</a> <a href="#HMinfoFilter">[filter]</a><br>
- statistic about message transferes over a week<br>
- </li>
- <li><a name="#HMinfoprotoEvents">protoEvents </a><a href="#HMinfoFilter">[filter]</a> <br>
- <B>important view</B> about pending commands and failed executions for all devices in a single table.<br>
- Consider to clear this statistic use <a name="#HMinfoclear">clear msgEvents</a>.<br>
- </li>
- <li><a name="#HMinforssi">rssi </a><a href="#HMinfoFilter">[filter]</a><br>
- statistic over rssi data for HM entities.<br>
- </li>
- <li><a name="#HMinfotemplateChk">templateChk</a> <a href="#HMinfoFilter">[filter]</a> <template> <peer:[long|short]> [<param1> ...]<br>
- verifies if the register-readings comply to the template <br>
- Parameter are identical to <a href="#HMinfotemplateSet">templateSet</a><br>
- The procedure will check if the register values match the ones provided by the template<br>
- If no peer is necessary use <b>none</b> to skip this entry<br>
- Example to verify settings<br>
- <ul><code>
- set hm templateChk -f RolloNord BlStopUpLg none 1 2 # RolloNord, no peer, parameter 1 and 2 given<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName:long # RolloNord peerName, long only<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName # RolloNord peerName, long and short<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName:all # RolloNord peerName, long and short<br>
- set hm templateChk -f RolloNord BlStopUpLg all:long # RolloNord any peer, long only<br>
- set hm templateChk -f RolloNord BlStopUpLg all # RolloNord any peer,long and short<br>
- set hm templateChk -f Rollo.* BlStopUpLg all # each Rollo* any peer,long and short<br>
- set hm templateChk BlStopUpLg # each entities<br>
- set hm templateChk # all assigned templates<br>
- set hm templateChk sortTemplate # all assigned templates sortiert nach Template<br>
- set hm templateChk sortPeer # all assigned templates sortiert nach Peer<br>
- </code></ul>
- </li>
- </ul>
- <a name="HMinfoset"><b>Set</b></a>
- <ul>
- Even though the commands are a get funktion they are implemented
- as set to allow simple web interface usage<br>
- <li><a name="#HMinfoupdate">update</a><br>
- updates HM status counter.
- </li>
- <li><a name="#HMinfoautoReadReg">autoReadReg</a> <a href="#HMinfoFilter">[filter]</a><br>
- schedules a read of the configuration for the CUL_HM devices with attribut autoReadReg set to 1 or higher.
- </li>
- <li><a name="#HMinfoclear">clear</a> <a href="#HMinfoFilter">[filter]</a> [msgEvents|readings|msgStat|register|rssi]<br>
- executes a set clear ... on all HM entities<br>
- <ul>
- <li>protocol relates to set clear msgEvents</li>
- <li>readings relates to set clear readings</li>
- <li>rssi clears all rssi counters </li>
- <li>msgStat clear HM general message statistics</li>
- <li>register clears all register-entries in readings</li>
- </ul>
- </li>
- <li><a name="#HMinfosaveConfig">saveConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- performs a save for all HM register setting and peers. See <a href="#CUL_HMsaveConfig">CUL_HM saveConfig</a>.<br>
- <a ref="#HMinfopurgeConfig">purgeConfig</a> will be executed automatically if the stored filesize exceeds 1MByte.<br>
- </li>
- <li><a name="#HMinfoarchConfig">archConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- performs <a href="#HMinfosaveConfig">saveConfig</a> for entities that appeare to have achanged configuration.
- It is more conservative that saveConfig since incomplete sets are not stored.<br>
- Option -a force an archieve for all devices that have a complete set of data<br>
- </li>
- <li><a name="#HMinfoloadConfig">loadConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- loads register and peers from a file saved by <a href="#HMinfosaveConfig">saveConfig</a>.<br>
- It should be used carefully since it will add data to FHEM which cannot be verified. No readings will be replaced, only
- missing readings will be added. The command is mainly meant to be fill in readings and register that are
- hard to get. Those from devices which only react to config may not easily be read. <br>
- Therefore it is strictly up to the user to fill valid data. User should consider using autoReadReg for devices
- that can be read.<br>
- The command will update FHEM readings and attributes. It will <B>not</B> reprogramm any device.
- </li>
- <li><a name="#HMinfopurgeConfig">purgeConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- purge (reduce) the saved config file. Due to the cumulative storage of the register setting
- purge will use the latest stored readings and remove older one.
- See <a href="#CUL_HMsaveConfig">CUL_HM saveConfig</a>.
- </li>
- <li><a name="#HMinfoverifyConfig">verifyConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- Compare date in config file to the currentactive data and report differences.
- Possibly usable with a known-good configuration that was saved before.
- It may make sense to purge the config file before.
- See <a href="#CUL_HMpurgeConfig">CUL_HM purgeConfig</a>.
- </li>
-
- <br>
- <li><a name="#HMinfotempList">tempList</a> <a href="#HMinfoFilter">[filter] [save|restore|verify|status|genPlot] [<file>]</a><br>
- this function supports handling of tempList for thermstates.
- It allows templists to be saved in a separate file, verify settings against the file
- and write the templist of the file to the devices. <br>
- <ul>
- <li><B>save</B> saves tempList readings of the system to the file. <br>
- Note that templist as available in FHEM is put to the file. It is up to the user to make
- sure the data is actual<br>
- Storage is not cumulative - former content of the file will be removed</li>
- <li><B>restore</B> available templist as defined in the file are written directly
- to the device</li>
- <li><B>verify</B> file data is compared to readings as present in FHEM. It does not
- verify data in the device - user needs to ensure actuallity of present readings</li>
- <li><B>status</B> gives an overview of templates being used by any CUL_HM thermostat. It alls showes
- templates being defined in the relevant files.
- <br></li>
- <li><B>genPlot</B> generates a set of records to display templates graphicaly.<br>
- Out of the given template-file it generates a .log extended file which contains log-formated template data. timestamps are
- set to begin Year 2000.<br>
- A prepared .gplot file will be added to gplot directory.<br>
- Logfile-entity <file>_Log will be added if not already present. It is necessary for plotting.<br>
- SVG-entity <file>_SVG will be generated if not already present. It will display the graph.<br>
- <br></li>
- <li><B>file</B> name of the file to be used. Default: <B>tempList.cfg</B></li>
- <br>
- <li><B>filename</B> is the name of the file to be used. Default ist <B>tempList.cfg</B></li>
- File example<br>
- <ul><code>
- entities:HK1_Climate,HK2_Clima<br>
- tempListFri>07:00 14.0 13:00 16.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListMon>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListSat>08:00 14.0 15:00 18.0 21:30 19.0 24:00 14.0<br>
- tempListSun>08:00 14.0 15:00 18.0 21:30 19.0 24:00 14.0<br>
- tempListThu>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListTue>07:00 14.0 13:00 16.0 16:00 18.0 21:00 19.0 24:00 15.0<br>
- tempListWed>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- entities:hk3_Climate<br>
- tempListFri>06:00 17.0 12:00 21.0 23:00 20.0 24:00 19.5<br>
- tempListMon>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListSat>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListSun>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListThu>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListTue>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListWed>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- </code></ul>
- File keywords<br>
- <li><B>entities</B> comma separated list of entities which refers to the temp lists following.
- The actual entity holding the templist must be given - which is channel 04 for RTs or channel 02 for TCs</li>
- <li><B>tempList...</B> time and temp couples as used in the set tempList commands</li>
- </ul>
- <br>
- </li>
- <br>
- <li><a name="#HMinfocpRegs">cpRegs <src:peer> <dst:peer> </a><br>
- allows to copy register, setting and behavior of a channel to
- another or for peers from the same or different channels. Copy therefore is allowed
- intra/inter device and intra/inter channel. <br>
- <b>src:peer</b> is the source entity. Peer needs to be given if a peer behabior beeds to be copied <br>
- <b>dst:peer</b> is the destination entity.<br>
- Example<br>
- <ul><code>
- set hm cpRegs blindR blindL # will copy all general register (list 1)for this channel from the blindR to the blindL entity.
- This includes items like drive times. It does not include peers related register (list 3/4) <br>
- set hm cpRegs blindR:Btn1 blindL:Btn2 # copy behavior of Btn1/blindR relation to Btn2/blindL<br>
- set hm cpRegs blindR:Btn1 blindR:Btn2 # copy behavior of Btn1/blindR relation to Btn2/blindR, i.e. inside the same Actor<br>
- </code></ul>
- <br>
- Restrictions:<br>
- <ul>
- cpRegs will <u>not add any peers</u> or read from the devices. It is up to the user to read register in advance<br>
- cpRegs is only allowed between <u>identical models</u><br>
- cpRegs expets that all <u>readings are up-to-date</u>. It is up to the user to ensure data consistency.<br>
- </ul>
- </li>
- <li><a name="#HMinfotemplateDef">templateDef <name> <param> <desc> <reg1:val1> [<reg2:val2>] ...</a><br>
- define a template.<br>
- <b>param</b> gives the names of parameter necesary to execute the template. It is template dependant
- and may be onTime or brightnesslevel. A list of parameter needs to be separated with colon<br>
- param1:param2:param3<br>
- if del is given as parameter the template is removed<br>
- <b>desc</b> shall give a description of the template<br>
- <b>reg:val</b> is the registername to be written and the value it needs to be set to.<br>
- In case the register is from link set and can destinguist between long and short it is necessary to leave the
- leading sh or lg off. <br>
- if parameter are used it is necessary to enter p. as value with p0 first, p1 second parameter
- <br>
- Example<br>
- <ul><code>
- set hm templateDef SwOnCond level:cond "my description" CtValLo:p0 CtDlyOn:p1 CtOn:geLo<br>
- set hm templateDef SwOnCond del # delete a template<br>
- set hm templateDef SwOnCond fromMaster <masterChannel> <peer:[long|short]># define a template with register as of the example<br>
- set hm templateDef SwOnCond fromMaster myChannel peerChannel:long # <br>
- </code></ul>
- </li>
- <li><a name="#HMinfotemplateSet">templateSet</a> <entity> <template> <peer:[long|short]> [<param1> ...]<br>
- sets a bunch of register accroding to a given template. Parameter may be added depending on
- the template setup. <br>
- templateSet will collect and accumulate all changes. Finally the results are written streamlined.<br>
- <b>entity:</b> peer is the source entity. Peer needs to be given if a peer behabior beeds to be copied <br>
- <b>template:</b> one of the programmed template<br>
- <b>peer:</b> [long|short]:if necessary a peer needs to be given. If no peer is used enter '0'.
- with a peer it should be given whether it is for long or short keypress<br>
- <b>param:</b> number and meaning of parameter depends on the given template<br>
- Example could be (templates not provided, just theoretical)<br>
- <ul><code>
- set hm templateSet Licht1 staircase FB1:short 20 <br>
- set hm templateSet Licht1 staircase FB1:long 100 <br>
- </code></ul>
- Restrictions:<br>
- <ul>
- User must ensure to read configuration prior to execution.<br>
- templateSet may not setup a complete register block but only a part if it. This is up to template design.<br>
- <br>
- </ul>
- </li>
- <li><a name="#HMinfotemplateDel">templateDel</a> <entity> <template> <peer:[long|short]> ]<br>
- remove a template installed by templateSet
- <br>
- </li>
- <li><a name="#HMinfotemplateExe">templateExe</a> <template> <br>
- executes the register write once again if necessary (e.g. a device had a reset)<br>
- </li>
- </ul>
- <br>
- <br><br>
- <a name="HMinfoattr"><b>Attributes</b></a>
- <ul>
- <li><a name="#HMinfosumStatus">sumStatus</a><br>
- Warnings: list of readings that shall be screend and counted based on current presence.
- I.e. counter is the number of entities with this reading and the same value.
- Readings to be searched are separated by comma. <br>
- Example:<br>
- <ul><code>
- attr hm sumStatus battery,sabotageError<br>
- </code></ul>
- will cause a reading like<br>
- W_sum_batterie ok:5 low:3<br>
- W_sum_sabotageError on:1<br>
- <br>
- Note: counter with '0' value will not be reported. HMinfo will find all present values autonomously<br>
- Setting is meant to give user a fast overview of parameter that are expected to be system critical<br>
- </li>
- <li><a name="#HMinfosumERROR">sumERROR</a>
- Similar to sumStatus but with a focus on error conditions in the system.
- Here user can add reading<b>values</b> that are <b>not displayed</b>. I.e. the value is the
- good-condition that will not be counted.<br>
- This way user must not know all error values but it is sufficient to supress known non-ciritical ones.
- <br>
- Example:<br>
- <ul><code>
- attr hm sumERROR battery:ok,sabotageError:off,overheat:off,Activity:alive:unknown<br>
- </code></ul>
- will cause a reading like<br>
- <ul><code>
- ERR_batterie low:3<br>
- ERR_sabotageError on:1<br>
- ERR_overheat on:3<br>
- ERR_Activity dead:5<br>
- </code></ul>
- </li>
- <li><a name="#HMinfoautoUpdate">autoUpdate</a>
- retriggers the command update periodically.<br>
- Example:<br>
- <ul><code>
- attr hm autoUpdate 00:10<br>
- </code></ul>
- will trigger the update every 10 min<br>
- </li>
- <li><a name="#HMinfoautoArchive">autoArchive</a>
- if set fhem will update the configFile each time the new data is available.
- The update will happen with <a ref="#HMinfoautoUpdate">autoUpdate</a>. It will not
- work it autoUpdate is not used.<br>
- see also <a ref="#HMinfoarchConfig">archConfig</a>
- <br>
- </li>
- <li><a name="#HMinfohmAutoReadScan">hmAutoReadScan</a>
- defines the time in seconds CUL_HM tries to schedule the next autoRead
- from the queue. Despite this timer FHEM will take care that only one device from the queue will be
- handled at one point in time. With this timer user can stretch timing even further - to up to 300sec
- min delay between execution. <br>
- Setting to 1 still obeys the "only one at a time" prinzip.<br>
- Note that compressing will increase message load while stretch will extent waiting time.<br>
- </li>
- <li><a name="#HMinfohmIoMaxDly">hmIoMaxDly</a>
- max time in seconds CUL_HM stacks messages if the IO device is not ready to send.
- If the IO device will not reappear in time all command will be deleted and IOErr will be reported.<br>
- Note: commands will be executed after the IO device reappears - which could lead to unexpected
- activity long after command issue.<br>
- default is 60sec. max value is 3600sec<br>
- </li>
- <li><a name="#HMinfoconfigDir">configDir</a>
- default directory where to store and load configuration files from.
- This path is used as long as the path is not given in a filename of
- a given command.<br>
- It is used by commands like <a ref="#HMinfotempList">tempList</a> or <a ref="#HMinfosaveConfig">saveConfig</a><br>
- </li>
- <li><a name="#HMinfoconfigFilename">configFilename</a>
- default filename used by
- <a ref="#HMinfosaveConfig">saveConfig</a>,
- <a ref="#HMinfopurgeConfig">purgeConfig</a>,
- <a ref="#HMinfoloadConfig">loadConfig</a><br>
- <a ref="#HMinfoverifyConfig">verifyConfig</a><br>
- </li>
- <li><a name="#HMinfoconfigTempFile">configTempFile<,configTempFile2><,configTempFile2> </a>
- Liste of Templfiles (weekplan) which are considered in HMInfo and CUL_HM<br>
- Files are comma separated. The first file is default. Its name may be skipped when setting a tempalte.<br>
- </li>
- <li><a name="#HMinfohmManualOper">hmManualOper</a>
- set to 1 will prevent any automatic operation, update or default settings
- in CUL_HM.<br>
- </li>
- <li><a name="#HMinfohmDefaults">hmDefaults</a>
- set default params for HM devices. Multiple attributes are possible, comma separated.<br>
- example:<br>
- attr hm hmDefaults hmProtocolEvents:0_off,rssiLog:0<br>
- </li>
- <li><a name="#HMinfoautoLoadArchive">autoLoadArchive</a>
- if set the register config will be loaded after reboot automatically. See <a ref="#HMinfoloadConfig">loadConfig</a> for details<br>
- </li>
-
- </ul>
- <br>
- <a name="HMinfovariables"><b>Variables</b></a>
- <ul>
- <li><b>I_autoReadPend:</b> Info:list of entities which are queued to retrieve config and status.
- This is typically scheduled thru autoReadReg</li>
- <li><b>ERR___rssiCrit:</b> Error:list of devices with RSSI reading n min level </li>
- <li><b>W_unConfRegs:</b> Warning:list of entities with unconfirmed register changes. Execute getConfig to clear this.</li>
- <li><b>I_rssiMinLevel:</b> Info:counts of rssi min readings per device, clustered in blocks</li>
-
- <li><b>ERR__protocol:</b> Error:count of non-recoverable protocol events per device.
- Those events are NACK, IOerr, ResendFail, CmdDel, CmdPend.<br>
- Counted are the number of device with those events, not the number of events!</li>
- <li><b>ERR__protoNames:</b> Error:name-list of devices with non-recoverable protocol events</li>
- <li><b>I_HM_IOdevices:</b> Info:list of IO devices used by CUL_HM entities</li>
- <li><b>I_actTotal:</b> Info:action detector state, count of devices with ceratin states</li>
- <li><b>ERRactNames:</b> Error:names of devices that are not alive according to ActionDetector</li>
- <li><b>C_sumDefined:</b> Count:defined entities in CUL_HM. Entites might be count as
- device AND channel if channel funtion is covered by the device itself. Similar to virtual</li>
- <li><b>ERR_<reading>:</b> Error:count of readings as defined in attribut
- <a href="#HMinfosumERROR">sumERROR</a>
- that do not match the good-content. </li>
- <li><b>ERR_names:</b> Error:name-list of entities that are counted in any ERR_<reading>
- W_sum_<reading>: count of readings as defined in attribut
- <a href="#HMinfosumStatus">sumStatus</a>. </li>
- Example:<br>
- <ul><code>
- ERR___rssiCrit LightKittchen,WindowDoor,Remote12<br>
- ERR__protocol NACK:2 ResendFail:5 CmdDel:2 CmdPend:1<br>
- ERR__protoNames LightKittchen,WindowDoor,Remote12,Ligth1,Light5<br>
- ERR_battery: low:2;<br>
- ERR_names: remote1,buttonClara,<br>
- I_rssiMinLevel 99>:3 80<:0 60<:7 59<:4<br>
- W_sum_battery: ok:5;low:2;<br>
- W_sum_overheat: off:7;<br>
- C_sumDefined: entities:23 device:11 channel:16 virtual:5;<br>
- </code></ul>
- </ul>
- </ul>
- =end html
- =begin html_DE
- <a name="HMinfo"></a>
- <h3>HMinfo</h3>
- <ul>
- Das Modul HMinfo ermöglicht einen Überblick über eQ-3 HomeMatic Geräte, die mittels <a href="#CUL_HM">CUL_HM</a> definiert sind.<br><br>
- <B>Status Informationen und Zähler</B><br>
- HMinfo gibt einen Überlick über CUL_HM Installationen einschliesslich aktueller Zustände.
- Readings und Zähler werden aus Performance Gründen nicht automatisch aktualisiert. <br>
- Mit dem Kommando <a href="#HMinfoupdate">update</a> können die Werte aktualisiert werden.
- <ul><code><br>
- set hm update<br>
- </code></ul><br>
- Die Webansicht von HMinfo stellt Details über CUL_HM Instanzen mit ungewöhnlichen Zuständen zur Verfügung. Dazu gehören:
- <ul>
- <li>Action Detector Status</li>
- <li>CUL_HM Geräte und Zustände</li>
- <li>Ereignisse im Zusammenhang mit Kommunikationsproblemen</li>
- <li>Zähler für bestimmte Readings und Zustände (z.B. battery) - <a href="#HMinfoattr">attribut controlled</a></li>
- <li>Zähler für Readings, die auf Fehler hindeuten (z.B. overheat, motorErr) - <a href="#HMinfoattr">attribut controlled</a></li>
- </ul>
- <br>
- Weiterhin stehen HM Kommandos zur Verfügung, z.B. für das Speichern aller gesammelten Registerwerte.<br><br>
- Ein Kommando wird für alle HM Instanzen der kompletten Installation ausgeführt.
- Die Ausführung ist jedoch auf die dazugehörigen Instanzen beschränkt.
- So wird rssi nur auf Geräte angewendet, da Kanäle RSSI Werte nicht unterstützen.<br><br>
- <a name="HMinfoFilter"><b>Filter</b></a>
- <ul> werden wie folgt angewendet:<br><br>
- <code>set <name> <cmd> <filter> [<param>]</code><br>
- wobei sich filter aus Typ und Name zusammensetzt<br>
- [-dcasev] [-f <filter>]<br><br>
- <b>Typ</b> <br>
- <ul>
- <li>d - device :verwende Gerät</li>
- <li>c - channels :verwende Kanal</li>
- <li>v - virtual :unterdrücke virtuelle Instanz</li>
- <li>p - physical :unterdrücke physikalische Instanz</li>
- <li>a - aktor :unterdrücke Aktor</li>
- <li>s - sensor :unterdrücke Sensor</li>
- <li>e - empty :verwendet das Resultat auch wenn die Felder leer sind</li>
- <li>2 - alias :2ter name alias anzeigen</li>
- </ul>
- und/oder <b>Name</b>:<br>
- <ul>
- <li>-f <filter> :Regulärer Ausdruck (regexp), um die Instanznamen zu filtern</li>
- </ul>
- Beispiel:<br>
- <ul><code>
- set hm param -d -f dim state # Zeige den Parameter 'state' von allen Geräten, die "dim" im Namen enthalten<br>
- set hm param -c -f ^dimUG$ peerList # Zeige den Parameter 'peerList' für alle Kanäle mit dem Namen "dimUG"<br>
- set hm param -dcv expert # Ermittle das Attribut expert für alle Geräte, Kanäle und virtuelle Instanzen<br>
- </code></ul>
- </ul>
- <br>
- <a name="HMinfodefine"><b>Define</b></a>
- <ul>
- <code>define <name> HMinfo</code><br>
- Es muss nur eine Instanz ohne jegliche Parameter definiert werden.<br>
- </ul>
- <br>
- <a name="HMinfoget"><b>Get</b></a>
- <ul>
- <li><a name="#HMinfomodels">models</a><br>
- zeige alle HM Modelle an, die von FHEM unterstützt werden
- </li>
- <li><a name="#HMinfoparam">param</a> <a href="#HMinfoFilter">[filter]</a> <name> <name>...<br>
- zeigt Parameterwerte (Attribute, Readings, ...) für alle Instanzen in Tabellenform an
- </li>
- <li><a name="#HMinforegister">register</a> <a href="#HMinfoFilter">[filter]</a><br>
- zeigt eine Tabelle mit Registern einer Instanz an
- </li>
- <li><a name="#HMinforegCheck">regCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- validiert Registerwerte
- </li>
- <li><a name="#HMinfopeerCheck">peerCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- validiert die Einstellungen der Paarungen (Peers). Hat ein Kanal einen Peer gesetzt, muss dieser auch auf
- der Gegenseite gesetzt sein.
- </li>
- <li><a name="#HMinfopeerXref">peerXref</a> <a href="#HMinfoFilter">[filter]</a><br>
- erzeugt eine komplette Querverweisliste aller Paarungen (Peerings)
- </li>
- <li><a name="#HMinfoconfigCheck">configCheck</a> <a href="#HMinfoFilter">[filter]</a><br>
- Plausibilitätstest aller HM Einstellungen inklusive regCheck und peerCheck
- </li>
- <li><a name="#HMinfotemplateList">templateList [<name>]</a><br>
- zeigt eine Liste von Vorlagen. Ist kein Name angegeben, werden alle Vorlagen angezeigt<br>
- </li>
- <li><a name="#HMinfotemplateUsg">templateUsg</a> <template> [sortPeer|sortTemplate]<br>
- Liste der genutzten templates.<br>
- template filtert die Einträge nach diesem template
- </li>
- <li><a name="#HMinfomsgStat">msgStat</a> <a href="#HMinfoFilter">[filter]</a><br>
- zeigt eine Statistik aller Meldungen der letzen Woche<br>
- </li>
- <li><a name="#HMinfoprotoEvents">protoEvents</a> <a href="#HMinfoFilter">[filter]</a> <br>
- vermutlich die <B>wichtigste Auflistung</B> für Meldungsprobleme.
- Informationen über ausstehende Kommandos und fehlgeschlagene Sendevorgänge
- für alle Geräte in Tabellenform.<br>
- Mit <a name="#HMinfoclear">clear msgEvents</a> kann die Statistik gelöscht werden.<br>
- </li>
- <li><a name="#HMinforssi">rssi </a><a href="#HMinfoFilter">[filter]</a><br>
- Statistik über die RSSI Werte aller HM Instanzen.<br>
- </li>
- <li><a name="#HMinfotemplateChk">templateChk</a> <a href="#HMinfoFilter">[filter]</a> <template> <peer:[long|short]> [<param1> ...]<br>
- Verifiziert, ob die Registerwerte mit der Vorlage in Einklang stehen.<br>
- Die Parameter sind identisch mit denen aus <a href="#HMinfotemplateSet">templateSet</a>.<br>
- Wenn kein Peer benötigt wird, stattdessen none verwenden.
- Beispiele für die Überprüfung von Einstellungen<br>
- <ul><code>
- set hm templateChk -f RolloNord BlStopUpLg none 1 2 # RolloNord, no peer, parameter 1 and 2 given<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName:long # RolloNord peerName, long only<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName # RolloNord peerName, long and short<br>
- set hm templateChk -f RolloNord BlStopUpLg peerName:all # RolloNord peerName, long and short<br>
- set hm templateChk -f RolloNord BlStopUpLg all:long # RolloNord any peer, long only<br>
- set hm templateChk -f RolloNord BlStopUpLg all # RolloNord any peer,long and short<br>
- set hm templateChk -f Rollo.* BlStopUpLg all # each Rollo* any peer,long and short<br>
- set hm templateChk BlStopUpLg # each entities<br>
- set hm templateChk # all assigned templates<br>
- set hm templateChk sortTemplate # all assigned templates, sort by template<br>
- set hm templateChk sortPeer # all assigned templates, sort by peer<br>
- </code></ul>
- </li>
- </ul>
- <a name="HMinfoset"><b>Set</b></a>
- <ul>
- Obwohl die Kommandos Einstellungen abrufen (get function), werden sie mittels set ausgeführt, um die
- Benutzung mittels Web Interface zu erleichtern.<br>
- <ul>
- <li><a name="#HMinfoupdate">update</a><br>
- Aktualisiert HM Status Zähler.
- </li>
- <li><a name="#HMinfoautoReadReg">autoReadReg</a> <a href="#HMinfoFilter">[filter]</a><br>
- Aktiviert das automatische Lesen der Konfiguration für ein CUL_HM Gerät, wenn das Attribut autoReadReg auf 1 oder höher steht.
- </li>
- <li><a name="#HMinfoclear">clear</a> <a href="#HMinfoFilter">[filter]</a> [msgEvents|readings|msgStat|register|rssi]<br>
- Führt ein set clear ... für alle HM Instanzen aus<br>
- <ul>
- <li>Protocol bezieht sich auf set clear msgEvents</li>
- <li>readings bezieht sich auf set clear readings</li>
- <li>rssi löscht alle rssi Zähler</li>
- <li>msgStat löscht die HM Meldungsstatistik</li>
- <li>register löscht alle Einträge in den Readings</li>
- </ul>
- </li>
- <li><a name="#HMinfosaveConfig">saveConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- Sichert alle HM Registerwerte und Peers. Siehe <a href="#CUL_HMsaveConfig">CUL_HM saveConfig</a>.<br>
- <a ref="#HMinfopurgeConfig">purgeConfig</a> wird automatisch ausgeführt, wenn die Datenmenge 1 MByte übersteigt.<br>
- </li>
- <li><a name="#HMinfoarchConfig">archConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- Führt <a href="#HMinfosaveConfig">saveConfig</a> für alle Instanzen aus, sobald sich deren Konfiguration ändert.
- Es schont gegenüber saveConfig die Resourcen, da es nur vollständige Konfigurationen sichert.<br>
- Die Option -a erzwingt das sofortige Archivieren für alle Geräte, die eine vollständige Konfiguration aufweisen.<br>
- </li>
- <li><a name="#HMinfoloadConfig">loadConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- Lädt Register und Peers aus einer zuvor mit <a href="#HMinfosaveConfig">saveConfig</a> gesicherten Datei.<br>
- Es sollte mit Vorsicht verwendet werden, da es Daten zu FHEM hinzufügt, die nicht verifiziert sind.
- Readings werden nicht ersetzt, nur fehlende Readings werden hinzugefügt. Der Befehl ist dazu geignet, um Readings
- zu erstellen, die schwer zu erhalten sind. Readings von Geräten, die nicht dauerhaft empfangen sondern nur auf Tastendruck
- aufwachen (z.B. Türsensoren), können nicht ohne Weiteres gelesen werden.<br>
- Daher liegt es in der Verantwortung des Benutzers gültige Werte zu verwenden. Es sollte autoReadReg für Geräte verwendet werden,
- die einfach ausgelesen werden können.<br>
- Der Befehl aktualisiert lediglich FHEM Readings und Attribute. Die Programmierung des Gerätes wird <B>nicht</B> verändert.
- </li>
- <li><a name="#HMinfopurgeConfig">purgeConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- Bereinigt die gespeicherte Konfigurationsdatei. Durch die kumulative Speicherung der Registerwerte bleiben die
- zuletzt gespeicherten Werte erhalten und alle älteren werden gelöscht.
- Siehe <a href="#CUL_HMsaveConfig">CUL_HM saveConfig</a>.
- </li>
- <li><a name="#HMinfoverifyConfig">verifyConfig</a> <a href="#HMinfoFilter">[filter] [<file>]</a><br>
- vergleicht die aktuellen Daten mit dem configFile und zeigt unterschiede auf.
- Es ist hilfreich wenn man eine bekannt gute Konfiguration gespeichert hat und gegen diese vergleiche will.
- Ein purge vorher macht sinn.
- Siehe <a href="#CUL_HMpurgeConfig">CUL_HM purgeConfig</a>.
- </li>
- <br>
-
- <li><a name="#HMinfotempList">tempList</a> <a href="#HMinfoFilter">[filter]</a>[save|restore|verify] [<file>]</a><br>
- Diese Funktion ermöglicht die Verarbeitung von temporären Temperaturlisten für Thermostate.
- Die Listen können in Dateien abgelegt, mit den aktuellen Werten verglichen und an das Gerät gesendet werden.<br>
- <li><B>save</B> speichert die aktuellen tempList Werte des Systems in eine Datei. <br>
- Zu beachten ist, dass die aktuell in FHEM vorhandenen Werte benutzt werden. Der Benutzer muss selbst sicher stellen,
- dass diese mit den Werten im Gerät überein stimmen.<br>
- Der Befehl arbeitet nicht kummulativ. Alle evtl. vorher in der Datei vorhandenen Werte werden überschrieben.</li>
- <li><B>restore</B> in der Datei gespeicherte Termperaturliste wird direkt an das Gerät gesendet.</li>
- <li><B>verify</B> vergleicht die Temperaturliste in der Datei mit den aktuellen Werten in FHEM. Der Benutzer muss
- selbst sicher stellen, dass diese mit den Werten im Gerät überein stimmen.</li>
- <li><B>status</B> gibt einen Ueberblick aller genutzten template files. Ferner werden vorhandene templates in den files gelistst.
- <br></li>
- <li><B>genPlot</B> erzeugt einen Satz Daten um temp-templates graphisch darzustellen<br>
- Aus den gegebenen template-file wird ein .log erweitertes file erzeugt welches log-formatierte daten beinhaltet.
- Zeitmarken sind auf Beginn 2000 terminiert.<br>
- Ein .gplot file wird in der gplt directory erzeugt.<br>
- Eine Logfile-entity <file>_Log, falls nicht vorhanden, wird erzeugt.<br>
- Eine SVG-entity <file>_SVG, falls nicht vorhanden, wird erzeugt.<br>
- </li>
- <br>
- <li><B>filename</B> Name der Datei. Vorgabe ist <B>tempList.cfg</B></li>
- Beispiel für einen Dateiinhalt:<br>
- <ul><code>
- entities:HK1_Climate,HK2_Clima<br>
- tempListFri>07:00 14.0 13:00 16.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListMon>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListSat>08:00 14.0 15:00 18.0 21:30 19.0 24:00 14.0<br>
- tempListSun>08:00 14.0 15:00 18.0 21:30 19.0 24:00 14.0<br>
- tempListThu>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- tempListTue>07:00 14.0 13:00 16.0 16:00 18.0 21:00 19.0 24:00 15.0<br>
- tempListWed>07:00 14.0 16:00 18.0 21:00 19.0 24:00 14.0<br>
- entities:hk3_Climate<br>
- tempListFri>06:00 17.0 12:00 21.0 23:00 20.0 24:00 19.5<br>
- tempListMon>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListSat>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListSun>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListThu>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListTue>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- tempListWed>06:00 17.0 12:00 21.0 23:00 20.0 24:00 17.0<br>
- </code></ul>
- Datei Schlüsselwörter<br>
- <li><B>entities</B> mittels Komma getrennte Liste der Instanzen für die die nachfolgende Liste bestimmt ist.
- Es muss die tatsächlich für die Temperaturliste zuständige Instanz angegeben werden. Bei RTs ist das der Kanal 04,
- bei TCs der Kanal 02.</li>
- <li><B>tempList...</B> Zeiten und Temperaturen sind genau wie im Befehl "set tempList" anzugeben</li>
- <br>
- </li>
- <br>
- <li><a name="#HMinfocpRegs">cpRegs <src:peer> <dst:peer> </a><br>
- ermöglicht das Kopieren von Registern, Einstellungen und Verhalten zwischen gleichen Kanälen, bei einem Peer auch
- zwischen unterschiedlichen Kanälen. Das Kopieren kann daher sowohl von Gerät zu Gerät, als auch innerhalb eines
- Gerätes stattfinden.<br>
- <b>src:peer</b> ist die Quell-Instanz. Der Peer muss angegeben werden, wenn dessen Verhalten kopiert werden soll.<br>
- <b>dst:peer</b> ist die Ziel-Instanz.<br>
- Beispiel:<br>
- <ul><code>
- set hm cpRegs blindR blindL # kopiert alle Register (list 1) des Kanals von blindR nach blindL einschliesslich z.B. der
- Rolladen Fahrzeiten. Register, die den Peer betreffen (list 3/4), werden nicht kopiert.<br>
- set hm cpRegs blindR:Btn1 blindL:Btn2 # kopiert das Verhalten der Beziehung Btn1/blindR nach Btn2/blindL<br>
- set hm cpRegs blindR:Btn1 blindR:Btn2 # kopiert das Verhalten der Beziehung Btn1/blindR nach Btn2/blindR, hier
- innerhalb des Aktors<br>
- </code></ul>
- <br>
- Einschränkungen:<br>
- <ul>
- cpRegs <u>verändert keine Peerings</u> oder liest direkt aus den Geräten. Die Readings müssen daher aktuell sein.<br>
- cpRegs kann nur auf <u>identische Gerätemodelle</u> angewendet werden<br>
- cpRegs erwartet <u>aktuelle Readings</u>. Dies muss der Benutzer sicher stellen.<br>
- </ul>
- </li>
- <li><a name="#HMinfotemplateDef">templateDef <name> <param> <desc> <reg1:val1> [<reg2:val2>] ...</a><br>
- definiert eine Vorlage.<br>
- <b>param</b> definiert die Namen der Parameters, die erforderlich sind, um die Vorlage auszuführen.
- Diese sind abhängig von der Vorlage und können onTime oder brightnesslevel sein.
- Bei einer Liste mehrerer Parameter müssen diese mittels Kommata separiert werden.<br>
- param1:param2:param3<br>
- Der Parameter del führt zur Löschung der Vorlage.<br>
- <b>desc</b> eine Beschreibung für die Vorlage<br>
- <b>reg:val</b> der Name des Registers und der dazugehörige Zielwert.<br>
- Wenn das Register zwischen long und short unterscheidet, muss das führende sh oder lg weggelassen werden.<br>
- Parameter müssen mit p angegeben werden, p0 für den ersten, p1 für den zweiten usw.
- <br>
- Beispiel<br>
- <ul><code>
- set hm templateDef SwOnCond level:cond "my description" CtValLo:p0 CtDlyOn:p1 CtOn:geLo<br>
- set hm templateDef SwOnCond del # lösche template SwOnCond<br>
- set hm templateDef SwOnCond fromMaster <masterChannel> <peer:[long|short]># masterKanal mit peer wird als Vorlage genommen<br>
- set hm templateDef SwOnCond fromMaster myChannel peerChannel:long <br>
- </code></ul>
- </li>
- <li><a name="#HMinfotemplateSet">templateSet</a> <entity> <template> <peer:[long|short]> [<param1> ...]<br>
- setzt mehrere Register entsprechend der angegebenen Vorlage. Die Parameter müssen entsprechend der Vorlage angegeben werden.<br>
- templateSet akkumuliert alle Änderungen und schreibt das Ergebnis gesammelt.<br>
- <b>entity:</b> ist die Quell-Instanz. Der Peer muss angegeben werden, wenn dessen Verhalten kopiert werden soll.<br>
- <b>template:</b> eine der vorhandenen Vorlagen<br>
- <b>peer:</b> [long|short]:falls erforderlich muss der Peer angegeben werden. Wird kein Peer benötigt, '0' verwenden.
- Bei einem Peer muss für den Tastendruck long oder short angegeben werden.<br>
- <b>param:</b> Nummer und Bedeutung des Parameters hängt von der Vorlage ab.<br>
- Ein Beispiel könnte sein (theoretisch, ohne die Vorlage anzugeben)<br>
- <ul><code>
- set hm templateSet Licht1 staircase FB1:short 20 <br>
- set hm templateSet Licht1 staircase FB1:long 100 <br>
- </code></ul>
- Einschränkungen:<br>
- <ul>
- Der Benutzer muss aktuelle Register/Konfigurationen sicher stellen.<br>
- templateSet konfiguriert ggf. nur einzelne Register und keinen vollständigen Satz. Dies hängt vom Design der Vorlage ab.<br>
- <br>
- </ul>
- </li>
- <li><a name="#HMinfotemplateDel">templateDel</a> <entity> <template> <peer:[long|short]><br>
- entfernt ein Template das mit templateSet eingetragen wurde
- </li>
- <li><a name="#HMinfotemplateExe">templateExe</a> <template> <br>
- führt das templateSet erneut aus. Die Register werden nochmals geschrieben, falls sie nicht zum template passen. <br>
- </li>
- </ul>
- </ul>
- <br>
- <a name="HMinfoattr"><b>Attribute</b></a>
- <ul>
- <li><a name="#HMinfosumStatus">sumStatus</a><br>
- erzeugt eine Liste von Warnungen. Die zu untersuchenden Readings werden mittels Komma separiert angegeben.
- Die Readings werden, so vorhanden, von allen Instanzen ausgewertet, gezählt und getrennt nach Readings mit
- gleichem Inhalt ausgegeben.<br>
- Beispiel:<br>
- <ul><code>
- attr hm sumStatus battery,sabotageError<br>
- </code></ul>
- könnte nachfolgende Ausgaben erzeugen<br>
- W_sum_batterie ok:5 low:3<br>
- W_sum_sabotageError on:1<br>
- <br>
- Anmerkung: Zähler mit Werten von '0' werden nicht angezeigt. HMinfo findet alle vorhanden Werte selbstständig.<br>
- Das Setzen des Attributes ermöglicht einen schnellen Überblick über systemkritische Werte.<br>
- </li>
- <li><a name="#HMinfosumERROR">sumERROR</a>
- Ähnlich sumStatus, jedoch mit dem Fokus auf signifikante Fehler.
- Hier können Reading <b>Werte</b> angegeben werden, die dazu führen, dass diese <b>nicht angezeigt</b> werden.
- Damit kann beispielsweise verhindert werden, dass der zu erwartende Normalwert oder ein anderer nicht
- kritischer Wert angezeigt wird.<br>
- Beispiel:<br>
- <ul><code>
- attr hm sumERROR battery:ok,sabotageError:off,overheat:off,Activity:alive:unknown<br>
- </code></ul>
- erzeugt folgende Ausgabe:<br>
- <ul><code>
- ERR_batterie low:3<br>
- ERR_sabotageError on:1<br>
- ERR_overheat on:3<br>
- ERR_Activity dead:5<br>
- </code></ul>
- </li>
- <li><a name="#HMinfoautoUpdate">autoUpdate</a>
- führt den Befehl periodisch aus.<br>
- Beispiel:<br>
- <ul><code>
- attr hm autoUpdate 00:10<br>
- </code></ul>
- führt den Befehl alle 10 Minuten aus<br>
- </li>
- <li><a name="#HMinfoautoArchive">autoArchive</a>
- Sobald neue Daten verfügbar sind, wird das configFile aktualisiert.
- Für die Aktualisierung ist <a ref="#HMinfoautoUpdate">autoUpdate</a> zwingend erforderlich.<br>
- siehe auch <a ref="#HMinfoarchConfig">archConfig</a>
- <br>
- </li>
- <li><a name="#HMinfohmAutoReadScan">hmAutoReadScan</a>
- definiert die Zeit in Sekunden bis zum nächsten autoRead durch CUL_HM. Trotz dieses Zeitwertes stellt
- FHEM sicher, dass zu einem Zeitpunkt immer nur ein Gerät gelesen wird, auch wenn der Minimalwert von 1
- Sekunde eingestellt ist. Mit dem Timer kann der Zeitabstand
- ausgeweitet werden - bis zu 300 Sekunden zwischen zwei Ausführungen.<br>
- Das Herabsetzen erhöht die Funkbelastung, Heraufsetzen erhöht die Wartzezeit.<br>
- </li>
- <li><a name="#HMinfohmIoMaxDly">hmIoMaxDly</a>
- maximale Zeit in Sekunden für die CUL_HM Meldungen puffert, wenn das Gerät nicht sendebereit ist.
- Ist das Gerät nicht wieder rechtzeitig sendebereit, werden die gepufferten Meldungen verworfen und
- IOErr ausgelöst.<br>
- Hinweis: Durch die Pufferung kann es vorkommen, dass Aktivität lange nach dem Absetzen des Befehls stattfindet.<br>
- Standard ist 60 Sekunden, maximaler Wert ist 3600 Sekunden.<br>
- </li>
- <li><a name="#HMinfoconfigDir">configDir</a>
- Verzeichnis für das Speichern und Lesen der Konfigurationsdateien, sofern in einem Befehl nur ein Dateiname ohne
- Pfad angegen wurde.<br>
- Verwendung beispielsweise bei <a ref="#HMinfotempList">tempList</a> oder <a ref="#HMinfosaveConfig">saveConfig</a><br>
- </li>
- <li><a name="#HMinfoconfigFilename">configFilename</a>
- Standard Dateiname zur Verwendung von
- <a ref="#HMinfosaveConfig">saveConfig</a>,
- <a ref="#HMinfopurgeConfig">purgeConfig</a>,
- <a ref="#HMinfoloadConfig">loadConfig</a><br>
- </li>
- <li><a name="#HMinfoconfigTempFile">configTempFile<,configTempFile2><,configTempFile2> </a>
- Liste der Templfiles (weekplan) welche in HM berücksichtigt werden<br>
- Die Files werden kommasepariert eingegeben. Das erste File ist der Default. Dessen Name muss beim Template nicht eingegeben werden.<br>
- </li>
- <li><a name="#HMinfohmManualOper">hmManualOper</a>
- auf 1 gesetzt, verhindert dieses Attribut jede automatische Aktion oder Aktualisierung seitens CUL_HM.<br>
- </li>
- <li><a name="#HMinfohmDefaults">hmDefaults</a>
- setzt default Atribute fuer HM devices. Mehrere Attribute sind moeglich, Komma separiert.<br>
- Beispiel:<br>
- attr hm hmDefaults hmProtocolEvents:0_off,rssiLog:0<br>
- </li>
- <li><a name="#HMinfoautoLoadArchive">autoLoadArchive</a>
- das Register Archive sowie Templates werden nach reboot automatischgeladen.
- Siehe <a ref="#HMinfoloadConfig">loadConfig</a> fuer details<br>
- </li>
- </ul>
- <br>
- <a name="HMinfovariables"><b>Variablen</b></a>
- <ul>
- <li><b>I_autoReadPend:</b> Info: Liste der Instanzen, für die das Lesen von Konfiguration und Status ansteht,
- üblicherweise ausgelöst durch autoReadReg.</li>
- <li><b>ERR___rssiCrit:</b> Fehler: Liste der Geräte mit kritischem RSSI Wert </li>
- <li><b>W_unConfRegs:</b> Warnung: Liste von Instanzen mit unbestätigten Änderungen von Registern.
- Die Ausführung von getConfig ist für diese Instanzen erforderlich.</li>
- <li><b>I_rssiMinLevel:</b> Info: Anzahl der niedrigen RSSI Werte je Gerät, in Blöcken angeordnet.</li>
- <li><b>ERR__protocol:</b> Fehler: Anzahl nicht behebbarer Protokollfehler je Gerät.
- Protokollfehler sind NACK, IOerr, ResendFail, CmdDel, CmdPend.<br>
- Gezählt wird die Anzahl der Geräte mit Fehlern, nicht die Anzahl der Fehler!</li>
- <li><b>ERR__protoNames:</b> Fehler: Liste der Namen der Geräte mit nicht behebbaren Protokollfehlern</li>
- <li><b>I_HM_IOdevices:</b> Info: Liste der IO Geräte, die von CUL_HM Instanzen verwendet werden</li>
- <li><b>I_actTotal:</b> Info: Status des Actiondetectors, Zähler für Geräte mit bestimmten Status</li>
- <li><b>ERRactNames:</b> Fehler: Namen von Geräten, die der Actiondetector als ausgefallen meldet</li>
- <li><b>C_sumDefined:</b> Count: In CUL_HM definierte Instanzen. Instanzen können als Gerät UND
- als Kanal gezählt werden, falls die Funktion des Kanals durch das Gerät
- selbst abgedeckt ist. Ähnlich virtual</li>
- <li><b>ERR_<reading>:</b> Fehler: Anzahl mittels Attribut <a href="#HMinfosumERROR">sumERROR</a>
- definierter Readings, die nicht den Normalwert beinhalten. </li>
- <li><b>ERR_names:</b> Fehler: Namen von Instanzen, die in einem ERR_<reading> enthalten sind.</li>
- <li><b>W_sum_<reading></b> Warnung: Anzahl der mit Attribut <a href="#HMinfosumStatus">sumStatus</a> definierten Readings.</li>
- Beispiele:<br>
- <ul>
- <code>
- ERR___rssiCrit LightKittchen,WindowDoor,Remote12<br>
- ERR__protocol NACK:2 ResendFail:5 CmdDel:2 CmdPend:1<br>
- ERR__protoNames LightKittchen,WindowDoor,Remote12,Ligth1,Light5<br>
- ERR_battery: low:2;<br>
- ERR_names: remote1,buttonClara,<br>
- I_rssiMinLevel 99>:3 80<:0 60<:7 59<:4<br>
- W_sum_battery: ok:5;low:2;<br>
- W_sum_overheat: off:7;<br>
- C_sumDefined: entities:23 device:11 channel:16 virtual:5;<br>
- </code>
- </ul>
- </ul>
- </ul>
- =end html_DE
- =cut
|