diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCU.pm index 3ad665546..cfd0584e9 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.011 +# Version 4.4.013 # # Module for communication between FHEM and Homematic CCU2/3. # @@ -43,7 +43,8 @@ use SubProcess; use HMCCUConf; # Import configuration data -my $HMCCU_ROLES = \%HMCCUConf::HMCCU_ROLES; +my $HMCCU_STATECONTROL = \%HMCCUConf::HMCCU_STATECONTROL; +my $HMCCU_ROLECMDS = \%HMCCUConf::HMCCU_ROLECMDS; 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.011'; +my $HMCCU_VERSION = '4.4.013'; # Constants and default values my $HMCCU_MAX_IOERRORS = 100; @@ -343,14 +344,14 @@ sub HMCCU_GetDatapointCount ($$$); sub HMCCU_GetDatapointList ($$$); sub HMCCU_GetSpecialCommands ($$); sub HMCCU_GetSpecialDatapoints ($$$$$); -sub HMCCU_GetStateValues ($$$;$); +sub HMCCU_GetStateValues ($$;$); sub HMCCU_GetSwitchDatapoint ($$$); sub HMCCU_GetValidDatapoints ($$$$$); sub HMCCU_IsValidDatapoint ($$$$$); # sub HMCCU_SetDatapoint ($$$); sub HMCCU_SetDefaultAttributes ($;$); sub HMCCU_SetMultipleDatapoints ($$); -sub HMCCU_SetMultipleParameters ($$$); +sub HMCCU_SetMultipleParameters ($$$;$); # Internal RPC server functions sub HMCCU_ResetRPCQueue ($$); @@ -1657,8 +1658,7 @@ sub HMCCU_Set ($@) my $dh = $defs{$devName}; my $ccuif = $dh->{ccuif}; my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($dh, '', '', '', ''); - my $roleCmds = HMCCU_GetSpecialCommands ($dh, $cc); - my $stateVals = HMCCU_GetStateValues ($dh, $roleCmds, $cd, 2); + my $stateVals = HMCCU_GetStateValues ($dh, $cd, $cc); if ($dh->{TYPE} eq 'HMCCUCHN') { if (defined ($t2)) { @@ -1905,7 +1905,7 @@ sub HMCCU_Get ($@) return "No get command specified" if (!defined ($opt)); $opt = lc($opt); - my $options = "defaults:noArg exportDefaults deviceList dump dutycycle:noArg vars update". + my $options = "ccuconfig create defaults:noArg exportDefaults dump dutycycle:noArg vars update". " updateccu deviceDesc paramsetDesc firmware rpcEvents:noArg rpcState:noArg deviceInfo". " ccuMsg:alarm,service ccuConfig:noArg"; my $usage = "HMCCU: Unknown argument $opt, choose one of $options"; @@ -2027,111 +2027,88 @@ sub HMCCU_Get ($@) return HMCCU_SetState ($hash, "OK", $result); } elsif ($opt eq 'ccuconfig') { - HMCCU_ResetDeviceTables ($hash); - my ($cDev, $cPar, $cLnk) = HMCCU_GetDeviceConfig ($hash); - return "Device descriptions: $cDev\nParameter set descriptions: $cPar\nLinks/Peerings: $cLnk"; - } - elsif ($opt eq 'devicelist') { my ($devcount, $chncount, $ifcount, $prgcount, $gcount) = HMCCU_GetDeviceList ($hash); return HMCCU_SetError ($hash, -2) if ($devcount < 0); return HMCCU_SetError ($hash, "No devices received from CCU") if ($devcount == 0); - $result = "Read $devcount devices with $chncount channels from CCU"; + HMCCU_ResetDeviceTables ($hash); + my ($cDev, $cPar, $cLnk) = HMCCU_GetDeviceConfig ($hash); + return "Devices: $devcount, Channels: $chncount\nDevice descriptions: $cDev\n". + "Paramset descriptions: $cPar\nLinks/Peerings: $cLnk"; + } + elsif ($opt eq 'create') { + $usage = "Usage: get $name create {devexp|chnexp} [t={'chn'|'dev'|'all'}] [s=suffix] ". + "[p=prefix] [f=format] ['defattr'] [save] [attr=val [...]]"; + my $devdefaults = 0; + my $savedef = 0; + my $newcount = 0; - my $optcmd = shift @$a; - if (defined ($optcmd)) { - if ($optcmd eq 'dump') { - $result .= "\n-----------------------------------------\n"; - my $n = 0; - foreach my $add (sort keys %{$hash->{hmccu}{dev}}) { - if ($hash->{hmccu}{dev}{$add}{addtype} eq 'dev') { - $result .= "Device ".'"'.$hash->{hmccu}{dev}{$add}{name}.'"'." [".$add."] ". - "Type=".$hash->{hmccu}{dev}{$add}{type}."\n"; - $n = 0; - } - else { - $result .= " Channel $n ".'"'.$hash->{hmccu}{dev}{$add}{name}.'"'. - " [".$add."]\n"; - $n++; - } - } - return $result; - } - elsif ($optcmd eq 'create') { - $usage = "Usage: get $name create {devexp|chnexp} [t={'chn'|'dev'|'all'}] [s=suffix] ". - "[p=prefix] [f=format] ['defattr'] [save] [attr=val [...]]"; - my $devdefaults = 0; - my $savedef = 0; - my $newcount = 0; - - # Process command line parameters - my $devspec = shift @$a; - my $devprefix = exists ($h->{p}) ? $h->{p} : ''; - my $devsuffix = exists ($h->{'s'}) ? $h->{'s'} : ''; - my $devtype = exists ($h->{t}) ? $h->{t} : 'dev'; - my $devformat = exists ($h->{f}) ? $h->{f} : '%n'; - return HMCCU_SetError ($hash, $usage) - if ($devtype !~ /^(dev|chn|all)$/ || !defined ($devspec)); - foreach my $defopt (@$a) { - if ($defopt eq 'defattr') { $devdefaults = 1; } - elsif ($defopt eq 'save') { $savedef = 1; } - else { return HMCCU_SetError ($hash, $usage); } - } - - # Get list of existing client devices - my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", undef, undef); - - foreach my $add (sort keys %{$hash->{hmccu}{dev}}) { - my $defmod = $hash->{hmccu}{dev}{$add}{addtype} eq 'dev' ? 'HMCCUDEV' : 'HMCCUCHN'; - my $ccuname = $hash->{hmccu}{dev}{$add}{name}; - my $ccudevname = HMCCU_GetDeviceName ($hash, $add, $ccuname); - next if ($devtype ne 'all' && $devtype ne $hash->{hmccu}{dev}{$add}{addtype}); - next if (HMCCU_ExprNotMatch ($ccuname, $devspec, 1)); - - # Build FHEM device name - my $devname = $devformat; - $devname = $devprefix.$devname.$devsuffix; - $devname =~ s/%n/$ccuname/g; - $devname =~ s/%d/$ccudevname/g; - $devname =~ s/%a/$add/g; - $devname =~ s/[^A-Za-z\d_\.]+/_/g; - - # Check for duplicate device definitions - next if (exists ($defs{$devname})); - my $devexists = 0; - foreach my $exdev (@devlist) { - if ($defs{$exdev}->{ccuaddr} eq $add) { - $devexists = 1; - last; - } - } - next if ($devexists); - - # Define new client device - my $ret = CommandDefine (undef, $devname." $defmod ".$add); - if ($ret) { - HMCCU_Log ($hash, 2, "Define command failed $devname $defmod $ccuname. $ret"); - $result .= "\nCan't create device $devname. $ret"; - next; - } - - # Set device attributes - HMCCU_SetDefaults ($defs{$devname}) if ($devdefaults); - foreach my $da (keys %$h) { - next if ($da =~ /^[pstf]$/); - $ret = CommandAttr (undef, "$devname $da ".$h->{$da}); - HMCCU_Log ($hash, 2, "Attr command failed $devname $da ".$h->{$da}.". $ret") - if ($ret); - } - HMCCU_Log ($hash, 2, "Created device $devname"); - $result .= "\nCreated device $devname"; - $newcount++; - } - - CommandSave (undef, undef) if ($newcount > 0 && $savedef); - $result .= "\nCreated $newcount client devices"; - } + # Process command line parameters + my $devspec = shift @$a; + my $devprefix = exists ($h->{p}) ? $h->{p} : ''; + my $devsuffix = exists ($h->{'s'}) ? $h->{'s'} : ''; + my $devtype = exists ($h->{t}) ? $h->{t} : 'dev'; + my $devformat = exists ($h->{f}) ? $h->{f} : '%n'; + return HMCCU_SetError ($hash, $usage) + if ($devtype !~ /^(dev|chn|all)$/ || !defined ($devspec)); + foreach my $defopt (@$a) { + if ($defopt eq 'defattr') { $devdefaults = 1; } + elsif ($defopt eq 'save') { $savedef = 1; } + else { return HMCCU_SetError ($hash, $usage); } } + # Get list of existing client devices + my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)", undef, undef); + + foreach my $add (sort keys %{$hash->{hmccu}{dev}}) { + my $defmod = $hash->{hmccu}{dev}{$add}{addtype} eq 'dev' ? 'HMCCUDEV' : 'HMCCUCHN'; + my $ccuname = $hash->{hmccu}{dev}{$add}{name}; + my $ccudevname = HMCCU_GetDeviceName ($hash, $add, $ccuname); + next if ($devtype ne 'all' && $devtype ne $hash->{hmccu}{dev}{$add}{addtype}); + next if (HMCCU_ExprNotMatch ($ccuname, $devspec, 1)); + + # Build FHEM device name + my $devname = $devformat; + $devname = $devprefix.$devname.$devsuffix; + $devname =~ s/%n/$ccuname/g; + $devname =~ s/%d/$ccudevname/g; + $devname =~ s/%a/$add/g; + $devname =~ s/[^A-Za-z\d_\.]+/_/g; + + # Check for duplicate device definitions + next if (exists ($defs{$devname})); + my $devexists = 0; + foreach my $exdev (@devlist) { + if ($defs{$exdev}->{ccuaddr} eq $add) { + $devexists = 1; + last; + } + } + next if ($devexists); + + # Define new client device + my $ret = CommandDefine (undef, $devname." $defmod ".$add); + if ($ret) { + HMCCU_Log ($hash, 2, "Define command failed $devname $defmod $ccuname. $ret"); + $result .= "\nCan't create device $devname. $ret"; + next; + } + + # Set device attributes + HMCCU_SetDefaults ($defs{$devname}) if ($devdefaults); + foreach my $da (keys %$h) { + next if ($da =~ /^[pstf]$/); + $ret = CommandAttr (undef, "$devname $da ".$h->{$da}); + HMCCU_Log ($hash, 2, "Attr command failed $devname $da ".$h->{$da}.". $ret") + if ($ret); + } + HMCCU_Log ($hash, 2, "Created device $devname"); + $result .= "\nCreated device $devname"; + $newcount++; + } + + CommandSave (undef, undef) if ($newcount > 0 && $savedef); + $result .= "\nCreated $newcount client devices"; + return HMCCU_SetState ($hash, "OK", $result); } elsif ($opt eq 'dutycycle') { @@ -2714,8 +2691,8 @@ sub HMCCU_FormatReadingValue ($$$) HMCCU_Trace ($hash, 2, $fnc, "sn = $stripnumber, dpt=$dpt, isint=$isint, value $value not changed"); } else { - my $h = unpack "H*", $value; - HMCCU_Trace ($hash, 2, $fnc, "sn = $stripnumber, Value $value $h not changed"); + my $h = uc(unpack "H*", $value); + HMCCU_Trace ($hash, 2, $fnc, "sn = $stripnumber, Value $value 0x$h not changed"); } return $value; @@ -4248,7 +4225,7 @@ sub HMCCU_FindParamDef ($$$) ###################################################################### # Check if parameter exists # Parameters: -# $hash - Hash reference of IO device. +# $clHash - Hash reference of client device. # $object - Device or channel address or device description # reference. # $ps - Parameter set name. @@ -4258,16 +4235,19 @@ sub HMCCU_FindParamDef ($$$) sub HMCCU_IsValidParameter ($$$$) { - my ($hash, $object, $ps, $parameter) = @_; + my ($clHash, $object, $ps, $parameter) = @_; - my $devDesc = ref($object) eq 'HASH' ? $object : HMCCU_GetDeviceDesc ($hash, $object); + my $ioHash = HMCCU_GetHash ($clHash); + return 0 if (!defined ($ioHash)); + + my $devDesc = ref($object) eq 'HASH' ? $object : HMCCU_GetDeviceDesc ($ioHash, $object); if (defined($devDesc)) { # Build device address and channel number my $a = $devDesc->{ADDRESS}; my ($devAddr, $chnNo) = ($a =~ /:[0-9]{1,2}$/) ? HMCCU_SplitChnAddr ($a) : ($a, 'd'); - my $model = HMCCU_GetDeviceModel ($hash, $devDesc->{_model}, $devDesc->{_fw_ver}, $chnNo); + my $model = HMCCU_GetDeviceModel ($ioHash, $devDesc->{_model}, $devDesc->{_fw_ver}, $chnNo); if (defined($model)) { my @parList = ref($parameter) eq 'HASH' ? keys %$parameter : ($parameter); foreach my $p (@parList) { @@ -6344,7 +6324,7 @@ sub HMCCU_IsValidDatapoint ($$$$$) return 1 if (!exists ($hmccu_hash->{hmccu}{dp})); my $chnno; - if (defined ($chn)) { + if (defined ($chn) && $chn ne '') { if ($chn =~ /^[0-9]{1,2}$/) { $chnno = $chn; } @@ -6354,6 +6334,7 @@ sub HMCCU_IsValidDatapoint ($$$$$) } else { HMCCU_Trace ($hash, 2, $fnc, "$chn is not a valid channel address or number"); + HMCCU_Trace ($hash, 2, $fnc, stacktraceAsString(undef)); return 0; } } @@ -6962,24 +6943,16 @@ sub HMCCU_SetDefaultAttributes ($;$) # Return '' if no state values available ###################################################################### -sub HMCCU_GetStateValues ($$$;$) +sub HMCCU_GetStateValues ($$;$) { - my ($clHash, $roleCmds, $dpt, $oper) = @_; - - return '' if (!defined($roleCmds)); - my $ioHash = HMCCU_GetHash ($clHash); - return '' if (!defined($ioHash)); + my ($clHash, $dpt, $ctrlChn) = @_; - $oper = 2 if (!defined($oper)); - my $sv = AttrVal ($clHash->{NAME}, 'statevals', ''); if ($sv eq '') { - my $paramDef = HMCCU_GetParamDef ($ioHash, $clHash->{ccuaddr}, 'VALUES', $dpt); - return $roleCmds->{$dpt} if (defined($paramDef) && - $paramDef->{OPERATIONS} & $oper && exists($roleCmds->{$dpt})); - } - else { - $sv =~ s/,/ /g; + my $role = HMCCU_GetChannelRole ($clHash, $ctrlChn); + if ($role ne '' && exists($HMCCU_STATECONTROL->{$role}) && $HMCCU_STATECONTROL->{$role}{C} eq $dpt) { + return $HMCCU_STATECONTROL->{$role}{V}; + } } return $sv; @@ -6994,7 +6967,7 @@ sub HMCCU_GetSpecialCommands ($$) my ($clHash, $ctrlChn) = @_; my $role = HMCCU_GetChannelRole ($clHash, $ctrlChn); - return $HMCCU_ROLES->{$role} if ($role ne '' && exists($HMCCU_ROLES->{$role})); + return $HMCCU_ROLECMDS->{$role} if ($role ne '' && exists($HMCCU_ROLECMDS->{$role})); return undef; } @@ -7018,19 +6991,6 @@ sub HMCCU_GetSpecialDatapoints ($$$$$) my $type = $hash->{TYPE}; my $ccutype = $hash->{ccutype}; - # F: 1=Channel, 2=Device, 3=Both - # S: State Datapoint, C: Control datapoint - my %roleDPs = ( - 'SHUTTER_CONTACT' => { F => 3, S => 'STATE', C => '' }, - 'KEY' => { F => 3, S => 'PRESS_SHORT', C => 'PRESS_SHORT' }, - 'BLIND' => { F => 3, S => 'LEVEL', C => 'LEVEL' }, - 'SWITCH' => { F => 3, S => 'STATE', C => 'STATE' }, - 'DIMMER' => { F => 3, S => 'LEVEL', C => 'LEVEL' }, - 'WEATHER_TRANSMIT' => { F => 1, S => 'TEMPERATURE', C => 'TEMPERATURE' }, - 'THERMALCONTROL_TRANSMIT' => { F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE' }, - 'CLIMATECONTROL_RT_TRANSCEIVER' => { F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE' } - ); - my $statedatapoint = AttrVal ($name, 'statedatapoint', ''); my $statechannel = AttrVal ($name, 'statechannel', ''); my $controldatapoint = AttrVal ($name, 'controldatapoint', $statedatapoint); @@ -7072,21 +7032,21 @@ sub HMCCU_GetSpecialDatapoints ($$$$$) my ($da, $dc) = HMCCU_SplitChnAddr ($hash->{ccuaddr}); $sc = $dc; $cc = $dc; - if (exists($roleDPs{$ccuRole}) && $roleDPs{$ccuRole}{F} & 1) { - $sd = $roleDPs{$ccuRole}{S} if ($roleDPs{$ccuRole}{S} ne ''); - $cd = $roleDPs{$ccuRole}{C} if ($roleDPs{$ccuRole}{C} ne ''); + if (exists($HMCCU_STATECONTROL->{$ccuRole}) && $HMCCU_STATECONTROL->{$ccuRole}{F} & 1) { + $sd = $HMCCU_STATECONTROL->{$ccuRole}{S} if ($HMCCU_STATECONTROL->{$ccuRole}{S} ne ''); + $cd = $HMCCU_STATECONTROL->{$ccuRole}{C} if ($HMCCU_STATECONTROL->{$ccuRole}{C} ne ''); } } elsif ($type eq 'HMCCUDEV') { foreach my $roleDef (split(',', $ccuRole)) { my ($dc, $role) = split(':', $roleDef); - if (exists($roleDPs{$role}) && $roleDPs{$role}{F} & 2) { - if ($roleDPs{$role}{S} ne '' && $sd eq '') { - $sd = $roleDPs{$role}{S}; + if (exists($HMCCU_STATECONTROL->{$role}) && $HMCCU_STATECONTROL->{$role}{F} & 2) { + if ($HMCCU_STATECONTROL->{$role}{S} ne '' && $sd eq '') { + $sd = $HMCCU_STATECONTROL->{$role}{S}; $sc = $dc; } - if ($roleDPs{$role}{C} ne '' && $cd eq '') { - $cd = $roleDPs{$role}{C} ; + if ($HMCCU_STATECONTROL->{$role}{C} ne '' && $cd eq '') { + $cd = $HMCCU_STATECONTROL->{$role}{C} ; $cc = $dc; } } @@ -7873,19 +7833,21 @@ sub HMCCU_GetDatapoint ($@) # Parameter address must be a channel address. ###################################################################### -sub HMCCU_SetMultipleParameters ($$$) +sub HMCCU_SetMultipleParameters ($$$;$) { - my ($clHash, $address, $params) = @_; + my ($clHash, $address, $params, $paramSet) = @_; + $paramSet = 'VALUES' if (!defined($paramSet)); my ($add, $chn) = HMCCU_SplitChnAddr ($address); return -1 if (!defined ($chn)); foreach my $p (sort keys %$params) { - return -8 if (!HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $p, 2)); + return -8 if ($paramSet eq 'VALUES' && !HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $p, 2)); + return -8 if ($paramSet eq 'MASTER' && !HMCCU_IsValidParameter ($clHash, $address, $paramSet, $p)); $params->{$p} = HMCCU_ScaleValue ($clHash, $chn, $p, $params->{$p}, 1); } - return HMCCU_RPCRequest ($clHash, "putParamset", $address, 'VALUES', $params); + return HMCCU_RPCRequest ($clHash, "putParamset", $address, $paramSet, $params); } ###################################################################### @@ -7943,7 +7905,10 @@ sub HMCCU_SetMultipleDatapoints ($$) { my $clType = $clHash->{TYPE}; my $ccuType = $clHash->{ccutype}; return -1 if ($clType ne 'HMCCUCHN' && $clType ne 'HMCCUDEV'); - return -8 if (!HMCCU_IsValidDatapoint ($clHash, $ccuType, $chn, $dpt, 2)); + if (!HMCCU_IsValidDatapoint ($clHash, $ccuType, $chn, $dpt, 2)) { + HMCCU_Trace ($clHash, 2, $fnc, "Invalid datapoint $chn $dpt"); + return -8; + } my $ccuVerify = AttrVal ($clName, 'ccuverify', 0); my $ccuChange = AttrVal ($clName, 'ccuSetOnChange', 'null'); @@ -8121,57 +8086,70 @@ sub HMCCU_ScaleValue ($$$$$) my $ioHash = HMCCU_GetHash ($hash); my $ccuscaleval = AttrVal ($name, 'ccuscaleval', ''); - return $value if ($ccuscaleval eq ''); - my @sl = split (',', $ccuscaleval); - foreach my $sr (@sl) { - my $f = 1.0; - my @a = split (':', $sr); - my $n = scalar (@a); - next if ($n != 2 && $n != 5); + if ($ccuscaleval ne '') { + my @sl = split (',', $ccuscaleval); + foreach my $sr (@sl) { + my $f = 1.0; + my @a = split (':', $sr); + my $n = scalar (@a); + next if ($n != 2 && $n != 5); - my $rev = 0; - my $dn = $a[0]; - my $cn = $chnno; - if ($dn =~ /^\!(.+)$/) { - # Invert - $dn = $1; - $rev = 1; - } - if ($dn =~ /^([0-9]{1,2})\.(.+)$/) { - # Compare channel number - $cn = $1; - $dn = $2; - } - next if ($dpt ne $dn || ($chnno ne '' && $cn ne $chnno)); - - if ($n == 2) { - $f = ($a[1] == 0.0) ? 1.0 : $a[1]; - return ($mode == 0) ? $value/$f : $value*$f; - } - else { - # Do not scale if value out of range or interval wrong - return $value if ($a[1] > $a[2] || $a[3] > $a[4]); - return $value if ($mode == 0 && ($value < $a[1] || $value > $a[2])); - return $value if ($mode == 1 && ($value < $a[3] || $value > $a[4])); - - # Reverse value - if ($rev) { - my $dr = ($mode == 0) ? $a[1]+$a[2] : $a[3]+$a[4]; - $value = $dr-$value; + my $rev = 0; + my $dn = $a[0]; + my $cn = $chnno; + if ($dn =~ /^\!(.+)$/) { + # Invert + $dn = $1; + $rev = 1; } + if ($dn =~ /^([0-9]{1,2})\.(.+)$/) { + # Compare channel number + $cn = $1; + $dn = $2; + } + next if ($dpt ne $dn || ($chnno ne '' && $cn ne $chnno)); + + if ($n == 2) { + $f = ($a[1] == 0.0) ? 1.0 : $a[1]; + return ($mode == 0) ? $value/$f : $value*$f; + } + else { + # Do not scale if value out of range or interval wrong + return $value if ($a[1] > $a[2] || $a[3] > $a[4]); + return $value if ($mode == 0 && ($value < $a[1] || $value > $a[2])); + return $value if ($mode == 1 && ($value < $a[3] || $value > $a[4])); - my $d1 = $a[2]-$a[1]; - my $d2 = $a[4]-$a[3]; - return $value if ($d1 == 0.0 || $d2 == 0.0); - $f = $d1/$d2; - return ($mode == 0) ? $value/$f+$a[3] : ($value-$a[3])*$f; + # Reverse value + if ($rev) { + my $dr = ($mode == 0) ? $a[1]+$a[2] : $a[3]+$a[4]; + $value = $dr-$value; + } + + my $d1 = $a[2]-$a[1]; + my $d2 = $a[4]-$a[3]; + return $value if ($d1 == 0.0 || $d2 == 0.0); + $f = $d1/$d2; + return ($mode == 0) ? $value/$f+$a[3] : ($value-$a[3])*$f; + } } } if ($dpt eq 'LEVEL') { return ($mode == 0) ? min($value,100.0)/100.0 : min($value,1.0)*100.0; } + elsif ($dpt =~ /^P[0-9]_ENDTIME/) { + if ($mode == 0) { + my $hh = sprintf ("%02d", int($value/60)); + my $mm = sprintf ("%02d", $value%60); + return "$hh:$mm"; + } + else { + my ($hh, $mm) = split (':', $value); + $mm = 0 if (!defined($mm)); + return $hh*60+$mm; + } + } # my $address = $hash->{TYPE} eq 'HMCCUDEV' ? $hash->{ccuaddr}.":$chnno" : $hash->{ccuaddr}; # my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $hash->{ccuif}); # if (defined($devDesc)) { @@ -8836,9 +8814,9 @@ sub HMCCU_GetHMState ($$$) my ($dptexpr, $subst) = split ('!', $rule, 2); my $dp = ''; next if (!defined ($dptexpr) || !defined ($subst)); - HMCCU_Trace ($clhash, 2, $fnc, "rule=$rule, dptexpr=$dptexpr, subst=$subst"); +# HMCCU_Trace ($clhash, 2, $fnc, "rule=$rule, dptexpr=$dptexpr, subst=$subst"); foreach my $d (keys %{$clhash->{hmccu}{dp}}) { - HMCCU_Trace ($clhash, 2, $fnc, "Check $d match $dptexpr"); +# HMCCU_Trace ($clhash, 2, $fnc, "Check $d match $dptexpr"); if ($d =~ /$dptexpr/) { $dp = $d; last; @@ -9962,6 +9940,15 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
  • get <name> aggregation {<rule>|all}
    Process aggregation rule defined with attribute ccuaggregate.

  • +
  • get <name> ccuconfig
    + Read configuration of CCU (devices, channels, programs). This command is executed automatically + after the definition of an I/O device. It must be executed manually after + module HMCCU is reloaded or after devices have changed in CCU (added, removed or + 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. +

  • get <name> ccumsg {service|alarm}
    Query active service or alarm messages from CCU. Generate FHEM event for each message.

  • @@ -9975,19 +9962,10 @@ sub HMCCU_CCURPC_ListDevicesCB ($$) List device channels and datapoints. If option 'State' is specified the device is queried directly. Otherwise device information from CCU is listed.
    -
  • get <name> devicelist [dump]
    - Read list of devices and channels from CCU. This command is executed automatically - after the definition of an I/O device. It must be executed manually after - module HMCCU is reloaded or after devices have changed in CCU (added, removed or - renamed). With option 'dump' devices are displayed in browser window. 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. -

  • -
  • get <name> devicelist create <devexp> [t={chn|dev|all}] +
  • get <name> create <devexp> [t={chn|dev|all}] [p=<prefix>] [s=<suffix>] [f=<format>] [defattr] [save] [<attr>=<value> [...]]
    - With option 'create' HMCCU will automatically create client devices for all CCU devices + 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 diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUCHN.pm index 4f2ed95f3..9bcca4049 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.011 +# Version 4.4.012 # # (c) 2020 zap (zap01 t-online de) # @@ -279,30 +279,24 @@ sub HMCCUCHN_Set ($@) my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc); my $cmdList = ''; - my %addCmds; - foreach my $d (keys %$roleCmds) { - my @cmds = split(' ', $roleCmds->{$d}); - foreach my $cmdDef (@cmds) { - my ($cmd, $argDef) = split(':', $cmdDef); - $addCmds{$cmd} = "$d=$argDef"; - $cmdList .= " $cmd"; - if ($argDef !~ /^\?/) { - my @argList = split(',', $argDef); - $cmdList .= scalar(@argList) > 1 ? ':'.$argDef : ':noArg'; + foreach my $cmd (keys %$roleCmds) { + $cmdList .= " $cmd"; + my @setList = split (/\s+/, $roleCmds->{$cmd}); + foreach my $set (@setList) { + my ($ps, $dpt, $par) = split(/:/, $set); + if ($par !~ /^\?/) { + my @argList = split (',', $par); + $cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg"; } } } # Get state values related to control command and datapoint - my $stateVals = HMCCU_GetStateValues ($hash, $roleCmds, $cd, 2); - my @stateCmdList = split (/[:\s]/, $stateVals); + my $stateVals = HMCCU_GetStateValues ($hash, $cd); + my @stateCmdList = split (/[:,]/, $stateVals); my %stateCmds = @stateCmdList; my @states = keys %stateCmds; -# HMCCU_Log ($hash, 2, "Additional commands ".join(',', keys %addCmds)) -# if (scalar(keys %addCmds) > 0); -# HMCCU_Log ($hash, 2, "sd=$sc.$sd cd=$cc.$cd StateVals=$stateVals states=".join(',', @states)); - my $result = ''; my $rc; @@ -351,14 +345,18 @@ sub HMCCUCHN_Set ($@) } elsif ($opt eq 'control') { return HMCCU_SetError ($hash, -14) if ($cd eq ''); - return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2)); + if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2)) { + HMCCU_Trace ($hash, 2, "Set", "Invalid datapoint $cc $cd"); + return HMCCU_SetError ($hash, -8); + } my $objvalue = shift @$a; return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue)); $objvalue =~ s/\\_/%20/g; + $objvalue =~ HMCCU_Substitute ($objvalue, $stateVals, 1, undef, ''); $rc = HMCCU_SetMultipleDatapoints ($hash, - { "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '') } + { "001.$ccuif.$ccuaddr.$cd" => $objvalue } ); return HMCCU_SetError ($hash, min(0, $rc)); } @@ -393,59 +391,91 @@ sub HMCCUCHN_Set ($@) ); return HMCCU_SetError ($hash, min(0, $rc)); } - elsif (exists($addCmds{$opt})) { + elsif (defined($roleCmds) && exists($roleCmds->{$opt})) { my $value; my %dpval; - my ($dpt, $par) = split('=', $addCmds{$opt}); - $par = '' if (!defined($par)); + my %cfval; + + my @setList = split (/\s+/, $roleCmds->{$opt}); + my $i = 0; + foreach my $set (@setList) { + my ($ps, $dpt, $par) = split(/:/, $set); + $ps = $ps eq 'V' ? 'VALUES' : 'MASTER'; + + return HMCCU_SetError ($hash, "Syntax error in definition of command $opt") + if (!defined($par)); + if (!HMCCU_IsValidParameter ($hash, $ccuaddr, $ps, $dpt)) { + HMCCU_Trace ($hash, 2, "Set", "Invalid parameter $ps $dpt"); + return HMCCU_SetError ($hash, -8); + } - return HMCCU_SetError ($hash, -8) - if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $dpt, 2)); + if ($par =~ /^\?(.+)$/) { + $par = $1; + my ($parName, $parDef) = split ('=', $par); + $value = shift @$a; + if (!defined($value) && defined($parDef)) { + if ($parDef =~ /^[+-][0-9]+$/) { + return HMCCU_SetError ($hash, "Current value of $cc.$dpt not available") + if (!defined($hash->{hmccu}{dp}{"$cc.$dpt"}{$ps}{SVAL})); + $value = $hash->{hmccu}{dp}{"$cc.$dpt"}{$ps}{SVAL}+int($parDef); + } + else { + $value = $parDef; + } + } + + return HMCCU_SetError ($hash, "Missing parameter $parName") + if (!defined($value)); + } + else { + $value = $par; + } + + if ($opt eq 'pct' || $opt eq 'level') { + my $timespec = shift @$a; + my $ramptime = shift @$a; - if ($par =~ /^\?(.+)$/) { - $par = $1; - my ($parName, $parDef) = split ('=', $par); - $value = shift @$a; - if (!defined($value) && defined($parDef)) { - if ($parDef =~ /^[+-][0-9]+$/) { - return HMCCU_SetError ($hash, "Current value of $cc.$dpt not available") - if (!defined($hash->{hmccu}{dp}{"$cc.$dpt"}{VALUES}{SVAL})); - $value = $hash->{hmccu}{dp}{"$cc.$dpt"}{VALUES}{SVAL}+int($parDef); + # Set on time + if (defined ($timespec)) { + return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype") + if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2)); + if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) { + $timespec = HMCCU_GetTimeSpec ($timespec); + return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0); + } + $dpval{"001.$ccuif.$ccuaddr.ON_TIME"} = $timespec if ($timespec > 0); + } + + # Set ramp time + if (defined($ramptime)) { + return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype") + if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2)); + $dpval{"002.$ccuif.$ccuaddr.RAMP_TIME"} = $ramptime if (defined ($ramptime)); + } + + $dpval{"003.$ccuif.$ccuaddr.$dpt"} = $value; + last; + } + else { + if ($ps eq 'VALUES') { + my $no = sprintf ("%03d", $i); + $dpval{"$i.$ccuif.$ccuaddr.$dpt"} = $value; + $i++; } else { - $value = $parDef; + $cfval{$dpt} = $value; } } } - else { - my @parList = split(',', $par); - $value = (scalar(@parList) > 1) ? shift @$a : $par; + + if (scalar(keys %dpval) > 0) { + $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); + return HMCCU_SetError ($hash, min(0, $rc)); } - - return HMCCU_SetError ($hash, "Missing parameter") if (!defined($value)); - - if ($opt eq 'pct' || $opt eq 'level') { - my $timespec = shift @$a; - my $ramptime = shift @$a; - - # Set on time - if (defined ($timespec)) { - return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype") - if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2)); - if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) { - $timespec = HMCCU_GetTimeSpec ($timespec); - return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0); - } - $dpval{"001.$ccuif.$ccuaddr.ON_TIME"} = $timespec if ($timespec > 0); - } - - # Set ramp time - $dpval{"002.$ccuif.$ccuaddr.RAMP_TIME"} = $ramptime if (defined ($ramptime)); + if (scalar(keys %cfval) > 0) { + ($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, 'MASTER'); + return HMCCU_SetError ($hash, min(0, $rc)); } - $dpval{"003.$ccuif.$ccuaddr.$dpt"} = $value; - - $rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval); - return HMCCU_SetError ($hash, min(0, $rc)); } elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') { return HMCCU_SetError ($hash, -15) if ($stateVals eq ''); @@ -508,10 +538,10 @@ sub HMCCUCHN_Set ($@) join(',', @parList)); } - if ($paramset eq 'VALUES') { - ($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h); + if ($paramset eq 'VALUES' || $paramset eq 'MASTER') { + ($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, $paramset); } - elsif ($paramset eq 'LINK') { + else { if (exists($defs{$receiver}) && defined($defs{$receiver}->{TYPE})) { my $clHash = $defs{$receiver}; if ($clHash->{TYPE} eq 'HMCCUDEV') { @@ -538,9 +568,6 @@ sub HMCCUCHN_Set ($@) if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver)); ($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $receiver, $h); } - else { - ($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $paramset, $h); - } return HMCCU_SetError ($hash, min(0, $rc)); } @@ -552,10 +579,12 @@ sub HMCCUCHN_Set ($@) else { my $retmsg = "clear defaults:noArg"; if ($hash->{readonly} ne 'yes') { - $retmsg .= " config control datapoint".$cmdList; + $retmsg .= " config control"; + $retmsg .= ':'.join(',', @states) if (scalar(@states) > 0); + $retmsg .= " datapoint".$cmdList; $retmsg .= ' toggle:noArg' if (scalar(@states) > 0); $retmsg .= " on-for-timer on-till" - if (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "ON_TIME", 2)); + if ($sc ne '' && HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "ON_TIME", 2)); } return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); } diff --git a/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm b/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm index 255b37c09..e73834226 100644 --- a/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm +++ b/fhem/contrib/HMCCU/FHEM/88_HMCCUDEV.pm @@ -66,7 +66,7 @@ sub HMCCUDEV_Define ($@) my $name = $hash->{NAME}; my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [state-channel] ". - "['readonly'] ['defaults'] [iodev={iodev-name}] [address={virtual-device-no}]". + "['readonly'] ['noDefaults'] [iodev={iodev-name}] [address={virtual-device-no}]". "[{groupexp=regexp|group={device|channel}[,...]]"; return $usage if (scalar (@$a) < 3); @@ -107,16 +107,11 @@ sub HMCCUDEV_Define ($@) else { return "Option address not specified" if (!$init_done && $devspec eq 'virtual'); } - - # Defaults - $hash->{hmccu}{statevals} = 'devstate'; # Parse optional command line parameters foreach my $arg (@$a) { - if ($arg eq 'readonly') { $hash->{readonly} = 'yes'; $hash->{hmccu}{statevals} = '' } - elsif ($arg eq 'defaults') { - HMCCU_SetDefaults ($hash) if ($init_done); - } + if ($arg eq 'readonly') { $hash->{readonly} = 'yes'; } + elsif ($arg ne 'noDefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; } elsif ($arg =~ /^[0-9]+$/) { $attr{$name}{statechannel} = $arg; } else { return $usage; } } @@ -177,17 +172,17 @@ sub HMCCUDEV_Define ($@) sub HMCCUDEV_InitDevice ($$) { - my ($ioHash, $dev_hash) = @_; - my $name = $dev_hash->{NAME}; - my $devspec = $dev_hash->{hmccu}{devspec}; + my ($ioHash, $devHash) = @_; + my $name = $devHash->{NAME}; + my $devspec = $devHash->{hmccu}{devspec}; my $gdcount = 0; my $gdname = $devspec; if ($devspec eq 'virtual') { my $no = 0; - if (exists ($dev_hash->{hmccu}{address})) { + if (exists ($devHash->{hmccu}{address})) { # Only true during FHEM start - $no = $dev_hash->{hmccu}{address}; + $no = $devHash->{hmccu}{address}; } else { # Search for free address. Maximum of 10000 virtual devices allowed. @@ -199,11 +194,11 @@ sub HMCCUDEV_InitDevice ($$) } } return 7 if ($no == 0); - $dev_hash->{DEF} .= " address=$no"; + $devHash->{DEF} .= " address=$no"; } - $dev_hash->{ccuif} = 'fhem'; - $dev_hash->{ccuaddr} = sprintf ("VIR%07d", $no); - $dev_hash->{ccuname} = $name; + $devHash->{ccuif} = 'fhem'; + $devHash->{ccuaddr} = sprintf ("VIR%07d", $no); + $devHash->{ccuname} = $name; } else { return 1 if (!HMCCU_IsValidDevice ($ioHash, $devspec, 7)); @@ -212,25 +207,38 @@ sub HMCCUDEV_InitDevice ($$) return 1 if (!defined ($da)); $gdname = $dn; - $dev_hash->{ccuif} = $di; - $dev_hash->{ccuaddr} = $da; - $dev_hash->{ccuname} = $dn; - $dev_hash->{ccutype} = $dt; - $dev_hash->{hmccu}{channels} = $dc; + $devHash->{ccuif} = $di; + $devHash->{ccuaddr} = $da; + $devHash->{ccuname} = $dn; + $devHash->{ccutype} = $dt; + $devHash->{hmccu}{channels} = $dc; + + if ($init_done) { + # Interactive device definition + HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME}); + HMCCU_UpdateDevice ($ioHash, $devHash); + HMCCU_UpdateDeviceRoles ($ioHash, $devHash); + if (!exists($devHash->{hmccu}{nodefaults})) { + if (!HMCCU_SetDefaultAttributes ($devHash)) { + HMCCU_SetDefaults ($devHash); + } + } + HMCCU_GetUpdate ($devHash, $da, 'Value'); + } } # Parse group options - if ($dev_hash->{ccuif} eq 'VirtualDevices' || $dev_hash->{ccuif} eq 'fhem') { + if ($devHash->{ccuif} eq 'VirtualDevices' || $devHash->{ccuif} eq 'fhem') { my @devlist = (); - if (exists ($dev_hash->{hmccu}{groupexp})) { + if (exists ($devHash->{hmccu}{groupexp})) { # Group devices specified by name expression - $gdcount = HMCCU_GetMatchingDevices ($ioHash, $dev_hash->{hmccu}{groupexp}, 'dev', \@devlist); + $gdcount = HMCCU_GetMatchingDevices ($ioHash, $devHash->{hmccu}{groupexp}, 'dev', \@devlist); return 4 if ($gdcount == 0); } - elsif (exists ($dev_hash->{hmccu}{group})) { + elsif (exists ($devHash->{hmccu}{group})) { # Group devices specified by comma separated name list - my @gdevlist = split (",", $dev_hash->{hmccu}{group}); - $dev_hash->{ccugroup} = '' if (@gdevlist > 0); + my @gdevlist = split (",", $devHash->{hmccu}{group}); + $devHash->{ccugroup} = '' if (@gdevlist > 0); foreach my $gd (@gdevlist) { my ($gda, $gdc, $gdo) = ('', '', '', ''); @@ -251,7 +259,7 @@ sub HMCCUDEV_InitDevice ($$) return 3 if ($gdcount == 0); - $dev_hash->{ccugroup} = join (',', @devlist); + $devHash->{ccugroup} = join (',', @devlist); if ($devspec eq 'virtual') { my $dev = shift @devlist; my $devtype = HMCCU_GetDeviceType ($ioHash, $dev, 'n/a'); @@ -265,13 +273,13 @@ sub HMCCUDEV_InitDevice ($$) my $rc = 0; if ($devna) { - $dev_hash->{ccutype} = 'n/a'; - $dev_hash->{readonly} = 'yes'; - $rc = HMCCU_CreateDevice ($ioHash, $dev_hash->{ccuaddr}, $name, undef, $dev); + $devHash->{ccutype} = 'n/a'; + $devHash->{readonly} = 'yes'; + $rc = HMCCU_CreateDevice ($ioHash, $devHash->{ccuaddr}, $name, undef, $dev); } else { - $dev_hash->{ccutype} = $devtype; - $rc = HMCCU_CreateDevice ($ioHash, $dev_hash->{ccuaddr}, $name, $devtype, $dev); + $devHash->{ccutype} = $devtype; + $rc = HMCCU_CreateDevice ($ioHash, $devHash->{ccuaddr}, $name, $devtype, $dev); } return $rc+4 if ($rc > 0); @@ -281,10 +289,9 @@ sub HMCCUDEV_InitDevice ($$) } # Inform HMCCU device about client device - return 2 if (!HMCCU_AssignIODevice ($dev_hash, $ioHash->{NAME}, undef)); + return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef)); -# readingsSingleUpdate ($dev_hash, "state", "Initialized", 1); - $dev_hash->{ccudevstate} = 'active'; + $devHash->{ccudevstate} = 'active'; return 0; } @@ -335,21 +342,13 @@ sub HMCCUDEV_Attr ($@) } elsif ($attrname eq "statevals") { return "Device is read only" if ($hash->{readonly} eq 'yes'); - $hash->{hmccu}{statevals} = 'devstate'; - my @states = split /,/,$attrval; - foreach my $st (@states) { - my @statesubs = split /:/,$st; - return "value := text:substext[,...]" if (@statesubs != 2); - $hash->{hmccu}{statevals} .= '|'.$statesubs[0]; - } - } - } - elsif ($cmd eq "del") { - if ($attrname eq "statevals") { - $hash->{hmccu}{statevals} = $hash->{readonly} eq 'yes' ? '' : "devstate"; } } + if ($init_done) { + HMCCU_RefreshReadings ($hash); + } + return; } @@ -396,23 +395,22 @@ sub HMCCUDEV_Set ($@) my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc); my $cmdList = ''; - my %addCmds; - foreach my $d (keys %$roleCmds) { - my @cmds = split(' ', $roleCmds->{$d}); - foreach my $cmdDef (@cmds) { - my ($cmd, $argDef) = split(':', $cmdDef); - $addCmds{$cmd} = "$d=$argDef"; - $cmdList .= " $cmd"; - if ($argDef !~ /^\?/) { - my @argList = split(',', $argDef); - $cmdList .= scalar(@argList) > 1 ? ':'.$argDef : ':noArg'; + foreach my $cmd (keys %$roleCmds) { + $cmdList .= " $cmd"; + my @setList = split (/\s+/, $roleCmds->{$cmd}); + foreach my $set (@setList) { + my ($ps, $dpt, $par) = split(/:/, $set); + if ($par !~ /^\?/) { + my @argList = split (',', $par); + $cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg"; } } } # Get state values related to control command and datapoint - my $stateVals = HMCCU_GetStateValues ($hash, $roleCmds, $cd, 2); - my @stateCmdList = split (/[:\s]/, $stateVals); + my $stateVals = HMCCU_GetStateValues ($hash, $cd, $cc); + my @stateCmdList = split (/[:,]/, $stateVals); + my %stateCmds = @stateCmdList; my @states = keys %stateCmds; @@ -664,26 +662,17 @@ sub HMCCUDEV_Set ($@) return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK"); } else { - my $retmsg = "clear config defaults:noArg"; + my $retmsg = "clear defaults:noArg"; if ($hash->{readonly} ne 'yes') { - $retmsg .= " control datapoint rpcparameter"; + $retmsg .= " datapoint rpcparameter"; if ($sc ne '') { - $retmsg .= " devstate"; - if ($hash->{hmccu}{statevals} ne '') { - my @cmdlist = split /\|/,$hash->{hmccu}{statevals}; - shift @cmdlist; - $retmsg .= ':'.join(',',@cmdlist) if (@cmdlist > 0); - foreach my $sv (@cmdlist) { - $retmsg .= ' '.$sv.':noArg'; - } - $retmsg .= " toggle:noArg"; - $retmsg .= " on-for-timer on-till" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "ON_TIME", 2)); - $retmsg .= " pct up down level" - if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "LEVEL", 2) || - HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $cc, "LEVEL", 2)); - } + $retmsg .= " config control"; + $retmsg .= ':'.join(',', @states) if (scalar(@states) > 0); + $retmsg .= $cmdList; + $retmsg .= " toggle:noArg" if (scalar(@states) > 0); + $retmsg .= " on-for-timer on-till" + if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "ON_TIME", 2)); } } return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a); diff --git a/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm b/fhem/contrib/HMCCU/FHEM/HMCCUConf.pm index b3c410ca2..d68a639bb 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.7 +# Version 4.8 # # Configuration parameters for HomeMatic devices. # @@ -17,7 +17,8 @@ package HMCCUConf; use strict; use warnings; -use vars qw(%HMCCU_ROLES); +use vars qw(%HMCCU_STATECONTROL); +use vars qw(%HMCCU_ROLECMDS); use vars qw(%HMCCU_ATTR); use vars qw(%HMCCU_CONVERSIONS); use vars qw(%HMCCU_CHN_DEFAULTS); @@ -25,38 +26,112 @@ use vars qw(%HMCCU_DEV_DEFAULTS); use vars qw(%HMCCU_SCRIPTS); ###################################################################### -# Channel roles with commands and state values +# Channel roles with state and control datapoints +# F: 1=Channel/HMCCUCHN, 2=Device/HMCCUDEV, 3=Both +# S: State datapoint, C: Control datapoint, V: Control values ###################################################################### -%HMCCU_ROLES = ( +%HMCCU_STATECONTROL = ( + 'SHUTTER_CONTACT' => { + F => 3, S => 'STATE', C => '', V => '' + }, 'KEY' => { - 'PRESS_SHORT' => 'on:true press:true' + F => 3, S => 'PRESS_SHORT', C => 'PRESS_SHORT', V => 'pressed:true' }, 'BLIND' => { - 'LEVEL' => 'pct:?level open:100 close:0 up:?delta=+10 down:?delta=-10', - 'STOP' => 'stop:true' + F => 3, S => 'LEVEL', C => 'LEVEL', V => 'open:100,close:0' }, 'SWITCH' => { - 'STATE' => 'on:true off:false' + F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false' + }, + 'SWITCH_VIRTUAL_RECEIVER' => { + F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false' }, 'DIMMER' => { - 'LEVEL' => 'pct:?level on:100 off:0', - 'RAMP_STOP' => 'stop:true' + F => 3, S => 'LEVEL', C => 'LEVEL', V => 'on:100,off:0' + }, + 'WEATHER_TRANSMIT' => { + F => 1, S => 'TEMPERATURE', C => 'TEMPERATURE', V => '' }, 'THERMALCONTROL_TRANSMIT' => { - 'SET_TEMPERATURE' => 'desiredTemp:?temperature', - 'MANU_MODE' => 'manu:?temperature on:30.5 off:4.5', - 'AUTO_MODE' => 'auto:true', - 'BOOST_MODE' => 'boost:true' + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => '' }, 'CLIMATECONTROL_RT_TRANSCEIVER' => { - 'SET_TEMPERATURE' => 'desiredTemp:?temperature', - 'MANU_MODE' => 'manu:?temperature on:30.5 off:4.5', - 'AUTO_MODE' => 'auto:true', - 'BOOST_MODE' => 'boost:true' + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_TEMPERATURE', V => '' + }, + 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { + F => 3, S => 'ACTUAL_TEMPERATURE', C => 'SET_POINT_TEMPERATURE', V => '' } ); +###################################################################### +# Set commands related to channel role +# Role => { Command-Definition, ... } +# Command-Defintion: +# Command => 'Datapoint-Definition [...]' +# Datapoint-Definition: +# Paramset:Datapoint:FixedValue[,FixedValue] +# Paramset:Datapoint:?Parameter +# Paramset:Datapoint:?Parameter=Default-Value +# Paramset: +# V=VALUES or M=MASTER +# If Default-Value is preceeded by + or -, value is added to or +# subtracted from current datapoint value +###################################################################### + +%HMCCU_ROLECMDS = ( + 'KEY' => { + 'on' => 'V:PRESS_SHORT:true', + 'off' => 'V:PRESS_SHORT:true' + }, + 'BLIND' => { + 'pct' => 'V:LEVEL:?level', + 'open' => 'V:LEVEL:100', + 'close' => 'V:LEVEL:0', + 'up' => 'V:LEVEL:?delta=+10', + 'down' => 'V:LEVEL:?delta=-10', + 'stop' => 'V:STOP:true' + }, + 'SWITCH' => { + 'on' => 'V:STATE:true', + 'off' => 'V:STATE:false' + }, + 'SWITCH_VIRTUAL_RECEIVER' => { + 'on' => 'V:STATE:true', + 'off' => 'V:STATE:false' + }, + 'DIMMER' => { + 'pct' => 'V:LEVEL:?level', + 'on' => 'V:LEVEL:100', + 'off' => 'V:LEVEL:0', + 'stop' => 'V:RAMP_STOP:true' + }, + 'THERMALCONTROL_TRANSMIT' => { + 'desired-temp' => 'V:SET_TEMPERATURE:?temperature', + 'manu' => 'V:MANU_MODE:?temperature', + 'on' => 'V:MANU_MODE:30.5', + 'off' => 'V:MANU_MODE:4.5', + 'auto' => 'V:AUTO_MODE:true', + 'boost' => 'V:BOOST_MODE:true' + }, + 'CLIMATECONTROL_RT_TRANSCEIVER' => { + 'desired-temp' => 'V:SET_TEMPERATURE:?temperature', + 'manu' => 'V:MANU_MODE:?temperature', + 'on' => 'V:MANU_MODE:30.5', + 'off' => 'V:MANU_MODE:4.5', + 'auto' => 'V:AUTO_MODE:true', + 'boost' => 'V:BOOST_MODE:true' + }, + 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { + 'desired-temp' => 'V:SET_POINT_TEMPERATURE:?temperature', + 'auto' => 'V:CONTROL_MODE:0', + 'manu' => 'V:CONTROL_MODE:1', + 'holiday' => 'V:CONTROL_MODE:2', + 'boost' => 'V:BOOST_MODE:true', + 'on' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:30.5', + 'off' => 'V:CONTROL_MODE:1 V:SET_POINT_TEMPERATURE:4.5' + } +); ###################################################################### # Channel roles with attributes @@ -64,30 +139,40 @@ use vars qw(%HMCCU_SCRIPTS); %HMCCU_ATTR = ( 'BLIND' => { - 'ccureadingname' => 'LEVEL$:+pct', + 'ccureadingname' => 'LEVEL$:pct', 'webCmd' => 'up:down:stop:control', - 'widgetOverride' => 'control:slider,0,10,100' + 'widgetOverride' => 'control:slider,0,10,100 pct:slider,0,10,100' }, 'SWITCH' => { 'webCmd' => 'control', 'widgetOverride' => 'control:uzsuToggle,off,on' }, + 'SWITCH_VIRTUAL_RECEIVER' => { + 'webCmd' => 'control', + 'widgetOverride' => 'control:uzsuToggle,off,on' + }, 'DIMMER' => { - 'ccureadingname' => 'LEVEL$:+pct', + 'ccureadingname' => 'LEVEL$:pct', 'webCmd' => 'control', 'widgetOverride' => 'pct:slider,0,10,100 level:slider,0,10,100 control:slider,0,10,100' }, 'THERMALCONTROL_TRANSMIT' => { - 'ccureadingname' => 'SET_TEMPERATURE$:+desiredTemp', + 'ccureadingname' => 'SET_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp', 'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus', - 'webCmd' => 'desiredTemp:auto:manu:boost:on:off', - 'widgetOverride' => 'control:slider,4.5,0.5,30.5,1 desiredTemp:slider,4.5,0.5,30.5,1' + 'webCmd' => 'desired-temp:auto:manu:boost:on:off', + 'widgetOverride' => 'control:slider,4.5,0.5,30.5,1 desired-temp:slider,4.5,0.5,30.5,1' }, 'CLIMATECONTROL_RT_TRANSCEIVER' => { - 'ccureadingname' => 'SET_TEMPERATURE$:+desiredTemp', + 'ccureadingname' => 'SET_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp', 'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus', - 'webCmd' => 'desiredTemp', - 'widgetOverride' => 'control:slider,4.5,0.5,30.5,1 desiredTemp:slider,4.5,0.5,30.5,1' + 'webCmd' => 'desired-temp', + 'widgetOverride' => 'control:slider,4.5,0.5,30.5,1 desired-temp:slider,4.5,0.5,30.5,1' + }, + 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { + 'ccureadingname' => 'SET_POINT_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp', + 'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus', + 'webCmd' => 'desired-temp:auto:manu:boost', + 'widgetOverride' => 'control:slider,4.5,0.5,30.5,1 desired-temp:slider,4.5,0.5,30.5,1' } ); @@ -102,12 +187,25 @@ use vars qw(%HMCCU_SCRIPTS); 'SWITCH' => { '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' }, + }, 'BLIND' => { 'LEVEL' => { '0' => 'closed', '100' => 'open', 'close' => '0', 'open' => '100' } }, 'DIMMER' => { 'LEVEL' => { '0' => 'off', '100' => 'on', 'off' => '0', 'on' => '100' } }, + 'THERMALCONTROL_TRANSMIT' => { + 'SET_TEMPERATURE' => { '4.5' => 'off', '30.5' => 'on' } + }, + 'CLIMATECONTROL_RT_TRANSCEIVER' => { + 'SET_TEMPERATURE' => { '4.5' => 'off', '30.5' => 'on' } + }, + 'HEATING_CLIMATECONTROL_TRANSCEIVER' => { + 'SET_POINT_TEMPERATURE' => { '4.5' => 'off', '30.5' => 'on' }, + 'WINDOW_STATE' => { '0' => 'closed', '1' => 'open', 'false' => 'closed', 'true' => 'open' } + }, 'DEFAULT' => { 'AES_KEY' => { '0' => 'off', 'false' => 'off', '1' => 'on', 'true' => 'on' }, 'LOW_BAT' => { '0' => 'ok', 'false' => 'ok', '1' => 'low', 'true' => 'low' },