diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm index ac6f65ff0..0ed80d4af 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.050 +# Version 4.4.051 # # Module for communication between FHEM and Homematic CCU2/3. # @@ -43,7 +43,8 @@ use HMCCUConf; # Import configuration data my $HMCCU_STATECONTROL = \%HMCCUConf::HMCCU_STATECONTROL; my $HMCCU_READINGS = \%HMCCUConf::HMCCU_READINGS; -my $HMCCU_ROLECMDS = \%HMCCUConf::HMCCU_ROLECMDS; +my $HMCCU_ROLECMDS = \%HMCCUConf::HMCCU_ROLECMDS; +my $HMCCU_GETROLECMDS = \%HMCCUConf::HMCCU_GETROLECMDS; my $HMCCU_ATTR = \%HMCCUConf::HMCCU_ATTR; my $HMCCU_CONVERSIONS = \%HMCCUConf::HMCCU_CONVERSIONS; my $HMCCU_CHN_DEFAULTS = \%HMCCUConf::HMCCU_CHN_DEFAULTS; @@ -55,7 +56,7 @@ my %HMCCU_CUST_CHN_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS; # HMCCU version -my $HMCCU_VERSION = '4.4.049'; +my $HMCCU_VERSION = '4.4.051'; # Timeout for CCU requests (seconds) my $HMCCU_TIMEOUT_REQUEST = 4; @@ -249,7 +250,8 @@ sub HMCCU_ExecuteGetParameterCommand ($@); sub HMCCU_ExecuteSetClearCommand ($@); sub HMCCU_ExecuteSetDatapointCommand ($@); sub HMCCU_ExecuteSetParameterCommand ($@); -sub HMCCU_DisplayWeekProgram ($;$); +sub HMCCU_DisplayGetParameterResult ($$$); +sub HMCCU_DisplayWeekProgram ($$$); sub HMCCU_ExistsDeviceModel ($$$;$); sub HMCCU_FindParamDef ($$$); sub HMCCU_FormatDeviceInfo ($); @@ -3398,6 +3400,11 @@ sub HMCCU_GetDeviceConfig ($) HMCCU_Log ($ioHash, 2, "No RPC device found for interface $iface. Can't read device config."); } } + + # Set CCU firmware version + if (exists($ioHash->{hmccu}{device}{'BidCos-RF'}) && exists($ioHash->{hmccu}{device}{'BidCos-RF'}{'BidCoS-RF'})) { + $ioHash->{firmware} = $ioHash->{hmccu}{device}{'BidCos-RF'}{'BidCoS-RF'}{FIRMWARE} // '?'; + } # Get defined FHEM devices my @devList = HMCCU_FindClientDevices ($ioHash, '(HMCCUDEV|HMCCUCHN)'); @@ -3831,7 +3838,8 @@ sub HMCCU_GetClientDeviceModel ($;$) # $paramset - Valid paramset for device or channel. # $parameter - Parameter name. # Returns undef on error. On success return a reference to the -# parameter or parameter set definition (if $parameter is not specified). +# parameter or parameter set definition, if $parameter is not +# specified. ###################################################################### sub HMCCU_GetParamDef ($$$;$) @@ -3849,8 +3857,8 @@ sub HMCCU_GetParamDef ($$$;$) my $model = HMCCU_GetDeviceModel ($hash, $devDesc->{_model}, $devDesc->{_fw_ver}, $chnNo); if (defined($model) && exists($model->{$paramset})) { - if (defined($parameter) && exists($model->{$paramset}{$parameter})) { - return $model->{$paramset}{$parameter}; + if (defined($parameter)) { + return exists($model->{$paramset}{$parameter}) ? $model->{$paramset}{$parameter} : undef; } else { return $model->{$paramset} @@ -4182,6 +4190,8 @@ sub HMCCU_UpdateParamsetReadings ($$$;$) my $cv = $v; my $sv; + HMCCU_Trace ($clHash, 2, "ParamsetReading $a.$c.$ps.$p=$v"); + # Key for storing values in client device hash. Indirect updates of virtual # devices are stored with device address in key. my $chKey = $devAddr ne $a ? "$chnAddr.$p" : "$c.$p"; @@ -4299,6 +4309,7 @@ sub HMCCU_UpdateInternalValues ($$$$$) if ($type eq 'SVAL') { if ($chkey =~ /^[0-9d]+\.P([0-9])_([A-Z]+)_($weekDayExp)_([0-9]+)$/) { my ($prog, $valName, $day, $time) = ($1, $2, $3, $4); + $prog--; if (exists($weekDay{$day})) { $ch->{hmccu}{tt}{$prog}{$valName}{$weekDay{$day}}{$time} = $value; } @@ -4306,7 +4317,7 @@ sub HMCCU_UpdateInternalValues ($$$$$) elsif ($chkey =~ /^[0-9d]+\.([A-Z]+)_($weekDayExp)_([0-9]+)$/) { my ($valName, $day, $time) = ($1, $2, $3); if (exists($weekDay{$day})) { - $ch->{hmccu}{tt}{1}{$valName}{$weekDay{$day}}{$time} = $value; + $ch->{hmccu}{tt}{0}{$valName}{$weekDay{$day}}{$time} = $value; } } } @@ -6188,22 +6199,25 @@ sub HMCCU_GetStateValues ($;$$) # subtracted from current datapoint value. # # Output format: -# {'cmd'}{syntax} - Command syntax (input definition) -# {'cmd'}{channel} - Channel number -# {'cmd'}{role} - Channel role -# {'cmd'}{usage} - Usage string -# {'cmd'}{cmdlist} - Set command definition -# {'cmd'}{subcount} - Number of sub commands -# {'cmd'}{subcmd}{'nnn'}{ps} - Parameter set name -# {'cmd'}{subcmd}{'nnn'}{dpt} - Datapoint name -# {'cmd'}{subcmd}{'nnn'}{type} - Datapoint type -# {'cmd'}{subcmd}{'nnn'}{parname} - Parameter name (default=datapoint) -# {'cmd'}{subcmd}{'nnn'}{partype} - Parameter type (s. below) -# {'cmd'}{subcmd}{'nnn'}{args} - Comma separated list of valid values -# or default value or fix value or '' -# {'cmd'}{subcmd}{'nnn'}{min} - Minimum value -# {'cmd'}{subcmd}{'nnn'}{max} - Maximum value -# {'cmd'}{subcmd}{'nnn'}{unit} - Unit of parameter value +# {cmdType} - Command type 'set' or 'get' +# {'cmd'}{syntax} - Command syntax (input definition) +# {'cmd'}{channel} - Channel number +# {'cmd'}{role} - Channel role +# {'cmd'}{usage} - Usage string +# {'cmd'}{subcount} - Number of sub commands +# {'cmd'}{subcmd}{'nnn'}{ps} - Parameter set name +# {'cmd'}{subcmd}{'nnn'}{dpt} - Datapoint name +# {'cmd'}{subcmd}{'nnn'}{type} - Datapoint type +# {'cmd'}{subcmd}{'nnn'}{parname} - Parameter name (default=datapoint) +# {'cmd'}{subcmd}{'nnn'}{partype} - Parameter type (s. below) +# {'cmd'}{subcmd}{'nnn'}{args} - Comma separated list of valid values +# or default value or fix value or '' +# {'cmd'}{subcmd}{'nnn'}{min} - Minimum value +# {'cmd'}{subcmd}{'nnn'}{max} - Maximum value +# {'cmd'}{subcmd}{'nnn'}{unit} - Unit of parameter value +# {'cmd'}{subcmd}{'nnn'}{fnc} - Function name (called with parameter value) +# {cmdlist}{set} - Set command definition +# {cmdlist}{get} - Get command definition # # Datapoint types: BOOL, INTEGER, ENUM, ACTION, STRING # @@ -6218,7 +6232,8 @@ sub HMCCU_UpdateRoleCommands ($$;$) my ($ioHash, $clHash, $chnNo) = @_; my %pset = ('V' => 'VALUES', 'M' => 'MASTER', 'D' => 'MASTER'); - my @cmdList = (); + my @cmdSetList = (); + my @cmdGetList = (); return if (!defined($clHash->{hmccu}{role}) || $clHash->{hmccu}{role} eq ''); delete $clHash->{hmccu}{roleCmds} if (exists($clHash->{hmccu}{roleCmds})); @@ -6227,110 +6242,127 @@ sub HMCCU_UpdateRoleCommands ($$;$) my ($channel, $role) = split(':', $chnRole); next if (!defined($role) || !exists($HMCCU_ROLECMDS->{$role})); - foreach my $cmd (keys %{$HMCCU_ROLECMDS->{$role}}) { + foreach my $cmdKey (keys %{$HMCCU_ROLECMDS->{$role}}) { next if (defined($chnNo) && $chnNo ne '' && $chnNo != $channel && $chnNo ne 'd'); my $cmdChn = $channel; + my $cmdType = 'set'; + my $cmd = $cmdKey; + if ($cmdKey =~ /^(set|get) (.+)$/) { + $cmdType = $1; + $cmd = $2; + } - $clHash->{hmccu}{roleCmds}{$cmd}{syntax} = $HMCCU_ROLECMDS->{$role}{$cmd}; - $clHash->{hmccu}{roleCmds}{$cmd}{role} = $role; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{syntax} = $HMCCU_ROLECMDS->{$role}{$cmdKey}; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{role} = $role; my $cnt = 0; - my $usage = $cmd; + my $cmdDef = $cmd; + my $usage = $cmdDef; my $cmdArgList = ''; - my @parTypes = (0, 0, 0); + my @parTypes = (0, 0, 0, 0); - foreach my $subCmd (split(/\s+/, $HMCCU_ROLECMDS->{$role}{$cmd})) { - my $pt; + foreach my $subCmd (split(/\s+/, $HMCCU_ROLECMDS->{$role}{$cmdKey})) { + my $pt = 0; # Default = no parameter my $scn = sprintf ("%03d", $cnt); - my ($ps, $dpt, $par) = split(/:/, $subCmd); + my ($ps, $dpt, $par, $fnc) = split(/:/, $subCmd); my ($addr, undef) = HMCCU_SplitChnAddr ($clHash->{ccuaddr}); $cmdChn = 'd' if ($ps eq 'D'); + my $paramDef = HMCCU_GetParamDef ($ioHash, "$addr:$cmdChn", $pset{$ps}, $dpt); if (!defined($paramDef)) { HMCCU_Log ($ioHash, 2, "Can't get paramdef of $addr:$cmdChn.$dpt"); next; } + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{min} = $paramDef->{MIN}; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{max} = $paramDef->{MAX}; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{unit} = $paramDef->{UNIT}; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{ps} = $pset{$ps}; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{dpt} = $dpt; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{fnc} = $fnc // ''; + + if (defined($par) && $par ne '') { + if ($par =~ /^#(.+)$/) { + # Parameter list + my $argList = ''; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{parname} = $1; + $pt = 1; # Enum - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{ps} = $pset{$ps}; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{dpt} = $dpt; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{min} = $paramDef->{MIN}; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{max} = $paramDef->{MAX}; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{unit} = $paramDef->{UNIT}; - - if ($par =~ /^#(.+)$/) { - my $argList = ''; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{parname} = $1; - $pt = 1; + if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) { + $par = $paramDef->{VALUE_LIST}; + $par =~ s/[ ]+/-/g; + $argList = $par; + my @el = split(',', $par); - if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) { - $par = $paramDef->{VALUE_LIST}; - $par =~ s/[ ]+/-/g; - $argList = $par; - my @el = split(',', $par); - - while (my ($i, $e) = each @el) { - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{look}{$e} = $i; + while (my ($i, $e) = each @el) { + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$e} = $i; + } } + else { + my ($pn, $pv) = split('=', $par); + $argList = $pv // ''; + foreach my $e (split(',', $argList)) { + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{look}{$e} = $e; + } + } + + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{args} = $argList; + $cmdArgList = $argList; + $usage .= " {$argList}"; + } + elsif ($par =~ /^\?(.+)$/) { + # User must specify a parameter (default value possible) + my ($pn, $pv) = split('=', $1); + $pt = 2; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{parname} = $pn; + if (defined($pv)) { + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{args} = "$pv"; + $usage .= " [$pn]"; + } + else { + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{args} = $paramDef->{DEFAULT} // ''; + $usage .= " $pn"; + } } else { - my ($pn, $pv) = split('=', $par); - $argList = $pv // ''; - foreach my $e (split(',', $argList)) { - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{look}{$e} = $e; - } + # Fix value. Command has no argument + $pt = 3; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{parname} = $dpt; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{args} = $par; } + } - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{args} = $argList; - $cmdArgList = $argList; - $usage .= " {$argList}"; - } - elsif ($par =~ /^\?(.+)$/) { - # User must specify a parameter (default value possible) - my ($pn, $pv) = split('=', $1); - $pt = 2; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{parname} = $pn; - if (defined($pv)) { - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{args} = "$pv"; - $usage .= " [$pn]"; - } - else { - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{args} = $paramDef->{DEFAULT} // ''; - $usage .= " $pn"; - } - } - else { - # Fix value. Command has no argument - $pt = 3; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{parname} = $dpt; - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{args} = $par; - } - - $clHash->{hmccu}{roleCmds}{$cmd}{subcmd}{$scn}{partype} = $pt; - $parTypes[$pt-1]++; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcmd}{$scn}{partype} = $pt; + $parTypes[$pt]++; $cnt++; } - my $cmdDef = $cmd; - if ($parTypes[0] == 1 && $parTypes[1] == 0 && $cmdArgList ne '') { + if ($parTypes[1] == 1 && $parTypes[2] == 0 && $cmdArgList ne '') { $cmdDef .= ":$cmdArgList"; } - elsif ($parTypes[0] == 0 && $parTypes[1] == 0) { + elsif ($parTypes[1] == 0 && $parTypes[2] == 0) { $cmdDef .= ':noArg'; } - if (exists($clHash->{hmccu}{roleCmds}{$cmd}{channel})) { - $clHash->{hmccu}{roleCmds}{$cmd}{channel} = '?'; + if (exists($clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{channel})) { + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{channel} = '?'; } else { - $clHash->{hmccu}{roleCmds}{$cmd}{channel} = $cmdChn; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{channel} = $cmdChn; + } + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{usage} = $usage; + $clHash->{hmccu}{roleCmds}{$cmdType}{$cmd}{subcount} = $cnt; + + if ($cmdType eq 'set') { + push @cmdSetList, $cmdDef; + } + else { + push @cmdGetList, $cmdDef; } - $clHash->{hmccu}{roleCmds}{$cmd}{usage} = $usage; - $clHash->{hmccu}{roleCmds}{$cmd}{subcount} = $cnt; - push @cmdList, $cmdDef; } } - $clHash->{hmccu}{cmdlist} = join(' ', @cmdList); + $clHash->{hmccu}{cmdlist}{set} = join(' ', @cmdSetList); + $clHash->{hmccu}{cmdlist}{get} = join(' ', @cmdGetList); return; } @@ -6348,7 +6380,7 @@ sub HMCCU_UpdateAdditionalCommands ($$;$$) HMCCU_Trace ($clHash, 2, "stateVals=$stateVals, cd=$cd, cc=$cc"); my %stateCmds = split (/[:,]/, $stateVals); my @states = keys %stateCmds; - $clHash->{hmccu}{cmdlist} .= ' toggle:noArg' if (scalar(@states) > 1); + $clHash->{hmccu}{cmdlist}{set} .= ' toggle:noArg' if (scalar(@states) > 1); } ###################################################################### @@ -6357,28 +6389,29 @@ sub HMCCU_UpdateAdditionalCommands ($$;$$) sub HMCCU_ExecuteRoleCommand ($@) { - my ($ioHash, $clHash, $command, $cc, $a, $h) = @_; + my ($ioHash, $clHash, $mode, $command, $cc, $a, $h) = @_; my $rc; my %dpval; my %cfval; + my %cmdFnc; my ($devAddr, undef) = HMCCU_SplitChnAddr ($clHash->{ccuaddr}); - my $usage = $clHash->{hmccu}{roleCmds}{$command}{usage}; + my $usage = $clHash->{hmccu}{roleCmds}{$mode}{$command}{usage}; my $c = 0; - my $channel = $clHash->{hmccu}{roleCmds}{$command}{channel}; + my $channel = $clHash->{hmccu}{roleCmds}{$mode}{$command}{channel}; if ("$channel" eq '?') { return HMCCU_SetError ($clHash, -12) if ($cc eq ''); $channel = $cc; } my $chnAddr = "$devAddr:$channel"; - foreach my $cmdNo (sort keys %{$clHash->{hmccu}{roleCmds}{$command}{subcmd}}) { - my $cmd = $clHash->{hmccu}{roleCmds}{$command}{subcmd}{$cmdNo}; + foreach my $cmdNo (sort keys %{$clHash->{hmccu}{roleCmds}{$mode}{$command}{subcmd}}) { + my $cmd = $clHash->{hmccu}{roleCmds}{$mode}{$command}{subcmd}{$cmdNo}; my $value; if (!HMCCU_IsValidParameter ($clHash, $chnAddr, $cmd->{ps}, $cmd->{dpt})) { - HMCCU_Trace ($clHash, 2, "Invalid parameter $cmd->{ps} $cmd->{dpt} for command $command"); + HMCCU_Trace ($clHash, 2, "Invalid parameter $cmd->{ps}.$cmd->{dpt} for command $command"); return HMCCU_SetError ($clHash, -8); } @@ -6425,18 +6458,48 @@ sub HMCCU_ExecuteRoleCommand ($@) else { $cfval{$cmd->{dpt}} = $value; } + $cmdFnc{$cmdNo}{fnc} = $cmd->{fnc}; + $cmdFnc{$cmdNo}{par} = $value; } - if (scalar(keys %dpval) > 0) { - foreach my $dpv (keys %dpval) { - HMCCU_Trace ($clHash, 2, "$dpv=$dpval{$dpv}"); + my $ndpval = scalar(keys %dpval); + my $ncfval = scalar(keys %cfval); + + if ($mode eq 'set') { + # Set commands + if ($ndpval > 0) { + foreach my $dpv (keys %dpval) { HMCCU_Trace ($clHash, 2, "Datapoint $dpv=$dpval{$dpv}"); } + $rc = HMCCU_SetMultipleDatapoints ($clHash, \%dpval); + return HMCCU_SetError ($clHash, HMCCU_Min(0, $rc)); + } + if ($ncfval > 0) { + foreach my $pv (keys %cfval) { HMCCU_Trace ($clHash, 2, "Paramaeter $pv=$cfval{$pv}"); } + ($rc, undef) = HMCCU_SetMultipleParameters ($clHash, $chnAddr, \%cfval, 'MASTER'); + return HMCCU_SetError ($clHash, HMCCU_Min(0, $rc)); } - $rc = HMCCU_SetMultipleDatapoints ($clHash, \%dpval); - return HMCCU_SetError ($clHash, HMCCU_Min(0, $rc)); } - if (scalar(keys %cfval) > 0) { - ($rc, undef) = HMCCU_SetMultipleParameters ($clHash, $chnAddr, \%cfval, 'MASTER'); - return HMCCU_SetError ($clHash, HMCCU_Min(0, $rc)); + else { + # Get commands + my $opt = ''; + if ($ndpval > 0 && $ncfval == 0) { $opt = 'values'; } + elsif ($ndpval == 0 && $ncfval > 0) { $opt = 'config'; } + elsif ($ndpval > 0 && $ncfval > 0) { $opt = 'update'; } + + if ($opt ne '') { + $chnAddr =~ s/:d$//; + my $resp = HMCCU_ExecuteGetParameterCommand ($ioHash, $clHash, $opt, [ $chnAddr ]); + return HMCCU_SetError ($clHash, "Cannot get values for command") if (!defined($resp)); + my $disp = ''; + foreach my $cmdNo (sort keys %cmdFnc) { + if ($cmdFnc{$cmdNo}{fnc} ne '') { + # :( + no strict "refs"; + $disp .= &{$cmdFnc{$cmdNo}{fnc}}($ioHash, $clHash, $resp, $cmdFnc{$cmdNo}{par}); + use strict "refs"; + } + } + return $disp; + } } return HMCCU_SetError ($clHash, "Command $command not executed"); @@ -6699,9 +6762,20 @@ sub HMCCU_ExecuteGetParameterCommand ($@) } } + return \%objects; +} + +###################################################################### +# Convert results into a readable format +###################################################################### + +sub HMCCU_DisplayGetParameterResult ($$$) +{ + my ($ioHash, $clHash, $objects) = @_; + my $res = ''; - if (scalar(keys %objects) > 0) { - my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, \%objects); + if (scalar(keys %$objects) > 0) { + my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, $objects); if (defined($convRes)) { foreach my $da (sort keys %$convRes) { $res .= "Device $da\n"; @@ -6717,25 +6791,27 @@ sub HMCCU_ExecuteGetParameterCommand ($@) } } - return $res eq '' ? 'No data found' : $res; + return $res; } ###################################################################### # Get week program(s) as html table ###################################################################### -sub HMCCU_DisplayWeekProgram ($;$) +sub HMCCU_DisplayWeekProgram ($$$) { - my ($hash, $program) = @_; + my ($ioHash, $clHash, $resp, $program) = @_; my @weekDay = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'); - return "No data available for week program(s)" if (!exists($hash->{hmccu}{tt})); + my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, $resp); + return "No data available for week program(s)" if (!exists($clHash->{hmccu}{tt})); + my $s = ''; - foreach my $w (sort keys %{$hash->{hmccu}{tt}}) { + foreach my $w (sort keys %{$clHash->{hmccu}{tt}}) { next if (defined($program) && "$w" ne "$program" && "$program" ne 'all'); - my $p = $hash->{hmccu}{tt}{$w}; + my $p = $clHash->{hmccu}{tt}{$w}; $s .= '

