2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 12:49:34 +00:00

HMCCU: Update for version 4.4 beta

git-svn-id: https://svn.fhem.de/fhem/trunk@21372 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-03-07 15:52:11 +00:00
parent 0c9c09e063
commit 6a460a423f
4 changed files with 477 additions and 383 deletions

View File

@ -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));
$oper = 2 if (!defined($oper));
my ($clHash, $dpt, $ctrlChn) = @_;
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));
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 ($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 $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 ($$)
<li><b>get &lt;name&gt; aggregation {&lt;rule&gt;|all}</b><br/>
Process aggregation rule defined with attribute ccuaggregate.
</li><br/>
<li><b>get &lt;name&gt; ccuconfig</b><br/>
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 "<i>count</i> devices added in CCU" or
"<i>count</i> devices deleted in CCU". It's recommended to set up a notification
which reacts with execution of command 'get devicelist' on these events.
</li><br/>
<li><b>get &lt;name&gt; ccumsg {service|alarm}</b><br/>
Query active service or alarm messages from CCU. Generate FHEM event for each message.
</li><br/>
@ -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.
</li><br/>
<li><b>get &lt;name&gt; devicelist [dump]</b><br/>
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 "<i>count</i> devices added in CCU" or
"<i>count</i> devices deleted in CCU". It's recommended to set up a notification
which reacts with execution of command 'get devicelist' on these events.
</li><br/>
<li><b>get &lt;name&gt; devicelist create &lt;devexp&gt; [t={chn|<u>dev</u>|all}]
<li><b>get &lt;name&gt; create &lt;devexp&gt; [t={chn|<u>dev</u>|all}]
[p=&lt;prefix&gt;] [s=&lt;suffix&gt;] [f=&lt;format&gt;] [defattr]
[save] [&lt;attr&gt;=&lt;value&gt; [...]]</b><br/>
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.<br/>
Optionally a <i>prefix</i> and/or a

View File

@ -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 <at> t-online <dot> 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;
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $dpt, 2));
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';
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);
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);
}
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;
# 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);
}

View File

@ -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);
@ -108,15 +108,10 @@ sub HMCCUDEV_Define ($@)
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,19 +342,11 @@ 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);

View File

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