From 82fa0ca9be9fae54c56b50cb0a756252cb37e2bb Mon Sep 17 00:00:00 2001 From: zap <> Date: Sun, 17 Jan 2021 12:27:00 +0000 Subject: [PATCH] HMCCU: Updated 4.4 Beta in contrib git-svn-id: https://svn.fhem.de/fhem/trunk@23537 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/HMCCU/CHANGED | 1 + fhem/contrib/HMCCU/FHEM/88_HMCCU.pm | 258 ++++++++++++++++--------- fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm | 44 +++-- fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm | 78 +++++--- fhem/contrib/HMCCU/FHEM/HMCCUConf.pm | 11 +- fhem/contrib/HMCCU/controls_HMCCU.txt | 8 +- 6 files changed, 260 insertions(+), 140 deletions(-) diff --git a/fhem/contrib/HMCCU/CHANGED b/fhem/contrib/HMCCU/CHANGED index 20748f7a1..a050d502b 100644 --- a/fhem/contrib/HMCCU/CHANGED +++ b/fhem/contrib/HMCCU/CHANGED @@ -1,2 +1,3 @@ + - bugfix: 88_HMCCU.pm: Fixed some bugs. New command set readingFilter - bugfix: 88_HMCCU.pm: Fixed device detection bugs diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm index 424e6e529..0eccea983 100644 --- a/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm +++ b/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm @@ -4,7 +4,7 @@ # # $Id: 88_HMCCU.pm 18745 2019-02-26 17:33:23Z zap $ # -# Version 4.4.057 +# Version 4.4.058 # # Module for communication between FHEM and Homematic CCU2/3. # @@ -58,7 +58,7 @@ my %HMCCU_CUST_CHN_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS; # HMCCU version -my $HMCCU_VERSION = '4.4.057'; +my $HMCCU_VERSION = '4.4.058'; # Timeout for CCU requests (seconds) my $HMCCU_TIMEOUT_REQUEST = 4; @@ -254,7 +254,7 @@ sub HMCCU_ExecuteSetClearCommand ($@); sub HMCCU_ExecuteSetDatapointCommand ($@); sub HMCCU_ExecuteSetParameterCommand ($@); sub HMCCU_DisplayGetParameterResult ($$$); -sub HMCCU_DisplayWeekProgram ($$$); +sub HMCCU_DisplayWeekProgram ($$$;$$); sub HMCCU_ExistsDeviceModel ($$$;$); sub HMCCU_FindParamDef ($$$); sub HMCCU_FormatDeviceInfo ($); @@ -304,6 +304,7 @@ sub HMCCU_GetDatapoint ($@); sub HMCCU_GetDatapointAttr ($$$$$); sub HMCCU_GetDatapointList ($;$$); sub HMCCU_GetSCDatapoints ($); +sub HMCCU_SetSCDatapoints ($$;$); sub HMCCU_GetStateValues ($;$$); sub HMCCU_GetValidDatapoints ($$$$;$); sub HMCCU_IsValidDatapoint ($$$$$); @@ -676,9 +677,7 @@ sub HMCCU_AggregationRules ($$) # Parse aggregation rule foreach my $spec (split(',', $r)) { - if ($spec =~ /^(name|filter|read|if|else|prefix|coll|html):(.+)$/) { - $opt{$1} = $2; - } + if ($spec =~ /^(name|filter|read|if|else|prefix|coll|html):(.+)$/) { $opt{$1} = $2; } } # Check if mandatory parameters are specified @@ -1021,23 +1020,35 @@ sub HMCCU_Notify ($$) # Process events foreach my $event (@{$events}) { if ($devname eq 'global') { + # Global event if ($event eq 'INITIALIZED') { + # FHEM initialized. Schedule post initialization tasks my $delay = $hash->{ccustate} eq 'active' && $hash->{hmccu}{ccu}{delayed} == 0 ? $HMCCU_INIT_INTERVAL0 : $hash->{hmccu}{ccu}{delay}+$HMCCU_CCU_RPC_OFFSET; HMCCU_Log ($hash, 0, "Scheduling post FHEM initialization tasks in $delay seconds"); InternalTimer (gettimeofday()+$delay, "HMCCU_PostInit", $hash, 0); } - elsif ($event =~ /^(ATTR|DELETEATTR)/) { - my $refreshAttrList = "ccucalculate|ccuflags|ccureadingfilter|ccureadingformat|". - "ccureadingname|ccuReadingPrefix|ccuscaleval|controldatapoint|hmstatevals|". - "statedatapoint|statevals|substitute:textField-long|substexcl|stripnumber"; + elsif ($event =~ /^(ATTR|DELETEATTR)/ && $init_done) { + # Attribute of client device set or deleted + my $refreshAttrList = 'ccucalculate|ccuflags|ccureadingfilter|ccureadingformat|'. + 'ccureadingname|ccuReadingPrefix|ccuscaleval|controldatapoint|hmstatevals|'. + 'statedatapoint|statevals|substitute:textField-long|substexcl|stripnumber'; + my $cmdAttrList = 'statechannel|statedatapoint|controlchannel|controldatapoint'; + my ($aCmd, $aDev, $aAtt, $aVal) = split (/\s+/, $event); if (defined($aAtt)) { my $clHash = $defs{$aDev}; - if (defined($clHash->{TYPE}) && - ($clHash->{TYPE} eq 'HMCCUCHN' || $clHash->{TYPE} eq 'HMCCUDEV') && - $aAtt =~ /^($refreshAttrList)$/) { - HMCCU_RefreshReadings ($clHash); + if (defined($clHash->{TYPE}) && ($clHash->{TYPE} eq 'HMCCUCHN' || $clHash->{TYPE} eq 'HMCCUDEV')) { + if ($aAtt =~ /^($cmdAttrList)$/) { + my ($sc, $sd, $cc, $cd, $sdCnt, $cdCnt) = HMCCU_GetSCDatapoints ($hash); + if ($cdCnt < 2) { + HMCCU_UpdateRoleCommands ($hash, $clHash, $cc); + HMCCU_UpdateAdditionalCommands ($hash, $clHash, $cc, $cd); + } + } + if ($aAtt =~ /^($refreshAttrList)$/) { + HMCCU_RefreshReadings ($clHash); + } } } } @@ -1721,9 +1732,9 @@ sub HMCCU_Get ($@) # Process command line parameters my $devSpec = shift @$a // return HMCCU_SetError ($hash, $usage); - my $devPrefix = $h->{p} // ''; # Prefix of FHEM device name - my $devSuffix = $h->{s} // ''; # Suffix of FHEM device name - my $devFormat = $h->{f} // '%n'; # Format string for FHEM device name + my $devPrefix = $h->{p} // ''; # Prefix of FHEM device name + my $devSuffix = $h->{s} // ''; # Suffix of FHEM device name + my $devFormat = $h->{f} // '%n'; # Format string for FHEM device name my ($devDefaults, $saveDef) = (1, 0); foreach my $defOpt (@$a) { if (lc($defOpt) eq 'nodefaults') { $devDefaults = 0; } @@ -1776,16 +1787,20 @@ sub HMCCU_Get ($@) my $ret = CommandDefine (undef, $cmd); if ($ret) { HMCCU_Log ($hash, 2, "Define command failed $cmd. $ret"); - push @defFailed, "$devName=$ccuName"; + push @defFailed, "definition of $devName = $ccuName: $ret"; } else { - push @defSuccess, "$devName=$ccuName"; + push @defSuccess, "defined $devName = $ccuName"; # Set device attributes - $ah{statedatapoint} = @{$detect->{stateRoles}}[$detect->{defSCh}] - if ($defMod eq 'HMCCUDEV' && $detect->{defSCh} >= 0); - $ah{controldatapoint} = @{$detect->{controlRoles}}[$detect->{defCCh}] - if ($defMod eq 'HMCCUDEV' && $detect->{defCCh} >= 0); + if ($defMod eq 'HMCCUDEV' && $detect->{defSCh} >= 0) { + my $dh = @{$detect->{stateRoles}}[$detect->{defSCh}]; + $ah{statedatapoint} = $dh->{channel}.'.'.$dh->{datapoint}; + } + if ($defMod eq 'HMCCUDEV' && $detect->{defCCh} >= 0) { + my $dh = @{$detect->{controlRoles}}[$detect->{defCCh}]; + $ah{controldatapoint} = $dh->{channel}.'.'.$dh->{datapoint}; + } foreach my $da (keys %ah) { $ret = CommandAttr (undef, "$devName $da ".$ah{$da}); if ($ret) { @@ -1805,8 +1820,8 @@ sub HMCCU_Get ($@) CommandSave (undef, undef) if (scalar(@defSuccess) > 0 && $saveDef); $result = "Results of create command:"; - $result .= "\nNew devices successfuly defined: ".join(',', @defSuccess) if (scalar(@defSuccess) > 0); - $result .= "\nFailed to define devices: ".join(',', @defFailed) if (scalar(@defFailed) > 0); + $result .= "\nNew devices successfuly defined: ".join('', map { " $_\n" } @defSuccess) if (scalar(@defSuccess) > 0); + $result .= "\nFailed to define devices: ".join('', map { " $_\n" } @defFailed) if (scalar(@defFailed) > 0); $result .= "\nFailed to assign attributes: ".join(',', @defAttrFailed) if (scalar(@defAttrFailed) > 0); $result .= "\nNot detected CCU devices: ".join(',', @notDetected) if (scalar(@notDetected) > 0); $result .= "\nHMCCUCHN devices already defined for: ".join(',', @devDefined) if (scalar(@devDefined) > 0); @@ -3325,32 +3340,32 @@ sub HMCCU_UpdateDeviceRoles ($$;$$) $address //= $clHash->{ccuaddr}; return if (!defined($address)); - my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface); - if (!defined($devDesc)) { - HMCCU_Log ($clHash, 2, "Can't get device description for $address"); + my $dd = HMCCU_GetDeviceDesc ($ioHash, $address, $iface); + if (!defined($dd)) { + HMCCU_Log ($clHash, 2, "Can't get device description for $address ".stacktraceAsString(undef)); return; } - if ($clType eq 'HMCCUCHN' && defined($devDesc->{TYPE})) { -# $clHash->{ccurole} = $devDesc->{TYPE}; - $clHash->{hmccu}{role} = $devDesc->{INDEX}.':'.$devDesc->{TYPE}; - my $parentDevDesc = HMCCU_GetDeviceDesc ($ioHash, $devDesc->{PARENT}, $iface); - if (defined($parentDevDesc)) { - $clHash->{ccutype} = $parentDevDesc->{TYPE} // '?'; - $clHash->{ccusubtype} = $parentDevDesc->{SUBTYPE} // $clHash->{ccutype}; + if ($clType eq 'HMCCUCHN' && defined($dd->{TYPE})) { +# $clHash->{ccurole} = $dd->{TYPE}; + $clHash->{hmccu}{role} = $dd->{INDEX}.':'.$dd->{TYPE}; + my $pdd = HMCCU_GetDeviceDesc ($ioHash, $dd->{PARENT}, $iface); + if (defined($pdd)) { + $clHash->{ccutype} = defined($pdd->{TYPE}) && $pdd->{TYPE} ne '' ? $pdd->{TYPE} : '?'; + $clHash->{ccusubtype} = defined($pdd->{SUBTYPE}) && $pdd->{SUBTYPE} ne '' ? $pdd->{SUBTYPE} : $clHash->{ccutype}; } } - elsif ($clType eq 'HMCCUDEV' && defined($devDesc->{CHILDREN})) { + elsif ($clType eq 'HMCCUDEV' && defined($dd->{CHILDREN})) { my @roles = (); - foreach my $c (split(',', $devDesc->{CHILDREN})) { - my $childDevDesc = HMCCU_GetDeviceDesc ($ioHash, $c, $iface); - if (defined($childDevDesc) && defined($childDevDesc->{TYPE})) { - push @roles, $childDevDesc->{INDEX}.':'.$childDevDesc->{TYPE}; + foreach my $c (split(',', $dd->{CHILDREN})) { + my $cdd = HMCCU_GetDeviceDesc ($ioHash, $c, $iface); + if (defined($cdd) && defined($cdd->{TYPE}) && $cdd->{TYPE} ne '') { + push @roles, $cdd->{INDEX}.':'.$cdd->{TYPE}; } } $clHash->{hmccu}{role} = join(',', @roles) if (scalar(@roles) > 0); - $clHash->{ccutype} = $devDesc->{TYPE} // '?'; - $clHash->{ccusubtype} = $devDesc->{SUBTYPE} // $clHash->{ccutype}; + $clHash->{ccutype} = defined($dd->{TYPE}) && $dd->{TYPE} ne '' ? $dd->{TYPE} : '?'; + $clHash->{ccusubtype} = defined($dd->{SUBTYPE}) && $dd->{SUBTYPE} ne '' ? $dd->{SUBTYPE} : $clHash->{ccutype}; } } @@ -3525,6 +3540,7 @@ sub HMCCU_GetDeviceConfig ($) foreach my $d (@devList) { my $clHash = $defs{$d}; + HMCCU_SetSCAttributes ($ioHash, $clHash); HMCCU_UpdateDevice ($ioHash, $clHash); HMCCU_UpdateDeviceRoles ($ioHash, $clHash); @@ -5534,7 +5550,7 @@ sub HMCCU_GetCCUDeviceParam ($$) # hash = hash of client or IO device # devtype = Homematic device type # chn = Channel number, -1=all channels -# oper = Valid operation: 1=Read, 2=Write, 4=Event +# oper = Valid operation, combination of 1=Read, 2=Write, 4=Event # dplistref = Reference for array with datapoints (optional) # Return number of datapoints. ###################################################################### @@ -5660,6 +5676,7 @@ sub HMCCU_IsValidDatapoint ($$$$$) return 1 if (HMCCU_IsFlag ($ioHash->{NAME}, "dptnocheck") || !exists($ioHash->{hmccu}{dp})); my $chnno; + if (defined($chn) && $chn ne '') { if ($chn =~ /^[0-9]{1,2}$/) { $chnno = $chn; @@ -5674,12 +5691,14 @@ sub HMCCU_IsValidDatapoint ($$$$$) return 0; } } - elsif ($dpt =~ /^([0-9]{1,2})\.(.+)$/) { + + if ($dpt =~ /^([0-9]{1,2})\.(.+)$/) { $chnno = $1; $dpt = $2; } - else { - HMCCU_Trace ($hash, 2, "channel number missing in datapoint $dpt"); + + if (!defined($chnno) || $chnno eq '') { + HMCCU_Trace ($hash, 2, "channel number missing for datapoint $dpt"); return 0; } @@ -6362,6 +6381,7 @@ sub HMCCU_UpdateRoleCommands ($$;$) my @cmdGetList = (); return if (!defined($clHash->{hmccu}{role}) || $clHash->{hmccu}{role} eq ''); + # Delete existing role commands delete $clHash->{hmccu}{roleCmds} if (exists($clHash->{hmccu}{roleCmds})); foreach my $chnRole (split(',', $clHash->{hmccu}{role})) { @@ -6558,6 +6578,7 @@ sub HMCCU_ExecuteRoleCommand ($@) foreach my $cmdNo (sort keys %{$clHash->{hmccu}{roleCmds}{$mode}{$command}{subcmd}}) { my $cmd = $clHash->{hmccu}{roleCmds}{$mode}{$command}{subcmd}{$cmdNo}; my $value; + my @par = (); if ($cmd->{ps} ne 'INTERNAL' && !HMCCU_IsValidParameter ($clHash, $chnAddr, $cmd->{ps}, $cmd->{dpt})) { HMCCU_Trace ($clHash, 2, "Invalid parameter $cmd->{ps}.$cmd->{dpt} for command $command"); @@ -6604,6 +6625,7 @@ sub HMCCU_ExecuteRoleCommand ($@) $clHash, "Missing parameter $cmd->{parname}. Usage: $mode $name $usage"); $value = $cmd->{look}{$vl} // return HMCCU_SetError ( $clHash, "Illegal value $vl. Use one of ". join(',', keys %{$cmd->{look}})); + push @par, $vl; } $value = HMCCU_Min ($value, HMCCU_ScaleValue ($clHash, $channel, $cmd->{dpt}, $cmd->{max}, 0)) @@ -6622,8 +6644,10 @@ sub HMCCU_ExecuteRoleCommand ($@) else { $cfval{$cmd->{dpt}} = $value; } + + push @par, $value if (defined($value)); $cmdFnc{$cmdNo}{fnc} = $cmd->{fnc}; - $cmdFnc{$cmdNo}{par} = $value; + $cmdFnc{$cmdNo}{par} = \@par; } my $ndpval = scalar(keys %dpval); @@ -6669,7 +6693,7 @@ sub HMCCU_ExecuteRoleCommand ($@) if ($cmdFnc{$cmdNo}{fnc} ne '') { # :( no strict "refs"; - $disp .= &{$cmdFnc{$cmdNo}{fnc}}($ioHash, $clHash, $resp, $cmdFnc{$cmdNo}{par}); + $disp .= &{$cmdFnc{$cmdNo}{fnc}}($ioHash, $clHash, $resp, @{$cmdFnc{$cmdNo}{par}}); use strict "refs"; } } @@ -7011,21 +7035,25 @@ sub HMCCU_DisplayGetParameterResult ($$$) # Get week program(s) as html table ###################################################################### -sub HMCCU_DisplayWeekProgram ($$$) +sub HMCCU_DisplayWeekProgram ($$$;$$) { - my ($ioHash, $clHash, $resp, $program) = @_; + my ($ioHash, $clHash, $resp, $programName, $program) = @_; + $programName //= 'all'; + $program //= 'all'; my @weekDay = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'); my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, $resp); - return "No data available for week program(s)" if (!exists($clHash->{hmccu}{tt})); + return "No data available for week program(s) $program" + if (!exists($clHash->{hmccu}{tt}) || ($program ne 'all' && !exists($clHash->{hmccu}{tt}{$program}))); my $s = ''; foreach my $w (sort keys %{$clHash->{hmccu}{tt}}) { - next if (defined($program) && "$w" ne "$program" && "$program" ne 'all'); + next if ("$w" ne "$program" && "$program" ne 'all'); my $p = $clHash->{hmccu}{tt}{$w}; - $s .= '