Week Program '.$w.'


'; foreach my $d (sort keys %{$p->{ENDTIME}}) { $s .= ''; @@ -7306,6 +7382,7 @@ sub HMCCU_SetMultipleParameters ($$$;$) return (-1, undef) if ($paramSet eq 'VALUES' && !defined($chn)); foreach my $p (sort keys %$params) { + HMCCU_Trace ($clHash, 2, "Parameter=$address.$paramSet.$p Value=$params->{$p}"); return (-8, undef) if ( ($paramSet eq 'VALUES' && !HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $p, 2)) || ($paramSet eq 'MASTER' && !HMCCU_IsValidParameter ($clHash, $address, $paramSet, $p)) @@ -8735,7 +8812,7 @@ sub HMCCU_MaxHashEntries ($$)
  • Optionally enable automatic start of RPC servers with attribute 'rpcserver'

  • Then start with the definition of client devices using modules HMCCUDEV (CCU devices) - and HMCCUCHN (CCU channels) or with command 'get devicelist create'.
    + and HMCCUCHN (CCU channels) or with command 'get create'.

    @@ -8824,7 +8901,7 @@ sub HMCCU_MaxHashEntries ($$) renamed).
    If a RPC server is running HMCCU will raise events "count devices added in CCU" or "count devices deleted in CCU". It's recommended to set up a notification - which reacts with execution of command 'get devicelist' on these events. + which reacts with execution of command 'get ccuConfig' on these events.
  • get <name> ccuDevices
    Show table of CCU devices. @@ -8832,28 +8909,32 @@ sub HMCCU_MaxHashEntries ($$)
  • get <name> ccumsg {service|alarm}
    Query active service or alarm messages from CCU. Generate FHEM event for each message.

  • +
  • get <name> create <devexp> [t={chn|dev|all}] + [p=<prefix>] [s=<suffix>] [f=<format>] [defattr] + [save] [<attr>=<value> [...]]
    + Create client devices for all CCU devices and channels matching specified regular + expression. Parameter devexp is a regular expression for CCU device or channel + names.
    + With option t=chn or t=dev (default) the creation of devices is limited to CCU channels + or devices. With options 'p' and 's' a prefix and/or a suffix for the FHEM device + name can be specified. The option 'f' with parameter format + defines a template for the FHEM device names. Prefix, suffix and format can contain + format identifiers which are substituted by corresponding values of the CCU device or + channel:
    + %n = CCU object name (channel or device)
    + %d = CCU device name, %a = CCU address
    + In addition a list of default attributes for the created client devices can be specified. + If option 'defattr' is specified HMCCU tries to set default attributes for device. + This is not necessary of HMCCU is able to detect the role of a device or channel. + With option 'duplicates' HMCCU will overwrite existing devices and/or create devices + for existing device addresses. Option 'save' will save FHEM config after device definition. +

  • get <name> defaults
    List device types and channels with default attributes available.

  • get <name> deviceinfo <device-name-or-address>
    List device channels, datapoints and the device description.

  • -
  • get <name> create <devexp> [t={chn|dev|all}] - [p=<prefix>] [s=<suffix>] [f=<format>] [defattr] - [save] [<attr>=<value> [...]]
    - Create client devices for all CCU devices - and channels matching specified regular expression. With option t=chn or t=dev (default) - the creation of devices is limited to CCU channels or devices.
    - Optionally a prefix and/or a - suffix for the FHEM device name can be specified. The parameter format - defines a template for the FHEM device names. Prefix, suffix and format can contain - format identifiers which are substituted by corresponding values of the CCU device or - channel: %n = CCU object name (channel or device), %d = CCU device name, %a = CCU address. - In addition a list of default attributes for the created client devices can be specified. - If option 'defattr' is specified HMCCU tries to set default attributes for device. - With option 'duplicates' HMCCU will overwrite existing devices and/or create devices - for existing device addresses. Option 'save' will save FHEM config after device definition. -

  • get <name> dutycycle
    Read CCU interface and gateway information. For each interface/gateway the following information is stored in readings:
    diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm index bed34144c..68882b093 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.028 +# Version 4.4.029 # # (c) 2020 zap (zap01 t-online de) # @@ -111,7 +111,7 @@ sub HMCCUCHN_Define ($@) my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates (); return $ccuinactive > 0 ? 'CCU and/or IO device not ready. Please try again later' : - 'Cannot detect IO device'; + 'Cannot detect IO device or CCU device not found'; } } else { @@ -163,8 +163,11 @@ sub HMCCUCHN_InitDevice ($$) HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); HMCCU_UpdateDevice ($ioHash, $devHash); HMCCU_UpdateDeviceRoles ($ioHash, $devHash); - HMCCU_UpdateRoleCommands ($ioHash, $devHash); - HMCCU_UpdateAdditionalCommands ($ioHash, $devHash); + + my ($sc, $sd, $cc, $cd, $sdCnt, $cdCnt) = HMCCU_GetSpecialDatapoints ($devHash); + + HMCCU_UpdateRoleCommands ($ioHash, $devHash, $cc); + HMCCU_UpdateAdditionalCommands ($ioHash, $devHash, $cc, $cd); if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) { if (!HMCCU_SetDefaultAttributes ($devHash)) { @@ -267,7 +270,7 @@ sub HMCCUCHN_Set ($@) my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); # Additional commands, including state commands - my $cmdList = $hash->{hmccu}{cmdlist} // ''; + my $cmdList = $hash->{hmccu}{cmdlist}{set} // ''; # Some commands require a control datapoint if ($opt =~ /^(control|toggle)$/) { @@ -297,8 +300,8 @@ sub HMCCUCHN_Set ($@) elsif ($opt eq 'toggle') { return HMCCU_ExecuteToggleCommand ($hash, $cc, $cd); } - elsif (exists($hash->{hmccu}{roleCmds}{$opt})) { - return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $cc, $a, $h); + elsif (exists($hash->{hmccu}{roleCmds}{set}{$opt})) { + return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'set', $opt, $cc, $a, $h); } elsif ($opt eq 'clear') { return HMCCU_ExecuteSetClearCommand ($hash, $a); @@ -352,6 +355,9 @@ sub HMCCUCHN_Get ($@) my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); + # Additional commands, including state commands + my $cmdList = $hash->{hmccu}{cmdlist}{get} // ''; + my $result = ''; my $rc; @@ -375,19 +381,20 @@ sub HMCCUCHN_Get ($@) elsif ($opt =~ /^(config|values|update)$/) { my ($devAddr, undef) = HMCCU_SplitChnAddr ($ccuaddr); my @addList = ($devAddr, "$devAddr:0", $ccuaddr); - return HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList); + my $resp = HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList); + return HMCCU_SetError ($hash, "Can't get device description") if (!defined($resp)); + return HMCCU_DisplayGetParameterResult ($ioHash, $hash, $resp); } elsif ($opt eq 'paramsetdesc') { $result = HMCCU_ParamsetDescToStr ($ioHash, $hash); return defined($result) ? $result : HMCCU_SetError ($hash, "Can't get device model"); } + elsif (exists($hash->{hmccu}{roleCmds}{get}{$opt})) { + return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'get', $opt, $cc, $a, $h); + } elsif ($opt eq 'defaults') { return HMCCU_GetDefaults ($hash, 0); } - elsif ($opt eq 'weekprogram') { - my $program = shift @$a; - return HMCCU_DisplayWeekProgram ($hash, $program); - } else { my $retmsg = "HMCCUCHN: Unknown argument $opt, choose one of defaults:noArg datapoint"; @@ -397,8 +404,7 @@ sub HMCCUCHN_Get ($@) $retmsg .= ":".join(",",@valuelist) if ($valuecount > 0); $retmsg .= " update:noArg deviceInfo:noArg config:noArg". " paramsetDesc:noArg values:noArg"; - $retmsg .= ' weekProgram:all,'.join(',', sort keys %{$hash->{hmccu}{tt}}) - if (exists($hash->{hmccu}{tt})); + $retmsg .= " $cmdList" if ($cmdList ne ''); return $retmsg; } diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm index 56e3f53da..d0a9070ad 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.033 +# Version 4.4.034 # # (c) 2020 zap (zap01 t-online de) # @@ -226,8 +226,8 @@ sub HMCCUDEV_InitDevice ($$) my ($sc, $sd, $cc, $cd, $sdCnt, $cdCnt) = HMCCU_GetSpecialDatapoints ($devHash); return -1 if ($cdCnt > 2); - HMCCU_UpdateRoleCommands ($ioHash, $devHash, $attr{$devHash->{NAME}}{controlchannel}); - HMCCU_UpdateAdditionalCommands ($ioHash, $devHash, $attr{$devHash->{NAME}}{controlchannel}); + HMCCU_UpdateRoleCommands ($ioHash, $devHash, $cc); + HMCCU_UpdateAdditionalCommands ($ioHash, $devHash, $cc, $cd); if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) { if (!HMCCU_SetDefaultAttributes ($devHash, { @@ -404,7 +404,7 @@ sub HMCCUDEV_Set ($@) my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); # Get additional commands - my $cmdList = $hash->{hmccu}{cmdlist} // ''; + my $cmdList = $hash->{hmccu}{cmdlist}{set} // ''; # Some commands require a control channel and datapoint if ($opt =~ /^(control|toggle)$/) { @@ -436,8 +436,8 @@ sub HMCCUDEV_Set ($@) elsif ($opt eq 'toggle') { return HMCCU_ExecuteToggleCommand ($hash, $cc, $cd); } - elsif (exists($hash->{hmccu}{roleCmds}{$opt})) { - return HMCCU_ExecuteRoleCommand ($ioHash, $hash, $opt, $cc, $a, $h); + elsif (exists($hash->{hmccu}{roleCmds}{set}{$opt})) { + return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'set', $opt, $cc, $a, $h); } elsif ($opt eq 'clear') { return HMCCU_ExecuteSetClearCommand ($hash, $a); @@ -492,6 +492,9 @@ sub HMCCUDEV_Get ($@) my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash); + # Get additional commands + my $cmdList = $hash->{hmccu}{cmdlist}{get} // ''; + # Virtual devices only support command get update return "HMCCUDEV: Unknown argument $opt, choose one of update:noArg" if ($ccuif eq 'fhem' && $opt ne 'update'); @@ -535,20 +538,21 @@ sub HMCCUDEV_Get ($@) return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc)); push @addList, split (',', $devDesc->{CHILDREN}); - return HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList); + my $resp = HMCCU_ExecuteGetParameterCommand ($ioHash, $hash, $opt, \@addList); + return HMCCU_SetError ($hash, "Can't get device description") if (!defined($resp)); + return HMCCU_DisplayGetParameterResult ($ioHash, $hash, $resp); } elsif ($opt eq 'paramsetdesc') { $result = HMCCU_ParamsetDescToStr ($ioHash, $hash); return defined($result) ? $result : HMCCU_SetError ($hash, "Can't get device model"); } + elsif (exists($hash->{hmccu}{roleCmds}{get}{$opt})) { + return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'get', $opt, $cc, $a, $h); + } elsif ($opt eq 'defaults') { $result = HMCCU_GetDefaults ($hash, 0); return $result; } - elsif ($opt eq 'weekprogram') { - my $program = shift @$a; - return HMCCU_DisplayWeekProgram ($hash, $program); - } else { my $retmsg = "HMCCUDEV: Unknown argument $opt, choose one of datapoint"; @@ -557,8 +561,7 @@ sub HMCCUDEV_Get ($@) $retmsg .= ':'.join(",", @valuelist) if ($valuecount > 0); $retmsg .= ' defaults:noArg update:noArg config:noArg'. ' paramsetDesc:noArg deviceInfo:noArg values:noArg'; - $retmsg .= ' weekProgram:all,'.join(',', sort keys %{$hash->{hmccu}{tt}}) - if (exists($hash->{hmccu}{tt})); + $retmsg .= " $cmdList" if ($cmdList ne ''); return $retmsg; } diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCURPCPROC.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCURPCPROC.pm index 5752377e9..ca0ea0eaa 100755 --- a/fhem/contrib/HMCCU/FHEM/88_HMCCURPCPROC.pm +++ b/fhem/contrib/HMCCU/FHEM/88_HMCCURPCPROC.pm @@ -4,7 +4,7 @@ # # $Id: 88_HMCCURPCPROC.pm 18745 2019-02-26 17:33:23Z zap $ # -# Version 4.4.012 +# Version 4.4.013 # # Subprocess based RPC Server module for HMCCU. # @@ -39,7 +39,7 @@ require "$attr{global}{modpath}/FHEM/88_HMCCU.pm"; ###################################################################### # HMCCURPC version -my $HMCCURPCPROC_VERSION = '4.4.012'; +my $HMCCURPCPROC_VERSION = '4.4.013'; # Maximum number of events processed per call of Read() my $HMCCURPCPROC_MAX_EVENTS = 100; @@ -1202,7 +1202,7 @@ sub HMCCURPCPROC_GetParamsetDesc ($;$) HMCCU_AddDeviceModel ($ioHash, $rm, $devDesc->{_model}, $devDesc->{_fw_ver}, $ps, $chnNo); } else { - HMCCU_Log ($hash, 2, "Can't get description of paramset $ps for address $a"); + HMCCU_Log ($hash, 2, "Can't get description of paramset $ps for address $address"); } } diff --git a/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm b/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm index 396ff54ac..98f88fbb6 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.006 +# Version 4.8.007 # # Configuration parameters for HomeMatic devices. # @@ -63,6 +63,9 @@ use vars qw(%HMCCU_SCRIPTS); 'KEY_TRANSCEIVER' => { F => 3, S => 'PRESS_SHORT', C => 'PRESS_SHORT', V => 'pressed:true' }, + 'VIRTUAL_KEY' => { + F => 3, S => 'PRESS_SHORT', C => 'PRESS_SHORT', V => 'pressed:true' + }, 'BLIND' => { F => 3, S => 'LEVEL', C => 'LEVEL', V => 'open:100,close:0' }, @@ -85,13 +88,13 @@ use vars qw(%HMCCU_SCRIPTS); F => 1, S => 'TEMPERATURE', C => 'TEMPERATURE', V => '' }, 'THERMALCONTROL_TRANSMIT' => { - F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => '' + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => 'on:30.5,off:4.5' }, 'CLIMATECONTROL_RT_TRANSCEIVER' => { - F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => '' + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => 'on:30.5,off:4.5' }, 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { - F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_POINT_TEMPERATURE', V => '' + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_POINT_TEMPERATURE', V => 'on:30.5,off:4.5' } ); @@ -171,6 +174,11 @@ use vars qw(%HMCCU_SCRIPTS); 'off' => 'V:PRESS_SHORT:1', 'press' => 'V:PRESS_SHORT:1' }, + 'VIRTUAL_KEY' => { + 'on' => 'V:PRESS_SHORT:1', + 'off' => 'V:PRESS_SHORT:1', + 'press' => 'V:PRESS_SHORT:1' + }, 'BLIND' => { 'pct' => 'V:LEVEL:?level', 'open' => 'V:LEVEL:100', @@ -229,7 +237,8 @@ use vars qw(%HMCCU_SCRIPTS); 'off' => 'V:MANU_MODE:4.5', 'auto' => 'V:AUTO_MODE:1', 'boost' => 'V:BOOST_MODE:1', - 'week-program' => 'D:WEEK_PROGRAM_POINTER:#program' + 'week-program' => 'D:WEEK_PROGRAM_POINTER:#program', + 'get week-program' => 'D:WEEK_PROGRAM_POINTER:#program:HMCCU_DisplayWeekProgram' }, 'CLIMATECONTROL_RT_TRANSCEIVER' => { 'desired-temp' => 'V:SET_TEMPERATURE:?temperature', @@ -237,7 +246,9 @@ use vars qw(%HMCCU_SCRIPTS); 'on' => 'V:MANU_MODE:30.5', 'off' => 'V:MANU_MODE:4.5', 'auto' => 'V:AUTO_MODE:1', - 'boost' => 'V:BOOST_MODE:1' + 'boost' => 'V:BOOST_MODE:1', + 'week-program' => 'D:WEEK_PROGRAM_POINTER:#program', + 'get week-program' => 'D:WEEK_PROGRAM_POINTER:#program:HMCCU_DisplayWeekProgram' }, 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { 'desired-temp' => 'V:SET_POINT_TEMPERATURE:?temperature', @@ -324,6 +335,10 @@ use vars qw(%HMCCU_SCRIPTS); 'PRESS_SHORT' => { '1' => 'pressed', 'true' => 'pressed' }, 'PRESS_LONG' => { '1' => 'pressed', 'true' => 'pressed' } }, + 'VIRTUAL_KEY' => { + 'PRESS_SHORT' => { '1' => 'pressed', 'true' => 'pressed' }, + 'PRESS_LONG' => { '1' => 'pressed', 'true' => 'pressed' } + }, 'SHUTTER_CONTACT' => { 'STATE' => { '0' => 'closed', '1' => 'open', 'false' => 'closed', 'true' => 'open' } }, diff --git a/fhem/contrib/HMCCU/controls_HMCCU.txt b/fhem/contrib/HMCCU/controls_HMCCU.txt index 782aad130..398b64df7 100644 --- a/fhem/contrib/HMCCU/controls_HMCCU.txt +++ b/fhem/contrib/HMCCU/controls_HMCCU.txt @@ -1,5 +1,5 @@ -UPD 2020-09-29_17:52:14 102651 FHEM/88_HMCCURPCPROC.pm -UPD 2020-09-29_17:52:28 75170 FHEM/HMCCUConf.pm -UPD 2020-09-29_17:51:53 39023 FHEM/88_HMCCUCHN.pm -UPD 2020-09-29_17:51:43 299006 FHEM/88_HMCCU.pm -UPD 2020-09-29_17:52:01 30630 FHEM/88_HMCCUDEV.pm +UPD 2020-11-08_17:25:29 102657 FHEM/88_HMCCURPCPROC.pm +UPD 2020-11-08_17:25:44 75793 FHEM/HMCCUConf.pm +UPD 2020-11-08_17:23:47 39378 FHEM/88_HMCCUCHN.pm +UPD 2020-11-08_17:23:36 302150 FHEM/88_HMCCU.pm +UPD 2020-11-08_17:23:59 30769 FHEM/88_HMCCUDEV.pm
  • '.$weekDay[$d].'