diff --git a/FHEM/00_CUL.pm b/FHEM/00_CUL.pm index 00c1c5e28..aae21f57e 100755 --- a/FHEM/00_CUL.pm +++ b/FHEM/00_CUL.pm @@ -101,7 +101,9 @@ CUL_Initialize($) $hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 " . "showtime:1,0 model:CUL,CUN,CUR loglevel:0,1,2,3,4,5,6 " . "sendpool addvaltrigger " . - "rfmode:SlowRF,HomeMatic,MAX hmId hmProtocolEvents"; + "rfmode:SlowRF,HomeMatic,MAX hmId ". + "hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger"; + $hash->{ShutdownFn} = "CUL_Shutdown"; } diff --git a/FHEM/00_HMLAN.pm b/FHEM/00_HMLAN.pm index c56177144..922465f5f 100755 --- a/FHEM/00_HMLAN.pm +++ b/FHEM/00_HMLAN.pm @@ -43,7 +43,8 @@ HMLAN_Initialize($) $hash->{UndefFn} = "HMLAN_Undef"; $hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 " . "loglevel:0,1,2,3,4,5,6 addvaltrigger " . - "hmId hmProtocolEvents hmKey"; + "hmId hmKey " . + "hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger"; } ##################################### @@ -190,8 +191,6 @@ HMLAN_ReadAnswer($$$) } } -my %lhash; - ##################################### sub HMLAN_Write($$$) @@ -199,7 +198,7 @@ HMLAN_Write($$$) my ($hash,$fn,$msg) = @_; my $dst = substr($msg, 16, 6); - if(!$lhash{$dst} && $dst ne "000000") { # Don't think I grok the logic + if(hex(substr($msg, 6, 2))&0x01) { # wakeup flag set, shake actor awake HMLAN_SimpleWrite($hash, "+$dst,00,00,"); HMLAN_SimpleWrite($hash, "+$dst,00,00,"); HMLAN_SimpleWrite($hash, "+$dst,00,00,"); @@ -208,7 +207,6 @@ HMLAN_Write($$$) HMLAN_SimpleWrite($hash, "+$dst,00,00,"); HMLAN_SimpleWrite($hash, "+$dst,00,00,"); HMLAN_SimpleWrite($hash, "+$dst,00,00,"); - $lhash{$dst} = 1; } my $tm = int(gettimeofday()*1000) % 0xffffffff; $msg = sprintf("S%08X,00,00000000,01,%08X,%s", @@ -217,7 +215,8 @@ HMLAN_Write($$$) # Avoid problems with structure set # TODO: rewrite it to use a queue+internaltimer like the CUL - select(undef, undef, undef, 0.3); # needed for structure set by meesus. + select(undef, undef, undef, 0.01); # needed for structure set by meesus. + # may not be needed at all if acks are handled properly } ##################################### @@ -278,7 +277,8 @@ HMLAN_Parse($$) ($1, $2, $3, $4, $5, $6); $dmsg = sprintf("A%02X%s", length($msg)/2, uc($msg)); - $dmsg .= "NACK" if($status !~ m/00(01|02|21)/); + $dmsg .= "NACK" if($status !~ m/00(01|02|21)/); + $hash->{uptime} = HMLAN_uptime($msec); } elsif($rmsg =~ diff --git a/FHEM/10_CUL_HM.pm b/FHEM/10_CUL_HM.pm index c4f3e2b28..b5458ba5d 100755 --- a/FHEM/10_CUL_HM.pm +++ b/FHEM/10_CUL_HM.pm @@ -20,7 +20,6 @@ sub CUL_HM_getConfig($$$$$); sub CUL_HM_SendCmd($$$$); sub CUL_HM_responseSetup($$$); sub CUL_HM_eventP($$); -sub CUL_HM_convPendTout($); sub CUL_HM_respPendRm($); sub CUL_HM_respPendTout($); sub CUL_HM_PushCmdStack($$); @@ -73,119 +72,125 @@ my %culHmDevProps=( # c: receive on config # w: receive in wakeup # b: receive on burst +#register list definition - identifies valid register lists +# 1,3,5:3p.4.5 => list 1 valid for all channel +# => list 3 for all channel +# => list 5 only for channel 3 but assotiated with peers +# => list 5 for channel 4 and 5 with peer=00000000 +# my %culHmModel=( - "0001" => {name=>"HM-LC-SW1-PL-OM54" ,rxt=>'' ,chn=>"",}, - "0002" => {name=>"HM-LC-SW1-SM" ,rxt=>'' ,chn=>"",}, - "0003" => {name=>"HM-LC-SW4-SM" ,rxt=>'' ,chn=>"Sw:1:4",}, - "0004" => {name=>"HM-LC-SW1-FM" ,rxt=>'' ,chn=>"",}, - "0005" => {name=>"HM-LC-BL1-FM" ,rxt=>'' ,chn=>"",}, - "0006" => {name=>"HM-LC-BL1-SM" ,rxt=>'' ,chn=>"",}, - "0007" => {name=>"KS550" ,rxt=>'' ,chn=>"",}, - "0008" => {name=>"HM-RC-4" ,rxt=>'c' ,chn=>"Btn:1:4",}, - "0009" => {name=>"HM-LC-SW2-FM" ,rxt=>'' ,chn=>"Sw:1:2",}, - "000A" => {name=>"HM-LC-SW2-SM" ,rxt=>'' ,chn=>"Sw:1:2",}, - "000B" => {name=>"HM-WDC7000" ,rxt=>'' ,chn=>"",}, - "000D" => {name=>"ASH550" ,rxt=>'c:w' ,chn=>"",}, - "000E" => {name=>"ASH550I" ,rxt=>'c:w' ,chn=>"",}, - "000F" => {name=>"S550IA" ,rxt=>'c:w' ,chn=>"",}, - "0011" => {name=>"HM-LC-SW1-PL" ,rxt=>'' ,chn=>"",}, - "0012" => {name=>"HM-LC-DIM1L-CV" ,rxt=>'' ,chn=>"",}, - "0013" => {name=>"HM-LC-DIM1L-PL" ,rxt=>'' ,chn=>"",}, - "0014" => {name=>"HM-LC-SW1-SM-ATMEGA168" ,rxt=>'' ,chn=>"",}, - "0015" => {name=>"HM-LC-SW4-SM-ATMEGA168" ,rxt=>'' ,chn=>"Sw:1:4",}, - "0016" => {name=>"HM-LC-DIM2L-CV" ,rxt=>'' ,chn=>"Sw:1:2",}, - "0018" => {name=>"CMM" ,rxt=>'' ,chn=>"",}, - "0019" => {name=>"HM-SEC-KEY" ,rxt=>'' ,chn=>"",}, - "001A" => {name=>"HM-RC-P1" ,rxt=>'c' ,chn=>"",}, - "001B" => {name=>"HM-RC-SEC3" ,rxt=>'c' ,chn=>"Btn:1:3",}, - "001C" => {name=>"HM-RC-SEC3-B" ,rxt=>'c' ,chn=>"Btn:1:3",}, - "001D" => {name=>"HM-RC-KEY3" ,rxt=>'c' ,chn=>"Btn:1:3",}, - "001E" => {name=>"HM-RC-KEY3-B" ,rxt=>'c' ,chn=>"Btn:1:3",}, - "0022" => {name=>"WS888" ,rxt=>'' ,chn=>"",}, - "0026" => {name=>"HM-SEC-KEY-S" ,rxt=>'' ,chn=>"",}, - "0027" => {name=>"HM-SEC-KEY-O" ,rxt=>'' ,chn=>"",}, - "0028" => {name=>"HM-SEC-WIN" ,rxt=>'b' ,chn=>"",}, - "0029" => {name=>"HM-RC-12" ,rxt=>'c' ,chn=>"Btn:1:12",}, - "002A" => {name=>"HM-RC-12-B" ,rxt=>'c' ,chn=>"Btn:1:12",}, - "002D" => {name=>"HM-LC-SW4-PCB" ,rxt=>'' ,chn=>"Sw:1:4",}, - "002E" => {name=>"HM-LC-DIM2L-SM" ,rxt=>'' ,chn=>"Sw:1:2",}, - "002F" => {name=>"HM-SEC-SC" ,rxt=>'c:w' ,chn=>"",}, - "0030" => {name=>"HM-SEC-RHS" ,rxt=>'c:w' ,chn=>"",}, - "0034" => {name=>"HM-PBI-4-FM" ,rxt=>'c' ,chn=>"Btn:1:4",}, - "0035" => {name=>"HM-PB-4-WM" ,rxt=>'c' ,chn=>"Btn:1:4",}, - "0036" => {name=>"HM-PB-2-WM" ,rxt=>'c' ,chn=>"Btn:1:2",}, - "0037" => {name=>"HM-RC-19" ,rxt=>'c:b' ,chn=>"Btn:1:17,Disp:18",}, - "0038" => {name=>"HM-RC-19-B" ,rxt=>'c:b' ,chn=>"Btn:1:17,Disp:18",}, - "0039" => {name=>"HM-CC-TC" ,rxt=>'c:w' ,chn=>"",}, - "003A" => {name=>"HM-CC-VD" ,rxt=>'c:w' ,chn=>"",}, - "003B" => {name=>"HM-RC-4-B" ,rxt=>'c' ,chn=>"Btn:1:4",}, - "003C" => {name=>"HM-WDS20-TH-O" ,rxt=>'c:w' ,chn=>"",}, - "003D" => {name=>"HM-WDS10-TH-O" ,rxt=>'c:w' ,chn=>"",}, - "003E" => {name=>"HM-WDS30-T-O" ,rxt=>'c:w' ,chn=>"",}, - "003F" => {name=>"HM-WDS40-TH-I" ,rxt=>'c:w' ,chn=>"",}, - "0040" => {name=>"HM-WDS100-C6-O" ,rxt=>'c:w' ,chn=>"",}, - "0041" => {name=>"HM-WDC7000" ,rxt=>'' ,chn=>"",}, - "0042" => {name=>"HM-SEC-SD" ,rxt=>'' ,chn=>"",}, - "0043" => {name=>"HM-SEC-TIS" ,rxt=>'c:w' ,chn=>"",}, - "0044" => {name=>"HM-SEN-EP" ,rxt=>'c:w' ,chn=>"",}, - "0045" => {name=>"HM-SEC-WDS" ,rxt=>'c:w' ,chn=>"",}, - "0047" => {name=>"KFM-Sensor" ,rxt=>'' ,chn=>"",}, - "0046" => {name=>"HM-SWI-3-FM" ,rxt=>'c' ,chn=>"Sw:1:3",}, - "0048" => {name=>"IS-WDS-TH-OD-S-R3" ,rxt=>'c:w' ,chn=>"",}, - "0049" => {name=>"KFM-Display" ,rxt=>'' ,chn=>"",}, - "004A" => {name=>"HM-SEC-MDIR" ,rxt=>'c:w' ,chn=>"",}, - "004B" => {name=>"HM-Sec-Cen" ,rxt=>'' ,chn=>"",}, - "004C" => {name=>"HM-RC-12-SW" ,rxt=>'c' ,chn=>"Btn:1:12",}, - "004D" => {name=>"HM-RC-19-SW" ,rxt=>'c:b' ,chn=>"Btn:1:17,Disp:18",}, - "004E" => {name=>"HM-LC-DDC1-PCB" ,rxt=>'' ,chn=>"",}, - "004F" => {name=>"HM-SEN-MDIR-SM" ,rxt=>'c:w' ,chn=>"",}, - "0050" => {name=>"HM-SEC-SFA-SM" ,rxt=>'' ,chn=>"",}, - "0051" => {name=>"HM-LC-SW1-PB-FM" ,rxt=>'' ,chn=>"",}, - "0052" => {name=>"HM-LC-SW2-PB-FM" ,rxt=>'' ,chn=>"Sw:1:2",}, - "0053" => {name=>"HM-LC-BL1-PB-FM" ,rxt=>'' ,chn=>"",}, - "0054" => {name=>"DORMA_RC-H" ,rxt=>'c' ,chn=>"",}, - "0056" => {name=>"HM-CC-SCD" ,rxt=>'c:w' ,chn=>"",}, - "0057" => {name=>"HM-LC-DIM1T-PL" ,rxt=>'' ,chn=>"",}, - "0058" => {name=>"HM-LC-DIM1T-CV" ,rxt=>'' ,chn=>"",}, - "0059" => {name=>"HM-LC-DIM1T-FM" ,rxt=>'' ,chn=>"",}, - "005A" => {name=>"HM-LC-DIM2T-SM" ,rxt=>'' ,chn=>"Sw:1:2",}, - "005C" => {name=>"HM-OU-CF-PL" ,rxt=>'' ,chn=>"",}, - "005D" => {name=>"HM-Sen-MDIR-O" ,rxt=>'c:w' ,chn=>"",}, - "005F" => {name=>"HM-SCI-3-FM" ,rxt=>'c:w' ,chn=>"",}, - "0060" => {name=>"HM-PB-4DIS-WM" ,rxt=>'c' ,chn=>"",}, - "0061" => {name=>"HM-LC-SW4-DR" ,rxt=>'' ,chn=>"Sw:1:4",}, - "0062" => {name=>"HM-LC-SW2-DR" ,rxt=>'' ,chn=>"Sw:1:2",}, - "0064" => {name=>"DORMA_atent" ,rxt=>'c' ,chn=>"",}, - "0065" => {name=>"DORMA_BRC-H" ,rxt=>'c' ,chn=>"",}, - "0066" => {name=>"HM_LC_Sw4-WM" ,rxt=>'b' ,chn=>"Sw:1:4",}, - "0067" => {name=>"HM-LC_Dim1PWM-CV" ,rxt=>'' ,chn=>"",}, - "0068" => {name=>"HM-LC_Dim1TPBU-FM" ,rxt=>'' ,chn=>"",}, - "0069" => {name=>"HM-LC_Sw1PBU-FM" ,rxt=>'' ,chn=>"",}, - "006A" => {name=>"HM-LC_Bl1PBU-FM" ,rxt=>'' ,chn=>"",}, - "006B" => {name=>"HM-PB-2-WM55" ,rxt=>'c:w' ,chn=>"",}, - "006C" => {name=>"HM-LC-SW1-BA-PCB" ,rxt=>'b' ,chn=>"",}, - "006D" => {name=>"HM-OU-LED16" ,rxt=>'' ,chn=>"Led:1:16",}, - "0075" => {name=>"HM-OU-CFM-PL" ,rxt=>'' ,chn=>"Led:1:1,Mp3:2:2",}, - "0078" => {name=>"HM-Dis-TD-T" ,rxt=>'b' ,chn=>"",}, - "0079" => {name=>"ROTO_ZEL-STG-RM-FWT" ,rxt=>'c:w' ,chn=>"",}, - "0x7A" => {name=>"ROTO_ZEL-STG-RM-FSA" ,rxt=>'' ,chn=>"",}, - "007B" => {name=>"ROTO_ZEL-STG-RM-FEP-230V",rxt=>'' ,chn=>"",}, - "007D" => {name=>"ROTO_ZEL-STG-RM-WT-2" ,rxt=>'c:w' ,chn=>"",}, - "007E" => {name=>"ROTO_ZEL-STG-RM-DWT-10" ,rxt=>'c' ,chn=>"",}, - "007F" => {name=>"ROTO_ZEL-STG-RM-FST-UP4" ,rxt=>'c' ,chn=>"",}, - "0080" => {name=>"ROTO_ZEL-STG-RM-HS-4" ,rxt=>'c' ,chn=>"",}, - "0081" => {name=>"ROTO_ZEL-STG-RM-FDK" ,rxt=>'c:w' ,chn=>"",}, - "0082" => {name=>"Roto_ZEL-STG-RM-FFK" ,rxt=>'c:w' ,chn=>"",}, - "0083" => {name=>"Roto_ZEL-STG-RM-FSS-UP3" ,rxt=>'c' ,chn=>"",}, - "0084" => {name=>"Schueco_263-160" ,rxt=>'c:w' ,chn=>"",}, - "0086" => {name=>"263-146" ,rxt=>'' ,chn=>"",}, - "008D" => {name=>"Schueco_263-1350" ,rxt=>'c:w' ,chn=>"",}, - "008E" => {name=>"263-155" ,rxt=>'c' ,chn=>"",}, - "008F" => {name=>"263-145" ,rxt=>'c' ,chn=>"",}, - "0090" => {name=>"Schueco_263-162" ,rxt=>'c:w' ,chn=>"",}, - "0092" => {name=>"Schueco_263-144" ,rxt=>'c' ,chn=>"",}, - "0093" => {name=>"263-158" ,rxt=>'c:w' ,chn=>"",}, - "0094" => {name=>"263-157" ,rxt=>'c:w' ,chn=>"",}, + "0001" => {name=>"HM-LC-SW1-PL-OM54" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0002" => {name=>"HM-LC-SW1-SM" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0003" => {name=>"HM-LC-SW4-SM" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Sw:1:4",}, + "0004" => {name=>"HM-LC-SW1-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0005" => {name=>"HM-LC-BL1-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0006" => {name=>"HM-LC-BL1-SM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0007" => {name=>"KS550" ,cyc=>'' ,rxt=>'' ,lst=>'1' ,chn=>"",}, + "0008" => {name=>"HM-RC-4" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:4",}, + "0009" => {name=>"HM-LC-SW2-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2",}, + "000A" => {name=>"HM-LC-SW2-SM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2",}, + "000B" => {name=>"HM-WDC7000" ,cyc=>'' ,rxt=>'' ,lst=>'' ,chn=>"",}, + "000D" => {name=>"ASH550" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "000E" => {name=>"ASH550I" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "000F" => {name=>"S550IA" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "0011" => {name=>"HM-LC-SW1-PL" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0012" => {name=>"HM-LC-DIM1L-CV" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Vtr:2:3",}, + "0013" => {name=>"HM-LC-DIM1L-PL" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0014" => {name=>"HM-LC-SW1-SM-ATMEGA168" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0015" => {name=>"HM-LC-SW4-SM-ATMEGA168" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:4",}, + "0016" => {name=>"HM-LC-DIM2L-CV" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2,Vtr:3:6",}, + "0018" => {name=>"CMM" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0019" => {name=>"HM-SEC-KEY" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"",}, + "001A" => {name=>"HM-RC-P1" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "001B" => {name=>"HM-RC-SEC3" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:3",}, + "001C" => {name=>"HM-RC-SEC3-B" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:3",}, + "001D" => {name=>"HM-RC-KEY3" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:3",}, + "001E" => {name=>"HM-RC-KEY3-B" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:3",}, + "0022" => {name=>"WS888" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0026" => {name=>"HM-SEC-KEY-S" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"",}, + "0027" => {name=>"HM-SEC-KEY-O" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"",}, + "0028" => {name=>"HM-SEC-WIN" ,cyc=>'' ,rxt=>'b' ,lst=>'1,3' ,chn=>"",}, + "0029" => {name=>"HM-RC-12" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:12",}, + "002A" => {name=>"HM-RC-12-B" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:12",}, + "002D" => {name=>"HM-LC-SW4-PCB" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Sw:1:4",}, + "002E" => {name=>"HM-LC-DIM2L-SM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2,Vtr:3:6",}, + "002F" => {name=>"HM-SEC-SC" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0030" => {name=>"HM-SEC-RHS" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0034" => {name=>"HM-PBI-4-FM" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:4",}, + "0035" => {name=>"HM-PB-4-WM" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:4",}, + "0036" => {name=>"HM-PB-2-WM" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:2",}, + "0037" => {name=>"HM-RC-19" ,cyc=>'' ,rxt=>'c:b' ,lst=>'1,4' ,chn=>"Btn:1:17,Disp:18",}, + "0038" => {name=>"HM-RC-19-B" ,cyc=>'' ,rxt=>'c:b' ,lst=>'1,4' ,chn=>"Btn:1:17,Disp:18",}, + "0039" => {name=>"HM-CC-TC" ,cyc=>'00:10' ,rxt=>'c:w' ,lst=>'5:2.3p,6:2' ,chn=>"Weather:1:1,Climate:2:2,WindowRec:3:3",}, + "003A" => {name=>"HM-CC-VD" ,cyc=>'28:00' ,rxt=>'c:w' ,lst=>'5' ,chn=>"",}, + "003B" => {name=>"HM-RC-4-B" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:4",}, + "003C" => {name=>"HM-WDS20-TH-O" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "003D" => {name=>"HM-WDS10-TH-O" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "003E" => {name=>"HM-WDS30-T-O" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "003F" => {name=>"HM-WDS40-TH-I" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "0040" => {name=>"HM-WDS100-C6-O" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1' ,chn=>"",}, + "0041" => {name=>"HM-WDC7000" ,cyc=>'' ,rxt=>'' ,lst=>'1,4' ,chn=>"",}, + "0042" => {name=>"HM-SEC-SD" ,cyc=>'' ,rxt=>'b' ,lst=>'' ,chn=>"",}, + "0043" => {name=>"HM-SEC-TIS" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0044" => {name=>"HM-SEN-EP" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0045" => {name=>"HM-SEC-WDS" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0047" => {name=>"KFM-Sensor" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0046" => {name=>"HM-SWI-3-FM" ,cyc=>'' ,rxt=>'c' ,lst=>'4' ,chn=>"Sw:1:3",}, + "0048" => {name=>"IS-WDS-TH-OD-S-R3" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,3' ,chn=>"",}, + "0049" => {name=>"KFM-Display" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "004A" => {name=>"HM-SEC-MDIR" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "004B" => {name=>"HM-Sec-Cen" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "004C" => {name=>"HM-RC-12-SW" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:12",}, + "004D" => {name=>"HM-RC-19-SW" ,cyc=>'' ,rxt=>'c:b' ,lst=>'1,4' ,chn=>"Btn:1:17,Disp:18",}, + "004E" => {name=>"HM-LC-DDC1-PCB" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "004F" => {name=>"HM-SEN-MDIR-SM" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0050" => {name=>"HM-SEC-SFA-SM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0051" => {name=>"HM-LC-SW1-PB-FM" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",}, + "0052" => {name=>"HM-LC-SW2-PB-FM" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Sw:1:2",}, + "0053" => {name=>"HM-LC-BL1-PB-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0054" => {name=>"DORMA_RC-H" ,cyc=>'' ,rxt=>'c' ,lst=>'1,3' ,chn=>"",}, + "0056" => {name=>"HM-CC-SCD" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0057" => {name=>"HM-LC-DIM1T-PL" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Vtr:2:3",}, + "0058" => {name=>"HM-LC-DIM1T-CV" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Vtr:2:3",}, + "0059" => {name=>"HM-LC-DIM1T-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Vtr:2:3",}, + "005A" => {name=>"HM-LC-DIM2T-SM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2,Vtr:3:6",}, + "005C" => {name=>"HM-OU-CF-PL" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Led:1:1,Sound:2:2",}, + "005D" => {name=>"HM-Sen-MDIR-O" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "005F" => {name=>"HM-SCI-3-FM" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0060" => {name=>"HM-PB-4DIS-WM" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:20",}, + "0061" => {name=>"HM-LC-SW4-DR" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Sw:1:4",}, + "0062" => {name=>"HM-LC-SW2-DR" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"Sw:1:2",}, + "0064" => {name=>"DORMA_atent" ,cyc=>'' ,rxt=>'c' ,lst=>'1,3' ,chn=>"",}, + "0065" => {name=>"DORMA_BRC-H" ,cyc=>'' ,rxt=>'c' ,lst=>'1,3' ,chn=>"",}, + "0066" => {name=>"HM-LC-SW4-WM" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"Sw:1:4",}, + "0067" => {name=>"HM-LC-Dim1PWM-CV" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0068" => {name=>"HM-LC-Dim1TPBU-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "0069" => {name=>"HM-LC-Sw1PBU-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "006A" => {name=>"HM-LC-Bl1PBU-FM" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "006B" => {name=>"HM-PB-2-WM55" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "006C" => {name=>"HM-LC-SW1-BA-PCB" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"",}, + "006D" => {name=>"HM-OU-LED16" ,cyc=>'' ,rxt=>'' ,lst=>'' ,chn=>"Led:1:16",}, + "0075" => {name=>"HM-OU-CFM-PL" ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"Led:1:1,Mp3:2:2",}, + "0078" => {name=>"HM-Dis-TD-T" ,cyc=>'' ,rxt=>'b' ,lst=>'3' ,chn=>"",}, + "0079" => {name=>"ROTO_ZEL-STG-RM-FWT" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,3' ,chn=>"",}, + "0x7A" => {name=>"ROTO_ZEL-STG-RM-FSA" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "007B" => {name=>"ROTO_ZEL-STG-RM-FEP-230V",cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "007D" => {name=>"ROTO_ZEL-STG-RM-WT-2" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "007E" => {name=>"ROTO_ZEL-STG-RM-DWT-10" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "007F" => {name=>"ROTO_ZEL-STG-RM-FST-UP4" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "0080" => {name=>"ROTO_ZEL-STG-RM-HS-4" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "0081" => {name=>"ROTO_ZEL-STG-RM-FDK" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,3' ,chn=>"",}, + "0082" => {name=>"Roto_ZEL-STG-RM-FFK" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0083" => {name=>"Roto_ZEL-STG-RM-FSS-UP3" ,cyc=>'' ,rxt=>'c' ,lst=>'4' ,chn=>"",}, + "0084" => {name=>"Schueco_263-160" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,4' ,chn=>"",}, + "0086" => {name=>"Schueco_263-146" ,cyc=>'' ,rxt=>'' ,lst=>'1,3' ,chn=>"",}, + "008D" => {name=>"Schueco_263-1350" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,3' ,chn=>"",}, + "008E" => {name=>"Schueco_263-155" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "008F" => {name=>"Schueco_263-145" ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"",}, + "0090" => {name=>"Schueco_263-162" ,cyc=>'' ,rxt=>'c:w' ,lst=>'1,3' ,chn=>"",}, + "0092" => {name=>"Schueco_263-144" ,cyc=>'' ,rxt=>'c' ,lst=>'4' ,chn=>"",}, + "0093" => {name=>"Schueco_263-158" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, + "0094" => {name=>"Schueco_263-157" ,cyc=>'' ,rxt=>'c:w' ,lst=>'' ,chn=>"",}, ); sub CUL_HM_Initialize($) @@ -198,12 +203,14 @@ CUL_HM_Initialize($) $hash->{ParseFn} = "CUL_HM_Parse"; $hash->{SetFn} = "CUL_HM_Set"; $hash->{GetFn} = "CUL_HM_Get"; - $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 dummy:1,0 " . - "showtime:1,0 loglevel:0,1,2,3,4,5,6 " . + $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 dummy:1,0 ". + "showtime:1,0 loglevel:0,1,2,3,4,5,6 ". "hmClass:receiver,sender serialNr firmware devInfo ". "rawToReadable unit ". "chanNo device peerList ". - "protCmdPend protLastRcv protSndCnt protSndLast protCmdDel protNackCnt protNackLast rxType ". + "actCycle actStatus ". + "protCmdPend protLastRcv protSndCnt protSndLast protCmdDel protNackCnt protNackLast ". + "protResndFailLast protResndLast protResndFailCnt protResndCnt protToutRespLast protToutRespCnt ". "channel_01 channel_02 channel_03 channel_04 channel_05 channel_06 ". "channel_07 channel_08 channel_09 channel_0A channel_0B channel_0C ". "channel_0D channel_0E channel_0F channel_10 channel_11 channel_12 ". @@ -285,7 +292,6 @@ CUL_HM_Parse($$) { my ($iohash, $msg) = @_; my $id = CUL_HM_Id($iohash); - # Msg format: Allnnffttssssssddddddpp... $msg =~ m/A(..)(..)(..)(..)(......)(......)(.*)/; my @msgarr = ($1,$2,$3,$4,$5,$6,$7); @@ -302,12 +308,9 @@ CUL_HM_Parse($$) my $target = " (to $dname)"; return "" if($p =~ m/NACK$/);#discard TCP errors from HMlan. Resend will cover it - return ""if ($src eq $id);#discard mirrored messages - - CUL_HM_DumpProtocol("RCV",$iohash,$len,$msgcnt,$msgFlag,$msgType,$src,$dst,$p); + return "" if($src eq $id);#discard mirrored messages if(!$shash) { # Unknown source - # Generate an UNKNOWN event for pairing requests, ignore everything else if($msgType eq "00") { my $sname = "CUL_HM_$src"; @@ -317,16 +320,14 @@ CUL_HM_Parse($$) my $stc = substr($p, 26, 2); # subTypeCode if($culHmDevProps{$stc}) { $sname = "CUL_HM_".$culHmDevProps{$stc}{st} . "_" . $src; - - } elsif($culHmModel{$model}{name}) { + } + elsif($culHmModel{$model}{name}) { $sname = "CUL_HM_".$culHmModel{$model}{name} . "_" . $src; $sname =~ s/-/_/g; } - Log 3, "CUL_HM Unknown device $sname, please define it"; return "UNDEFINED $sname CUL_HM $src $msg"; } - return ""; } CUL_HM_eventP($shash,"Rcv"); @@ -336,22 +337,24 @@ CUL_HM_Parse($$) my $model = AttrVal($name, "model", ""); my $tn = TimeNow(); - # msgX used for duplicate detection - msgFlag and len removed + # return if duplicate my $msgX = "No:$msgcnt - t:$msgType s:$src d:$dst $p"; if($shash->{lastMsg} && $shash->{lastMsg} eq $msgX) { Log GetLogLevel($name,4), "CUL_HM $name dup mesg"; return ""; #return something to please dispatcher - }else{ - $shash->{lastMsg} = $msgX; - } + } + $shash->{lastMsg} = $msgX; + $iohash->{HM_CMDNR} = hex($msgcnt) if($dst eq $id);# update messag counter to receiver + + CUL_HM_DumpProtocol("RCV",$iohash,$len,$msgcnt,$msgFlag,$msgType,$src,$dst,$p); + #----------start valid messages parsing --------- my $parse = CUL_HM_parseCommon($msgcnt,$msgType,$src,$dst,$p); push @event, "powerOn" if($parse eq "powerOn"); my $sendAck = "yes";# if yes Ack will be determined automatically - $sendAck = "" if ($parse eq "STATresp"); - + if ($parse eq "ACK"){# remember - ACKinfo will be passed on push @event, ""; } @@ -364,12 +367,11 @@ CUL_HM_Parse($$) } elsif($lcm eq "09A112") { #### Another fhem wants to talk (HAVE_DATA) ; - } elsif($msgType eq "00" ){ #### DEVICE_INFO, Pairing-Request CUL_HM_infoUpdtDevData($name, $shash,$p);#update data - if($shash->{cmdStack} && (AttrVal($name, "rxType", "0") =~ m/config/)) { + if($shash->{cmdStack} && (CUL_HM_getRxType($shash) & 0x04)) { CUL_HM_ProcessCmdStack($shash);# sender devices may have msgs stacked push @event,""; } @@ -418,17 +420,17 @@ CUL_HM_Parse($$) } elsif($model eq "HM-CC-TC") { #################################### - + my ($sType,$chn) = ($1,$2) if($p =~ m/^(..)(..)/); if($cmd eq "8670" && $p =~ m/^(....)(..)/) {# weather event + $chn = '01'; # fix definition my ( $t, $h) = (hex($1), hex($2));# temp is 15 bit signed $t = ($t & 0x3fff)/10*(($t & 0x4000)?-1:1); push @event, "state:T: $t H: $h"; - push @event, "measured-temp:$t";# todo - why report this twice? Check and remove! - push @event, "temperature:$t"; + push @event, "measured-temp:$t"; push @event, "humidity:$h"; - } elsif($cmd eq "A258" && $p =~ m/^(..)(..)/) {#climate event + $chn = '02'; # fix definition my ( $d1, $vp) = # adjust_command[0..4] adj_data[0..250] ( $1, hex($2)); $vp = int($vp/2.56+0.5); # valve position in % @@ -445,7 +447,7 @@ CUL_HM_Parse($$) elsif($cmd eq "A410" && $p =~ m/^0403(......)(..)0505(..)0000/) { # change of chn 3(window) list 5 register 5 - a peer window changed! my ( $tdev, $tchan, $v1) = (($1), hex($2), hex($3)); - push @event, sprintf("windowopen-temp-%d: %.1f (sensor:%s)" + push @event, sprintf("windowopen-temp-%d: %.1f (sensor:%s)" ,$tchan, $v1/2, $tdev); } # idea: remember all possible 24 value-pairs per day and reconstruct list @@ -483,7 +485,7 @@ CUL_HM_Parse($$) foreach my $wd (@days) { my $twentyfour = 0; - my $msg = sprintf("tempList%s:", $wd); + my $msg = 'tempList'.$wd.':'; foreach(my $idx=0; $idx<24; $idx++) { my $ptr = $shash->{TEMPLIST}{$wd}{$idx}; if(defined ($ptr->{TEMP}) && $ptr->{TEMP} ne "") { @@ -500,7 +502,6 @@ CUL_HM_Parse($$) } push @event, $msg; # generate one event per day entry } - } elsif($cmd eq "A410" && $p =~ m/^04020000000005(..)(..)/) { my ( $o1, $v1) = (hex($1),hex($2));# only parse list 5 for chn 2 @@ -508,11 +509,11 @@ CUL_HM_Parse($$) my @days = ("Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"); if($o1 == 1) { ### bitfield containing multiple values... my %mode = (0 => "manual",1 => "auto",2 => "central",3 => "party"); - push @event,"displayMode:temperature ".(($v1 & 1)?" and humidity":" only"); - push @event,"displayTemp:" .(($v1 & 2)?"setpoint" :"actual"); - push @event,"displayTempUnit:" .(($v1 & 4)?"fahrenheit" :"celsius"); - push @event,"controlMode:" .($mode{(($v1 & 0x18)>>3)}); - push @event,sprintf("decalcDay:%s", $days[($v1 & 0xE0)>>5]); + push @event,'displayMode:temperature '.(($v1 & 1)?" and humidity":" only"); + push @event,'displayTemp:' .(($v1 & 2)?"setpoint" :"actual"); + push @event,'displayTempUnit:' .(($v1 & 4)?"fahrenheit" :"celsius"); + push @event,'controlMode:' .($mode{(($v1 & 0x18)>>3)}); + push @event,'decalcDay:' .$days[($v1 & 0xE0)>>5]; } elsif($o1 == 2) { @@ -520,23 +521,20 @@ CUL_HM_Parse($$) push @event,"tempValveMode:".$pos{(($v1 & 0xC0)>>6)}; } else{ - push @event,sprintf("param-change: offset=%s, value=%s", $o1, $v1); + push @event,'param-change: offset='.$o1.', value='.$v1; } } elsif($cmd eq "A001" && $p =~ m/^01080900(..)(..)/) { + # channel is in sType for this message my ( $of, $vep) = (hex($1), hex($2)); push @event, "ValveErrorPosition $dname: $vep %"; push @event, "ValveOffset $dname: $of %"; } - elsif(($cmd eq "A410" && $p =~ m/^0602(..)........$/) || - ($cmd eq "A112" && $p =~ m/^0202(..)$/)) { # Set desired temp - push @event, "desired-temp:" .sprintf("%0.1f", hex($1)/2); - } - elsif($cmd eq "8002" && $p =~ m/^0102(..)(....)/) { # Ack for fhem-command - push @event, "desired-temp-ack:" .sprintf("%0.1f", hex($1)/2); - # FIXME: following is needed, else a set won't show up. - push @event, "desired-temp:" .sprintf("%0.1f", hex($1)/2); +# ($cmd eq "A112" && $p =~ m/^0202(..)$/)) { # Set desired temp + elsif(($msgType eq '02' &&$sType eq '01')|| # ackStatus + ($msgType eq '10' &&$sType eq '06')){ #infoStatus + push @event, "desired-temp:" .sprintf("%0.1f", hex(substr($p,4,2))/2); } elsif($cmd eq "A03F" && $id eq $dst) { # Timestamp request my $s2000 = sprintf("%02X", CUL_HM_secSince2000()); @@ -549,25 +547,38 @@ CUL_HM_Parse($$) CUL_HM_SendCmd($shash, $msgcnt."8002$id${src}00",1,0) # Send Ack } $sendAck = ""; #todo why is this special? - CUL_HM_ProcessCmdStack($shash); } elsif($model eq "HM-CC-VD") { ################### # CMD:8202 SRC:13F251 DST:15B50D 010100002A # status ACK to controlling HM-CC-TC if($msgType eq "02" && $p =~ m/^(..)(..)(..)(..)/) {#subtype+chn+value+err - my ( $vp, $st) = - (hex($3), hex($4)); + my ($chn,$vp, $err) = ($2,hex($3), hex($4)); $vp = int($vp)/2; # valve position in % push @event, "actuator:$vp %"; + $shash = $modules{CUL_HM}{defptr}{"$src$chn"} + if($modules{CUL_HM}{defptr}{"$src$chn"}); + + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $err)|$err); # all error,only one goto normal + $shash->{helper}{addVal} = $err; #store to handle changes # Status-Byte Auswertung - push @event, "motor:opening" if($st&0x10); - push @event, "motor:closing" if($st&0x20); - push @event, "motor:blocked" if($st&0x06) == 2; - push @event, "motor:loose" if($st&0x06) == 4; - push @event, "motor:adjusting range too small" if($st&0x06) == 6; - push @event, "motor:ok" if($st&0x06) == 0; - push @event, "battery:". (($st&0x08)?"low":"ok"); + my $stErr = ($err >>1) & 0x7; + if ($cmpVal&0x0E){# report bad always, good only once + if (!$stErr){#remove both conditions + push @event, "battery:ok"; + push @event, "motorErr:ok"; + } + else{ + push @event, "motorErr:blocked" if($stErr == 1); + push @event, "motorErr:loose" if($stErr == 2); + push @event, "motorErr:adjusting range too small" if($stErr == 3); + push @event, "battery:low" if($stErr == 4); + } + } + push @event, "motor:opening" if(($err&0x30) == 0x10); + push @event, "motor:closing" if(($err&0x30) == 0x20); + push @event, "motor:stop" if(($err&0x30) == 0x00); } # CMD:A010 SRC:13F251 DST:5D24C9 0401 00000000 05 09:00 0A:07 00:00 @@ -576,8 +587,7 @@ CUL_HM_Parse($$) #list 5 is channel-dependant not link dependant # => Link discriminator (00000000) is fixed elsif($msgType eq "10" && $p =~ m/^0401000000000509(..)0A(..)/) { - my ( $of, $vep) = - (hex($1), hex($2)); + my ( $of, $vep) = (hex($1), hex($2)); push @event, "valve error position:$vep %"; push @event, "ValveOffset $dname: $of %"; } @@ -623,11 +633,14 @@ CUL_HM_Parse($$) if (($msgType eq "02" && $p =~ m/^01/) || # handle Ack_Status ($msgType eq "10" && $p =~ m/^06/)) { # or Info_Status message here - my ($subType,$chn,$level,$addVal) = ($1,$2,$3,hex($4)) + my ($subType,$chn,$level,$err) = ($1,$2,$3,hex($4)) if($p =~ m/^(..)(..)(..)(..)/); # Multi-channel device: Use channel if defined $shash = $modules{CUL_HM}{defptr}{"$src$chn"} if($modules{CUL_HM}{defptr}{"$src$chn"}); + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $err)|$err); # all error,only one goto normal + $shash->{helper}{addVal} = $err; #store to handle changes my $val = hex($level)/2; $val = ($val == 100 ? "on" : ($val == 0 ? "off" : "$val %")); @@ -644,12 +657,13 @@ CUL_HM_Parse($$) $eventName = "motor" if($st eq "blindActuator"); $eventName = "dim" if($st eq "dimmer"); my $action; #determine action - push @event, "$eventName:up:$val" if($addVal&0x10);# see HM-CC-VDstates - push @event, "$eventName:down:$val" if($addVal&0x20);# align names - push @event, "$eventName:stop:$val" if($addVal&0x40 || (($addVal == 0) && - ($st ne "switch"))); - push @event, "battery:" . (($addVal&0x80) ? "low" : "ok" ) - if($model eq "HM-LC-SW1-BA-PCB"); + if ($st ne "switch"){ + push @event, "$eventName:up:$val" if(($err&0x30) == 0x10); + push @event, "$eventName:down:$val" if(($err&0x30) == 0x20); + push @event, "$eventName:stop:$val" if(($err&0x30) == 0x00); + } + push @event, "battery:" . (($err&0x80) ? "low" : "ok" ) + if(($model eq "HM-LC-SW1-BA-PCB")&&($cmpVal&0x80)); push @event, "state:$val"; } @@ -660,10 +674,13 @@ CUL_HM_Parse($$) my $buttonID = $buttonField&0x3f;# only 6 bit are valid my $btnName; my $state = ""; - my $chnHash = $modules{CUL_HM}{defptr}{$src.uc(sprintf("%02x",$buttonID))}; + my $chnHash = $modules{CUL_HM}{defptr}{$src.uc(sprintf("%02x",$buttonID))}; + if ($chnHash){# use userdefined name - ignore this irritating on-off naming $btnName = $chnHash->{NAME}; - }else{# Button not defined, use default naming + } + else{# Button not defined, use default naming + $chnHash = $shash; if ($st eq "swi"){#maintain history for event naming $btnName = "Btn$buttonField"; }else{ @@ -681,13 +698,20 @@ CUL_HM_Parse($$) $shash->{BNOCNT}+=1; $state .= "Long" .($msgFlag eq "A0" ? "Release" : ""). " ".$shash->{BNOCNT}."-".$cmd."-"; - }else{ + } + else{ $state .= ($st eq "swi")?"toggle":"Short";#swi only support toggle } - + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $buttonField)|$buttonField); # all error,only one goto normal + $shash->{helper}{addVal} = $buttonField; #store to handle changes + push @event,"battery:". (($buttonField&0x80)?"low":"ok")if($cmpVal&0x80); push @event, "state:$btnName $state$target"; - push @event, "battery:". (($buttonField & 0x80) ? "low" : "ok"); #By peterp - if($id eq $dst && $msgType ne "02") { # Send Ack + + $chnHash->{STATE} = $state.$target; #handle channel manually, others to device + DoTrigger($btnName,"$state$target"); + + if($id eq $dst) { # Send Ack CUL_HM_SendCmd($shash, $msgcnt."8002".$id.$src."0101". ($state =~ m/on/?"C8":"00")."00", 1, 0);#todo why that??? # did someone simulate an actor? @@ -724,7 +748,7 @@ CUL_HM_Parse($$) my $devState = $shash->{READINGS}{color}{VAL}; $devState = "00000000" if (!$devState); if($parse eq "powerOn"){# reset LEDs after power on - CUL_HM_PushCmdStack($shash,sprintf("++A011%s%s8100%s",$id,$src,$devState)); + CUL_HM_PushCmdStack($shash,'++A011'.$id.$src.'%s%s8100'.$devState); CUL_HM_ProcessCmdStack($shash); } else {# just update datafields in storage @@ -756,16 +780,18 @@ CUL_HM_Parse($$) } } elsif($st eq "motionDetector") { ##################################### - # Code with help of Bassem my $state; if($msgType eq "10" && $p =~ m/^06..(..)(..)/) {#InfoLevel - my $addVal; - ($state, $addVal) = ($1, hex($2)); + my $err; + ($state, $err) = ($1, hex($2)); + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $err)|$err); # all error,only one goto normal + $shash->{helper}{addVal} = $err;#store to handle changes push @event, "brightness:".hex($state); push @event, "state:alive"; - push @event, "cover:". (($addVal&0x0E eq "00")?"closed":"open"); - push @event, "battery:". (($addVal&0x80) ?"low" :"ok" ); + push @event, "cover:". (($err&0x0E)?"open" :"closed") if ($cmpVal&0x0E); + push @event, "battery:". (($err&0x80)?"low" :"ok" ) if ($cmpVal&0x80); } elsif($msgType eq "41" && $p =~ m/^..(......)/) { $state = $1; @@ -815,18 +841,22 @@ CUL_HM_Parse($$) #AckStatus: msgType=0x02 p(..)(..)(..)(..) subty=01, chn, state,err (3bit) if($p =~ m/^(..)(..)(..)(..)?$/) { - my ($b12, $b34, $state, $err) = ($1, $2, $3, $4); + my ($b12, $b34, $state, $err) = ($1, $2, $3, hex($4)); my $chn = ($msgType eq "41")?$b12:$b34; - my $addState = ""; + # Multi-channel device: Switch to channel hash + $shash = $modules{CUL_HM}{defptr}{"$src$chn"} + if($modules{CUL_HM}{defptr}{"$src$chn"}); if ($msgType eq "02"||$msgType eq "10"){ + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $err)|$err); # all error,only one goto normal + $shash->{helper}{addVal} = $err;#store to handle changes + push @event, "alive:yes"; - if($err) { - push @event, "battery:". ((hex($err) & 0x80) ? "low" : "ok"); - if (!$model eq "HM-SEC-WDS"){ - $addState =" cover: ".(($err =~ m/^.E/) ? "open" : "closed"); - } - } + push @event, "battery:". (($err&0x80)?"low" :"ok" ) if($cmpVal&0x80); + if (!$model eq "HM-SEC-WDS"){ + push @event, "cover:". (($err&0x0E)?"open" :"closed")if($cmpVal&0x0E); + } } my %txt; @@ -835,17 +865,13 @@ CUL_HM_Parse($$) if($model eq "HM-SEC-WDS"); my $txt = $txt{$state}; $txt = "unknown:$state" if(!$txt); - push @event, "state:$txt$addState"; + push @event, "state:$txt"; push @event, "contact:$txt$target"; - # Multi-channel device: Switch to channel hash - $shash = $modules{CUL_HM}{defptr}{"$src$chn"} - if($modules{CUL_HM}{defptr}{"$src$chn"}); CUL_HM_SendCmd($shash, $msgcnt."8002$id$src${chn}00",1,0) # Send Ack if($id eq $dst); $sendAck = ""; #todo why is this special? } - push @event, "3SSunknownMsg:$p" if(!@event); } elsif($model eq "HM-WDC7000" ||$st eq "THSensor") { #################### @@ -903,27 +929,33 @@ CUL_HM_Parse($$) if(($msgType eq "10" && $p =~ m/^06/) || ($msgType eq "02" && $p =~ m/^01/)) { - $p =~ m/^....(..)(..)/; - my ($val, $err) = (hex($1), hex($2)); + $p =~ m/^..(..)(..)(..)/; + my ($chn,$val, $err) = ($1,hex($2), hex($3)); + $shash = $modules{CUL_HM}{defptr}{"$src$chn"} + if($modules{CUL_HM}{defptr}{"$src$chn"}); + + my $cmpVal = defined($shash->{helper}{addVal})?$shash->{helper}{addVal}:0xff; + $cmpVal = (($cmpVal ^ $err)|$err); # all error,only one goto normal + $shash->{helper}{addVal} = $err; #store to handle changes - my $error = 'none'; my $stErr = ($err >>1) & 0x7; - $error = 'motor aborted' if ($stErr == 2); + my $error = 'unknown_'.$stErr; + $error = 'motor aborted' if ($stErr == 2); $error = 'clutch failure' if ($stErr == 1); + $error = 'none' if ($stErr == 0); - push @event, "unknown:" . ( ($err & 0x40) ? "40" : ""); # Todo: unknown error? - push @event, "battery:". (($err & 0x80) ? "low" : "ok"); - push @event, "lock:" . (($val == 1) ? "unlocked" : "locked"); - - push @event, "uncertain:" . (($err & 0x30) ? "yes" : "no"); + push @event, "unknown:" . (($err&0x40) ? "40" :"") if($cmpVal&0x40); + push @event, "battery:". (($err&0x80) ? "low":"ok") if($cmpVal&0x80); + push @event, "uncertain:" .(($err&0x30) ? "yes":"no") if($cmpVal&0x30); + push @event, "error:" . ($error) if($cmpVal&0x0E); my $state = ($err & 0x30) ? " (uncertain)" : ""; + push @event, "lock:" . (($val == 1) ? "unlocked" : "locked"); push @event, "state:" . (($val == 1) ? "unlocked" : "locked") . $state; } } else{##################################### ; # no one wants the message } - #------------ send default ACK if not applicable------------------ # ack if we are destination, anyone did accept the message (@event) # parser did not supress @@ -944,23 +976,19 @@ CUL_HM_Parse($$) if($vn eq "state") { if($shash->{cmdSent} && $shash->{cmdSent} eq $vv) { delete($shash->{cmdSent}); # Skip second "on/off" after our own command - } else { $shash->{STATE} = $vv; push @changed, $vv; } - } else { push @changed, "$vn: $vv"; - } $shash->{READINGS}{$vn}{TIME} = $tn; $shash->{READINGS}{$vn}{VAL} = $vv; } $shash->{CHANGED} = \@changed; - return $shash->{NAME} ;# shash could have changed to support channel } @@ -975,100 +1003,102 @@ CUL_HM_Parse($$) # min: minimal input value # max: maximal input value # c: conversion, will point to a routine for calculation - # uc: unconversion, revert conversion to make data visible + # f: factor to be used if c = 'factor' # u: unit for description # t: txt description # caution: !!! bitfield setting will zero the rest of the register # if less then a byte !!!!!!!!!!! my %culHmRegDefine = ( - intKeyVisib =>{a=> 2.7,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"visibility of internal keys"}, + intKeyVisib =>{a=> 2.7,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>"" ,f=>"" ,u=>"bool",t=>"visibility of internal keys"}, #blindActuator mainly - driveUp =>{a=> 13.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'$d=$d*10' ,uc=>'$d=$d/10' ,u=>"s" ,t=>"drive time up"}, - driveDown =>{a=> 11.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'$d=$d*10' ,uc=>'$d=$d/10' ,u=>"s" ,t=>"drive time up"}, - driveTurn =>{a=> 15.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'$d=$d*10' ,uc=>'$d=$d/10' ,u=>"s" ,t=>"fliptime up <=>down"}, - maxTimeFSh =>{a=> 29.0,s=>1.0,l=>3,min=>0 ,max=>25.4 ,c=>'$d=$d*10' ,uc=>'$d=$d/10' ,u=>"s" ,t=>"Short:max time first direction"}, - maxTimeFLg =>{a=>157.0,s=>1.0,l=>3,min=>0 ,max=>25.4 ,c=>'$d=$d*10' ,uc=>'$d=$d/10' ,u=>"s" ,t=>"Long:max time first direction"}, - #remote mainly - backOnTime =>{a=> 14.0,s=>1.0,l=>0,min=>0 ,max=>255 ,c=>"" ,uc=>"" ,u=>"s" ,t=>"Backlight On Time"}, - backAtEvnt =>{a=> 13.5,s=>0.3,l=>0,min=>0 ,max=>8 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Backlight at key=4,motion=2,charge=1"}, - longPress =>{a=> 4.4,s=>0.4,l=>1,min=>0.3,max=>1.8 ,c=>'$d=$d*10-3' ,uc=>'$d=($d+3)/10' ,u=>"s" ,t=>"time to detect key long press"}, - msgShowTime =>{a=> 45.0,s=>1.0,l=>1,min=>0.0,max=>120 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"s" ,t=>"Message show time(RC19). 0=always on"}, - #dimmer mainly - ovrTempLvl =>{a=> 50.0,s=>1.0,l=>1,min=>30 ,max=>100 ,c=>"" ,uc=>"" ,u=>"degC",t=>"overtemperatur level"}, - redTempLvl =>{a=> 52.0,s=>1.0,l=>1,min=>30 ,max=>100 ,c=>"" ,uc=>"" ,u=>"degC",t=>"reduced temperatur recover"}, - redLvl =>{a=> 53.0,s=>1.0,l=>1,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"reduced power level"}, + driveUp =>{a=> 13.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'factor' ,f=>10 ,u=>'s' ,t=>"drive time up"}, + driveDown =>{a=> 11.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'factor' ,f=>10 ,u=>'s' ,t=>"drive time up"}, + driveTurn =>{a=> 15.0,s=>2.0,l=>1,min=>0 ,max=>6000.0,c=>'factor' ,f=>10 ,u=>'s' ,t=>"fliptime up <=>down"}, + maxTimeFSh =>{a=> 29.0,s=>1.0,l=>3,min=>0 ,max=>25.4 ,c=>'factor' ,f=>10 ,u=>'s' ,t=>"Short:max time first direction"}, + maxTimeFLg =>{a=>157.0,s=>1.0,l=>3,min=>0 ,max=>25.4 ,c=>'factor' ,f=>10 ,u=>'s' ,t=>"Long:max time first direction"}, + #remote mainly + language =>{a=> 7.0,s=>1.0,l=>0,min=>0 ,max=>1 ,c=>"" ,f=>"" ,u=>'' ,t=>"Language 0:English, 1:German"}, + stbyTime =>{a=> 14.0,s=>1.0,l=>0,min=>1 ,max=>99 ,c=>"" ,f=>"" ,u=>'s' ,t=>"Standby Time"}, + backOnTime =>{a=> 14.0,s=>1.0,l=>0,min=>0 ,max=>255 ,c=>"" ,f=>"" ,u=>'s' ,t=>"Backlight On Time"}, + backAtEvnt =>{a=> 13.5,s=>0.3,l=>0,min=>0 ,max=>8 ,c=>"" ,f=>"" ,u=>'' ,t=>"Backlight at key=4,motion=2,charge=1"}, + longPress =>{a=> 4.4,s=>0.4,l=>1,min=>0.3,max=>1.8 ,c=>'m10s3' ,f=>"" ,u=>'s' ,t=>"time to detect key long press"}, + msgShowTime =>{a=> 45.0,s=>1.0,l=>1,min=>0.0,max=>120 ,c=>'factor' ,f=>2 ,u=>'s' ,t=>"Message show time(RC19). 0=always on"}, + #dimmer mainly + ovrTempLvl =>{a=> 50.0,s=>1.0,l=>1,min=>30 ,max=>100 ,c=>"" ,f=>"" ,u=>"degC",t=>"overtemperatur level"}, + redTempLvl =>{a=> 52.0,s=>1.0,l=>1,min=>30 ,max=>100 ,c=>"" ,f=>"" ,u=>"degC",t=>"reduced temperatur recover"}, + redLvl =>{a=> 53.0,s=>1.0,l=>1,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>"%" ,t=>"reduced power level"}, - OnDlySh =>{a=> 6.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:on delay "}, - OnTimeSh =>{a=> 7.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:on time"}, - OffDlySh =>{a=> 8.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:off delay"}, - OffTimeSh =>{a=> 9.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:off time"}, + OnDlySh =>{a=> 6.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:on delay "}, + OnTimeSh =>{a=> 7.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:on time"}, + OffDlySh =>{a=> 8.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:off delay"}, + OffTimeSh =>{a=> 9.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:off time"}, - OffLevelSh =>{a=> 15.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:PowerLevel Off"}, - OnMinLevelSh =>{a=> 16.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:minimum PowerLevel"}, - OnLevelSh =>{a=> 17.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:PowerLevel on"}, + OffLevelSh =>{a=> 15.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:PowerLevel Off"}, + OnMinLevelSh =>{a=> 16.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:minimum PowerLevel"}, + OnLevelSh =>{a=> 17.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:PowerLevel on"}, - rampSstepSh =>{a=> 18.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:rampStartStep"}, - rampOnTimeSh =>{a=> 19.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:rampOnTime"}, - rampOffTimeSh=>{a=> 20.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Short:rampOffTime"}, - dimMinLvlSh =>{a=> 21.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:dimMinLevel"}, - dimMaxLvlSh =>{a=> 22.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:dimMaxLevel"}, - dimStepSh =>{a=> 23.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Short:dimStep"}, + rampSstepSh =>{a=> 18.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:rampStartStep"}, + rampOnTimeSh =>{a=> 19.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:rampOnTime"}, + rampOffTimeSh=>{a=> 20.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Short:rampOffTime"}, + dimMinLvlSh =>{a=> 21.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:dimMinLevel"}, + dimMaxLvlSh =>{a=> 22.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:dimMaxLevel"}, + dimStepSh =>{a=> 23.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Short:dimStep"}, - OnDlyLg =>{a=>134.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:on delay"}, - OnTimeLg =>{a=>135.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:on time"}, - OffDlyLg =>{a=>136.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:off delay"}, - OffTimeLg =>{a=>137.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:off time"}, + OnDlyLg =>{a=>134.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:on delay"}, + OnTimeLg =>{a=>135.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:on time"}, + OffDlyLg =>{a=>136.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:off delay"}, + OffTimeLg =>{a=>137.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:off time"}, - OffLevelLg =>{a=>143.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:PowerLevel Off"}, - OnMinLevelLg =>{a=>144.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:minimum PowerLevel"}, - OnLevelLg =>{a=>145.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:PowerLevel on"}, + OffLevelLg =>{a=>143.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:PowerLevel Off"}, + OnMinLevelLg =>{a=>144.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:minimum PowerLevel"}, + OnLevelLg =>{a=>145.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:PowerLevel on"}, - rampSstepLg =>{a=>146.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:rampStartStep"}, - rampOnTimeLg =>{a=>147.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:off delay"}, - rampOffTimeLg=>{a=>148.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'$d=CUL_HM_fltCvT($d)',uc=>'$d=CUL_HM_CvTflt($d)',u=>"s" ,t=>"Long:off delay"}, - dimMinLvlLg =>{a=>149.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:dimMinLevel"}, - dimMaxLvlLg =>{a=>150.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:dimMaxLevel"}, - dimStepLg =>{a=>151.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"%" ,t=>"Long:dimStep"}, + rampSstepLg =>{a=>146.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:rampStartStep"}, + rampOnTimeLg =>{a=>147.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:off delay"}, + rampOffTimeLg=>{a=>148.0,s=>1.0,l=>3,min=>0 ,max=>111600,c=>'fltCvT' ,f=>'' ,u=>'s' ,t=>"Long:off delay"}, + dimMinLvlLg =>{a=>149.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:dimMinLevel"}, + dimMaxLvlLg =>{a=>150.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:dimMaxLevel"}, + dimStepLg =>{a=>151.0,s=>1.0,l=>3,min=>0 ,max=>100 ,c=>'factor' ,f=>2 ,u=>'%' ,t=>"Long:dimStep"}, #tc - BacklOnTime =>{a=>5.0 ,s=>0.6,l=>0,min=>1 ,max=>25 ,c=>"" ,uc=>"" ,u=>"s" ,t=>"Backlight ontime"}, - BacklOnMode =>{a=>5.6 ,s=>0.2,l=>0,min=>0 ,max=>1 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"bool",t=>"Backlight mode 0=OFF, 1=AUTO"}, - BtnLock =>{a=>15 ,s=>1 ,l=>0,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"Button Lock 0=OFF, 1=Lock"}, - DispTempHum =>{a=>1.0 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"0=temp ,1=temp-humidity"}, - DispTempInfo =>{a=>1.1 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"0=actual ,1=setPoint"}, - DispTempUnit =>{a=>1.2 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"0=Celsius ,1=Fahrenheit"}, - MdTempReg =>{a=>1.3 ,s=>0.2,l=>5,min=>0 ,max=>3 ,c=>"" ,uc=>"" ,u=>"" ,t=>"0=MANUAL ,1=AUTO ,2=CENTRAL ,3=PARTY"}, - MdTempValve =>{a=>2.6 ,s=>0.2,l=>5,min=>0 ,max=>2 ,c=>"" ,uc=>"" ,u=>"" ,t=>"0=auto ,1=close ,2=open"}, - TempComfort =>{a=>3 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"C" ,t=>"confort temp value"}, - TempLower =>{a=>4 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"C" ,t=>"confort temp value"}, - PartyEndDay =>{a=>98 ,s=>1 ,l=>6,min=>0 ,max=>200 ,c=>"" ,uc=>"" ,u=>"d" ,t=>"Party end Day"}, - PartyEndMin =>{a=>97.7 ,s=>1 ,l=>6,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"min" ,t=>"Party end 0=:00, 1=:30"}, - PartyEndHr =>{a=>97 ,s=>0.6,l=>6,min=>0 ,max=>23 ,c=>"" ,uc=>"" ,u=>"h" ,t=>"Party end Hour"}, - TempParty =>{a=>6 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"C" ,t=>"Temperature for Party"}, - TempWinOpen =>{a=>5 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'$d=$d*2' ,uc=>'$d=$d/2' ,u=>"C" ,t=>"Temperature for Win open !chan 3 only!"}, - DecalDay =>{a=>1.5 ,s=>0.3,l=>5,min=>0 ,max=>7 ,c=>"" ,uc=>"" ,u=>"d" ,t=>"Decalc weekday 0=Sat...6=Fri"}, - DecalHr =>{a=>8.3 ,s=>0.5,l=>5,min=>0 ,max=>23 ,c=>"" ,uc=>"" ,u=>"h" ,t=>"Decalc hour"}, - DecalMin =>{a=>8 ,s=>0.5,l=>5,min=>0 ,max=>50 ,c=>'$d=$d/10' ,uc=>'$d=$d/10' ,u=>"min" ,t=>"Decalc min"}, + BacklOnTime =>{a=>5.0 ,s=>0.6,l=>0,min=>1 ,max=>25 ,c=>"" ,f=>'' ,u=>'s' ,t=>"Backlight ontime"}, + BacklOnMode =>{a=>5.6 ,s=>0.2,l=>0,min=>0 ,max=>1 ,c=>'factor' ,f=>2 ,u=>'bool',t=>"Backlight mode 0=OFF, 1=AUTO"}, + BtnLock =>{a=>15 ,s=>1 ,l=>0,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"Button Lock 0=OFF, 1=Lock"}, + DispTempHum =>{a=>1.0 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"0=temp ,1=temp-humidity"}, + DispTempInfo =>{a=>1.1 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"0=actual ,1=setPoint"}, + DispTempUnit =>{a=>1.2 ,s=>0.1,l=>5,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"0=Celsius ,1=Fahrenheit"}, + MdTempReg =>{a=>1.3 ,s=>0.2,l=>5,min=>0 ,max=>3 ,c=>'' ,f=>'' ,u=>'' ,t=>"0=MANUAL ,1=AUTO ,2=CENTRAL ,3=PARTY"}, + MdTempValve =>{a=>2.6 ,s=>0.2,l=>5,min=>0 ,max=>2 ,c=>'' ,f=>'' ,u=>'' ,t=>"0=auto ,1=close ,2=open"}, + TempComfort =>{a=>3 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'factor' ,f=>2 ,u=>'C' ,t=>"confort temp value"}, + TempLower =>{a=>4 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'factor' ,f=>2 ,u=>'C' ,t=>"confort temp value"}, + PartyEndDay =>{a=>98 ,s=>1 ,l=>6,min=>0 ,max=>200 ,c=>'' ,f=>'' ,u=>'d' ,t=>"Party end Day"}, + PartyEndMin =>{a=>97.7 ,s=>1 ,l=>6,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'min' ,t=>"Party end 0=:00, 1=:30"}, + PartyEndHr =>{a=>97 ,s=>0.6,l=>6,min=>0 ,max=>23 ,c=>'' ,f=>'' ,u=>'h' ,t=>"Party end Hour"}, + TempParty =>{a=>6 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'factor' ,f=>2 ,u=>'C' ,t=>"Temperature for Party"}, + TempWinOpen =>{a=>5 ,s=>0.6,l=>5,min=>6 ,max=>30 ,c=>'factor' ,f=>2 ,u=>'C' ,t=>"Temperature for Win open !chan 3 only!"}, + DecalDay =>{a=>1.5 ,s=>0.3,l=>5,min=>0 ,max=>7 ,c=>'' ,f=>'' ,u=>'d' ,t=>"Decalc weekday 0=Sat...6=Fri"}, + DecalHr =>{a=>8.3 ,s=>0.5,l=>5,min=>0 ,max=>23 ,c=>'' ,f=>'' ,u=>'h' ,t=>"Decalc hour"}, + DecalMin =>{a=>8 ,s=>0.3,l=>5,min=>0 ,max=>50 ,c=>'factor' ,f=>0.1 ,u=>'min' ,t=>"Decalc min"}, #output Unit - ActTypeSh =>{a=>36 ,s=>1 ,l=>3,min=>0 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Short:Action type(LED or Tone)"}, - ActNumSh =>{a=>37 ,s=>1 ,l=>3,min=>1 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Short:Action Number"}, - IntenseSh =>{a=>47 ,s=>1 ,l=>3,min=>10 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Short:Volume - Tone channel only!"}, + ActTypeSh =>{a=>36 ,s=>1 ,l=>3,min=>0 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Short:Action type(LED or Tone)"}, + ActNumSh =>{a=>37 ,s=>1 ,l=>3,min=>1 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Short:Action Number"}, + IntenseSh =>{a=>47 ,s=>1 ,l=>3,min=>10 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Short:Volume - Tone channel only!"}, - ActTypeLg =>{a=>164 ,s=>1 ,l=>3,min=>0 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Long:Action type(LED or Tone)"}, - ActNumLg =>{a=>165 ,s=>1 ,l=>3,min=>1 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Long:Action Number"}, - IntenseLg =>{a=>175 ,s=>1 ,l=>3,min=>10 ,max=>255 ,c=>"" ,uc=>"" ,u=>"" ,t=>"Long:Volume - Tone channel only!"}, + ActTypeLg =>{a=>164 ,s=>1 ,l=>3,min=>0 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Long:Action type(LED or Tone)"}, + ActNumLg =>{a=>165 ,s=>1 ,l=>3,min=>1 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Long:Action Number"}, + IntenseLg =>{a=>175 ,s=>1 ,l=>3,min=>10 ,max=>255 ,c=>'' ,f=>'' ,u=>'' ,t=>"Long:Volume - Tone channel only!"}, # keymatic secific register - signal =>{a=>3.4 ,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"Confirmation beep 0=OFF, 1=On"}, - signalTone =>{a=>3.6 ,s=>0.2,l=>0,min=>0 ,max=>3 ,c=>"" ,uc=>"" ,u=>"%" ,t=>"0=low 1=mid 2=high 3=very high"}, - keypressSignal=>{a=>3.0 ,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"Keypress beep 0=OFF, 1=On"}, - holdTime =>{a=>20 ,s=>1, l=>1,min=>0 ,max=>8.16 ,c=>'d=$d*31.25' ,uc=>'d=$d/31.25' ,u=>"s", t=>"Holdtime for door opening"}, - setupDir =>{a=>22 ,s=>0.1,l=>1,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"Rotation direction for locking. ,0=right, 1=left"}, - setupPosition =>{a=>23 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'$d=$d*15' ,uc=>'$d=$d/15' ,u=>"%" ,t=>"Rotation angle neutral position"}, - angelOpen =>{a=>24 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'$d=$d*15' ,uc=>'$d=$d/15' ,u=>"%" ,t=>"Door opening angle"}, - angelMax =>{a=>25 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'$d=$d*15' ,uc=>'$d=$d/15' ,u=>"%" ,t=>"Angle locked"}, - angelLocked =>{a=>26 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'$d=$d*15' ,uc=>'$d=$d/15' ,u=>"%" ,t=>"Angle Locked position"}, - ledFlashUnlocked=>{a=>31.3,s=>0.1,l=>1,min=>0,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"1=LED blinks when not locked"}, - ledFlashLocked=>{a=>31.6,s=>0.1,l=>1,min=>0 ,max=>1 ,c=>"" ,uc=>"" ,u=>"bool",t=>"1=LED blinks when locked"}, + signal =>{a=>3.4 ,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"Confirmation beep 0=OFF, 1=On"}, + signalTone =>{a=>3.6 ,s=>0.2,l=>0,min=>0 ,max=>3 ,c=>'' ,f=>'' ,u=>'%' ,t=>"0=low 1=mid 2=high 3=very high"}, + keypressSignal=>{a=>3.0 ,s=>0.1,l=>0,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"Keypress beep 0=OFF, 1=On"}, + holdTime =>{a=>20 ,s=>1, l=>1,min=>0 ,max=>8.16 ,c=>'factor' ,f=>31.25 ,u=>'s' ,t=>"Holdtime for door opening"}, + setupDir =>{a=>22 ,s=>0.1,l=>1,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"Rotation direction for locking. ,0=right, 1=left"}, + setupPosition =>{a=>23 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'factor' ,f=>15 ,u=>'%' ,t=>"Rotation angle neutral position"}, + angelOpen =>{a=>24 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'factor' ,f=>15 ,u=>'%' ,t=>"Door opening angle"}, + angelMax =>{a=>25 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'factor' ,f=>15 ,u=>'%' ,t=>"Angle locked"}, + angelLocked =>{a=>26 ,s=>1 ,l=>1,min=>0 ,max=>3000 ,c=>'factor' ,f=>15 ,u=>'%' ,t=>"Angle Locked position"}, + ledFlashUnlocked=>{a=>31.3,s=>0.1,l=>1,min=>0,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"1=LED blinks when not locked"}, + ledFlashLocked=>{a=>31.6,s=>0.1,l=>1,min=>0 ,max=>1 ,c=>'' ,f=>'' ,u=>'bool',t=>"1=LED blinks when locked"}, ); my %culHmRegGeneral = ( intKeyVisib=>1, @@ -1116,12 +1146,15 @@ my %culHmRegSupported = ( angelOpen =>1,angelMax =>1,angelLocked =>1, ledFlashUnlocked=>1,ledFlashLocked=>1, }, + dis4=> {language => 1,stbyTime => 1, #todo insert correct name + }, + ); ##--------------- Conversion routines for register settings my %fltCvT = (0.1=>3.1,1=>31,5=>155,10=>310,60=>1860,300=>9300, 600=>18600,3600=>111600); sub -CUL_HM_fltCvT($) #float config time +CUL_HM_fltCvT($) # float -> config time { my ($inValue) = @_; my $exp = 0; @@ -1169,14 +1202,16 @@ CUL_HM_Get($@) $devName = $name if (!$devName); # we control ourself if no chief available my $st = AttrVal($devName, "subType", ""); my $md = AttrVal($devName, "model", ""); + my $mId = CUL_HM_getMId($hash); + my $rxType = CUL_HM_getRxType($hash); + my $class = AttrVal($devName, "hmClass", "");#relevant is the chief my $cmd = $a[1]; my $dst = $hash->{DEF}; - my $chn = "01"; - if(length($dst) == 8) { # shadow switch device for multi-channel switch - $chn = substr($dst, 6, 2); - $dst = substr($dst, 0, 6); - } + my $isChannel = (length($dst) == 8)?"true":""; + my $chn = ($isChannel)?substr($dst,6,2):"01"; + $dst = substr($dst,0,6); + my $devHash = CUL_HM_getDeviceHash($hash); my $h = $culHmGlobalGets{$cmd}; $h = $culHmSubTypeGets{$st}{$cmd} if(!defined($h) && $culHmSubTypeGets{$st}); @@ -1201,46 +1236,15 @@ CUL_HM_Get($@) #----------- now start processing -------------- if($cmd eq "param") { ###################################################### - my $entityName = $name; - my $entityHash = $hash; - foreach (1,2){ #search channel and device - foreach my $entAttr (keys %{$attr{$entityName}}){ - if (ref($attr{$entAttr}) eq "HASH"){ - foreach my $entAttr2 (keys %{{$attr{$entityName}{$entAttr}}}){ - return $attr{$entityName}{$entAttr}{$entAttr2} if ($a[2] eq $entAttr2); - } - } - else{ - return $attr{$entityName}{$entAttr} if ($a[2] eq $entAttr); - } - } - foreach my $entAttr (keys %{$entityHash}){ - if (ref($entityHash->{$entAttr}) eq "HASH"){ - foreach my $entAttr2 (keys %{$entityHash->{$entAttr}}){ - if ($entAttr eq "READINGS" && $entAttr2 eq $a[2]){ - return $entityHash->{$entAttr}{$entAttr2}{VAL}; - } - if (ref($entityHash->{$entAttr}{$entAttr2}) eq "HASH"){ - foreach my $entAttr3 (keys %{$entityHash->{$entAttr}{$entAttr2}}){ - return $entityHash->{$entAttr}{$entAttr2}{$entAttr3} - if ($a[2] eq $entAttr3); - } - } - else { - return $entityHash->{$entAttr}{$entAttr2} if ($a[2] eq $entAttr2); - } - } - } - else{ - return $entityHash->{$entAttr} if ($a[2] eq $entAttr); - } - } - last if ($entityName eq $devName); - $entityName = $devName; # search deivce if nothing was found in channel - $entityHash = $devHash; - } - - return "undefined"; + my $val; + $val = AttrVal($name, $a[2], ""); + $val = $hash->{READINGS}{$a[2]}{VAL} if (!defined($val) && $hash->{READINGS}{$a[2]}); + $val = AttrVal($devName, $a[2], "") if (!defined($val)); + $val = $devHash->{READINGS}{$a[2]}{VAL} if (!defined($val) && $devHash->{READINGS}{$a[2]}); + $val = $hash->{helper}{$a[2]} if (!defined($val)); + $val = $devHash->{helper}{$a[2]} if (!defined($val)); + + return (defined ($val))?$val:"undefined"; } elsif($cmd eq "reg") { ##################################################### my (undef,undef,$addr,$list,$peerId) = @a; @@ -1261,10 +1265,9 @@ CUL_HM_Get($@) return $info; } - Log GetLogLevel($name,2), "CUL_HM get $name " . join(" ", @a[1..$#a]); + Log GetLogLevel($name,4), "CUL_HM get $name " . join(" ", @a[1..$#a]); - CUL_HM_ProcessCmdStack($devHash) - if(!$attr{$name}{rxType}||$attr{$name}{rxType}=~ m/burst/); + CUL_HM_ProcessCmdStack($devHash) if ($rxType & 0x03);#burst/all return ""; } ################################### @@ -1282,6 +1285,7 @@ my %culHmGlobalSets = ( getConfig => "", regSet =>" ... ", virtual =>"", + actiondetect =>"", ); my %culHmSubTypeSets = ( switch => @@ -1302,17 +1306,14 @@ my %culHmSubTypeSets = ( virtual =>"",}, #redef necessary for virtual smokeDetector => { test => "", "alarmOn"=>"", "alarmOff"=>"", }, - winMatic => - { matic => "", - read => "", - keydef => " ", - create => "" }, - - keyMatic => { - "lock"=>"", - "unlock"=>"[sec] ...", - "open"=>"[sec] ...", - "inhibit"=>"[on|off]", + winMatic =>{matic => "", + read => "", + keydef => " ", + create => "" }, + keyMatic =>{lock =>"", + unlock =>"[sec] ...", + open =>"[sec] ...", + inhibit=>"[on|off]", }, ); @@ -1355,6 +1356,56 @@ my %culHmModelSets = ( led => "[,..]", playTone => "[,..]",}, ); +############################################## +sub +CUL_HM_getMId($) +{#in: hash(chn or dev) out:model key (key for %culHmModel). + # Will store result in device helper + my ($hash) = @_; + $hash = CUL_HM_getDeviceHash($hash); + my $mId = $hash->{helper}{mId}; + if (!$mId){ + my $model = AttrVal($hash->{NAME}, "model", ""); + foreach my $mIdKey(keys%culHmModel){ + if ($culHmModel{$mIdKey}{name} && $culHmModel{$mIdKey}{name} eq $model){ + $mId = $hash->{helper}{mId} = $mIdKey; + return $mIdKey; + } + } + } + return $mId; +} +############################################## +sub +CUL_HM_getRxType($) +{ #in:hash(chn or dev) out:binary coded Rx type + # Will store result in device helper + my ($hash) = @_; + $hash = CUL_HM_getDeviceHash($hash); + no warnings; #cnvert regardless of content + my $rxtEntity = int($hash->{helper}{rxType}); + use warnings; + if (!$rxtEntity){ #at least one bit must be set + my $MId = CUL_HM_getMId($hash); + my $rxtOfModel = $culHmModel{$MId}{rxt} if ($MId && $culHmModel{$MId}{rxt}); + if ($rxtOfModel){ + $rxtEntity |= ($rxtOfModel =~ m/b/)?0x02:0;#burst + $rxtEntity |= ($rxtOfModel =~ m/c/)?0x04:0;#config + $rxtEntity |= ($rxtOfModel =~ m/w/)?0x08:0;#wakeup + } + $rxtEntity = 1 if (!$rxtEntity);#always + $hash->{helper}{rxType} = $rxtEntity; + } + return $rxtEntity; +} +############################################## +sub +CUL_HM_getFlag($) +{#msgFlag set to 'A0' for normal and 'B0' for burst devices + # currently not supported is the wakeupflag since it is hardly used + my ($hash) = @_; + return (CUL_HM_getRxType($hash) & 0x02)?"B0":"A0"; #set burst flag +} sub CUL_HM_Set($@) @@ -1365,19 +1416,20 @@ CUL_HM_Set($@) return "no set value specified" if(@a < 2); my $name = $hash->{NAME}; - my $devName = $attr{$name}{device};# get devName as protocol entity - $devName = $name if (!$devName); # we control ourself if no chief available - my $st = AttrVal($devName, "subType", ""); - my $md = AttrVal($devName, "model", ""); - my $class = AttrVal($devName, "hmClass", "");#relevant is the device + my $devName = AttrVal($name, "device" , $name);# devName as protocol entity + my $st = AttrVal($devName, "subType", ""); + my $md = AttrVal($devName, "model" , ""); + my $class = AttrVal($devName, "hmClass", "");#relevant is the device + + my $rxType = CUL_HM_getRxType($hash); + my $flag = CUL_HM_getFlag($hash); #set burst flag my $cmd = $a[1]; my $dst = $hash->{DEF}; my $isChannel = (length($dst) == 8)?"true":""; - my $chn = (length($dst) == 8)?substr($dst,6,2):"01"; + my $chn = ($isChannel)?substr($dst,6,2):"01"; $dst = substr($dst,0,6); - my $flag = ($st ne "keyMatic") ? "A0" : "B0"; - my $chash = CUL_HM_getDeviceHash($hash); + my $devHash = CUL_HM_getDeviceHash($hash); my $h = $culHmGlobalSets{$cmd} if($st ne "virtual"); $h = $culHmSubTypeSets{$st}{$cmd} if(!defined($h) && $culHmSubTypeSets{$st}); @@ -1387,7 +1439,6 @@ CUL_HM_Set($@) if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) { $cmd = "pct"; - } elsif(!defined($h)) { my @arr; @@ -1419,7 +1470,7 @@ CUL_HM_Set($@) } my $id = CUL_HM_Id($hash->{IODev}); - my $state = join(" ", @a[1..(int(@a)-1)]); + my $state = "set_".join(" ", @a[1..(int(@a)-1)]); if($cmd eq "raw") { ################################################## return "Usage: set $a[0] $cmd data [data ...]" if(@a < 3); @@ -1429,8 +1480,7 @@ CUL_HM_Set($@) } } elsif($cmd eq "reset") { ############################################ - CUL_HM_PushCmdStack($hash, - sprintf("++%s11%s%s0400",$flag,$id,$dst)); + CUL_HM_PushCmdStack($hash,"++".$flag."11".$id.$dst."0400"); } elsif($cmd eq "pair") { ############################################# return "pair is not enabled for this type of device, ". @@ -1439,8 +1489,7 @@ CUL_HM_Set($@) $state = ""; my $serialNr = AttrVal($name, "serialNr", undef); return "serialNr is not set" if(!$serialNr); - CUL_HM_PushCmdStack($hash, - sprintf("++A401%s000000010A%s", $id, unpack("H*",$serialNr))); + CUL_HM_PushCmdStack($hash,"++A401".$id."000000010A".unpack("H*",$serialNr)); $hash->{hmPairSerial} = $serialNr; } elsif($cmd eq "unpair") { ########################################### @@ -1461,42 +1510,38 @@ CUL_HM_Set($@) my $chnNo = $chnHash->{DEF}; $chnNo = substr($chnNo,6,2); $chnFound = 1 if ($chnNo eq "01"); - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s0E", - $flag,$id,$dst,$chnNo)); + CUL_HM_PushCmdStack($hash,"++".$flag.'01'.$id.$dst.$chnNo.'0E'); } } # if channel or single channel device - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s0E",$flag,$id,$dst,$chn)) + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chn.'0E') if (!$chnFound); - $state = ""; + $state = ""; } elsif($cmd eq "getpair") { ################################################## - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s00040000000000", - $flag,$id,$dst)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.'00040000000000'); $state = ""; } elsif($cmd eq "getdevicepair") { ############################################ - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s03", $flag,$id,$dst, $chn)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chn.'03'); $state = ""; } elsif($cmd eq "getConfig") { ################################################ - CUL_HM_PushCmdStack($hash, "++A112$id$dst") - if(AttrVal($name, "rxType", "0") =~ m/wakeup/); # Wakeup... - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s00040000000000", - $flag,$id,$dst)) if (length($dst) == 6); - my $chnFound; - foreach my $channel (keys %{$attr{$name}}){ - next if ($channel !~ m/^channel_/); - my $chnHash = CUL_HM_name2hash($attr{$name}{$channel}); - if ($chnHash){ - my $chnNo = $chnHash->{DEF}; - $chnNo = substr($chnNo,6,2); - $chnFound = 1 if ($chnNo eq "01"); - CUL_HM_getConfig($hash,$chnHash,$id,$dst,$chnNo); + my $chFound = 0; + if (!$isChannel){# get device with all defined channels + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.'00040000000000'); + foreach my $channel (keys %{$attr{$name}}){ + next if ($channel !~ m/^channel_/); + my $chnHash = CUL_HM_name2hash($attr{$name}{$channel}); + if ($chnHash){# 01 will be collected below + my $chnNo = $chnHash->{DEF}; + $chnNo = substr($chnNo,6,2); + CUL_HM_getConfig($hash,$chnHash,$id,$dst,$chnNo); + $chFound = 1; + } } } - # if channel or single channel device - CUL_HM_getConfig($hash,$hash,$id,$dst,$chn)if (!$chnFound); + CUL_HM_getConfig($hash,$hash,$id,$dst,$chn)if (!$chFound);#get default channel $state = ""; } elsif($cmd eq "regRaw" ||$cmd eq "getRegRaw") { ############################# @@ -1509,54 +1554,45 @@ CUL_HM_Set($@) # as of now only hex value allowed check range and convert $chn = "00" if ($list eq "00"); - if ($list =~m /0[34]/){# peer required for List 3 and 4 - my $tmpPeerID = ($peerID eq "all")?"all": CUL_HM_Name2Id($peerID); - $tmpPeerID = $dst if($peerID =~ m/^self(.*)/); - $tmpPeerID = $tmpPeerID.sprintf("%02X",$1) if($tmpPeerID eq $dst); - return "cannot identify peer:".$peerID if(!$tmpPeerID); - $peerID = $tmpPeerID.((length($peerID) == 6)?"01":""); - } - else { - $peerID = "00000000";# Peerlist only for List3 - } + my $tmpPeerID = ($peerID eq "all")?"all": CUL_HM_Name2Id($peerID); + $peerID =~ m/^self(.*)/; + $tmpPeerID = $dst.(($1)?sprintf("%02X",$1):""); + $peerID = $tmpPeerID.((length($tmpPeerID) == 6)?"01":""); + $peerID = "00000000" if (length($peerID) != 8);# no valid ID - use 0 my $peerChn = substr($peerID,6,2);# have to split chan and id $peerID = substr($peerID,0,6); if($cmd eq "getRegRaw"){ if ($list eq "00"){ - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s00040000000000", - $flag,$id,$dst)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.'00040000000000'); } - else{# for all channels assotiated + else{# other lists are per channel my $chnFound; - foreach my $channel (keys %{$attr{$name}}){ + foreach my $channel (keys %{$attr{$name}}){#all device channels next if ($channel !~ m/^channel_/); $chnFound = 1; my $chnHash = CUL_HM_name2hash($attr{$name}{$channel}); if ($chnHash){ - my $chnNo = $chnHash->{DEF}; - $chnNo = substr($chnNo,6,2); + my $chnNo = substr($chnHash->{DEF},6,2); if ($list =~m /0[34]/){#getPeers to see if list3 is available - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s03", - $flag,$id,$dst,$chnNo)); - $chnHash->{helper}{getCfgList3} = $peerID.$peerChn;#list3 regs + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chnNo.'03'); + $chnHash->{helper}{getCfgList} = $peerID.$peerChn;#list3 regs + $chnHash->{helper}{getCfgListNo} = int($list); } else{ - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s04%s%s%s", - $flag,$id,$dst,$chnNo,$peerID,$peerChn,$list)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chnNo.'04'.$peerID.$peerChn.$list); } } } if (!$chnFound){ if ($list =~m /0[34]/){#getPeers to see if list3 is available - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s03", - $flag,$id,$dst,$chn)); - $hash->{helper}{getCfgList3} = $peerID.$peerChn;#list3 regs + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chn.'03'); + $hash->{helper}{getCfgList} = $peerID.$peerChn;#list3 regs + $hash->{helper}{getCfgListNo} = int($list); } else{ - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s0400000000%s", - $flag,$id,$dst,$chn,$list)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'01'.$id.$dst.$chn.'0400000000'.$list); } } } @@ -1586,11 +1622,21 @@ CUL_HM_Set($@) return "value:".$data." out of range for Reg \"".$regName."\"" if ($data < $reg->{min} ||$data > $reg->{max}); - no strict; # convert data to register value - my $d = $data; - eval $reg->{c} if ($reg->{c}); - $data = $d; # conversion as specified - use strict; + my $conversion = $reg->{c}; + if (!$conversion){;# do nothing + } + elsif($conversion eq "factor"){# use factor + $data *= $reg->{f}; + } + elsif ($conversion eq "fltCvT"){ + $data = CUL_HM_fltCvT($data); + } + elsif($conversion eq "m10s3"){ + $data=$data*10-3; + } + else{ + return " conversion undefined - please contact admin"; + } my $addr = int($reg->{a}); # bit location later my $list = $reg->{l}; @@ -1635,14 +1681,10 @@ CUL_HM_Set($@) CUL_HM_pushConfig($hash,$id,$dst,$lChn,$peerID,$peerChn,$list,$addrData); } elsif($cmd eq "on") { ############################################### - my $headerbytes = $md eq "HM-LC-SW1-BA-PCB" ? "FF" : "A0"; # Needs Burst Headerbyte See CC1100 FM transceiver - CUL_HM_PushCmdStack($hash, - sprintf("++%s11%s%s02%sC80000", $headerbytes, $id,$dst, $chn)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'02'.$chn.'C80000'); } elsif($cmd eq "off") { ############################################## - my $headerbytes = $md eq "HM-LC-SW1-BA-PCB" ? "FF" : "A0"; # Needs Burst Headerbyte See CC1100 FM transceiver - CUL_HM_PushCmdStack($hash, - sprintf("++%s11%s%s02%s000000", $headerbytes, $id,$dst,$chn)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'02'.$chn.'000000'); } elsif($cmd eq "on-for-timer"||$cmd eq "on-till") { ########################## my (undef,undef,$duration,$edate) = @a; #date prepared extention to entdate @@ -1657,48 +1699,43 @@ CUL_HM_Set($@) } return "please enter the duration in seconds" if (!defined ($duration)); $tval = CUL_HM_encodeTime16($duration);# onTime 0.0..85825945.6, 0=forever - CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s02%sC80000%s",$id,$dst,$chn,$tval)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'02'.$chn.'C80000'.$tval); } elsif($cmd eq "toggle") { ################################################### $hash->{toggleIndex} = 1 if(!$hash->{toggleIndex}); $hash->{toggleIndex} = (($hash->{toggleIndex}+1) % 128); - CUL_HM_PushCmdStack($hash, sprintf("++A03E%s%s%s40%s%02X", $id, $dst, + CUL_HM_PushCmdStack($hash, sprintf("++%s3E%s%s%s40%s%02X",$flag,$id, $dst, $dst, $chn, $hash->{toggleIndex})); } elsif($cmd eq "lock") { ################################################### - CUL_HM_PushCmdStack($hash, sprintf("++B011%s%s800100FF",$id,$dst)); # LEVEL_SET - + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'800100FF'); # LEVEL_SET } elsif($cmd eq "unlock") { ################################################### $tval = (@a > 2) ? int($a[2]) : 0; my $delay = ($tval > 0) ? CUL_HM_encodeTime8($tval) : "FF"; # RELOCK_DELAY (FF=never) - CUL_HM_PushCmdStack($hash, sprintf("++B011%s%s800101%s",$id,$dst,$delay)); # LEVEL_SET - + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'800101'.$delay);# LEVEL_SET } elsif($cmd eq "open") { ################################################### $tval = (@a > 2) ? int($a[2]) : 0; my $delay = ($tval > 0) ? CUL_HM_encodeTime8($tval) : "FF"; # RELOCK_DELAY (FF=never) - CUL_HM_PushCmdStack($hash, sprintf("++B011%s%s8001C8%s",$id,$dst,$delay)); # OPEN + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'8001C8'.$delay);# OPEN $state = ""; } elsif($cmd eq "inhibit") { ############################################### return "$a[2] is not on or off" if($a[2] !~ m/^(on|off)$/); my $val = ($a[2] eq "on") ? "01" : "00"; - CUL_HM_PushCmdStack($hash, sprintf("++B011%s%s%s01",$id,$dst,$val)); # SET_LOCK + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.$val.'01'); # SET_LOCK $state = ""; } elsif($cmd eq "pct") { ###################################################### $a[1] = 100 if ($a[1] > 100); $tval = CUL_HM_encodeTime16((@a > 2)?$a[2]:85825945);# onTime 0.0..85825945.6, 0=forever - $rval = CUL_HM_encodeTime16((@a > 3)?$a[3]:2.5);# rampTime 0.0..85825945.6, 0=immediate + $rval = CUL_HM_encodeTime16((@a > 3)?$a[3]:2.5); # rampTime 0.0..85825945.6, 0=immediate CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s02%s%02X%s%s",$id,$dst,$chn,$a[1]*2,$rval,$tval)); + sprintf("++%s11%s%s02%s%02X%s%s",$flag,$id,$dst,$chn,$a[1]*2,$rval,$tval)); } elsif($cmd eq "stop") { ##################################### - my $headerbytes = $md eq "HM-LC-SW1-BA-PCB" ? "FF" : "A0"; - CUL_HM_PushCmdStack($hash, - sprintf("++%s11%s%s03%s", $headerbytes, $id,$dst, $chn)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'03'.$chn); } elsif($cmd eq "text") { ############################################# $state = ""; @@ -1757,15 +1794,15 @@ CUL_HM_Set($@) my $text = sprintf("%5.5s",$t);#pad left with space $text = uc(unpack("H*",$text)); - CUL_HM_PushCmdStack($hash, - sprintf("++B011%s%s8012%s%04X%02X",$id,$dst,$text,$symbAdd,$beepBack)); + CUL_HM_PushCmdStack($hash,sprintf("++%s11%s%s8012%s%04X%02X", + $flag,$id,$dst,$text,$symbAdd,$beepBack)); } elsif($cmd eq "alarm"||$cmd eq "service") { ################################# return "$a[2] must be below 255" if ($a[2] >255 ); $chn = 18 if ($chn eq "01"); my $subtype = ($cmd eq "alarm")?"81":"82"; CUL_HM_PushCmdStack($hash, - sprintf("++B011%s%s%s%s%02X", $id,$dst,$subtype,$chn, $a[2])); + sprintf("++%s11%s%s%s%s%02X",$flag,$id,$dst,$subtype,$chn, $a[2])); } elsif($cmd eq "led") { ###################################################### if ($md eq "HM-OU-LED16"){ @@ -1782,12 +1819,12 @@ CUL_HM_Set($@) else{ return "$a[2] unknown. use hex or: ".join(" ",sort keys(%color)); } - CUL_HM_PushCmdStack($hash,sprintf("++A011%s%s8100%s",$id,$dst,$col4all)); + CUL_HM_PushCmdStack($hash,sprintf("++%s11%s%s8100%s", + $flag,$id,$dst,$col4all)); }else{# operating on a channel return "$a[2] unknown. use: ".join(" ",sort keys(%color)) if (!defined($color{$a[2]}) ); - CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s80%s0%s", $id,$dst,$chn, $color{$a[2]})); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'80'.$chn.'0'.$color{$a[2]}); } } elsif($md eq "HM-OU-CFM-PL"){ @@ -1802,8 +1839,7 @@ CUL_HM_Set($@) } $ledBytes .= sprintf("%02X",$color{$led}); } - CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s80%s0101%s", $id,$dst,$chn, $ledBytes)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'80'.$chn.'0101'.$ledBytes); } else{ return "device for command cannot be identified"; @@ -1817,8 +1853,7 @@ CUL_HM_Set($@) foreach my $mp3 (@mp3List){ $mp3Bytes .= sprintf("%02X",$mp3); } - CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s80%s0202%s", $id,$dst,$chn,$mp3Bytes)); + CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'80'.$chn.'0202'.$mp3Bytes); } elsif($cmd eq "ilum") { ##################################################### return "$a[2] not specified. choose 0-15 for brightness" if ($a[2]>15); @@ -1859,16 +1894,14 @@ CUL_HM_Set($@) elsif($cmd eq "desired-temp") { ################## my $temp = CUL_HM_convTemp($a[2]); return $temp if(length($temp) > 2); - CUL_HM_PushCmdStack($hash, "++A112$id$dst"); # Wakeup... CUL_HM_PushCmdStack($hash, - sprintf("++A011%s%s0202%s", $id,$dst,$temp)); + sprintf("++%s11%s%s0202%s",$flag,$id,$dst,$temp)); } elsif($cmd =~ m/^(day|night|party)-temp$/) { ################## my %tt = (day=>"03", night=>"04", party=>"06"); my $tt = $tt{$1}; my $temp = CUL_HM_convTemp($a[2]); return $temp if(length($temp) > 2); - CUL_HM_PushCmdStack($hash, "++A112$id$dst"); # Wakeup... CUL_HM_pushConfig($hash, $id, $dst, 2,0,0,5, "$tt$temp"); # List 5 } elsif($cmd =~ m/^tempList(...)/) { ################################## @@ -1898,7 +1931,6 @@ CUL_HM_Set($@) $hash->{TEMPLIST}{$wd}{($idx-2)/2}{TEMP} = $a[$idx+1]; $msg .= sprintf(" %02d:%02d %.1f", $h, $m, $a[$idx+1]); } - CUL_HM_PushCmdStack($hash, "++A112$id$dst"); # Wakeup... CUL_HM_pushConfig($hash, $id, $dst, 2,0,0,$list, $data); my $vn = "tempList$wd"; @@ -1908,59 +1940,36 @@ CUL_HM_Set($@) elsif($cmd eq "matic") { ##################################### # Trigger pre-programmed action in the winmatic. These actions must be # programmed via the original software. - CUL_HM_PushCmdStack($hash, - sprintf("++B03E%s%s%s40%02X%s", $id, $dst, $id, $a[2], $chn)); - - } elsif($cmd eq "create") { ################################### + sprintf("++%s3E%s%s%s40%02X%s", $flag,$id, $dst, $id, $a[2], $chn)); + } + elsif($cmd eq "create") { ################################### CUL_HM_PushCmdStack($hash, - sprintf("++B001%s%s0101%s%02X%s", $id, $dst, $id, $a[2], $chn)); + sprintf("++%s01%s%s0101%s%02X%s",$flag,$id, $dst, $id, $a[2], $chn)); CUL_HM_PushCmdStack($hash, sprintf("++A001%s%s0104%s%02X%s", $id, $dst, $id, $a[2], $chn)); - } elsif($cmd eq "read") { ################################### + } + elsif($cmd eq "read") { ################################### CUL_HM_PushCmdStack($hash, - sprintf("++B001%s%s0104%s%02X03", $id, $dst, $id, $a[2])); - - } elsif($cmd eq "keydef") { ##################################### - - my $cmd; - if ($a[3] eq "tilt") { - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2],"0B220D838B228D83"); - - } elsif ($a[3] eq "close") { - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0B550D838B558D83"); - - } elsif ($a[3] eq "closed") { - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0F008F00"); - - } elsif ($a[3] eq "bolt") { - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0FFF8FFF"); - - } elsif ($a[3] eq "delete") { - $cmd = sprintf("++B001%s%s0102%s%02X%s", $id, $dst, $id, $a[2], $chn); - - } elsif ($a[3] eq "speedclose") { - $cmd = $a[4]*2; - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], - sprintf("23%02XA3%02X", $cmd, $cmd)); - - } elsif ($a[3] eq "speedtilt") { - $cmd = $a[4]*2; - $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], - sprintf("22%02XA2%02X", $cmd, $cmd)); + sprintf("++%s01%s%s0104%s%02X03",$flag,$id, $dst, $id, $a[2])); + } + elsif($cmd eq "keydef") { ##################################### + if ( $a[3] eq "tilt") {CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,"0B220D838B228D83"); + } elsif ($a[3] eq "close") {CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,"0B550D838B558D83"); + } elsif ($a[3] eq "closed") {CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,"0F008F00"); + } elsif ($a[3] eq "bolt") {CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,"0FFF8FFF"); + } elsif ($a[3] eq "speedclose"){CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,sprintf("23%02XA3%02X", $a[4]*2, $a[4]*2)); + } elsif ($a[3] eq "speedtilt") {CUL_HM_pushConfig($hash,$id,$dst,1,$id,$a[2],3,sprintf("22%02XA2%02X", $a[4]*2, $a[4]*2)); + } elsif ($a[3] eq "delete") {CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s0102%s%02X%s",$flag,$id, $dst, $id, $a[2], $chn)); } else { return "unknown argument $a[3]"; - } - CUL_HM_PushCmdStack($hash, $cmd) if($cmd); - } elsif($cmd eq "test") { ##################################################### my $testnr = $hash->{TESTNR} ? ($hash->{TESTNR} +1) : 1; $hash->{TESTNR} = $testnr; CUL_HM_SendCmd($hash, sprintf("++9440%s%s00%02X",$dst,$dst,$testnr), 1, 0); - } elsif($cmd =~ m/alarm(.*)/) { ############################################### CUL_HM_SendCmd($hash, sprintf("++9441%s%s01%s", @@ -1990,6 +1999,11 @@ CUL_HM_Set($@) } } + elsif($cmd eq "actiondetect"){ + $state = ""; + my (undef,undef,$cyctime) = @a; + return ($cyctime eq 'off')?CUL_HM_ActDel($dst):CUL_HM_ActAdd($dst,$cyctime); + } elsif($cmd eq "press") { #################################################### my (undef,undef,$mode) = @a; my ($srcId,$srcChn) = ($1,$2) if ($hash->{DEF} =~ m/(......)(..)/); @@ -2011,13 +2025,13 @@ CUL_HM_Set($@) my $peerHash = $modules{CUL_HM}{defptr}{$peer}; my $peerSt = AttrVal($peerHash->{NAME}, "subType", ""); my $peerFlag = ($peerSt ne "keyMatic") ? "A4" : "B4"; - CUL_HM_SendCmd($hash, sprintf("++%s40%s%s%s%02X", - $peerFlag,$srcId,$peer,$btn,$pressCnt),1,0); + CUL_HM_PushCmdStack($hash, sprintf("++%s40%s%s%s%02X", + $peerFlag,$srcId,$peer,$btn,$pressCnt)); $oldPeer = $peer; } - CUL_HM_SendCmd($hash, sprintf("++%40%s000000%s%02X", - $flag,$srcId,$btn,$pressCnt),1,0)if (!@peerList); + CUL_HM_PushCmdStack($hash, sprintf("++%s40%s000000%s%02X", + $flag,$srcId,$btn,$pressCnt))if (!@peerList); $hash->{helper}{count}=$pressCnt; } elsif($cmd eq "devicepair") { ############################################### @@ -2062,12 +2076,8 @@ CUL_HM_Set($@) # First the remote (one loop for on, one for off) if (!$target || $target eq "remote" || $target eq "both"){ for(my $i = 1; $i <= $nrCh2Pair; $i++) { - my $b = ($i==1 ? $b1 : $b2); - - my $devhash = CUL_HM_getDeviceHash($hash); - my $devName = $devhash->{NAME}; - - if ($attr{$devName}{subType} eq "virtual"){ + my $b = ($i==1 ? $b1 : $b2); + if ($st eq "virtual"){ my $btnName = CUL_HM_id2Name($dst.sprintf("%02X",$b)); return "button ".$b." not defined for virtual remote ".$name if (!defined $attr{$btnName}); @@ -2089,20 +2099,17 @@ CUL_HM_Set($@) } } if (!$target || $target eq "actor" || $target eq "both"){ - my $peerSt = AttrVal($peerHash->{NAME}, "subType", ""); - my $peerFlag = ($peerSt ne "keyMatic") ? "A0" : "B0"; + my $peerFlag = CUL_HM_getFlag($peerHash); CUL_HM_PushCmdStack($peerHash, sprintf("++%s01%s%s%s%s%s%02X%02X", $peerFlag,$id,$peerDst,$peerChn,$cmd,$dst,$b2,$b1 )); } - $chash = $peerHash; # Exchange the hash, as the switch is always alive. + $devHash = $peerHash; # Exchange the hash, as the switch is always alive. } - $hash->{STATE} = $state if($state); #todo: this is not the device state - Log GetLogLevel($name,2), "CUL_HM set $name " . join(" ", @a[1..$#a]); + $hash->{STATE} = $state if($state); + Log GetLogLevel($name,3), "CUL_HM set $name " . join(" ", @a[1..$#a]); - CUL_HM_ProcessCmdStack($chash) - if(!$attr{$chash->{NAME}}{rxType}|| - $attr{$chash->{NAME}}{rxType}=~ m/burst/); + CUL_HM_ProcessCmdStack($devHash) if($rxType & 0x03);#all/burst return ""; } @@ -2123,15 +2130,9 @@ CUL_HM_infoUpdtDevData($$$){ sprintf("%d.%d", hex(substr($p,0,1)),hex(substr($p,1,1))); $attr{$name}{devInfo} = $devInfo; - delete $attr{$name}{rxType}; - if ($culHmModel{$mId}{rxt}){ - foreach my $rxt (split(':',$culHmModel{$mId}{rxt})){ - $attr{$name}{rxType} .= "config," if ($rxt eq "c"); - $attr{$name}{rxType} .= "wakeup," if ($rxt eq "w"); - $attr{$name}{rxType} .= "burst," if ($rxt eq "b"); - } - } - #set rxType + delete $hash->{helper}{rxType}; + CUL_HM_getRxType($hash); #will update rxType + $mId = CUL_HM_getMId($hash);# set helper valiable and use result # autocreate undefined channels my @chanTypesList = split(',',$culHmModel{$mId}{chn}); @@ -2139,7 +2140,7 @@ CUL_HM_infoUpdtDevData($$$){ my ($chnTpName,$chnStart,$chnEnd) = split(':',$chantype); my $chnNoTyp = 1; for (my $chnNoAbs = $chnStart; $chnNoAbs <= $chnEnd;$chnNoAbs++){ - my $chnName = $name.$chnTpName.(($chnStart == $chnEnd)?"":"_".$chnNoTyp); + my $chnName = $name."_".$chnTpName.(($chnStart == $chnEnd)?"":"_".sprintf("%02d",$chnNoTyp)); my $chnId = $hash->{DEF}.sprintf("%02X",$chnNoAbs); if (!$modules{CUL_HM}{defptr}{$chnId}){ DoTrigger("global", "UNDEFINED $chnName CUL_HM $chnId"); @@ -2147,6 +2148,9 @@ CUL_HM_infoUpdtDevData($$$){ $chnNoTyp++; } } + if ($culHmModel{$mId}{cyc}){ + CUL_HM_ActAdd($hash->{DEF},$culHmModel{$mId}{cyc}); + } } ################################### @@ -2156,17 +2160,16 @@ CUL_HM_Pair(@) my ($name, $hash,$cmd,$src,$dst,$p) = @_; my $iohash = $hash->{IODev}; my $id = CUL_HM_Id($iohash); - my $l4 = GetLogLevel($name,4); my $serNo = $attr{$name}{serialNr}; - Log GetLogLevel($name,2), + Log GetLogLevel($name,3), "CUL_HM pair: $name $attr{$name}{subType}, model $attr{$name}{model} serialNr $serNo"; # Abort if we are not authorized if($dst eq "000000") { if(!$iohash->{hmPair} && (!$iohash->{hmPairSerial} || $iohash->{hmPairSerial} ne $serNo)) { - Log GetLogLevel($name,2), + Log GetLogLevel($name,3), $iohash->{NAME}. " pairing (hmPairForSec) not enabled"; return ""; } @@ -2192,15 +2195,39 @@ CUL_HM_Pair(@) sub CUL_HM_getConfig($$$$$){ my ($hash,$chnhash,$id,$dst,$chn) = @_; - my $st = AttrVal($hash->{NAME}, "subType", ""); - my $flag = ($st ne "keyMatic") ? "A0" : "B0"; - - #getList1 - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s040000000001",$flag,$id,$dst,$chn)); - #getPeers and config what List3 shall be retrieved - CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s03", $flag,$id,$dst,$chn)); - $chnhash->{helper}{getCfgList3} = "all";#get list3 regs of first peer in list + my $flag = CUL_HM_getFlag($hash); + my $lstAr = $culHmModel{CUL_HM_getMId($hash)}{lst}; + my @list = split(",",$lstAr); #get valid lists e.g."1, 5:2:3.p ,6:2" + foreach my$listEntry (@list){ + my ($peerReq,$chnValid,)= (0,0); + my ($listNo,$chnLst1) = split(":",$listEntry); + if (!$chnLst1){ + $chnValid = 1; #if no entry channel is valid + $peerReq = 1 if($listNo==3 ||$listNo==4); #default + } + else{ + my @chnLst = split('\.',$chnLst1); + foreach my $lchn (@chnLst){ + $peerReq = 1 if ($lchn =~ m/p/); + no warnings;# know that lchan may be followed by a 'p' causing a warning + $chnValid = 1 if (int($lchn) == hex($chn)); + use warnings; + last if ($chnValid); + } + } + #$listNo,$chnValid $peerReq + if ($chnValid){# yes, we will go for a list + if ($peerReq){# need to get the peers first + CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s03",$flag,$id,$dst,$chn)); + $chnhash->{helper}{getCfgList} = "all";# peers first + $chnhash->{helper}{getCfgListNo} = $listNo; + } + else{ + CUL_HM_PushCmdStack($hash,sprintf("++%s01%s%s%s0400000000%02X",$flag,$id,$dst,$chn,$listNo)); + } + } + } } ################################### sub @@ -2208,31 +2235,24 @@ CUL_HM_SendCmd($$$$) { my ($hash, $cmd, $sleep, $waitforack) = @_; my $io = $hash->{IODev}; - - select(undef, undef, undef, 0.1*$sleep) if($sleep); - + select(undef, undef, undef, 0.1) if($io->{TYPE} ne 'HMLAN'); $cmd =~ m/^(..)(.*)$/; my ($mn, $cmd2) = ($1, $2); if($mn eq "++") { - $mn = $io->{HM_CMDNR} ? ($io->{HM_CMDNR} +1) : 1; - $mn = 0 if($mn > 255); - + $mn = $io->{HM_CMDNR} ? (($io->{HM_CMDNR} +1)&0xff) : 1; } else { $mn = hex($mn); - } $io->{HM_CMDNR} = $mn; - $cmd = sprintf("As%02X%02X%s", length($cmd2)/2+1, $mn, $cmd2); + $cmd = sprintf("As%02X%02X%s", length($cmd2)/2+1, $mn, $cmd2); + IOWrite($hash, "", $cmd); $cmd =~ m/As(..)(..)(..)(..)(......)(......)(.*)/; - CUL_HM_DumpProtocol("SND", $io, ($1,$2,$3,$4,$5,$6,$7)); - - CUL_HM_responseSetup($hash,$cmd,$waitforack); - + CUL_HM_DumpProtocol("SND", $io, ($1,$2,$3,$4,$5,$6,$7)); + CUL_HM_responseSetup($hash,$cmd,$waitforack); } - ################################### sub CUL_HM_responseSetup($$$) @@ -2250,7 +2270,7 @@ CUL_HM_responseSetup($$$) $hash->{helper}{respWait}{forChn} = substr($p,0,2);#channel info we await # define timeout - holdup cmdStack until response complete or timeout - InternalTimer(gettimeofday()+3, "CUL_HM_respPendTout", "respPend:$dst", 0); + InternalTimer(gettimeofday()+1.5, "CUL_HM_respPendTout", "respPend:$dst", 0); #--- remove readings in channel my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"}; @@ -2269,7 +2289,7 @@ CUL_HM_responseSetup($$$) $hash->{helper}{respWait}{forPeer}= $peerID;# this is the HMid + channel # define timeout - holdup cmdStack until response complete or timeout - InternalTimer(gettimeofday()+3,"CUL_HM_respPendTout","respPend:$dst", 0); + InternalTimer(gettimeofday()+1.5,"CUL_HM_respPendTout","respPend:$dst", 0); #--- remove channel entries that will be replaced my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"}; $chnhash = $hash if(!$chnhash); @@ -2286,7 +2306,7 @@ CUL_HM_responseSetup($$$) $hash->{helper}{respWait}{forChn} = $chn; # define timeout - holdup cmdStack until response complete or timeout - InternalTimer(gettimeofday()+3, "CUL_HM_respPendTout", "respPend:$dst", 0); + InternalTimer(gettimeofday()+1.5, "CUL_HM_respPendTout", "respPend:$dst", 0); return; } } @@ -2326,18 +2346,6 @@ CUL_HM_eventP($$) } ################################### sub -CUL_HM_convPendTout($) -{ - my ($HMid) = @_; - $HMid =~ s/.*://; #remove timer identifier - my $hash = $modules{CUL_HM}{defptr}{$HMid}; - - if ($hash){ - delete ($hash->{helper}{respWait}{RegWrite}); - } -} -################################### -sub CUL_HM_respPendRm($) { # delete all response related entries in messageing entity my ($hash) = @_; @@ -2359,7 +2367,14 @@ CUL_HM_respPendTout($) CUL_HM_respPendRm($hash); } } - +################################### +sub +CUL_HM_respPendToutProlong($) #used when device sends part responses +{ + my ($hash) = @_; + RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer? + InternalTimer(gettimeofday()+1, "CUL_HM_respPendTout", "respPend:$hash->{DEF}", 0); +} ################################### sub CUL_HM_PushCmdStack($$) @@ -2372,7 +2387,6 @@ CUL_HM_PushCmdStack($$) my $entries = scalar @{$hash->{cmdStack}}; $attr{$hash->{NAME}}{protCmdPend} = $entries." CMDs pending"; } - ################################### sub CUL_HM_ProcessCmdStack($) @@ -2398,13 +2412,12 @@ CUL_HM_ProcessCmdStack($) ################################### sub CUL_HM_Resend($) -{ +{#resend a message if there is no answer my $hash = shift; my $name = $hash->{NAME}; return if(!$hash->{helper}{respWait}{reSent}); # Double timer? - if($hash->{helper}{respWait}{reSent} >= 3) { + if($hash->{helper}{respWait}{reSent} >= 1) { CUL_HM_eventP($hash,"ResndFail"); - CUL_HM_respPendRm($hash); delete($hash->{cmdStack}); delete($attr{$hash->{NAME}}{protCmdPend}); CUL_HM_respPendRm($hash); @@ -2415,33 +2428,30 @@ CUL_HM_Resend($) CUL_HM_eventP($hash,"Resnd"); IOWrite($hash, "", $hash->{helper}{respWait}{cmd}); $hash->{helper}{respWait}{reSent}++; - DoTrigger($name, "resend nr ".$hash->{helper}{respWait}{reSent}); - InternalTimer(gettimeofday()+0.5, "CUL_HM_Resend", $hash, 0); + Log GetLogLevel($name,4),"CUL_HM_Resend: ".$name. " nr ".$hash->{helper}{respWait}{reSent}; + InternalTimer(gettimeofday()+1, "CUL_HM_Resend", $hash, 0); } } ################################### sub CUL_HM_Id($) -{ +{#in ioHash out ioHMid my ($io) = @_; my $fhtid = defined($io->{FHTID}) ? $io->{FHTID} : "0000"; return AttrVal($io->{NAME}, "hmId", "F1$fhtid"); } - ################################### sub CUL_HM_name2hash($) -{ +{# in: name, out:hash my ($name) = @_; return $defs{$name}; } - ################################### sub CUL_HM_Name2Id($) -{ # get name for a hmId or a hmId channel combination - +{ # in: name or HMid out: HMid, undef if no match my ($idName) = @_; my $hash = $defs{$idName}; my $hmId; @@ -2452,7 +2462,7 @@ CUL_HM_Name2Id($) ################################### sub CUL_HM_id2Name($) -{ # get name for a HMid or a HMid channel combination +{ # in: name or HMid out: name my ($p) = @_; my $devId= substr($p, 0, 6); my $chn; @@ -2475,14 +2485,12 @@ CUL_HM_id2Name($) } ################################### sub -CUL_HM_getDeviceHash($){ - my ($hash) = @_; - my $HMid = substr($hash->{DEF},0,6) if ($hash->{DEF}); - return $hash if(!$hash->{DEF}); - my $devHash = $modules{CUL_HM}{defptr}{$HMid}; - $devHash = $modules{CUL_HM}{defptr}{$HMid."01"} if (!$devHash); - $devHash = $hash if (!$devHash); - return $devHash; +CUL_HM_getDeviceHash($) +{#in: hash (chn or dev) out: hash of the device (used e.g. for send messages) + my ($hash) = @_; + return $hash if(!$hash->{DEF}); + my $devHash = $modules{CUL_HM}{defptr}{substr($hash->{DEF},0,6)}; + return ($devHash)?$devHash:$hash; } ############################# @@ -2523,7 +2531,7 @@ my %culHmBits = ( "01;p11=08" => { txt => "CONFIG_WRITE_INDEX", params => { CHANNEL => "0,2", DATA => '4,,$val =~ s/(..)(..)/ $1:$2/g', } }, - "01;p11=0A" => { txt => "PAIR_SERIAL", params => { + "01;p11=0A" => { txt => "PAIR_SERIAL", params => { SERIALNO => '04,,$val=pack("H*",$val)', } }, "01;p11=0E" => { txt => "CONFIG_STATUS_REQUEST", params => { CHANNEL => "0,2", } }, @@ -2611,9 +2619,10 @@ CUL_HM_DumpProtocol($$@) { my ($prefix, $iohash, $len,$cnt,$msgFlags,$msgType,$src,$dst,$p) = @_; my $iname = $iohash->{NAME}; - my $ev = AttrVal($iname, "hmProtocolEvents", 0); - my $l4 = GetLogLevel($iname, 4); - return if(!$ev && $attr{global}{verbose} < $l4); + no warnings;# conv 2 number would cause a warning - which is ok + my $hmProtocolEvents = int(AttrVal($iname, "hmProtocolEvents", 0)); + use warnings; + return if(!$hmProtocolEvents); my $p01 = substr($p,0,2); my $p02 = substr($p,0,4); @@ -2630,7 +2639,7 @@ CUL_HM_DumpProtocol($$@) $ps = $culHmBits{"$msgType;p11=$p11"} if(!$ps); $ps = $culHmBits{"$msgType;p01=$p01"} if(!$ps); $ps = $culHmBits{"$msgType;p02=$p02"} if(!$ps); - $ps = $culHmBits{"$msgType"} if(!$ps); + $ps = $culHmBits{"$msgType"} if(!$ps); my $txt = ""; if($ps) { $txt = $ps->{txt}; @@ -2640,8 +2649,8 @@ CUL_HM_DumpProtocol($$@) my ($o,$l,$expr) = split(",", $ps->{$k}, 3); last if(length($p) <= $o); my $val = $l ? substr($p,$o,$l) : substr($p,$o); - eval $expr if($expr); - $txt .= " $k:$val"; + eval $expr if($hmProtocolEvents > 1 && $expr); + $txt .= " $k:".(($hmProtocolEvents > 1 && $expr)?"":"0x")."$val"; } } $txt = " ($txt)" if($txt); @@ -2649,9 +2658,8 @@ CUL_HM_DumpProtocol($$@) $src=CUL_HM_id2Name($src); $dst=CUL_HM_id2Name($dst); my $msg ="$prefix L:$len N:$cnt F:$msgFlags CMD:$msgType SRC:$src DST:$dst $p$txt ($msgFlLong)"; - Log $l4, $msg; - DoTrigger($iname, $msg) if($ev); - + Log GetLogLevel($iname, 4), $msg; + DoTrigger($iname, $msg) if($hmProtocolEvents > 2); } ############################# sub @@ -2694,131 +2702,140 @@ CUL_HM_parseCommon(@){ $reply = ($subType eq "01")?"ACKStatus":"ACK"; $success = "yes"; } - $chnhash->{READINGS}{CommandAccepted}{TIME} = TimeNow(); - $chnhash->{READINGS}{CommandAccepted}{VAL} = $success; + $chnhash->{READINGS}{CommandAccepted}{TIME} = TimeNow(); + $chnhash->{READINGS}{CommandAccepted}{VAL} = $success; CUL_HM_ProcessCmdStack($shash); # see if there is something left return $reply; - } - elsif($msgType eq "10" && $p =~ m/^01/){ #storePeerList################# - if ($pendType eq "PeerList"){ - my $chn = $shash->{helper}{respWait}{forChn}; - my $chnhash = $modules{CUL_HM}{defptr}{$src.$chn}; - $chnhash = $shash if (!$chnhash); - my @peers = substr($p,2,) =~ /(.{8})/g; - my @peerList; - my @peerID; - foreach my $peer(@peers){ - push(@peerList,CUL_HM_id2Name($peer)); - push(@peerID,$peer); - } - my $peerFound = join (',',@peerList); - - $peerFound =~ s/broadcast//; # remove end indication, not a peer - $chnhash->{READINGS}{peerList}{VAL}.= ",".$peerFound; - $chnhash->{READINGS}{peerList}{TIME} = TimeNow(); - - $peerFound = join (',',@peerID); - $peerFound =~ s/00000000//; - $chnhash->{helper}{peerList}.= ",".$peerFound; - - if ($p =~ m/00000000$/) {# last entry, peerList is complete - CUL_HM_respPendRm($shash); - # check for request to get List3 data - my $reqPeer = $chnhash->{helper}{getCfgList3}; - if ($reqPeer){ - - my $st = AttrVal($shash->{NAME}, "subType", ""); - my $flag = ($st ne "keyMatic") ? "A0" : "B0"; - - my $id = CUL_HM_Id($shash->{IODev}); - @peerID = split(",", $chnhash->{helper}{peerList}); - my $class = AttrVal(CUL_HM_id2Name($src), "hmClass", ""); - my $listNo = ($class eq "sender")?"04":"03";#list4 for sender - $reqPeer = $peerID[$reqPeer] if ($reqPeer < 100 && $reqPeer > 0 ); - foreach my $peer (@peerID){ - $peer .="01" if (length($peer) == 6); # add the default - if ($peer &&($peer eq $reqPeer || $reqPeer eq "all")){ - CUL_HM_PushCmdStack($shash,sprintf("++%s01%s%s%s04%s%s",$id, - $flag,$src,$chn,$peer,$listNo));# List3 or 4 - } - } - CUL_HM_ProcessCmdStack($shash) if($listNo ne "04"); - } - delete $chnhash->{helper}{getCfgList3}; - delete $chnhash->{helper}{peerList}; - } - return "done"; - } } - elsif($msgType eq "10" && $p =~ m/^0[23]/){ #ParamResp################## - if ($pendType eq "RegisterRead"){ - my $chnSrc = $src.$shash->{helper}{respWait}{forChn}; - my $chnhash = $modules{CUL_HM}{defptr}{$chnSrc}; - $chnhash = $shash if (!$chnhash); - my $chnName = $chnhash->{NAME}; - my ($format,$data) = ($1,$2) if ($p =~ m/^(..)(.*)/); - my $list = $shash->{helper}{respWait}{forList}; - $list = "00" if (!$list); #use the default - if ($format eq "02"){ # list 2: format aa:dd aa:dd ... - $data =~ s/(..)(..)/ $1:$2/g; + elsif($msgType eq "10"){ + my $subtype = substr($p,0,2); + if($subtype eq "01"){ #storePeerList################# + if ($pendType eq "PeerList"){ + my $chn = $shash->{helper}{respWait}{forChn}; + my $chnhash = $modules{CUL_HM}{defptr}{$src.$chn}; + $chnhash = $shash if (!$chnhash); + my @peers = substr($p,2,) =~ /(.{8})/g; + my @peerList; + my @peerID; + foreach my $peer(@peers){ + push(@peerList,CUL_HM_id2Name($peer)); + push(@peerID,$peer); + } + my $peerFound = join (',',@peerList); + $peerFound =~ s/broadcast//; # remove end indication, not a peer + $chnhash->{READINGS}{peerList}{VAL}.= ",".$peerFound; + $chnhash->{READINGS}{peerList}{TIME} = TimeNow(); + + $peerFound = join (',',@peerID); + $peerFound =~ s/00000000//; + $chnhash->{helper}{peerList}.= ",".$peerFound; + + if ($p =~ m/00000000$/) {# last entry, peerList is complete + CUL_HM_respPendRm($shash); + # check for request to get List3 data + my $reqPeer = $chnhash->{helper}{getCfgList}; + if ($reqPeer){ + my $flag = CUL_HM_getFlag($shash); + my $id = CUL_HM_Id($shash->{IODev}); + @peerID = split(",", $chnhash->{helper}{peerList}); + my $class = AttrVal(CUL_HM_id2Name($src), "hmClass", ""); + my $listNo = "0".$chnhash->{helper}{getCfgListNo}; + foreach my $peer (@peerID){ + $peer .="01" if (length($peer) == 6); # add the default + if ($peer &&($peer eq $reqPeer || $reqPeer eq "all")){ + CUL_HM_PushCmdStack($shash,sprintf("++%s01%s%s%s04%s%s", + $flag,$id,$src,$chn,$peer,$listNo));# List3 or 4 + } + } + CUL_HM_ProcessCmdStack($shash); + } + delete $chnhash->{helper}{getCfgList}; + delete $chnhash->{helper}{getCfgListNo}; + delete $chnhash->{helper}{peerList}; + } + else{ + CUL_HM_respPendToutProlong($shash);#wasn't last - reschedule timer + } + return "done"; } - elsif ($format eq "03"){ # list 3: format aa:dddd - my $addr; - my @dataList; - ($addr,$data) = (hex($1),$2) if ($data =~ m/(..)(.*)/); - $data =~s/(..)/$1:/g; - foreach my $d1 (split(":",$data)){ - push (@dataList,sprintf("%02X:%s",$addr++,$d1)); - } - $data = join(" ",@dataList); - } - my $peerN =($list =~ m/^0[34]$/)?$shash->{helper}{respWait}{forPeer}:""; - $chnhash->{READINGS}{"RegL_".$list.":".$peerN}{VAL}.= " ".$data if($data); - $chnhash->{READINGS}{"RegL_".$list.":".$peerN}{TIME}= TimeNow(); - - if ($data =~m/00:00$/){ # this was the last message in the block - if($list eq "00"){ - my $name = CUL_HM_id2Name($src); - $shash->{READINGS}{PairedTo}{VAL} = sprintf("%02X%02X%02X", + } + elsif($subtype eq "02" ||$subtype eq "03"){ #ParamResp################## + if ($pendType eq "RegisterRead"){ + my $chnSrc = $src.$shash->{helper}{respWait}{forChn}; + my $chnhash = $modules{CUL_HM}{defptr}{$chnSrc}; + $chnhash = $shash if (!$chnhash); + my $chnName = $chnhash->{NAME}; + my ($format,$data) = ($1,$2) if ($p =~ m/^(..)(.*)/); + my $list = $shash->{helper}{respWait}{forList}; + $list = "00" if (!$list); #use the default + if ($format eq "02"){ # list 2: format aa:dd aa:dd ... + $data =~ s/(..)(..)/ $1:$2/g; + } + elsif ($format eq "03"){ # list 3: format aa:dddd + my $addr; + my @dataList; + ($addr,$data) = (hex($1),$2) if ($data =~ m/(..)(.*)/); + $data =~s/(..)/$1:/g; + foreach my $d1 (split(":",$data)){ + push (@dataList,sprintf("%02X:%s",$addr++,$d1)); + } + $data = join(" ",@dataList); + } + my $peerN =($list =~ m/^0[34]$/)?$shash->{helper}{respWait}{forPeer}:""; + $chnhash->{READINGS}{"RegL_".$list.":".$peerN}{VAL}.= " ".$data if($data); + $chnhash->{READINGS}{"RegL_".$list.":".$peerN}{TIME}= TimeNow(); + + if ($data =~m/00:00$/){ # this was the last message in the block + if($list eq "00"){ + my $name = CUL_HM_id2Name($src); + $shash->{READINGS}{PairedTo}{VAL} = sprintf("%02X%02X%02X", CUL_HM_getRegFromStore($name,10,0,"00000000"), CUL_HM_getRegFromStore($name,11,0,"00000000"), CUL_HM_getRegFromStore($name,12,0,"00000000")); - $shash->{READINGS}{PairedTo}{TIME} = TimeNow(); + $shash->{READINGS}{PairedTo}{TIME} = TimeNow(); + } + CUL_HM_respPendRm($shash); } - CUL_HM_respPendRm($shash); + else{ + CUL_HM_respPendToutProlong($shash);#wasn't last - reschedule timer + } + return "done"; + } + } + elsif($subtype eq "04"){ #ParamChange################### + my($chn,$peerID,$list,$data) = @_ if($p =~ m/^04(..)(........)(..)(.*)/); + my $chnHash = $modules{CUL_HM}{defptr}{$src.$chn}; + $chnHash = $shash if(!$chnHash); # will add param to dev if no chan + my $listName = "RegL_".$list.":".CUL_HM_id2Name($peerID); + $listName =~ s/ /_/g; #remove blanks + $chnHash->{READINGS}{$listName}{VAL} = "" + if ($chnHash->{READINGS}{$listName}{VAL} =~m/00:00$/); + $data =~ s/(..)(..)/ $1:$2/g; + $chnHash->{READINGS}{$listName}{VAL}.= " ".$data; + $chnHash->{READINGS}{$listName}{TIME}= TimeNow(); + } + elsif($subtype eq "06"){ #reply to status request####### + #todo = what is the answer to a status request + if ($pendType eq "StatusReq"){#it is the answer to our request + my $chnSrc = $src.$shash->{helper}{respWait}{forChn}; + my $chnhash = $modules{CUL_HM}{defptr}{$chnSrc}; + $chnhash = $shash if (!$chnhash); + CUL_HM_respPendRm($shash); + return "STATresp";# todo dont send ACK - check what others do + } + else{ + my ($chn) = ($1) if($p =~ m/^..(..)/); + return "powerOn" if ($chn eq "00");# check dst eq "000000" as well? } - return "done"; - } - } - elsif($msgType eq "10" && $p =~ m/^04/){ #ParamChange################### - my($chn,$peerID,$list,$data) = @_ if($p =~ m/^04(..)(........)(..)(.*)/); - my $chnHash = $modules{CUL_HM}{defptr}{$src.$chn}; - $chnHash = $shash if(!$chnHash); # will add param to dev if no chan - my $listName = "RegL_".$list.":".CUL_HM_id2Name($peerID); - $listName =~ s/ /_/g; #remove blanks - $chnHash->{READINGS}{$listName}{VAL} = "" - if ($chnHash->{READINGS}{$listName}{VAL} =~m/00:00$/); - $data =~ s/(..)(..)/ $1:$2/g; - $chnHash->{READINGS}{$listName}{VAL}.= " ".$data; - $chnHash->{READINGS}{$listName}{TIME}= TimeNow(); - } - elsif($msgType eq "10" && $p =~ m/^06/){ #reply to status request####### - #todo = what is the answer to a status request - if ($pendType eq "StatusReq"){#it is the answer to our request - my $chnSrc = $src.$shash->{helper}{respWait}{forChn}; - my $chnhash = $modules{CUL_HM}{defptr}{$chnSrc}; - $chnhash = $shash if (!$chnhash); - CUL_HM_respPendRm($shash); - return "STATresp";# todo dont send ACK - check what others do - } - else{ - my ($chn) = ($1) if($p =~ m/^..(..)/); - return "powerOn" if ($chn eq "00");# check dst eq "000000" as well? } } elsif($msgType eq "70"){ #wakeup ####################################### - CUL_HM_ProcessCmdStack($shash) - if (AttrVal($shash->{NAME}, "rxType", "0") =~ m/wakeup/); + #CUL_HM_Id($hash->{IODev}) + if((CUL_HM_getRxType($shash) & 0x08) && $shash->{cmdStack}){ + #send wakeup and process command stack if applicable + CUL_HM_SendCmd($shash, '++A112'.CUL_HM_Id($shash->{IODev}).$src, 1, 1); + CUL_HM_ProcessCmdStack($shash); + } } return ""; } @@ -2828,7 +2845,7 @@ sub CUL_HM_getRegFromStore($$$$){ my($name,$addr,$list,$peerId)=@_; my $hash = CUL_HM_name2hash($name); - my ($size,$pos,$conv,$unit) = (8,0,"",""); # default 8bit, pos=0, no convertion + my ($size,$pos,$conversion,$factor,$unit) = (8,0,"",1,""); # default 8bit, pos=0, no convertion if ($culHmRegDefine{$addr}) { my $regName = $addr; @@ -2838,7 +2855,8 @@ CUL_HM_getRegFromStore($$$$){ $list = $culHmRegDefine{$regName}{l}; $size = $culHmRegDefine{$regName}{s}; $size = int($size)*8 + ($size*10)%10; - $conv = $culHmRegDefine{$regName}{uc}; #unconvert formula + $conversion = $culHmRegDefine{$regName}{c}; #unconvert formula + $factor = $culHmRegDefine{$regName}{f}; $unit = $culHmRegDefine{$regName}{u}; } $peerId = substr(CUL_HM_Name2Id($name),0,6). #deviceID @@ -2849,27 +2867,40 @@ CUL_HM_getRegFromStore($$$$){ $listName =~ s/ /_/g; my $listRegs = $hash->{READINGS}{$listName}{VAL} if ($listName); return "unknown" if (!$listRegs); - my $d = 0; + my $data = 0; my $size2go = $size; foreach my $AD(split(" ",$listRegs)){ my ($a,$dRead) = split(":",$AD); if(hex($a) == $addr){ if ($size2go<9){ - $d += hex($dRead); - $d = ($d>>$pos) & (0xffffffff>>(32-$size)); - eval $conv; - return $d.$unit; + $data += hex($dRead); + $data = ($data>>$pos) & (0xffffffff>>(32-$size)); + + if (!$conversion){;# do nothing + } + elsif($conversion eq "factor"){# use factor + $data /= $factor; + } + elsif ($conversion eq "fltCvT"){ + $data = CUL_HM_CvTflt($data); + } + elsif($conversion eq "m10s3"){ + $data=($data+3)/10; + } + else{ + return " conversion undefined - please contact admin"; + } + return $data.$unit; } else{ $size2go -=8; - $d = ($d+hex($dRead)) << 8; + $data = ($data+hex($dRead)) << 8; $addr++; } } } return "invalid"; } - ############################# my @culHmTimes8 = ( 0.1, 1, 5, 10, 60, 300, 600, 3600 ); sub @@ -2888,7 +2919,6 @@ CUL_HM_encodeTime8($) } return "FF"; } - ############################# sub CUL_HM_decodeTime8($) @@ -2899,7 +2929,6 @@ CUL_HM_decodeTime8($) my $v2 = $v%32; return $v2 * $culHmTimes8[$v1]; } - ############################# sub CUL_HM_encodeTime16($) @@ -2917,10 +2946,9 @@ CUL_HM_encodeTime16($) $mul /= 2; } my $v2 = CUL_HM_decodeTime16($ret); - Log 1, "Timeout $v rounded to $v2" if($v != $v2); + Log 2, "Timeout $v rounded to $v2" if($v != $v2); return ($ret); } - sub CUL_HM_convTemp($) { @@ -2936,7 +2964,6 @@ CUL_HM_convTemp($) $val = 0 if($val eq "off"); return sprintf("%02X", $val*2); } - ############################# sub CUL_HM_decodeTime16($) @@ -2950,15 +2977,12 @@ CUL_HM_decodeTime16($) } return $mul*$m; } - ############################# sub CUL_HM_pushConfig($$$$$$$$) { my ($hash,$src,$dst,$chn,$peerAddr,$peerChn,$list,$content) = @_; - - my $st = AttrVal($hash->{NAME}, "subType", ""); - my $flag = ($st ne "keyMatic") ? "A0" : "B0"; + my $flag = CUL_HM_getFlag($hash); $peerAddr = "000000" if(!$peerAddr); CUL_HM_PushCmdStack($hash, sprintf("++%s01%s%s%02X05%s%02X%02X", @@ -2967,27 +2991,11 @@ CUL_HM_pushConfig($$$$$$$$) my $tl = length($content); for(my $l = 0; $l < $tl; $l+=28) { my $ml = $tl-$l < 28 ? $tl-$l : 28; - - CUL_HM_PushCmdStack($hash, sprintf("++%s01%s%s%02X08%s", - $flag, $src,$dst,$chn, substr($content,$l,$ml))); + CUL_HM_PushCmdStack($hash, sprintf("++A001%s%s%02X08%s", + $src,$dst,$chn, substr($content,$l,$ml))); } - - CUL_HM_PushCmdStack($hash, - sprintf("++%s01%s%s%02X06", $flag, $src, $dst, $chn)); + CUL_HM_PushCmdStack($hash,sprintf("++A001%s%s%02X06",$src,$dst,$chn)); } - -sub -CUL_HM_maticFn($$$$$) -{ - my ($hash, $id, $dst, $a2, $cfg) = @_; - my $sndcmd = sprintf("++B001%s%s0105%s%02X03", $id, $dst, $id, $a2); - CUL_HM_SendCmd ($hash, $sndcmd, 10, 2); - $sndcmd = sprintf("++A001%s%s0108%s", $id, $dst, $cfg); - CUL_HM_SendCmd ($hash, $sndcmd, 10, 2); - $sndcmd = sprintf("++A001%s%s0106", $id, $dst); - return $sndcmd; -} - sub CUL_HM_secSince2000() { @@ -3000,5 +3008,137 @@ CUL_HM_secSince2000() return $t; } +############### Activity supervision section ################ +# verify that devices are seen in a certain period of time +# It will generate events if no message is seen sourced by the device during +# that period. +# ActionDetector will use the fixed HMid 100100 +sub +CUL_HM_ActGetCreateHash() +{# return hash of ActionDetector - create one if not existant + if (!$modules{CUL_HM}{defptr}{"100100"}){ + DoTrigger("global", "UNDEFINED ActionDetector CUL_HM 100100"); + $attr{ActionDetector}{actCycle} = 600; + } + my $actName = CUL_HM_id2Name("100100"); + my $actHash = $modules{CUL_HM}{defptr}{"100100"}; + + if (!$actHash->{helper}{actCycle} || + $actHash->{helper}{actCycle} != $attr{$actName}{actCycle}){ + $attr{$actName}{actCycle} = 30 if(!$attr{$actName}{actCycle} || + $attr{$actName}{actCycle}<30); + $actHash->{helper}{actCycle} = $attr{$actName}{actCycle}; + RemoveInternalTimer("ActionDetector"); + InternalTimer(gettimeofday()+$attr{$actName}{actCycle}, + "CUL_HM_ActCheck", "ActionDetector", 0); + } + return $actHash; +} + +sub +CUL_HM_time2sec($) +{ + my ($timeout) = @_; + my ($h,$m) = split(":",$timeout); + no warnings; + $h = int($h); + $m = int($m); + use warnings; + return ((sprintf("%03s:%02d",$h,$m)),((int($h)*60+int($m))*60)); +} +sub +CUL_HM_ActAdd($$) +{# add an HMid to list for activity supervision + my ($devId,$timeout) = @_; #timeout format [hh]h:mm + + return $devId." is not an HM device - action detection cannot be added" + if (length($devId) != 6); + + my ($cycleString,undef)=CUL_HM_time2sec($timeout); + my $devName = CUL_HM_id2Name($devId); + $attr{$devName}{actCycle} = $cycleString; + $attr{$devName}{actStatus} = "unknown"; + + my $acthash = CUL_HM_ActGetCreateHash(); + my $actName = $acthash->{NAME}; # could have been renamed + + my $peerList = (!defined($attr{$actName}{peerList}))?"":$attr{$actName}{peerList}; + $peerList .= $devId."," if($peerList !~ m/$devId,/);#add if not in + $attr{$actName}{peerList} = $peerList; + $acthash->{READINGS}{"status_".$devName}{TIME} = TimeNow(); # update new value + $acthash->{READINGS}{"status_".$devName}{VAL} = "unknown"; + Log GetLogLevel($actName,3),"Device ".$devName." added to ActionDetector with " + .$cycleString." time"; +} + +sub +CUL_HM_ActDel($) +{# delete HMid for activity supervision + my ($devId) = @_; + + return $devId." is not an HM device - action detection cannot be added" + if (length($devId) != 6); + + my $devName = CUL_HM_id2Name($devId); + delete ($attr{$devName}{actCycle}); + delete ($attr{$devName}{actStatus}); + + my $acthash = CUL_HM_ActGetCreateHash(); + my $actName = $acthash->{NAME}; + + $attr{$actName}{peerList} = "" if (!defined($attr{$actName}{peerList})); + $attr{$actName}{peerList} =~ s/$devId,//g; + Log GetLogLevel($actName,3),"Device ".$devName." removed from ActionDetector"; +} + +sub +CUL_HM_ActCheck() +{# perform supervision + my $actHash = CUL_HM_ActGetCreateHash(); + my $tn = TimeNow(); + my $tod = int(gettimeofday()); + my $actName = $actHash->{NAME}; + delete ($actHash->{READINGS}); #cleansweep + $actHash->{READINGS}{status}{VAL} = "check performed"; + $actHash->{READINGS}{status}{TIME} = $tn; + foreach my $devId (split(",",$attr{$actName}{peerList})){ + my $devName = CUL_HM_id2Name($devId); + if(!$devName || !defined($attr{$devName}{actCycle})){ + CUL_HM_ActDel($devId); + next; + } + + $actHash->{READINGS}{"status_".$devName}{TIME} = $tn; + my (undef,$tSec)=CUL_HM_time2sec($attr{$devName}{actCycle}); + if ($tSec == 0){# detection switched off + $attr{$devName}{actStatus} = "switchedOff"; + $actHash->{READINGS}{"status_".$devName}{VAL} = "switchedOff"; + next; + } + my $tLast = $attr{$devName}{"protLastRcv"}; + my @t = localtime($tod - $tSec); #time since when a trigger is expected + my $tSince = sprintf("%04d-%02d-%02d %02d:%02d:%02d", + $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]); + if (!$tLast || $tSince gt $tLast){#no message received in timeframe + $actHash->{READINGS}{"status_".$devName}{VAL}="timedOut - last: ".$tLast; + DoTrigger($devName,"Activity: dead") + if($attr{$devName}{actStatus} ne "dead"); + $attr{$devName}{actStatus} = "dead"; + Log GetLogLevel($actName,2),"Device ".$devName." is dead"; + } + else{ + $actHash->{READINGS}{"status_".$devName}{VAL} = "alive"; + DoTrigger($devName,"Activity: alive") + if($attr{$devName}{actStatus} ne "alive"); + $attr{$devName}{actStatus} = "alive"; + Log GetLogLevel($actName,5),"Device ".$devName." is alive"; + } + } + $attr{$actName}{actCycle} = 600 if($attr{$actName}{actCycle}<30); + $actHash->{helper}{actCycle} = $attr{$actName}{actCycle}; + InternalTimer(gettimeofday()+$attr{$actName}{actCycle}, + "CUL_HM_ActCheck", "ActionDetector", 0); +} + 1;