From 62a234b4d905eb0deb22e4a93d22e4e140362de9 Mon Sep 17 00:00:00 2001
From: zap <>
Date: Sun, 12 Dec 2021 13:01:01 +0000
Subject: [PATCH] HMCCU: Several improvements and bug fixes
git-svn-id: https://svn.fhem.de/fhem/trunk@25336 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 1 +
fhem/FHEM/88_HMCCU.pm | 320 ++++++++++++++++++++++++++---------
fhem/FHEM/88_HMCCUCHN.pm | 28 ++-
fhem/FHEM/88_HMCCUDEV.pm | 8 +-
fhem/FHEM/88_HMCCURPCPROC.pm | 2 +-
fhem/FHEM/HMCCUConf.pm | 262 +++++++++++++++++-----------
6 files changed, 428 insertions(+), 193 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index f5d17dc27..bdca26b04 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - bugfix: 88_HMCCU: Several improvements and bug fixes
- bugfix: 93_DbRep: fix some problems with reduceLog
(Forum: #/topic,53584.msg1177799.html#msg1177799
- feature: 98_weekprofile: support HMCCUCHN with CCU
diff --git a/fhem/FHEM/88_HMCCU.pm b/fhem/FHEM/88_HMCCU.pm
index dc0a542ac..d208a0286 100755
--- a/fhem/FHEM/88_HMCCU.pm
+++ b/fhem/FHEM/88_HMCCU.pm
@@ -31,7 +31,7 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
use strict;
use warnings;
-# use Data::Dumper;
+use Data::Dumper;
use Encode qw(decode encode);
use RPC::XML::Client;
use RPC::XML::Server;
@@ -57,7 +57,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
-my $HMCCU_VERSION = '5.0 213301607';
+my $HMCCU_VERSION = '5.0 213461309';
# Timeout for CCU requests (seconds)
my $HMCCU_TIMEOUT_REQUEST = 4;
@@ -4327,11 +4327,12 @@ sub HMCCU_GetParamDef ($$$;$)
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);
if (!defined($paramset)) {
HMCCU_Log ($hash, 2, "$a Paramset not defined ".stacktraceAsString(undef));
return undef;
}
+
+ my $model = HMCCU_GetDeviceModel ($hash, $devDesc->{_model}, $devDesc->{_fw_ver}, $chnNo);
if (defined($model) && exists($model->{$paramset})) {
if (defined($parameter)) {
return exists($model->{$paramset}{$parameter}) ? $model->{$paramset}{$parameter} : undef;
@@ -4378,6 +4379,46 @@ sub HMCCU_FindParamDef ($$$)
return (undef, undef);
}
+######################################################################
+# Get values of ENUM datapoint
+# object - Hash with parameter defintion or channel address
+# dpt - Datapoint name
+# value - Either a numeric value or an enumeration constant
+# If value is not specified, a comma separated list of enumeration
+# constants is returned.
+# Return value or undef if datapoint is not of type ENUM.
+######################################################################
+
+sub HMCCU_GetEnumValues ($$$;$)
+{
+ my ($ioHash, $object, $dpt, $value) = @_;
+
+ my $paramDef = ref($object) eq 'HASH' ? $object : HMCCU_GetParamDef ($ioHash, $object, 'VALUES', $dpt);
+ if (defined($paramDef) && defined($paramDef->{TYPE}) && $paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) {
+ my $i = defined($paramDef->{MIN}) && HMCCU_IsIntNum($paramDef->{MIN}) ? $paramDef->{MIN} : 0;
+ my $j = $i;
+ my @valList = split(',',$paramDef->{VALUE_LIST});
+ my %valIndex = map { $_ => $i++ } @valList;
+ if (defined($value)) {
+ if ($value eq '#') {
+ $j--;
+ return join(',', map { $j++; $_ ne '' ? "$_:$j" : () } @valList);
+ }
+ elsif (HMCCU_IsIntNum($value)) {
+ return $valList[$value] if ($value >= 0 && $value < scalar(@valList));
+ }
+ else {
+ return $valIndex{$value} if (exists($valIndex{$value}));
+ }
+ }
+ else {
+ return $paramDef->{VALUE_LIST};
+ }
+ }
+
+ return $value;
+}
+
######################################################################
# Check if parameter exists
# Parameters:
@@ -4683,7 +4724,7 @@ sub HMCCU_UpdateParamsetReadings ($$$;$)
HMCCU_UpdateInternalValues ($clHash, $chKey, $ps, 'VAL', $v);
# Modify value: scale, format, substitute
- $sv = HMCCU_ScaleValue ($clHash, $c, $p, $v, 0);
+ $sv = HMCCU_ScaleValue ($clHash, $c, $p, $v, 0, $ps);
HMCCU_UpdateInternalValues ($clHash, $chKey, $ps, 'NVAL', $sv);
HMCCU_Trace ($clHash, 2, "$p: sv = $sv");
$fv = HMCCU_FormatReadingValue ($clHash, $sv, $p);
@@ -5816,7 +5857,6 @@ sub HMCCU_IsDeviceActive ($)
return 1 if ($disabled == 0 && exists($clHash->{ccuaddr}) && exists($clHash->{ccuif}) && $devstate ne 'inactive');
}
- HMCCU_Log ($clHash, 2, "Device disabled or inactive and/or address or interface is missing");
return 0;
}
@@ -6803,8 +6843,8 @@ sub HMCCU_SetDefaultAttributes ($;$)
}
}
else {
- my ($sc, $sd, $cc, $cd) = HMCCU_GetSCDatapoints ($clHash);
- $role = $parRef->{role} // HMCCU_GetChannelRole ($clHash, $parRef->{roleChn} // $cc);
+ my $scc = HMCCU_StateOrControlChannel ($clHash);
+ $role = $parRef->{role} // HMCCU_GetChannelRole ($clHash, $parRef->{roleChn} // $scc);
}
if (defined($role) && $role ne '') {
@@ -6848,6 +6888,8 @@ sub HMCCU_GetStateValues ($;$$)
$dpt //= '';
$ctrlChn //= '';
+ my $ioHash = HMCCU_GetHash ($clHash);
+
my $sv = AttrVal ($clHash->{NAME}, 'statevals', '');
if ($sv eq '' && $dpt ne '' && $ctrlChn ne '') {
my $role = HMCCU_GetChannelRole ($clHash, $ctrlChn);
@@ -6855,7 +6897,9 @@ sub HMCCU_GetStateValues ($;$$)
if ($role ne '' && exists($HMCCU_STATECONTROL->{$role}) &&
HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$role}{C}, $clHash->{ccuif}) eq $dpt)
{
- return $HMCCU_STATECONTROL->{$role}{V};
+ return $HMCCU_STATECONTROL->{$role}{V} eq '#' ?
+ HMCCU_GetEnumValues ($ioHash, HMCCU_GetChannelAddr ($clHash, $ctrlChn), $HMCCU_STATECONTROL->{$role}{C}, '#') :
+ $HMCCU_STATECONTROL->{$role}{V};
}
}
@@ -7038,6 +7082,9 @@ sub HMCCU_UpdateRoleCommands ($$;$)
my %valList;
if ($dpt eq $HMCCU_STATECONTROL->{$role}{C}) {
# If parameter is control datapoint, use values/conversions from HMCCU_STATECONTROL
+ my $stVals = $HMCCU_STATECONTROL->{$role}{V} eq '#' ?
+ HMCCU_GetEnumValues ($ioHash, HMCCU_GetChannelAddr ($clHash, $chnNo), $HMCCU_STATECONTROL->{$role}{C}, '#') :
+ $HMCCU_STATECONTROL->{$role}{V};
foreach my $cv (split(',', $HMCCU_STATECONTROL->{$role}{V})) {
my ($vn, $vv) = split(':', $cv);
$valList{$vn} = $vv // $vn;
@@ -7182,7 +7229,10 @@ sub HMCCU_UpdateAdditionalCommands ($$;$$)
if ($role ne '' && exists($HMCCU_STATECONTROL->{$role}) &&
HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$role}{C}, $clHash->{ccuif}) eq $cd) {
# Only add toggle command, ignore attribute statevals
- my %stateCmds = split (/[:,]/, $HMCCU_STATECONTROL->{$role}{V});
+ my $stVals = $HMCCU_STATECONTROL->{$role}{V} eq '#' ?
+ HMCCU_GetEnumValues ($ioHash, HMCCU_GetChannelAddr ($clHash, $cc), $HMCCU_STATECONTROL->{$role}{C}, '#') :
+ $HMCCU_STATECONTROL->{$role}{V};
+ my %stateCmds = split (/[:,]/, $stVals);
my @states = keys %stateCmds;
$clHash->{hmccu}{cmdlist}{set} .= $s.'toggle:noArg' if (scalar(@states) > 1);
return;
@@ -7431,6 +7481,7 @@ sub HMCCU_ExecuteSetDatapointCommand ($@)
{
my ($clHash, $a, $h) = @_;
+ my $ioHash = HMCCU_GetHash ($clHash);
my $usage = "Usage: set $clHash->{NAME} datapoint [{channel-number}.]{datapoint} {value} [...]";
my %dpval;
my $i = 0;
@@ -7439,32 +7490,63 @@ sub HMCCU_ExecuteSetDatapointCommand ($@)
my $stVals = HMCCU_GetStateValues ($clHash, $cd, $cc);
push (@$a, %${h}) if (defined($h));
- while (my $dpt = shift @$a) {
+ while (my $cdpt = shift @$a) {
my $value = shift @$a // return HMCCU_SetError ($clHash, $usage);
$i++;
+ my $chnAddr = '';
+ my $dpt = '';
if ($clHash->{TYPE} eq 'HMCCUDEV') {
- if ($dpt =~ /^([0-9]+)\..+$/) {
+ if ($cdpt =~ /^([0-9]+)\.(.+)$/) {
+ $chnAddr = "$devAddr:$1";
+ $dpt = $2;
return HMCCU_SetError ($clHash, -7) if ($1 >= $clHash->{hmccu}{channels});
}
else {
return HMCCU_SetError ($clHash, -12) if ($cc eq '');
- $dpt = "$cc.$dpt";
+ $dpt = $cdpt;
+ $cdpt = "$cc.$cdpt";
+ $chnAddr = "$devAddr:$cc";
}
}
else {
- if ($dpt =~ /^([0-9]+)\..+$/) {
+ if ($cdpt =~ /^([0-9]+)\.(.+)$/) {
+ $chnAddr = "$devAddr:$1";
+ $dpt = $2;
return HMCCU_SetError ($clHash, -7) if ($1 != $chnNo);
}
else {
- $dpt = "$chnNo.$dpt";
+ $dpt = $cdpt;
+ $cdpt = "$chnNo.$cdpt";
+ $chnAddr = "$devAddr:$chnNo";
+ }
+ }
+
+ my $paramDef = HMCCU_GetParamDef ($ioHash, $chnAddr, 'VALUES', $dpt);
+ my $paramType = defined($paramDef) ? $paramDef->{TYPE} : '';
+
+ # Show values allowed for datapoint
+ if ($value eq '?' && defined($paramDef)) {
+ if ($paramDef->{OPERATIONS} & 2) {
+ if ($paramType ne 'ENUM') {
+ my $min = $paramDef->{MIN} // '?';
+ my $max = $paramDef->{MAX} // '?';
+ my $unit = $paramDef->{UNIT} // '?';
+ return "Usage: set $clHash->{NAME} datapoint $cdpt {$paramType} # min=$min max=$max unit=$unit";
+ }
+ else {
+ return "Usage: set $clHash->{NAME} datapoint $cdpt {$paramDef->{VALUE_LIST}}";
+ }
+ }
+ else {
+ return "Datapoint $cdpt is not writeable";
}
}
$value = HMCCU_Substitute ($value, $stVals, 1, undef, '') if ($stVals ne '' && $dpt eq $cd);
my $no = sprintf ("%03d", $i);
- $dpval{"$no.$clHash->{ccuif}.$devAddr:$dpt"} = $value;
+ $dpval{"$no.$clHash->{ccuif}.$chnAddr.$dpt"} = $value;
}
return HMCCU_SetError ($clHash, $usage) if (scalar(keys %dpval) < 1);
@@ -7526,9 +7608,13 @@ sub HMCCU_ExecuteSetParameterCommand ($@)
return HMCCU_SetError ($clHash, "Paramset $paramset not supported by device or channel")
if ($devDesc->{PARAMSETS} !~ /$paramset/);
if (!HMCCU_IsValidParameter ($ioHash, $devDesc, $paramset, $h)) {
- my @parList = HMCCU_GetParamDef ($ioHash, $devDesc, $paramset);
- return HMCCU_SetError ($clHash, 'Invalid parameter specified. Valid parameters are '.
- join(',', @parList));
+ my $paramDef = HMCCU_GetParamDef ($ioHash, $devDesc, $paramset);
+ if (defined($paramDef)) {
+ my @parList = map { $paramDef->{$_}{OPERATIONS} == 2 ? $_ : () } keys %$paramDef;
+ return HMCCU_SetError ($clHash, 'Invalid parameter specified. Valid parameters: '.
+ join(',', @parList)) if (scalar(@parList) > 0);
+ }
+ return HMCCU_SetError ($clHash, 'Invalid parameter specified');
}
if ($paramset eq 'VALUES' || $paramset eq 'MASTER') {
@@ -7978,7 +8064,7 @@ sub HMCCU_SetDefaultSCDatapoints ($$;$$)
$cc = $detect->{defCCh} if ($detect->{defCCh} != -1);
$sd = $detect->{stateRole}{$sc}{datapoint} if ($sc ne '' && exists($detect->{stateRole}{$sc}));
$cd = $detect->{controlRole}{$cc}{datapoint} if ($cc ne '' && exists($detect->{controlRole}{$cc}));
-# HMCCU_Log ($clHash, 2, "Prio 4: s=$sc.$sd c=$cc.$sd");
+# HMCCU_Log ($clHash, 2, "Prio 4: s=$sc.$sd c=$cc.$cd");
}
# Prio 3: Use information stored in device hash (HMCCUDEV only)
@@ -7986,22 +8072,34 @@ sub HMCCU_SetDefaultSCDatapoints ($$;$$)
# Support for level 5 devices
($sc, $sd) = HMCCU_SplitDatapoint ($clHash->{hmccu}{defSDP}) if (defined($clHash->{hmccu}{defSDP}));
($cc, $cd) = HMCCU_SplitDatapoint ($clHash->{hmccu}{defCDP}) if (defined($clHash->{hmccu}{defCDP}));
-# HMCCU_Log ($clHash, 2, "Prio 3: s=$sc.$sd c=$cc.$sd");
+# HMCCU_Log ($clHash, 2, "Prio 3: s=$sc.$sd c=$cc.$cd");
}
# Prio 2: Use attribute statechannel and controlchannel for HMCCUDEV and channel address for HMCCUCHN
+ my ($asc, $acc) = ('', '');
if ($clType eq 'HMCCUCHN') {
# State and control channel of HMCCUCHN devices is defined by channel address
my $da;
- ($da, $sc) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
- $cc = $sc;
+ ($da, $asc) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
+ $acc = $asc;
}
else {
# Consider attributes statechannel and controlchannel for HMCCUDEV devices
- $sc = AttrVal ($clName, 'statechannel', $sc);
- $cc = AttrVal ($clName, 'controlchannel', $cc);
+ $asc = AttrVal ($clName, 'statechannel', $sc);
+ $acc = AttrVal ($clName, 'controlchannel', $cc);
}
-# HMCCU_Log ($clHash, 2, "Prio 2: s=$sc.$sd c=$cc.$sd");
+ # Correct datapoints
+ if (defined($detect)) {
+ if ($asc ne '' && exists($detect->{stateRole}) && exists($detect->{stateRole}{$asc})) {
+ $sc = $asc;
+ $sd = $detect->{stateRole}{$asc}{datapoint};
+ }
+ if ($acc ne '' && exists($detect->{controlRole}) && exists($detect->{controlRole}{$acc})) {
+ $cc = $acc;
+ $cd = $detect->{controlRole}{$acc}{datapoint};
+ }
+ }
+# HMCCU_Log ($clHash, 2, "Prio 2: s=$sc.$sd c=$cc.$cd");
# Prio 1: Use attributes statedatapoint and controldatapoint
# Attributes are overriding attributes statechannel and controlchannel for HMCCUDEV
@@ -8023,13 +8121,13 @@ sub HMCCU_SetDefaultSCDatapoints ($$;$$)
}
$cd = $ca[0];
}
-# HMCCU_Log ($clHash, 2, "Prio 1: s=$sc.$sd c=$cc.$sd");
+# HMCCU_Log ($clHash, 2, "Prio 1: s=$sc.$sd c=$cc.$cd");
my $sr = $sc ne '' && defined($detect) && exists($detect->{stateRole}{$sc}) ? $detect->{stateRole}{$sc}{role} : '';
my $cr = $cc ne '' && defined($detect) && exists($detect->{controlRole}{$cc}) ? $detect->{controlRole}{$cc}{role} : '';
($sc, $sd) = ('', '') if (!HMCCU_SetSCDatapoints ($clHash, 'statedatapoint', "$sc.$sd", $sr));
($cc, $cd) = ('', '') if (!HMCCU_SetSCDatapoints ($clHash, 'controldatapoint', "$cc.$cd", $cr));
-# HMCCU_Log ($clHash, 2, "SetDC: s=$sc.$sd c=$cc.$sd sr=$sr cr=$cr");
+# HMCCU_Log ($clHash, 2, "SetDC: s=$sc.$sd c=$cc.$cd sr=$sr cr=$cr");
if ($cmd) {
my $chn = $cc ne '' ? $cc : $sc;
@@ -8047,46 +8145,44 @@ sub HMCCU_SetDefaultSCDatapoints ($$;$$)
######################################################################
# Get state and control channel and datapoint of a device.
-# Priority depends on FHEM device type:
-#
-# HMCCUCHN:
-# 1. Datapoints from attributes statedatapoint, controldatapoint
-# 2. Datapoints by role
-#
-# HMCCUDEV:
-# 1. Attributes statechannel, controlchannel
-# 2. Channel from attributes statedatapoint, controldatapoint
-# 3. Datapoints from attributes statedatapoint, controldatapoint
-# 4. Channel datapoint by role
-#
-# If controldatapoint is not specified it is synchronized with
-# statedatapoint.
-#
-# Return (sc, sd, cc, cd, sdCnt, cdCnt)
-# If sdCnt > 1 or cdCnt > 1 more than 1 matching rules were found
+# If neither statedatapoint nor controldatapoint is defined, try
+# setting default values.
######################################################################
sub HMCCU_GetSCDatapoints ($)
{
my ($clHash) = @_;
- my $ioHash = HMCCU_GetHash ($clHash);
my $type = $clHash->{TYPE};
my ($sc, $sd) = HMCCU_StateDatapoint ($clHash);
my ($cc, $cd) = HMCCU_ControlDatapoint ($clHash);
- my $rsdCnt;
- my $rcdCnt;
+
+ my $rsdCnt = $sc ne '' && $sd ne '' ? 1 : 0;
+ my $rcdCnt = $cc ne '' && $cd ne '' ? 1 : 0;
+
+ return ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt) if ($rsdCnt > 0 || $rcdCnt > 0);
# Detect by attributes
# ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt) = HMCCU_DetectSCAttr ($clHash, $sc, $sd, $cc, $cd);
# return ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt) if ($rsdCnt);
- # HMCCU_Log ($clHash, 2, "GetSCDatapoints 2: $sc, $sd, $cc, $cd");
-
+ my $ioHash = HMCCU_GetHash ($clHash);
return HMCCU_SetDefaultSCDatapoints ($ioHash, $clHash);
}
+sub HMCCU_StateOrControlChannel ($)
+{
+ my ($clHash) = @_;
+
+ my ($sc, $sd) = HMCCU_StateDatapoint ($clHash);
+ my ($cc, $cd) = HMCCU_ControlDatapoint ($clHash);
+
+ ($sc, $sd, $cc, $cd) = HMCCU_GetSCDatapoints ($clHash);
+
+ return $cc eq '' ? $sc : $cc;
+}
+
sub HMCCU_ControlDatapoint ($)
{
my ($clHash) = @_;
@@ -9066,16 +9162,18 @@ sub HMCCU_SetMultipleParameters ($$$;$)
$paramSet //= 'VALUES';
$address =~ s/:d$//;
- my ($add, $chn) = HMCCU_SplitChnAddr ($address);
- return (-1, undef) if ($paramSet eq 'VALUES' && !defined($chn));
+ my ($add, $chn) = HMCCU_SplitChnAddr ($address, 'd');
+ return (-1, undef) if ($paramSet eq 'VALUES' && $chn eq 'd');
foreach my $p (sort keys %$params) {
- HMCCU_Trace ($clHash, 2, "Parameter=$address.$paramSet.$p Value=$params->{$p}");
+ HMCCU_Trace ($clHash, 2, "Parameter=$address.$paramSet.$p chn=$chn Value=$params->{$p}");
return (-8, undef) if (
($paramSet eq 'VALUES' && !HMCCU_IsValidParameter ($clHash, $address, 'VALUES', $p, 2)) ||
($paramSet eq 'MASTER' && !HMCCU_IsValidParameter ($clHash, $address, 'MASTER', $p))
);
- $params->{$p} = HMCCU_ScaleValue ($clHash, $chn, $p, $params->{$p}, 1);
+ if ($params->{$p} !~ /:(STRING|BOOL|INTEGER|FLOAT|DOUBLE)$/) {
+ $params->{$p} = HMCCU_ScaleValue ($clHash, $chn, $p, $params->{$p}, 1, $paramSet);
+ }
}
return HMCCU_RPCRequest ($clHash, 'putParamset', $address, $paramSet, $params);
@@ -9090,7 +9188,8 @@ sub HMCCU_SetMultipleParameters ($$$;$)
# Return value < 0 on error.
######################################################################
-sub HMCCU_SetMultipleDatapoints ($$) {
+sub HMCCU_SetMultipleDatapoints ($$)
+{
my ($clHash, $params) = @_;
my $mdFlag = $clHash->{TYPE} eq 'HMCCU' ? 1 : 0;
my $ioHash;
@@ -9154,8 +9253,19 @@ sub HMCCU_SetMultipleDatapoints ($$) {
}
}
- my $dptType = HMCCU_GetDatapointAttr ($ioHash, $ccuType, $chn, $dpt, 'type');
- $v = "'".$v."'" if (defined($dptType) && $dptType == $HMCCU_TYPE_STRING);
+ my $paramDef = HMCCU_GetParamDef ($ioHash, "$add:$chn", 'VALUES', $dpt);
+ if (defined($paramDef)) {
+ if ($paramDef->{TYPE} eq 'STRING') {
+ $v = "'".$v."'";
+ }
+ elsif ($paramDef->{TYPE} eq 'ENUM' && !HMCCU_IsIntNum($v)) {
+ HMCCU_Log ($clHash, 2, "Enum datapoint value = $v");
+ $v = HMCCU_GetEnumValues ($ioHash, $paramDef, $dpt, $v);
+ HMCCU_Log ($clHash, 2, "Enum datapoint number = $v");
+ }
+ }
+# my $dptType = HMCCU_GetDatapointAttr ($ioHash, $ccuType, $chn, $dpt, 'type');
+# $v = "'".$v."'" if (defined($dptType) && $dptType == $HMCCU_TYPE_STRING);
my $c = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$v.");\n";
if ($dpt =~ /$ccuChange/) {
@@ -9197,15 +9307,19 @@ sub HMCCU_ScaleValue ($$$$$;$)
my $name = $hash->{NAME};
my $ioHash = HMCCU_GetHash ($hash);
- # Only numeric values allowed
- return $value if (!HMCCU_IsFltNum ($value));
+ my $boundsChecking = HMCCU_IsFlag ($name, 'noBoundsChecking') ? 0 : 1;
# Get parameter definition and min/max values
my $min;
my $max;
my $unit;
my $ccuaddr = $hash->{ccuaddr};
- $ccuaddr .= ':'.$chnno if ($hash->{TYPE} eq 'HMCCUDEV' && $chnno ne '');
+ if ($hash->{TYPE} eq 'HMCCUDEV' && $chnno ne '' && $chnno ne 'd') {
+ $ccuaddr .= ':'.$chnno;
+ }
+ elsif ($hash->{TYPE} eq 'HMCCUCHN' && $chnno eq 'd') {
+ ($ccuaddr, undef) = HMCCU_SplitChnAddr ($ccuaddr);
+ }
my $paramDef = HMCCU_GetParamDef ($ioHash, $ccuaddr, $paramSet, $dpt);
if (defined($paramDef)) {
$min = $paramDef->{MIN} if (defined($paramDef->{MIN}) && $paramDef->{MIN} ne '');
@@ -9214,7 +9328,7 @@ sub HMCCU_ScaleValue ($$$$$;$)
$unit = '100%' if ($dpt eq 'LEVEL' && !defined($unit));
}
else {
- HMCCU_Trace ($hash, 2, "Can't get parameter definion for addr=$hash->{ccuaddr} chn=$chnno");
+ HMCCU_Trace ($hash, 2, "Can't get parameter definion for addr=$ccuaddr chn=$chnno dpt=$dpt");
}
# Default values can be overriden by attribute
@@ -9222,7 +9336,11 @@ sub HMCCU_ScaleValue ($$$$$;$)
HMCCU_Trace ($hash, 2, "chnno=$chnno, dpt=$dpt, value=$value, mode=$mode");
+ # Scale by attribute ccuscaleval
if ($ccuscaleval ne '' && $mode != 2) {
+ # Only numeric or values allowed
+ return $value if (!HMCCU_IsFltNum ($value));
+
HMCCU_Trace ($hash, 2, "ccuscaleval");
my @sl = split (',', $ccuscaleval);
foreach my $sr (@sl) {
@@ -9270,37 +9388,34 @@ sub HMCCU_ScaleValue ($$$$$;$)
}
# Align value with min/max boundaries for set mode
- if ($mode == 1 && defined($min) && defined($max)) {
+ if ($mode == 1 && defined($min) && defined($max) && $boundsChecking) {
$value = HMCCU_MinMax ($value, $min, $max);
}
HMCCU_Trace ($hash, 2, "Attribute scaled value of $dpt = $value");
- return int($value) == $value ? int($value) : $value;
+ return $mode == 0 && int($value) == $value ? int($value) : $value;
}
-
- if ($dpt =~ /^RSSI_/) {
+
+ # Auto scale
+ if ($dpt =~ /^RSSI_/ && $mode == 0) {
# Subtract 256 from Rega value (Rega bug)
$value = abs ($value) == 65535 || $value == 0 ? 'N/A' : ($value > 0 ? $value-256 : $value);
}
- elsif ($dpt =~ /^(P[0-9]_)?ENDTIME/) {
- if ($mode == 0) {
- my $hh = sprintf ("%02d", int($value/60));
- my $mm = sprintf ("%02d", $value%60);
- $value = "$hh:$mm";
- }
- else {
- my ($hh, $mm) = split (':', $value);
- $mm //= 0;
- $value = $hh*60+$mm;
- }
+ elsif (defined($unit) && ($unit eq 'minutes' || $unit eq 's')) {
+ $value = HMCCU_ConvertTime ($value, $unit, $mode);
}
elsif (defined($unit) && $unit =~ /^([0-9]+)%$/) {
+ # percentage values
my $f = $1;
$min //= 0;
$max //= 1.0;
- $value = ($mode == 0 || $mode == 2) ? HMCCU_MinMax ($value, $min, $max)*$f :
- HMCCU_MinMax($value, $min*$f, $max*$f)/$f;
+ if ($mode == 0 || $mode == 2) {
+ $value = HMCCU_MinMax ($value, $min, $max)*$f;
+ }
+ else {
+ $value = $boundsChecking ? HMCCU_MinMax($value, $min*$f, $max*$f)/$f : $value/$f;
+ }
}
HMCCU_Trace ($hash, 2, "Auto scaled value of $dpt = $value");
@@ -9420,7 +9535,7 @@ sub HMCCU_GetUpdate ($$;$$)
return -4 if ($type ne 'HMCCU' && $clHash->{ccudevstate} eq 'deleted');
my $nam = '';
- my $list = '';
+ my @list = ();
my $script = '';
$ccuget = HMCCU_GetAttribute ($ioHash, $clHash, 'ccuget', 'Value') if ($ccuget eq 'Attr');
@@ -9429,12 +9544,14 @@ sub HMCCU_GetUpdate ($$;$$)
return -1 if ($nam eq '');
my ($stadd, $stchn) = split (':', $addr);
my $stnam = HMCCU_GetChannelName ($ioHash, "$stadd:0");
- $list = $stnam eq '' ? $nam : $stnam . "," . $nam;
+ push @list, $stnam if ($stnam ne '');
+ push @list, $nam;
$script = '!GetDatapointsByChannel';
}
elsif (HMCCU_IsValidDevice ($ioHash, $addr, $HMCCU_FL_ADDRESS)) {
$nam = HMCCU_GetDeviceName ($ioHash, $addr);
return -1 if ($nam eq '');
+ push @list, $nam;
$script = '!GetDatapointsByDevice';
# Consider members of group device
@@ -9442,7 +9559,7 @@ sub HMCCU_GetUpdate ($$;$$)
exists($clHash->{ccugroup}) && $clHash->{ccugroup} ne '') {
foreach my $gd (split (',', $clHash->{ccugroup})) {
$nam = HMCCU_GetDeviceName ($ioHash, $gd);
- $list .= ','.$nam if ($nam ne '');
+ push @list, $nam if ($nam ne '');
}
}
}
@@ -9452,14 +9569,14 @@ sub HMCCU_GetUpdate ($$;$$)
if (HMCCU_IsFlag ($ioHash->{NAME}, 'nonBlocking')) {
# Non blocking request
- HMCCU_HMScriptExt ($ioHash, $script, { list => $list, ccuget => $ccuget },
+ HMCCU_HMScriptExt ($ioHash, $script, { list => join(',',@list), ccuget => $ccuget },
\&HMCCU_UpdateCB, { filter => $filter });
return 1;
}
# Blocking request
my $response = HMCCU_HMScriptExt ($ioHash, $script,
- { list => $list, ccuget => $ccuget });
+ { list => join(',',@list), ccuget => $ccuget });
HMCCU_Trace ($clHash, 2, "Addr=$addr Name=$nam Script=$script
".
"Script response = \n".$response);
return -2 if ($response eq '' || $response =~ /^ERROR:.*/);
@@ -9864,6 +9981,45 @@ sub HMCCU_GetTimeSpec ($)
return ($s-$cs);
}
+######################################################################
+# Convert time values
+# $value - Time value, format:
+# $mode = 0: n
+# $mode = 1, unit = s: [[hh:]mm:]ss
+# $mode = 1, unit = minutes: [hh:]mm
+# $unit - s or minutes
+# $mode - 0 = Get, 1 = Set
+######################################################################
+
+sub HMCCU_ConvertTime ($$$)
+{
+ my ($value, $unit, $mode) = @_;
+
+ return $value if ($unit ne 'minutes' && $unit ne 's');
+
+ if ($mode == 0) {
+ my $f = $unit eq 'minutes' ? 60 : 3600;
+ my @t = ();
+ while ($f >= 60) {
+ push @t, sprintf('%02d',int($value/$f));
+ $value = $value%$f;
+ $f = $f/60;
+ }
+ push @t, sprintf('%02d',$value);
+ return join(':',@t);
+ }
+ else {
+ my @t = split(':',$value);
+ my $f = scalar(@t) == 1 ? 1 : ($unit eq 'minutes' ? 60 : (scalar(@t) == 3 ? 3600 : 60));
+ my $r = 0;
+ foreach my $v (@t) {
+ $r = $r+$v*$f;
+ $f = $f/60;
+ }
+ return $r;
+ }
+}
+
######################################################################
# Get minimum or maximum of 2 values
# Align value with boundaries
diff --git a/fhem/FHEM/88_HMCCUCHN.pm b/fhem/FHEM/88_HMCCUCHN.pm
index 8ced15091..c12d30c9b 100644
--- a/fhem/FHEM/88_HMCCUCHN.pm
+++ b/fhem/FHEM/88_HMCCUCHN.pm
@@ -30,7 +30,7 @@ sub HMCCUCHN_Set ($@);
sub HMCCUCHN_Get ($@);
sub HMCCUCHN_Attr ($@);
-my $HMCCUCHN_VERSION = '5.0 213281908';
+my $HMCCUCHN_VERSION = '5.0 213461309';
######################################################################
# Initialize module
@@ -51,7 +51,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = 'IODev ccucalculate '.
- 'ccuflags:multiple-strict,ackState,logCommand,noReadings,trace,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
+ 'ccuflags:multiple-strict,noBoundsChecking,ackState,logCommand,noReadings,trace,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
'ccureadingfilter:textField-long statedatapoint controldatapoint '.
'ccureadingformat:name,namelc,address,addresslc '.
'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix '.
@@ -212,7 +212,7 @@ sub HMCCUCHN_InitDevice ($$)
$rc = -2;
}
- HMCCU_GetUpdate ($devHash, $da, 'Value');
+ HMCCU_GetUpdate ($devHash, $da);
}
return $rc;
@@ -357,7 +357,7 @@ sub HMCCUCHN_Set ($@)
elsif ($lcopt =~ /^(config|values)$/) {
return HMCCU_ExecuteSetParameterCommand ($ioHash, $hash, $lcopt, $a, $h);
}
- elsif ($lcopt =~ 'readingfilter') {
+ elsif ($lcopt eq 'readingfilter') {
my $filter = shift @$a // return HMCCU_SetError ($hash, "Usage: set $name readingFilter {datapointList}");
$filter =~ s/,/\|/g;
$filter = '^('.$filter.')$';
@@ -519,6 +519,9 @@ sub HMCCUCHN_Get ($@)
Set
set myDev config device AES=1
dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY