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' },