Week Program '.$w.'


'; + my $pn = $programName ne 'all' ? $programName : $w+1; + $s .= '

Week Program '.$pn.'


'; foreach my $d (sort keys %{$p->{ENDTIME}}) { $s .= ''; foreach my $h (sort { $a <=> $b } keys %{$p->{ENDTIME}{$d}}) { @@ -7096,6 +7124,52 @@ sub HMCCU_CheckParameter ($$;$$$) return 0; } +###################################################################### +# Set or delete state and control datapoints +# Parameter d specifies the value to be set +###################################################################### + +sub HMCCU_SetSCDatapoints ($$;$) +{ + my ($clHash, $d, $v) = @_; + + my $ioHash = HMCCU_GetHash ($clHash); + + # Flags: 1=statechannel, 2=statedatapoint, 4=controlchannel, 8=controldatapoint + my %flags = ( + 'state' => 3, 'control' => 12, + 'statechannel' => 1, 'statedatapoint' => 2, + 'controlchannel' => 4, 'controldatapoint' => 8 + ); + + my $chn; + my $dpt; + my $f = $flags{$d} // return 0; + $d =~ s/^(state|control)(channel|datapoint)$/$1/; + + if (defined($v)) { + if ($f & 10) { + ($chn, $dpt) = $v =~ /^([0-9]{1,2})\.(.+)/ ? ($1, $2) : ($clHash->{hmccu}{$d}{chn}, $v); + } + elsif ($f & 5) { + return 0 if ($v !~ /^[0-9]{1,2}$/); + ($chn, $dpt) = ($v, $clHash->{hmccu}{$d}{dpt}); + } + + return 0 if ($init_done && defined($chn) && $chn ne '' && defined($dpt) && $dpt ne '' && + !HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $dpt, $f & 3 ? 1 : 2)); + } + else { + $chn = '' if ($f & 5); + $dpt = '' if ($f & 10); + } + + $clHash->{hmccu}{$d}{chn} = $chn if (defined($chn)); + $clHash->{hmccu}{$d}{dpt} = $dpt if (defined($dpt)); + + return 1; +} + ###################################################################### # Get state and control channel and datapoint of a device. # Priority depends on FHEM device type: @@ -7268,8 +7342,10 @@ sub HMCCU_DetectSCDev ($;$$$$) if ($sc ne '' && $rc eq $sc) { # If channel of current role matches state channel, use datapoint specified # in $HMCCU_STATECONTROL as state datapoint - $sd = $HMCCU_STATECONTROL->{$role}{S}; + $rsc = $sc; + $rsd = $HMCCU_STATECONTROL->{$role}{S}; $clHash->{ccurolestate} = $role; + $rsdCnt = 1; } else { # If state channel is not defined or role channel doesn't match state channel, @@ -7284,40 +7360,53 @@ sub HMCCU_DetectSCDev ($;$$$$) } elsif ($HMCCU_STATECONTROL->{$role}{P} == $scp) { # Priority of this role is equal to previous priority. We found more - # than 1 matching roles. Always use the last one - $rsc = $rc; - $rsd = $HMCCU_STATECONTROL->{$role}{S}; + # than 1 matching roles. We use the first matching role/channel, but count + # the number of matching roles. + if ($rsc eq '') { + $rsc = $rc; + $rsd = $HMCCU_STATECONTROL->{$role}{S}; + $clHash->{ccurolestate} = $role; + } $rsdCnt++; - $clHash->{ccurolestate} = $role; } } } if ($cd eq '' && $HMCCU_STATECONTROL->{$role}{C} ne '') { if ($cc ne '' && $rc eq $cc) { - $cd = $HMCCU_STATECONTROL->{$role}{C}; + $rcc = $cc; + $rcd = $HMCCU_STATECONTROL->{$role}{C}; $clHash->{ccurolectrl} = $role; + $rcdCnt = 1; } else { + # If control channel is not defined or role channel doesn't match control channel, + # assign control channel and datapoint considering role priority if ($HMCCU_STATECONTROL->{$role}{P} > $scp) { + # Priority of this role is higher than the previous priority $scp = $HMCCU_STATECONTROL->{$role}{P}; $rcc = $rc; $rcd = $HMCCU_STATECONTROL->{$role}{C}; $rcdCnt = 1; $clHash->{ccurolectrl} = $role; } - elsif ($HMCCU_STATECONTROL->{$role}{P} == $scp) { - $rcc = $rc; - $rcd = $HMCCU_STATECONTROL->{$role}{C}; + elsif ($HMCCU_STATECONTROL->{$role}{P} == $scp) { + # Priority of this role is equal to previous priority. We found more + # than 1 matching roles. We use the first matching role/channel, but count + # the number of matching roles. + if ($rcc eq '') { + $rcc = $rc; + $rcd = $HMCCU_STATECONTROL->{$role}{C}; + $clHash->{ccurolectrl} = $role; + } $rcdCnt++; - $clHash->{ccurolectrl} = $role; } } } } } - ($sc, $sd) = ($rsc, $rsd) if ($rsdCnt == 1 && $sd eq ''); - ($cc, $cd) = ($rcc, $rcd) if ($rcdCnt == 1 && $cd eq ''); + ($sc, $sd) = ($rsc, $rsd) if ($rsdCnt > 0 && $sd eq ''); + ($cc, $cd) = ($rcc, $rcd) if ($rcdCnt > 0 && $cd eq ''); return ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt); } @@ -7362,7 +7451,7 @@ sub HMCCU_DetectDevice ($$;$) my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface); if (!defined($devDesc)) { - HMCCU_Log ($ioHash, 2, "Can't get device description for $address"); + HMCCU_Log ($ioHash, 2, "Can't get device description for $address ".stacktraceAsString(undef)); return undef; } @@ -7409,10 +7498,10 @@ sub HMCCU_DetectDevice ($$;$) # If there are more than 1 stateRole but only one controlRole and only one of the stateRoles has # the same channel number as the controlRole, ignore all other stateRoles - if ($stateRoleCnt > 1 && $ctrlRoleCnt == 1) { - my @newStateRoles = grep { $_->{channel} == $controlRoles[0]->{channel} } @stateRoles; - @stateRoles = @newStateRoles if (scalar(@newStateRoles) == 1); - } +# if ($stateRoleCnt > 1 && $ctrlRoleCnt == 1) { +# my @newStateRoles = grep { $_->{channel} == $controlRoles[0]->{channel} } @stateRoles; +# @stateRoles = @newStateRoles if (scalar(@newStateRoles) == 1); +# } # Count unique state and control roles my %uniqStateRoles; @@ -8409,8 +8498,9 @@ sub HMCCU_RPCRequest ($$$$;$$) # *** HELPER FUNCTIONS *** ###################################################################### -sub HMCCU_SetIfDef { $_[0] = $_[1] if defined($_[1]) } -sub HMCCU_SetIfEx { $_[0] = $_[1] if exists($_[1]) } +sub HMCCU_SetIfDef { $_[0] = $_[1] if (defined($_[1])) } +sub HMCCU_SetIfEx { $_[0] = $_[1] if (exists($_[1])) } +sub HMCCU_SetVal { $_[0] = defined $_[1] && $_[1] ne '' ? $_[1] : $_[2] } ###################################################################### # Return Prefix.Value if value is defined. Otherwise default. @@ -8422,7 +8512,6 @@ sub HMCCU_DefStr ($;$$) $p //= ''; $d //= ''; - return defined($v) && $v ne '' ? $p.$v : $d; } @@ -8446,12 +8535,9 @@ sub HMCCU_IsFltNum ($;$) my ($value, $flag) = @_; $flag //= 0; - if ($flag) { - return defined($value) && $value =~ /^[+-]?\d*\.?\d+?$/ ? 1 : 0; - } - else { - return defined($value) && $value =~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/ ? 1 : 0; - } + return $flag ? + (defined($value) && $value =~ /^[+-]?\d*\.?\d+?$/ ? 1 : 0) : + (defined($value) && $value =~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/ ? 1 : 0); } ###################################################################### @@ -8467,7 +8553,7 @@ sub HMCCU_IsIntNum ($) ###################################################################### # Get device state from maintenance channel 0 -# Return values for readings (devState, battery, alive) +# Update corresponding readings. # Default is unknown for each reading ###################################################################### @@ -8817,12 +8903,11 @@ sub HMCCU_CalculateReading ($$) sub HMCCU_Encrypt ($) { my ($istr) = @_; - my $ostr = ''; - my $id = getUniqueId() // ''; - return '' if ($id eq ''); + my $id = getUniqueId() // return ''; my $key = $id; + my $ostr = ''; foreach my $c (split //, $istr) { my $k = chop($key); if ($k eq '') { @@ -8842,13 +8927,12 @@ sub HMCCU_Encrypt ($) sub HMCCU_Decrypt ($) { my ($istr) = @_; - my $ostr = ''; - my $id = getUniqueId() // ''; - return '' if ($id eq ''); + my $id = getUniqueId() // return ''; my $key = $id; - for my $c (map { pack('C', hex($_)) } ($istr =~ /(..)/g)) { + my $ostr = ''; + foreach my $c (map { pack('C', hex($_)) } ($istr =~ /(..)/g)) { my $k = chop($key); if ($k eq '') { $key = $id; diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm index d7dd9d2b7..ef0647f31 100644 --- a/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm +++ b/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm @@ -4,7 +4,7 @@ # # $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $ # -# Version 4.4.031 +# Version 4.4.033 # # (c) 2020 zap (zap01 t-online de) # @@ -158,11 +158,9 @@ sub HMCCUCHN_InitDevice ($$) $devHash->{ccutype} = $dt; $devHash->{ccudevstate} = 'active'; - # Initialize user attributes - HMCCU_SetSCAttributes ($ioHash, $devHash); - if ($init_done) { # Interactive device definition + HMCCU_SetSCAttributes ($ioHash, $devHash); HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); HMCCU_UpdateDevice ($ioHash, $devHash); HMCCU_UpdateDeviceRoles ($ioHash, $devHash); @@ -219,29 +217,30 @@ sub HMCCUCHN_Rename ($$) sub HMCCUCHN_Attr ($@) { my ($cmd, $name, $attrname, $attrval) = @_; - my $hash = $defs{$name}; + my $clHash = $defs{$name}; + my $ioHash = HMCCU_GetHash ($clHash); if ($cmd eq 'set') { return 'Missing attribute value' if (!defined($attrval)); if ($attrname eq 'IODev') { - $hash->{IODev} = $defs{$attrval}; + $clHash->{IODev} = $defs{$attrval}; } elsif ($attrname eq 'statevals') { - return 'Device is read only' if ($hash->{readonly} eq 'yes'); + return 'Device is read only' if ($clHash->{readonly} eq 'yes'); } - elsif ($attrname eq 'statedatapoint') { - return "Datapoint $attrval is not valid" if ($init_done && - !HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $hash->{ccuaddr}, $attrval, 1)); - $hash->{hmccu}{state}{dpt} = $attrval; + elsif ($attrname =~ /^(state|control)datapoint$/) { + return "Invalid value $attrval" + if (!HMCCU_SetSCDatapoints ($clHash, $attrname, $attrval)); } - elsif ($attrname eq 'controldatapoint') { - return "Datapoint $attrval is not valid" if ($init_done && - !HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $hash->{ccuaddr}, $attrval, 2)); - $hash->{hmccu}{control}{dpt} = $attrval; + } + elsif ($cmd eq 'del') { + if ($attrname =~ /^(state|control)datapoint$/) { + # Reset value + HMCCU_SetSCDatapoints ($clHash, $attrname); } } - HMCCU_RefreshReadings ($hash) if ($init_done); +# HMCCU_RefreshReadings ($clHash) if ($init_done); return undef; } @@ -312,6 +311,12 @@ sub HMCCUCHN_Set ($@) elsif ($lcopt =~ /^(config|values)$/) { return HMCCU_ExecuteSetParameterCommand ($ioHash, $hash, $lcopt, $a, $h); } + elsif ($lcopt =~ 'readingfilter') { + my $filter = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name readingFilter {datapointList}"); + $filter =~ s/,/\|/g; + $filter = '^('.$filter.')$'; + return CommandAttr (undef, "$name ccureadingfilter $filter"); + } elsif ($lcopt eq 'defaults') { my $mode = shift @$a // 'update'; $rc = HMCCU_SetDefaultAttributes ($hash, { mode => $mode, role => undef, ctrlChn => $cc }); @@ -326,6 +331,9 @@ sub HMCCUCHN_Set ($@) my ($a, $c) = split(":", $hash->{ccuaddr}); my $dpCount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, $c, 2); $retmsg .= ' datapoint' if ($dpCount > 0); + my @dpList = (); + $dpCount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, $c, 5, \@dpList); + $retmsg .= ' readingFilter:multiple-strict,'.join(',', @dpList) if ($dpCount > 0); $retmsg .= " $cmdList" if ($cmdList ne ''); } # return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); @@ -534,6 +542,10 @@ sub HMCCUCHN_Get ($@) Example: Turn dimmer on for 600 second. Increase light to 100% over 10 seconds
set myswitch pct 100 600 10
+
  • set <name> readingFilter <datapoint-list>
    + Set attribute ccureadingfilter by selecting a list of datapoints. Parameter datapoint-list + is a comma seperated list of datapoints. +

  • set <name> stop
    [blind] Set datapoint STOP of a channel to true. This command is only available, if the channel contains a datapoint STOP. diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm index 8465cd847..7a6cde2be 100644 --- a/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm +++ b/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm @@ -4,7 +4,7 @@ # # $Id: 88_HMCCUDEV.pm 18552 2019-02-10 11:52:28Z zap $ # -# Version 4.4.037 +# Version 4.4.040 # # (c) 2020 zap (zap01 t-online de) # @@ -98,6 +98,7 @@ sub HMCCUDEV_Define ($@) $hash->{hmccu}{group} = $h->{group} if (exists ($h->{group})); $hash->{hmccu}{nodefaults} = $init_done ? 0 : 1; $hash->{hmccu}{semDefaults} = 0; + $hash->{hmccu}{forcedev} = 0; if (exists($h->{address})) { return 'Option address not allowed' if ($init_done || $devspec ne 'virtual'); @@ -219,20 +220,19 @@ sub HMCCUDEV_InitDevice ($$) $devHash->{ccutype} = $dt; $devHash->{hmccu}{channels} = $dc; - # Initialize user attributes - my $detect = HMCCU_DetectDevice ($ioHash, $da, $di); - HMCCU_SetSCAttributes ($ioHash, $devHash, $detect); - # Inform HMCCU device about client device return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME})); $devHash->{ccudevstate} = 'active'; if ($init_done) { + # Initialize user attributes + my $detect = HMCCU_DetectDevice ($ioHash, $da, $di); return "Specify option 'force' for HMCCUDEV or use HMCCUCHN instead (recommended). Command: define $name HMCCUCHN $detect->{defAdd}" if (defined($detect) && $detect->{defMod} eq 'HMCCUCHN' && $devHash->{hmccu}{forcedev} == 0); # Interactive device definition + HMCCU_SetSCAttributes ($ioHash, $devHash, $detect); HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); HMCCU_UpdateDevice ($ioHash, $devHash); HMCCU_UpdateDeviceRoles ($ioHash, $devHash); @@ -352,43 +352,46 @@ sub HMCCUDEV_Rename ($$) sub HMCCUDEV_Attr ($@) { my ($cmd, $name, $attrname, $attrval) = @_; - my $hash = $defs{$name}; + my $clHash = $defs{$name}; + my $ioHash = HMCCU_GetHash ($clHash); if ($cmd eq 'set') { return "Missing value of attribute $attrname" if (!defined($attrval)); if ($attrname eq 'IODev') { - $hash->{IODev} = $defs{$attrval}; + $clHash->{IODev} = $defs{$attrval}; } elsif ($attrname eq 'statevals') { - return "Device is read only" if ($hash->{readonly} eq 'yes'); + return "Device is read only" if ($clHash->{readonly} eq 'yes'); } - elsif ($attrname eq 'statechannel') { - $hash->{hmccu}{state}{chn} = $attrval; - } - elsif ($attrname eq 'statedatapoint') { - if ($attrval =~ /^([0-9]{1,2})\.(.+)/) { - $hash->{hmccu}{state}{chn} = $1; - $hash->{hmccu}{state}{dpt} = $2; - } - else { - $hash->{hmccu}{state}{dpt} = $attrval; - } - } - elsif ($attrname eq 'controlchannel') { - $hash->{hmccu}{control}{chn} = $attrval; - } - elsif ($attrname eq 'controldatapoint') { - if ($attrval =~ /^([0-9]{1,2})\.(.+)/) { - $hash->{hmccu}{control}{chn} = $1; - $hash->{hmccu}{control}{dpt} = $2; - } - else { - $hash->{hmccu}{control}{dpt} = $attrval; + elsif ($attrname =~ /^(state|control)(channel|datapoint)$/) { + return "Invalid value $attrval" + if (!HMCCU_SetSCDatapoints ($clHash, $attrname, $attrval)); + if ($init_done && exists($clHash->{hmccu}{control}{chn}) && $clHash->{hmccu}{control}{chn} ne '') { + HMCCU_UpdateRoleCommands ($ioHash, $clHash, $clHash->{hmccu}{control}{chn}); + HMCCU_UpdateAdditionalCommands ($ioHash, $clHash, $clHash->{hmccu}{control}{chn}, $clHash->{hmccu}{control}{dpt}) + if (exists($clHash->{hmccu}{control}{dpt}) && $clHash->{hmccu}{control}{dpt} ne ''); } } } + elsif ($cmd eq 'del') { + if ($attrname =~ /^(state|control)(channel|datapoint)$/) { + # Reset value + HMCCU_SetSCDatapoints ($clHash, $attrname); + delete $clHash->{hmccu}{roleCmds} + if (exists($clHash->{hmccu}{roleCmds}) && + (!exists($clHash->{hmccu}{control}{chn}) || $clHash->{hmccu}{control}{chn} eq '')); + } + } - HMCCU_RefreshReadings ($hash) if ($init_done); +# if ($init_done && $attrname =~ /^(statechannel|controlchannel|statedatapoint|controldatapoint)$/) { +# my ($sc, $sd, $cc, $cd, $sdCnt, $cdCnt) = HMCCU_GetSCDatapoints ($ioHash); +# if ($cdCnt < 2) { +# HMCCU_UpdateRoleCommands ($ioHash, $clHash, $cc); +# HMCCU_UpdateAdditionalCommands ($ioHash, $clHash, $cc, $cd); +# } +# } + +# HMCCU_RefreshReadings ($clHash) if ($init_done); return; } @@ -460,6 +463,11 @@ sub HMCCUDEV_Set ($@) elsif ($lcopt =~ /^(config|values)$/) { return HMCCU_ExecuteSetParameterCommand ($ioHash, $hash, $opt, $a, $h); } + elsif ($lcopt =~ 'readingfilter') { + my $filter = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name readingFilter {datapointList}"); + $filter = join(';', map { (my $f = $_) =~ s/\.(.+)/\.\^$1\$/; $f } split(',', $filter)); + return CommandAttr (undef, "$name ccureadingfilter $filter"); + } elsif ($lcopt eq 'defaults') { my $mode = shift @$a // 'update'; $rc = HMCCU_SetDefaultAttributes ($hash, { mode => $mode, role => undef, ctrlChn => $cc }); @@ -474,6 +482,9 @@ sub HMCCUDEV_Set ($@) $retmsg .= ' config'; my $dpCount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, -1, 2); $retmsg .= ' datapoint' if ($dpCount > 0); + my @dpList = (); + $dpCount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, -1, 5, \@dpList); + $retmsg .= ' readingFilter:multiple-strict,'.join(',', @dpList) if ($dpCount > 0); $retmsg .= " $cmdList" if ($cmdList ne ''); } # return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); @@ -692,6 +703,11 @@ sub HMCCUDEV_Get ($@)
  • set <name> pct <value;> [<ontime> [<ramptime>]]
    see HMCCUCHN

  • +
  • set <name> readingFilter <datapoint-list>
    + Set attribute ccureadingfilter by selecting a list of datapoints. Parameter datapoint-list + is a comma seperated list of datapoints. The datapoints must be specifed in format + "channel-number.datapoint-name". +

  • set <name> <statevalue>
    State datapoint of a CCU device channel is set to 'statevalue'. State channel and state datapoint must be defined as attribute 'statedatapoint'. Values for statevalue diff --git a/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm b/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm index ba9f20e98..35e20aff3 100644 --- a/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm +++ b/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm @@ -4,7 +4,7 @@ # # $Id: HMCCUConf.pm 18552 2019-02-10 11:52:28Z zap $ # -# Version 4.8.016 +# Version 4.8.017 # # Configuration parameters for HomeMatic devices. # @@ -28,7 +28,7 @@ use vars qw(%HMCCU_CHN_DEFAULTS); use vars qw(%HMCCU_DEV_DEFAULTS); use vars qw(%HMCCU_SCRIPTS); -$HMCCU_CONFIG_VERSION = '4.8.016'; +$HMCCU_CONFIG_VERSION = '4.8.017'; ###################################################################### # Map subtype to default role. Subtype is only available for HMIP @@ -38,6 +38,7 @@ $HMCCU_CONFIG_VERSION = '4.8.016'; %HMCCU_DEF_ROLE = ( 'ASIR' => 'ALARM_SWITCH_VIRTUAL_RECEIVER', + 'FSM' => 'SWITCH_VIRTUAL_RECEIVER', 'PSM' => 'SWITCH_VIRTUAL_RECEIVER', 'SD' => 'SMOKE_DETECTOR' ); @@ -93,6 +94,9 @@ $HMCCU_CONFIG_VERSION = '4.8.016'; 'SWITCH' => { F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false', P => 2 }, + 'SWITCH_TRANSMITTER' => { + F => 3, S => 'STATE', C => '', V => '', P => 1 + }, 'SWITCH_VIRTUAL_RECEIVER' => { F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false', P => 2 }, @@ -418,6 +422,9 @@ $HMCCU_CONFIG_VERSION = '4.8.016'; 'SWITCH' => { 'STATE' => { '0' => 'off', 'false' => 'off', '1' => 'on', 'true' => 'on', 'off' => '0', 'on' => '1' }, }, + 'SWITCH_TRANSMITTER' => { + 'STATE' => { '0' => 'off', 'false' => 'off', '1' => 'on', 'true' => 'on', 'off' => '0', 'on' => '1' }, + }, 'SWITCH_VIRTUAL_RECEIVER' => { 'STATE' => { '0' => 'off', 'false' => 'off', '1' => 'on', 'true' => 'on', 'off' => '0', 'on' => '1' }, }, diff --git a/fhem/contrib/HMCCU/controls_HMCCU.txt b/fhem/contrib/HMCCU/controls_HMCCU.txt index f4b3814a1..3435a07dd 100644 --- a/fhem/contrib/HMCCU/controls_HMCCU.txt +++ b/fhem/contrib/HMCCU/controls_HMCCU.txt @@ -1,5 +1,5 @@ UPD 2020-12-30_19:07:35 102657 FHEM/88_HMCCURPCPROC.pm -UPD 2021-01-03_16:38:44 78201 FHEM/HMCCUConf.pm -UPD 2020-12-30_18:47:18 41583 FHEM/88_HMCCUCHN.pm -UPD 2020-12-30_18:47:01 320619 FHEM/88_HMCCU.pm -UPD 2020-12-30_18:47:10 32244 FHEM/88_HMCCUDEV.pm +UPD 2021-01-17_13:14:22 78455 FHEM/HMCCUConf.pm +UPD 2021-01-17_13:14:07 42113 FHEM/88_HMCCUCHN.pm +UPD 2021-01-17_13:13:53 323775 FHEM/88_HMCCU.pm +UPD 2021-01-17_13:14:00 33721 FHEM/88_HMCCUDEV.pm
  • '.$weekDay[$d].'