mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-26 04:24:53 +00:00
HMCCU: Fixed substitute and authentication
git-svn-id: https://svn.fhem.de/fhem/trunk@27988 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
f7fb686aaf
commit
c832ec4ddd
@ -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.
|
||||
- change: 88_HMCCU: Fixed substitute and authentication
|
||||
- change: 93_DbRep: Improvement of markouts in special cases, Forum:#134973
|
||||
- bugfix: 36_ShellyMonitor: Change written reading from relay_0 to state
|
||||
for non-relais devices
|
||||
|
@ -12,7 +12,7 @@
|
||||
# CCU group devices, HomeGear, CUxD, Osram Lightify, Homematic Virtual Layer
|
||||
# and Philips Hue (not tested)
|
||||
#
|
||||
# (c) 2022 by zap (zap01 <at> t-online <dot> de)
|
||||
# (c) 2023 by zap (zap01 <at> t-online <dot> de)
|
||||
#
|
||||
##############################################################################
|
||||
#
|
||||
@ -57,7 +57,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
|
||||
my %HMCCU_CUST_DEV_DEFAULTS;
|
||||
|
||||
# HMCCU version
|
||||
my $HMCCU_VERSION = '5.0 222930908';
|
||||
my $HMCCU_VERSION = '5.0 232641921';
|
||||
|
||||
# Timeout for CCU requests (seconds)
|
||||
my $HMCCU_TIMEOUT_REQUEST = 4;
|
||||
@ -250,7 +250,8 @@ sub HMCCU_CheckParameter ($$;$$$);
|
||||
sub HMCCU_DetectDevice ($$$);
|
||||
sub HMCCU_CreateFHEMDevices ($@);
|
||||
sub HMCCU_CreateDevice ($@);
|
||||
sub HMCCU_IdentifyRole ($$$$$);
|
||||
sub HMCCU_IdentifyDeviceRoles ($$$$$$);
|
||||
sub HMCCU_IdentifyChannelRole ($$$$$);
|
||||
sub HMCCU_DetectRolePattern ($;$$$$);
|
||||
sub HMCCU_DeviceDescToStr ($$);
|
||||
sub HMCCU_ExecuteRoleCommand ($@);
|
||||
@ -389,7 +390,8 @@ sub HMCCU_Initialize ($)
|
||||
' ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc'.
|
||||
' ccudef-stripnumber ccudef-attributes ccuReadingPrefix'.
|
||||
' ccuflags:multiple-strict,procrpc,dptnocheck,logCommand,noagg,nohmstate,updGroupMembers,'.
|
||||
'logEvents,noEvents,noInitialUpdate,noReadings,nonBlocking,reconnect,logPong,trace,logEnhanced'.
|
||||
'logEvents,noEvents,noInitialUpdate,noReadings,nonBlocking,reconnect,logPong,trace,logEnhanced,'.
|
||||
'noAutoDetect,noAutoSubstitute,unknownDeviceRoles'.
|
||||
' ccuReqTimeout ccuGetVars rpcPingCCU rpcinterfaces ccuAdminURLs'.
|
||||
' rpcserver:on,off rpcserveraddr rpcserverport rpctimeout rpcevtimeout substitute'.
|
||||
' ccuget:Value,State '.
|
||||
@ -404,7 +406,7 @@ sub HMCCU_Define ($$$)
|
||||
{
|
||||
my ($hash, $a, $h) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $usage = "Usage: define $name HMCCU {NameOrIP} [{ccunum}] [nosync] ccudelay={time} waitforccu={time} delayedinit={time}";
|
||||
my $usage = "Usage: define $name HMCCU {NameOrIP} [{ccunum}] [nosync] [ccudelay={time}] [waitforccu={time}] [delayedinit={time}]";
|
||||
|
||||
return $usage if (scalar(@$a) < 3);
|
||||
|
||||
@ -484,6 +486,11 @@ sub HMCCU_Define ($$$)
|
||||
$hash->{hmccu}{rpcports} = undef;
|
||||
$hash->{hmccu}{postInit} = 0;
|
||||
|
||||
# Check if authentication is active
|
||||
my ($erruser, $encuser) = getKeyValue ($name.'_username');
|
||||
my ($errpass, $encpass) = getKeyValue ($name.'_password');
|
||||
$hash->{authentication} = (defined($encuser) && defined($encpass)) ? 'on' : 'off';
|
||||
|
||||
HMCCU_Log ($hash, 1, "Initialized version $HMCCU_VERSION");
|
||||
|
||||
my $rc = 0;
|
||||
@ -545,11 +552,7 @@ sub HMCCU_InitDevice ($)
|
||||
$attributes =~ s/rpcinterfaces/$rpcinterfaces/;
|
||||
setDevAttrList ($name, $attributes);
|
||||
|
||||
HMCCU_Log ($hash, 1, [
|
||||
"Read $devcnt devices with $chncnt channels from CCU $host",
|
||||
"Read $prgcount programs from CCU $host",
|
||||
"Read $gcount virtual groups from CCU $host"
|
||||
]);
|
||||
HMCCU_Log ($hash, 1, "Read $devcnt devices with $chncnt channels, $prgcount programs, $gcount virtual groups from CCU $host");
|
||||
|
||||
# Interactive device definition or delayed initialization
|
||||
if ($init_done && !HMCCU_IsDelayedInit ($hash)) {
|
||||
@ -1505,6 +1508,7 @@ sub HMCCU_Set ($@)
|
||||
if (!defined($username)) {
|
||||
setKeyValue ($name."_username", undef);
|
||||
setKeyValue ($name."_password", undef);
|
||||
$hash->{authentication} = 'off';
|
||||
return 'Credentials for CCU authentication deleted';
|
||||
}
|
||||
return HMCCU_SetError ($hash, $usage) if (!defined($password));
|
||||
@ -1517,8 +1521,10 @@ sub HMCCU_Set ($@)
|
||||
return HMCCU_SetError ($hash, "Can't store credentials. $err") if (defined ($err));
|
||||
$err = setKeyValue ($name."_password", $encpass);
|
||||
return HMCCU_SetError ($hash, "Can't store credentials. $err") if (defined ($err));
|
||||
|
||||
$hash->{authentication} = 'on';
|
||||
|
||||
return 'Credentials for CCU authentication stored';
|
||||
return 'Credentials for CCU authentication stored';
|
||||
}
|
||||
elsif ($opt eq 'clear') {
|
||||
my $rnexp = shift @$a;
|
||||
@ -2913,6 +2919,12 @@ sub HMCCU_Substitute ($$$$$;$$)
|
||||
my $ioHash;
|
||||
my $rc = 0;
|
||||
my $newvalue;
|
||||
my $noAutoSubstitute = 0;
|
||||
|
||||
if ($mode == -1) {
|
||||
$mode = 0;
|
||||
$noAutoSubstitute = 1;
|
||||
}
|
||||
|
||||
if (defined($hashOrRule)) {
|
||||
if (ref($hashOrRule) eq 'HASH') {
|
||||
@ -2933,15 +2945,20 @@ sub HMCCU_Substitute ($$$$$;$$)
|
||||
foreach my $rule (@rulelist) {
|
||||
my @ruletoks = split ('!', $rule);
|
||||
if (scalar(@ruletoks) == 2 && $dpt ne '' && $mode == 0) {
|
||||
# Substitute if current role and/or datapoint is matching rule
|
||||
|
||||
# Left part of subst rule. r=role, f=channel/datapoint filter
|
||||
my ($r, $f) = split (':', $ruletoks[0], 2);
|
||||
if (!defined($f)) {
|
||||
# No role specified
|
||||
$f = $r;
|
||||
$r = undef;
|
||||
}
|
||||
if (!defined($r) || (defined($type) && $r eq $type)) {
|
||||
if (!defined($r) || (defined($type) && defined($r) && $r eq $type)) {
|
||||
# List of datapoints where rule should be applied on
|
||||
my @dptlist = split (',', $f);
|
||||
foreach my $d (@dptlist) {
|
||||
my $c = -1;
|
||||
my $c = -1; # Channel number (optional)
|
||||
if ($d =~ /^([0-9]{1,2})\.(.+)$/) {
|
||||
($c, $d) = ($1, $2);
|
||||
}
|
||||
@ -2953,7 +2970,11 @@ sub HMCCU_Substitute ($$$$$;$$)
|
||||
}
|
||||
}
|
||||
elsif (scalar(@ruletoks) == 1) {
|
||||
# Substitute independent from role/datapoint
|
||||
|
||||
# Do not substitute floating point values ???
|
||||
return $value if ($value !~ /^[+-]?\d+$/ && $value =~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/);
|
||||
|
||||
($rc, $newvalue) = HMCCU_SubstRule ($value, $ruletoks[0], $mode);
|
||||
return $newvalue if ($rc == 1);
|
||||
}
|
||||
@ -2961,6 +2982,7 @@ sub HMCCU_Substitute ($$$$$;$$)
|
||||
|
||||
# Original value not modified by rules. Use default conversion depending on type/role
|
||||
# Default conversion can be overriden by attribute ccudef-substitute in I/O device
|
||||
return $value if ($noAutoSubstitute);
|
||||
|
||||
# Substitute by rules defined in CONVERSIONS table
|
||||
if (!defined($type) || $type eq '') {
|
||||
@ -2972,7 +2994,7 @@ sub HMCCU_Substitute ($$$$$;$$)
|
||||
elsif (exists($HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value})) {
|
||||
return $HMCCU_CONVERSIONS->{DEFAULT}{$dpt}{$value};
|
||||
}
|
||||
|
||||
|
||||
# Substitute enumerations and default parameter type conversions
|
||||
if (defined($devDesc) && defined($ioHash)) {
|
||||
my $paramDef = HMCCU_GetParamDef ($ioHash, $devDesc, 'VALUES', $dpt);
|
||||
@ -3082,7 +3104,7 @@ sub HMCCU_SubstVariables ($$$)
|
||||
if (defined ($clhash->{hmccu}{dp}{$dp}{VALUES}{VAL})) {
|
||||
$text =~ s/\%\{?$dp\}?/$clhash->{hmccu}{dp}{$dp}{VALUES}{VAL}/g;
|
||||
$text =~ s/\%\{?$dpt\}?/$clhash->{hmccu}{dp}{$dp}{VALUES}{VAL}/g;
|
||||
$text =~ s/$dp/$clhash->{hmccu}{dp}{$dp}{VALUES}{VAL}/g;
|
||||
# $text =~ s/$dp/$clhash->{hmccu}{dp}{$dp}{VALUES}{VAL}/g;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3204,7 +3226,7 @@ sub HMCCU_UpdateDeviceTable ($$)
|
||||
my $devcount = 0;
|
||||
my $chncount = 0;
|
||||
|
||||
HMCCU_Log ($hash, 2, "Updating device table");
|
||||
HMCCU_Log ($hash, 3, "Updating device table");
|
||||
|
||||
# Update internal device table
|
||||
foreach my $da (keys %{$devices}) {
|
||||
@ -3790,41 +3812,43 @@ sub HMCCU_SetSCAttributes ($$;$)
|
||||
my $ccuType = $clHash->{ccutype} // return;
|
||||
my $ccuAddr = $clHash->{ccuaddr} // return;
|
||||
my $ccuIf = $clHash->{ccuif} // return;
|
||||
$detect //= HMCCU_DetectDevice ($ioHash, $ccuAddr, $ccuIf);
|
||||
# $detect //= HMCCU_DetectDevice ($ioHash, $ccuAddr, $ccuIf);
|
||||
|
||||
# Get readable and writeable datapoints
|
||||
my @dpWrite = ();
|
||||
my @dpRead = ();
|
||||
my ($da, $dc) = HMCCU_SplitChnAddr ($ccuAddr, -2);
|
||||
# my ($da, $dc) = HMCCU_SplitChnAddr ($ccuAddr, -2);
|
||||
my ($da, $dc) = HMCCU_SplitChnAddr ($ccuAddr, -1);
|
||||
my $dpWriteCnt = HMCCU_GetValidDatapoints ($clHash, $ccuType, $dc, 2, \@dpWrite);
|
||||
my $dpReadCnt = HMCCU_GetValidDatapoints ($clHash, $ccuType, $dc, 5, \@dpRead);
|
||||
|
||||
# Detect device and initialize attribute lists for statedatapoint and controldatapoint
|
||||
my @userattr = grep (!/statedatapoint|controldatapoint/, split(' ', $modules{$clHash->{TYPE}}{AttrList}));
|
||||
if (defined($detect) && $detect->{level} > 0) {
|
||||
$clHash->{hmccu}{detect} = $detect->{level};
|
||||
if ($type eq 'HMCCUDEV') {
|
||||
push @userattr, 'statedatapoint:select,'.
|
||||
join(',', sort map { $_.'.'.$detect->{stateRole}{$_}{datapoint} } keys %{$detect->{stateRole}})
|
||||
if ($detect->{stateRoleCount} > 0);
|
||||
push @userattr, 'controldatapoint:select,'.
|
||||
join(',', sort map { $_.'.'.$detect->{controlRole}{$_}{datapoint} } keys %{$detect->{controlRole}})
|
||||
if ($detect->{controlRoleCount} > 0);
|
||||
}
|
||||
elsif ($type eq 'HMCCUCHN') {
|
||||
push @userattr, 'statedatapoint:select,'.
|
||||
join(',', sort map { $detect->{stateRole}{$_}{datapoint} } keys %{$detect->{stateRole}})
|
||||
if ($detect->{stateRoleCount} > 0);
|
||||
push @userattr, 'controldatapoint:select,'.
|
||||
join(',', sort map { $detect->{controlRole}{$_}{datapoint} } keys %{$detect->{controlRole}})
|
||||
if ($detect->{controlRoleCount} > 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
# if (defined($detect) && $detect->{level} > 0) {
|
||||
# $clHash->{hmccu}{detect} = $detect->{level};
|
||||
# if ($type eq 'HMCCUDEV') {
|
||||
# push @userattr, 'statedatapoint:select,'.
|
||||
# join(',', sort map { $_.'.'.$detect->{stateRole}{$_}{datapoint} } keys %{$detect->{stateRole}})
|
||||
# if ($detect->{stateRoleCount} > 0);
|
||||
# push @userattr, 'controldatapoint:select,'.
|
||||
# join(',', sort map { $_.'.'.$detect->{controlRole}{$_}{datapoint} } keys %{$detect->{controlRole}})
|
||||
# if ($detect->{controlRoleCount} > 0);
|
||||
# }
|
||||
# elsif ($type eq 'HMCCUCHN') {
|
||||
# push @userattr, 'statedatapoint:select,'.
|
||||
# join(',', sort map { $detect->{stateRole}{$_}{datapoint} } keys %{$detect->{stateRole}})
|
||||
# if ($detect->{stateRoleCount} > 0);
|
||||
# push @userattr, 'controldatapoint:select,'.
|
||||
# join(',', sort map { $detect->{controlRole}{$_}{datapoint} } keys %{$detect->{controlRole}})
|
||||
# if ($detect->{controlRoleCount} > 0);
|
||||
# }
|
||||
# }
|
||||
# else {
|
||||
push @userattr, 'statedatapoint:select,'.join(',', sort @dpRead) if ($dpReadCnt > 0);
|
||||
push @userattr, 'controldatapoint:select,'.join(',', sort @dpWrite) if ($dpWriteCnt > 0);
|
||||
$clHash->{hmccu}{detect} = 0;
|
||||
}
|
||||
# $clHash->{hmccu}{detect} = 0;
|
||||
$clHash->{hmccu}{detect} = defined($detect) ? $detect->{level} : 0;
|
||||
# }
|
||||
|
||||
# Make sure that generic attributes are available, if no role attributes found
|
||||
push @userattr, 'statedatapoint' if (!grep(/statedatapoint/, @userattr));
|
||||
@ -3904,22 +3928,24 @@ sub HMCCU_GetDeviceConfig ($)
|
||||
my $c = 0;
|
||||
|
||||
my $interfaces = HMCCU_GetRPCInterfaceList ($ioHash, 0);
|
||||
foreach my $iface (keys %$interfaces) {
|
||||
my @ifList = keys %$interfaces;
|
||||
HMCCU_Log ($ioHash, 2, "Reading device configuration for interfaces ".join(',', @ifList));
|
||||
foreach my $iface (@ifList) {
|
||||
my ($rpcdev, $save) = HMCCU_GetRPCDevice ($ioHash, 1, $iface);
|
||||
if ($rpcdev ne '') {
|
||||
my $rpcHash = $defs{$rpcdev};
|
||||
HMCCURPCPROC_Connect ($rpcHash, $ioHash);
|
||||
HMCCU_Log ($ioHash, 2, "Reading Device Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Reading Device Descriptions for interface $iface");
|
||||
$c = HMCCURPCPROC_GetDeviceDesc ($rpcHash);
|
||||
HMCCU_Log ($ioHash, 2, "Read $c Device Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Read $c Device Descriptions for interface $iface");
|
||||
$cDev += $c;
|
||||
HMCCU_Log ($ioHash, 2, "Reading Paramset Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Reading Paramset Descriptions for interface $iface");
|
||||
$c = HMCCURPCPROC_GetParamsetDesc ($rpcHash);
|
||||
HMCCU_Log ($ioHash, 2, "Read $c Paramset Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Read $c Paramset Descriptions for interface $iface");
|
||||
$cPar += $c;
|
||||
HMCCU_Log ($ioHash, 2, "Reading Peer Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Reading Peer Descriptions for interface $iface");
|
||||
$c = HMCCURPCPROC_GetPeers ($rpcHash);
|
||||
HMCCU_Log ($ioHash, 2, "Read $c Peer Descriptions for interface $iface");
|
||||
HMCCU_Log ($ioHash, 5, "Read $c Peer Descriptions for interface $iface");
|
||||
$cLnk += $c;
|
||||
HMCCURPCPROC_Disconnect ($rpcHash, $ioHash);
|
||||
}
|
||||
@ -3927,12 +3953,15 @@ sub HMCCU_GetDeviceConfig ($)
|
||||
HMCCU_Log ($ioHash, 2, "No RPC device found for interface $iface. Can't read device config.");
|
||||
}
|
||||
}
|
||||
HMCCU_Log ($ioHash, 2, "Read descriptions of $cDev devices, $cPar paramsets, $cLnk links");
|
||||
|
||||
my @ccuDevList = ();
|
||||
my @ccuSuppDevList = ();
|
||||
my @ccuSuppTypes = ();
|
||||
my @ccuNotSuppTypes = ();
|
||||
foreach my $di (sort keys %{$ioHash->{hmccu}{device}}) {
|
||||
@ifList = sort keys %{$ioHash->{hmccu}{device}};
|
||||
HMCCU_Log ($ioHash, 2, "Detecting devices of interfaces ".join(',', @ifList));
|
||||
foreach my $di (@ifList) {
|
||||
foreach my $da (sort keys %{$ioHash->{hmccu}{device}{$di}}) {
|
||||
next if ($ioHash->{hmccu}{device}{$di}{$da}{_addtype} ne 'dev');
|
||||
my $devName = $ioHash->{hmccu}{device}{$di}{$da}{_name};
|
||||
@ -3943,12 +3972,19 @@ sub HMCCU_GetDeviceConfig ($)
|
||||
}
|
||||
push @ccuDevList, $devName;
|
||||
my $detect = HMCCU_DetectDevice ($ioHash, $da, $di);
|
||||
if (defined($detect) && $da ne 'HmIP-RCV-1' && $da ne 'BidCoS-RF') {
|
||||
push @ccuSuppDevList, $devName;
|
||||
push @ccuSuppTypes, $devModel;
|
||||
if (defined($detect)) {
|
||||
if ($da ne 'HmIP-RCV-1' && $da ne 'BidCoS-RF') {
|
||||
push @ccuSuppDevList, $devName;
|
||||
push @ccuSuppTypes, $devModel;
|
||||
HMCCU_Log ($ioHash, 5, "Device $da $devName detected");
|
||||
}
|
||||
else {
|
||||
HMCCU_Log ($ioHash, 5, "Device $da $devName ignored");
|
||||
}
|
||||
}
|
||||
else {
|
||||
push @ccuNotSuppTypes, $devModel;
|
||||
HMCCU_Log ($ioHash, 5, "Device $da $devName not detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4741,7 +4777,7 @@ sub HMCCU_UpdateParamsetReadings ($$$;$)
|
||||
my $vg = ($clHash->{ccuif} eq 'VirtualDevices' && exists($clHash->{ccugroup}) && $clHash->{ccugroup} ne '') ? 1 : 0;
|
||||
|
||||
# Get client device attributes
|
||||
my $clFlags = HMCCU_GetFlags ($clName);
|
||||
my $substMode = HMCCU_IsFlag($ioName,'noAutoSubstitute') || HMCCU_IsFlag($clName,'noAutoSubstitute') ? -1 : 0;
|
||||
my $clRF = HMCCU_GetAttrReadingFormat ($clHash, $ioHash);
|
||||
my $peer = AttrVal ($clName, 'peer', 'null');
|
||||
my $clInt = $clHash->{ccuif};
|
||||
@ -4794,7 +4830,7 @@ sub HMCCU_UpdateParamsetReadings ($$$;$)
|
||||
$sv = HMCCU_ScaleValue ($clHash, $c, $p, $v, 0, $ps);
|
||||
HMCCU_UpdateInternalValues ($clHash, $chKey, $ps, 'NVAL', $sv);
|
||||
$fv = HMCCU_FormatReadingValue ($clHash, $sv, $p);
|
||||
$cv = HMCCU_Substitute ($fv, $clHash, 0, $c, $p, $chnType, $devDesc);
|
||||
$cv = HMCCU_Substitute ($fv, $clHash, $substMode, $c, $p, $chnType, $devDesc);
|
||||
HMCCU_UpdateInternalValues ($clHash, $chKey, $ps, 'SVAL', $cv);
|
||||
push @chKeys, $chKey;
|
||||
|
||||
@ -5393,6 +5429,8 @@ sub HMCCU_FormatDeviceInfo ($)
|
||||
my %vtypes = (0, 'n', 2, 'b', 4, 'f', 6, 'a', 8, 'n', 11, 's', 16, 'i', 20, 's', 23, 'p', 29, 'e');
|
||||
my $result = '';
|
||||
my $c_oaddr = '';
|
||||
|
||||
return 'Device info is empty' if (!defined($devinfo) || $devinfo eq '');
|
||||
|
||||
foreach my $dpspec (split ("\n", $devinfo)) {
|
||||
if ($dpspec =~ /^D/) {
|
||||
@ -5401,13 +5439,18 @@ sub HMCCU_FormatDeviceInfo ($)
|
||||
}
|
||||
else {
|
||||
my ($t, $c_addr, $c_name, $d_name, $d_type, $d_value, $d_flags) = split (';', $dpspec);
|
||||
$d_name =~ s/^[^:]+:(.+)$/$1/;
|
||||
if ($c_addr ne $c_oaddr) {
|
||||
$result .= "CHN $c_addr $c_name<br/>";
|
||||
$c_oaddr = $c_addr;
|
||||
if (defined($d_flags)) {
|
||||
$d_name =~ s/^[^:]+:(.+)$/$1/;
|
||||
if ($c_addr ne $c_oaddr) {
|
||||
$result .= "CHN $c_addr $c_name<br/>";
|
||||
$c_oaddr = $c_addr;
|
||||
}
|
||||
my $dt = exists($vtypes{$d_type}) ? $vtypes{$d_type} : $d_type;
|
||||
$result .= " $d_name = $d_value {$dt} [$d_flags]<br/>";
|
||||
}
|
||||
else {
|
||||
return "Datapoint specification incomplete: $dpspec";
|
||||
}
|
||||
my $dt = exists($vtypes{$d_type}) ? $vtypes{$d_type} : $d_type;
|
||||
$result .= " $d_name = $d_value {$dt} [$d_flags]<br/>";
|
||||
}
|
||||
}
|
||||
|
||||
@ -5655,7 +5698,7 @@ sub HMCCU_GetDeviceList ($)
|
||||
$hash->{ccustate} = 'active';
|
||||
|
||||
# Delete old entries
|
||||
HMCCU_Log ($hash, 2, "Deleting old CCU configuration data");
|
||||
HMCCU_Log ($hash, 5, "Deleting old CCU configuration data");
|
||||
%{$hash->{hmccu}{dev}} = ();
|
||||
%{$hash->{hmccu}{adr}} = ();
|
||||
%{$hash->{hmccu}{interfaces}} = ();
|
||||
@ -6104,7 +6147,8 @@ sub HMCCU_GetValidDatapoints ($$$$;$)
|
||||
else {
|
||||
if (exists ($ioHash->{hmccu}{dp}{$devtype})) {
|
||||
foreach my $ch (sort keys %{$ioHash->{hmccu}{dp}{$devtype}{ch}}) {
|
||||
next if ($ch == 0 && $chn == -2);
|
||||
# next if ($ch == 0 && $chn == -2);
|
||||
next if ($ch == 0);
|
||||
foreach my $dp (sort keys %{$ioHash->{hmccu}{dp}{$devtype}{ch}{$ch}}) {
|
||||
if ($ioHash->{hmccu}{dp}{$devtype}{ch}{$ch}{$dp}{oper} & $oper) {
|
||||
push @$dplistref, $ch.".".$dp if (defined($dplistref));
|
||||
@ -7039,7 +7083,7 @@ sub HMCCU_UpdateRoleCommands ($$;$)
|
||||
my %pset = ('V' => 'VALUES', 'M' => 'MASTER', 'D' => 'MASTER', 'I' => 'INTERNAL');
|
||||
my @cmdSetList = ();
|
||||
my @cmdGetList = ();
|
||||
return if (!defined($clHash->{hmccu}{role}) || $clHash->{hmccu}{role} eq '');
|
||||
return if (HMCCU_IsFlag ($ioHash, 'noAutoDetect') || !defined($clHash->{hmccu}{role}) || $clHash->{hmccu}{role} eq '');
|
||||
|
||||
# Delete existing role commands
|
||||
delete $clHash->{hmccu}{roleCmds} if (exists($clHash->{hmccu}{roleCmds}));
|
||||
@ -8068,8 +8112,12 @@ sub HMCCU_SetSCDatapoints ($$;$$$)
|
||||
HMCCU_Log ($clHash, 2, "f=$f chn not defined in $d $v".stacktraceAsString(undef)) if (!defined($chn));
|
||||
HMCCU_Log ($clHash, 2, "f=$f dpt not defined in $d $v".stacktraceAsString(undef)) if (!defined($dpt) && !($f & 5));
|
||||
|
||||
return 0 if ($init_done && defined($chn) && $chn ne '' && defined($dpt) && $dpt ne '' &&
|
||||
!HMCCU_IsValidParameter ($clHash, HMCCU_GetChannelAddr ($clHash, $chn), 'VALUES', $dpt, $f & 3 ? 5 : 2));
|
||||
if ($init_done && defined($chn) && $chn ne '' && defined($dpt) && $dpt ne '' &&
|
||||
!HMCCU_IsValidParameter ($clHash, HMCCU_GetChannelAddr ($clHash, $chn), 'VALUES', $dpt, $f & 3 ? 5 : 2))
|
||||
{
|
||||
HMCCU_Log ($clHash, 2, "Invalid datapoint $chn.$dpt for parameter $d");
|
||||
return 0;
|
||||
}
|
||||
|
||||
$clHash->{ccurolestate} = $r if ($r ne '' && $f & 3);
|
||||
$clHash->{ccurolectrl} = $r if ($r ne '' && $f & 12);
|
||||
@ -8292,75 +8340,6 @@ sub HMCCU_IsValidStateDatapoint ($;$)
|
||||
return $sc ne '' && $sd ne '' && ($checkHashOnly || HMCCU_IsValidParameter ($clHash, "$da:$sc", 'VALUES', $sd, 5)) ? 1 : 0;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Get state and control datapoints from attributes
|
||||
# Return defaults passed as parameters if attribute(s) not defined
|
||||
######################################################################
|
||||
|
||||
sub HMCCU_DetectSCAttr ($$$$$)
|
||||
{
|
||||
my ($clHash, $sc, $sd, $cc, $cd) = @_;
|
||||
my $name = $clHash->{NAME};
|
||||
my $type = $clHash->{TYPE};
|
||||
$sc //= '';
|
||||
$cc //= '';
|
||||
|
||||
my $da;
|
||||
my $dc;
|
||||
if (defined($clHash->{ccuaddr})) {
|
||||
($da, $dc) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
|
||||
}
|
||||
|
||||
$sc = $dc if ($sc eq '');
|
||||
$cc = $dc if ($cc eq '');
|
||||
|
||||
my $statedatapoint = AttrVal ($name, 'statedatapoint', '');
|
||||
my $controldatapoint = AttrVal ($name, 'controldatapoint', '');
|
||||
|
||||
# Attributes controlchannel and statechannel are only valid for HMCCUDEV devices
|
||||
if ($type eq 'HMCCUDEV') {
|
||||
$sc = AttrVal ($name, 'statechannel', $sc);
|
||||
$cc = AttrVal ($name, 'controlchannel', $cc);
|
||||
}
|
||||
|
||||
# If attribute statedatapoint is specified, use it.
|
||||
if ($statedatapoint ne '') {
|
||||
if ($statedatapoint =~ /^([0-9]+)\.(.+)$/) {
|
||||
# Attribute statechannel overrides channel specification.
|
||||
($sc, $sd) = $sc eq '' ? ($1, $2) : ($sc, $2);
|
||||
}
|
||||
else {
|
||||
$sd = $statedatapoint;
|
||||
if ($sc eq '') {
|
||||
# Try to find state channel (datapoint must be readable or provide events)
|
||||
my $c = HMCCU_FindDatapoint ($clHash, $type, -1, $sd, 5);
|
||||
$sc = $c if ($c >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If attribute controldatapoint is specified, use it.
|
||||
if ($controldatapoint ne '') {
|
||||
if ($controldatapoint =~ /^([0-9]+)\.(.+)$/) {
|
||||
# Attribute controlchannel overrides channel specification in controldatapoint
|
||||
($cc, $cd) = $cc eq '' ? ($1, $2) : ($cc, $2);
|
||||
}
|
||||
else {
|
||||
$cd = $controldatapoint;
|
||||
if ($cc eq '') {
|
||||
# Try to find control channel (datapoint must be writeable)
|
||||
my $c = HMCCU_FindDatapoint ($clHash, $type, -1, $cd, 4);
|
||||
$cc = $c if ($c >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $rsdCnt = $sc ne '' && $sd ne '' ? 1 : 0;
|
||||
my $rcdCnt = $cc ne '' && $cd ne '' ? 1 : 0;
|
||||
|
||||
return ($sc, $sd, $cc, $cd, $rsdCnt, $rcdCnt);
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Detect roles, channel and datapoint to be used for controlling and
|
||||
# displaying the state of a device or channel identified by its
|
||||
@ -8410,11 +8389,10 @@ sub HMCCU_DetectDevice ($$$)
|
||||
{
|
||||
my ($ioHash, $address, $iface) = @_;
|
||||
|
||||
my @allRoles = ();
|
||||
my @definitions = (); # Detected device definitions
|
||||
my @allRoles = (); # Channel roles, index = channel number
|
||||
my @stateRoles = ();
|
||||
my @controlRoles = ();
|
||||
my @unknownStateRoles = (); # State roles not known by HMCCU
|
||||
my @unknownControlRoles = (); # Control roles not known by HMCCU
|
||||
my ($prioState, $prioControl) = (-1, -1);
|
||||
|
||||
if (!defined($address)) {
|
||||
@ -8424,31 +8402,18 @@ sub HMCCU_DetectDevice ($$$)
|
||||
|
||||
my ($devAdd, $devChn) = HMCCU_SplitChnAddr ($address);
|
||||
|
||||
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface);
|
||||
if (!defined($devDesc)) {
|
||||
HMCCU_Log ($ioHash, 2, "Can't get device description for $address ".stacktraceAsString(undef));
|
||||
my $roleCnt = HMCCU_IdentifyDeviceRoles ($ioHash, $address, $iface, \@allRoles, \@stateRoles, \@controlRoles);
|
||||
if ($roleCnt == 0 && HMCCU_IsFlag($ioHash, 'unknownDeviceRoles')) {
|
||||
$roleCnt = HMCCU_UnknownDeviceRoles ($ioHash, $address, $iface, \@stateRoles, \@controlRoles);
|
||||
}
|
||||
if ($roleCnt == 0) {
|
||||
HMCCU_Log ($ioHash, 5, "No roles detected for device $address");
|
||||
return undef;
|
||||
}
|
||||
|
||||
# Identify known roles
|
||||
if ($devDesc->{_addtype} eq 'dev') {
|
||||
foreach my $child (split(',', $devDesc->{CHILDREN})) {
|
||||
my $chnDesc = HMCCU_GetDeviceDesc ($ioHash, $child, $devDesc->{_interface}) // next;
|
||||
push @allRoles, $chnDesc->{TYPE};
|
||||
my $known = HMCCU_IdentifyRole ($ioHash, $chnDesc, $iface, \@stateRoles, \@controlRoles);
|
||||
# HMCCU_DetectUnknownRoles ($ioHash, $chnDesc, \@unknownStateRoles, \@unknownControlRoles) if (!$known);
|
||||
}
|
||||
}
|
||||
elsif ($devDesc->{_addtype} eq 'chn') {
|
||||
my $known = HMCCU_IdentifyRole ($ioHash, $devDesc, $iface, \@stateRoles, \@controlRoles);
|
||||
# HMCCU_DetectUnknownRoles ($ioHash, $devDesc, \@unknownStateRoles, \@unknownControlRoles) if (!$known);
|
||||
}
|
||||
|
||||
# Count roles and unique roles
|
||||
my $stateRoleCnt = scalar(@stateRoles);
|
||||
my $ctrlRoleCnt = scalar(@controlRoles);
|
||||
my $unknownStateRoleCnt = scalar(@unknownStateRoles);
|
||||
my $unknownCtrlRoleCnt = scalar(@unknownControlRoles);
|
||||
my %uniqStateRoles;
|
||||
my %uniqCtrlRoles;
|
||||
$uniqStateRoles{$_->{role}}++ for @stateRoles;
|
||||
@ -8595,8 +8560,6 @@ sub HMCCU_DetectDevice ($$$)
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($stateRoleCnt == 0 && $ctrlRoleCnt == 0 && ($unknownStateRoleCnt > 0 || $unknownCtrlRoleCnt > 0)) {
|
||||
}
|
||||
|
||||
if ($di{defSCh} != -1 && exists($di{stateRole}{$di{defSCh}})) {
|
||||
my $dpn = $di{stateRole}{$di{defSCh}}{datapoint} // '';
|
||||
@ -8612,60 +8575,133 @@ sub HMCCU_DetectDevice ($$$)
|
||||
return \%di;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Identify device roles
|
||||
# Return 0 on error or number of roles
|
||||
######################################################################
|
||||
|
||||
sub HMCCU_IdentifyDeviceRoles ($$$$$$)
|
||||
{
|
||||
my ($ioHash, $address, $iface, $allRoles, $stateRoles, $controlRoles) = @_;
|
||||
|
||||
return 0 if (HMCCU_IsFlag ($ioHash, 'noAutoDetect'));
|
||||
|
||||
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface);
|
||||
if (!defined($devDesc)) {
|
||||
HMCCU_Log ($ioHash, 2, "Can't get device description for $address ".stacktraceAsString(undef));
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Identify roles
|
||||
if ($devDesc->{_addtype} eq 'dev') {
|
||||
foreach my $child (split(',', $devDesc->{CHILDREN})) {
|
||||
my $chnDesc = HMCCU_GetDeviceDesc ($ioHash, $child, $devDesc->{_interface});
|
||||
if (defined($chnDesc)) {
|
||||
push @$allRoles, $chnDesc->{TYPE};
|
||||
HMCCU_IdentifyChannelRole ($ioHash, $chnDesc, $iface, $stateRoles, $controlRoles);
|
||||
}
|
||||
else {
|
||||
push @$allRoles, 'UNKNOWN';
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($devDesc->{_addtype} eq 'chn') {
|
||||
push @$allRoles, $devDesc->{TYPE};
|
||||
HMCCU_IdentifyChannelRole ($ioHash, $devDesc, $iface, $stateRoles, $controlRoles);
|
||||
}
|
||||
|
||||
return scalar(@$stateRoles)+scalar(@$controlRoles);
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Identify a channel role
|
||||
######################################################################
|
||||
|
||||
sub HMCCU_IdentifyRole ($$$$$)
|
||||
sub HMCCU_IdentifyChannelRole ($$$$$)
|
||||
{
|
||||
my ($ioHash, $chnDesc, $iface, $stateRoles, $controlRoles) = @_;
|
||||
|
||||
my $t = $chnDesc->{TYPE}; # Channel role
|
||||
|
||||
return 0 if ($HMCCU_IGNORE_ROLES ne '' && $t =~ /$HMCCU_IGNORE_ROLES/);
|
||||
return if (!exists($HMCCU_STATECONTROL->{$t}) || ($HMCCU_IGNORE_ROLES ne '' && $t =~ /$HMCCU_IGNORE_ROLES/));
|
||||
|
||||
if (exists($HMCCU_STATECONTROL->{$t})) {
|
||||
my ($a, $c) = HMCCU_SplitChnAddr ($chnDesc->{ADDRESS});
|
||||
my $p = $HMCCU_STATECONTROL->{$t}{P};
|
||||
# Role supported by HMCCU
|
||||
my ($a, $c) = HMCCU_SplitChnAddr ($chnDesc->{ADDRESS});
|
||||
my $p = $HMCCU_STATECONTROL->{$t}{P};
|
||||
|
||||
# State datapoint must be of type readable and/or event
|
||||
my $sDP = HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$t}{S}, $iface);
|
||||
push @$stateRoles, { 'channel' => $c, 'role' => $t, 'datapoint' => $sDP, 'priority' => $p }
|
||||
if (HMCCU_IsValidParameter ($ioHash, $chnDesc, 'VALUES', $sDP, 5));
|
||||
# State datapoint must be of type readable and/or event
|
||||
my $sDP = HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$t}{S}, $iface);
|
||||
push @$stateRoles, { 'channel' => $c, 'role' => $t, 'datapoint' => $sDP, 'priority' => $p }
|
||||
if (HMCCU_IsValidParameter ($ioHash, $chnDesc, 'VALUES', $sDP, 5));
|
||||
|
||||
# Control datapoint must be writeable
|
||||
my $cDP = HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$t}{C}, $iface);
|
||||
push @$controlRoles, { 'channel' => $c, 'role' => $t, 'datapoint' => $cDP, 'priority' => $p }
|
||||
if (HMCCU_IsValidParameter ($ioHash, $chnDesc, 'VALUES', $cDP, 2));
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
# Role not supported by HMCCU
|
||||
return 0;
|
||||
}
|
||||
# Control datapoint must be writeable
|
||||
my $cDP = HMCCU_DetectSCDatapoint ($HMCCU_STATECONTROL->{$t}{C}, $iface);
|
||||
push @$controlRoles, { 'channel' => $c, 'role' => $t, 'datapoint' => $cDP, 'priority' => $p }
|
||||
if (HMCCU_IsValidParameter ($ioHash, $chnDesc, 'VALUES', $cDP, 2));
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Check if unknown roles can be used as state and/or control role
|
||||
######################################################################
|
||||
sub HMCCU_UnknownDeviceRoles ($$$$$)
|
||||
{
|
||||
my ($ioHash, $address, $iface, $stateRoles, $controlRoles) = @_;
|
||||
|
||||
sub HMCCU_DetectUnknownRoles ($$$$)
|
||||
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $address, $iface);
|
||||
if (!defined($devDesc)) {
|
||||
HMCCU_Log ($ioHash, 2, "Can't get device description for $address ".stacktraceAsString(undef));
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Identify roles
|
||||
if ($devDesc->{_addtype} eq 'dev') {
|
||||
foreach my $child (split(',', $devDesc->{CHILDREN})) {
|
||||
my $chnDesc = HMCCU_GetDeviceDesc ($ioHash, $child, $devDesc->{_interface});
|
||||
if (defined($chnDesc)) {
|
||||
HMCCU_UnknownChannelRole ($ioHash, $chnDesc, $stateRoles, $controlRoles);
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($devDesc->{_addtype} eq 'chn') {
|
||||
HMCCU_UnknownChannelRole ($ioHash, $devDesc, $stateRoles, $controlRoles);
|
||||
}
|
||||
|
||||
return scalar(@$stateRoles)+scalar(@$controlRoles);
|
||||
}
|
||||
|
||||
sub HMCCU_UnknownChannelRole ($$$$)
|
||||
{
|
||||
my ($ioHash, $chnDesc, $stateRoles, $controlRoles) = @_;
|
||||
|
||||
my $t = $chnDesc->{TYPE}; # Channel role
|
||||
|
||||
return if ($HMCCU_IGNORE_ROLES ne '' && $t =~ /$HMCCU_IGNORE_ROLES/);
|
||||
|
||||
# Role not supported by HMCCU, check for usable datapoints
|
||||
my $model = HMCCU_GetDeviceModel ($ioHash, $chnDesc->{_model}, $chnDesc->{_fw_ver}, $chnDesc->{INDEX});
|
||||
if (defined($model) && exists($model->{VALUES})) {
|
||||
my $sdp = '';
|
||||
my $cdp = '';
|
||||
my @sdpList = ();
|
||||
my @cdpList = ();
|
||||
foreach my $p (keys %{$model->{VALUES}}) {
|
||||
$sdp = $p if (($p->{OPERATIONS} & 5) && $sdp eq '' && $sdp ne 'STATE' && $sdp ne 'LEVEL');
|
||||
$cdp = $p if (($p->{OPERATIONS} & 2) && $cdp eq '' && $cdp ne 'STATE' && $cdp ne 'LEVEL');
|
||||
if (exists($model->{VALUES}{$p}{OPERATIONS})) {
|
||||
if ($model->{VALUES}{$p}{OPERATIONS} & 5) {
|
||||
push @sdpList, $p;
|
||||
$sdp = $p if ($sdp eq '' || ($sdp ne 'STATE' && $sdp ne 'LEVEL'));
|
||||
}
|
||||
if ($model->{VALUES}{$p}{OPERATIONS} & 2) {
|
||||
push @cdpList, $p;
|
||||
$cdp = $p if ($cdp eq '' || ($cdp ne 'STATE' && $cdp ne 'LEVEL'));
|
||||
}
|
||||
}
|
||||
}
|
||||
push @$stateRoles, { 'channel' => $chnDesc->{INDEX}, 'role' => $chnDesc->{TYPE}, 'datapoint' => $sdp, 'priority' => 1 }
|
||||
if ($sdp ne '');
|
||||
push @$controlRoles, { 'channel' => $chnDesc->{INDEX}, 'role' => $chnDesc->{TYPE}, 'datapoint' => $cdp, 'priority' => 1 }
|
||||
if ($cdp ne '');
|
||||
push @$stateRoles, {
|
||||
'channel' => $chnDesc->{INDEX}, 'role' => $chnDesc->{TYPE}, 'datapoint' => $sdp,
|
||||
'dptList' => join(',', @sdpList), 'priority' => 0
|
||||
} if ($sdp ne '');
|
||||
push @$controlRoles, {
|
||||
'channel' => $chnDesc->{INDEX}, 'role' => $chnDesc->{TYPE}, 'datapoint' => $cdp,
|
||||
'dptList' => join(',',@cdpList), 'priority' => 0
|
||||
} if ($cdp ne '');
|
||||
HMCCU_Log ($ioHash, 3, "Unknown role $t. sdp=$sdp, cdp=$cdp") if ($t ne 'MAINTENANCE');
|
||||
}
|
||||
}
|
||||
|
||||
@ -8774,11 +8810,14 @@ sub HMCCU_GetFlags ($)
|
||||
|
||||
######################################################################
|
||||
# Check if specific CCU flag is set.
|
||||
# Parameter $flag is a regular expression.
|
||||
######################################################################
|
||||
|
||||
sub HMCCU_IsFlag ($$)
|
||||
{
|
||||
my ($name, $flag) = @_;
|
||||
my ($nameOrHash, $flag) = @_;
|
||||
|
||||
my $name = ref($nameOrHash) eq 'HASH' ? $nameOrHash->{NAME} : $nameOrHash;
|
||||
|
||||
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
|
||||
return $ccuflags =~ /$flag/ ? 1 : 0;
|
||||
@ -8866,13 +8905,14 @@ sub HMCCU_HMCommand ($$$)
|
||||
|
||||
my $io_hash = HMCCU_GetHash ($cl_hash);
|
||||
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, 'ccuReqTimeout', $HMCCU_TIMEOUT_REQUEST);
|
||||
my $url = HMCCU_BuildURL ($io_hash, 'rega');
|
||||
my ($url, $auth) = HMCCU_BuildURL ($io_hash, 'rega');
|
||||
my $value;
|
||||
|
||||
HMCCU_Trace ($cl_hash, 2, "URL=$url, cmd=$cmd");
|
||||
|
||||
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST" };
|
||||
$param->{sslargs} = { SSL_verify_mode => 0 };
|
||||
$param->{header} = "Authorization: Basic $auth" if ($auth ne '');
|
||||
my ($err, $response) = HttpUtils_BlockingGet ($param);
|
||||
|
||||
if ($err eq '') {
|
||||
@ -8904,7 +8944,7 @@ sub HMCCU_HMCommandNB ($$$)
|
||||
|
||||
my $ioHash = HMCCU_GetHash ($clHash);
|
||||
my $ccureqtimeout = AttrVal ($ioHash->{NAME}, 'ccuReqTimeout', $HMCCU_TIMEOUT_REQUEST);
|
||||
my $url = HMCCU_BuildURL ($ioHash, 'rega');
|
||||
my ($url, $auth) = HMCCU_BuildURL ($ioHash, 'rega');
|
||||
|
||||
HMCCU_Trace ($ioHash, 2, "Executing command $cmd non blocking");
|
||||
HMCCU_Trace ($clHash, 2, "URL=$url");
|
||||
@ -8912,6 +8952,7 @@ sub HMCCU_HMCommandNB ($$$)
|
||||
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST",
|
||||
callback => \&HMCCU_HMScriptCB, cbFunc => $cbFunc, devhash => $clHash, ioHash => $ioHash };
|
||||
$param->{sslargs} = { SSL_verify_mode => 0 };
|
||||
$param->{header} = "Authorization: Basic $auth" if ($auth ne '');
|
||||
HttpUtils_NonblockingGet ($param);
|
||||
}
|
||||
|
||||
@ -8996,7 +9037,9 @@ sub HMCCU_HMScriptExt ($$;$$$)
|
||||
HMCCU_Trace ($hash, 2, "Code=$code");
|
||||
|
||||
# Execute script on CCU
|
||||
my $url = HMCCU_BuildURL ($hash, 'rega');
|
||||
my ($url, $auth) = HMCCU_BuildURL ($hash, 'rega');
|
||||
my %header = ('Content-Type' => 'text/plain');
|
||||
$header{'Authorization'} = "Basic $auth" if ($auth ne '');
|
||||
if (defined($cbFunc)) {
|
||||
# Non blocking
|
||||
HMCCU_Trace ($hash, 2, "Executing $hmscript non blocking");
|
||||
@ -9006,6 +9049,7 @@ sub HMCCU_HMScriptExt ($$;$$$)
|
||||
foreach my $p (keys %{$cbParam}) { $param->{$p} = $cbParam->{$p}; }
|
||||
}
|
||||
$param->{sslargs} = { SSL_verify_mode => 0 };
|
||||
$param->{header} = \%header;
|
||||
HttpUtils_NonblockingGet ($param);
|
||||
return '';
|
||||
}
|
||||
@ -9013,8 +9057,9 @@ sub HMCCU_HMScriptExt ($$;$$$)
|
||||
# Blocking request
|
||||
my $param = { url => $url, timeout => $ccureqtimeout, data => $code, method => "POST" };
|
||||
$param->{sslargs} = { SSL_verify_mode => 0 };
|
||||
$param->{header} = \%header;
|
||||
my ($err, $response) = HttpUtils_BlockingGet ($param);
|
||||
HMCCU_Trace ($hash, 2, "err=$err\nresponse=$response");
|
||||
HMCCU_Trace ($hash, 2, "err=$err\nresponse=".($response // ''));
|
||||
if ($err eq '') {
|
||||
return HMCCU_FormatScriptResponse ($response);
|
||||
}
|
||||
@ -9324,11 +9369,7 @@ sub HMCCU_ScaleValue ($$$$$;$)
|
||||
my $name = $hash->{NAME};
|
||||
my $ioHash = HMCCU_GetHash ($hash);
|
||||
|
||||
if (!defined($value) || !HMCCU_IsFltNum($value)) {
|
||||
my $logValue = $value // 'undef';
|
||||
HMCCU_Log ($hash, 5, "Value $logValue is not numeric. chn=$chnno, dpt=$dpt");
|
||||
return $value;
|
||||
}
|
||||
return $value if (!defined($value) || !HMCCU_IsFltNum($value));
|
||||
|
||||
my $boundsChecking = (
|
||||
$mode == 2 ||
|
||||
@ -10027,27 +10068,30 @@ sub HMCCU_MinMax ($$$)
|
||||
# Build ReGa or RPC client URL
|
||||
# Parameter backend specifies type of URL, 'rega' or name or port of
|
||||
# RPC interface.
|
||||
# Return empty string on error.
|
||||
# Return array in format (url, authorization)
|
||||
# Return empty strings on error.
|
||||
######################################################################
|
||||
|
||||
sub HMCCU_BuildURL ($$)
|
||||
{
|
||||
my ($hash, $backend) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
my $url = '';
|
||||
|
||||
my $username = '';
|
||||
my $password = '';
|
||||
my $authorization = '';
|
||||
my ($erruser, $encuser) = getKeyValue ($name.'_username');
|
||||
my ($errpass, $encpass) = getKeyValue ($name.'_password');
|
||||
if (!defined($erruser) && !defined($errpass) && defined($encuser) && defined($encpass)) {
|
||||
$username = HMCCU_Decrypt ($encuser);
|
||||
$password = HMCCU_Decrypt ($encpass);
|
||||
$authorization = encode_base64 ("$username:$password", '');
|
||||
}
|
||||
my $auth = ($username ne '' && $password ne '') ? "$username:$password".'@' : '';
|
||||
|
||||
if ($backend eq 'rega') {
|
||||
$url = $hash->{prot}."://$auth".$hash->{host}.':'.
|
||||
$url = $hash->{prot}."://".$hash->{host}.':'.
|
||||
$HMCCU_REGA_PORT{$hash->{prot}}.'/tclrega.exe';
|
||||
}
|
||||
else {
|
||||
@ -10055,7 +10099,7 @@ sub HMCCU_BuildURL ($$)
|
||||
if (defined($url)) {
|
||||
if (exists($HMCCU_RPC_SSL{$backend})) {
|
||||
my $p = $hash->{prot} eq 'https' ? '4' : '';
|
||||
$url =~ s/^http:\/\//$hash->{prot}:\/\/$auth/;
|
||||
$url =~ s/^http:\/\//$hash->{prot}:\/\//;
|
||||
$url =~ s/:([0-9]+)/:$p$1/;
|
||||
}
|
||||
}
|
||||
@ -10064,7 +10108,10 @@ sub HMCCU_BuildURL ($$)
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
HMCCU_Trace ($hash, 2, "Build URL = " . $url);
|
||||
HMCCU_Trace ($hash, 2, "Authorization = " . $authorization);
|
||||
|
||||
return ($url, $authorization);
|
||||
}
|
||||
|
||||
######################################################################
|
||||
@ -10496,7 +10543,7 @@ sub HMCCU_GetDutyCycle ($)
|
||||
|
||||
foreach my $port (values %$interfaces) {
|
||||
next if ($port != 2001 && $port != 2010);
|
||||
my $url = HMCCU_BuildURL ($hash, $port) // next;
|
||||
my ($url, $auth) = HMCCU_BuildURL ($hash, $port) // next;
|
||||
my $rpcclient = RPC::XML::Client->new ($url);
|
||||
my $response = $rpcclient->simple_request ('listBidcosInterfaces');
|
||||
next if (!defined($response) || ref($response) ne 'ARRAY');
|
||||
@ -10959,15 +11006,18 @@ sub HMCCU_MaxHashEntries ($$)
|
||||
logEnhanced - Messages in FHEM logfile will contain line number and process ID.<br/>
|
||||
logEvents - Write events from CCU into FHEM logfile<br/>
|
||||
logPong - Write log message when receiving pong event if verbose level is at least 3.<br/>
|
||||
noAutoSubstitute - Do not substitute reading values by names. This global flag affects all devices. Set this flag in client devices to turn off substitutions in single devices<br/>
|
||||
noEvents - Ignore events / device updates sent by CCU. No readings will be updated!<br/>
|
||||
noInitialUpdate - Do not update datapoints of devices after RPC server start. Overrides
|
||||
settings in RPC devices.
|
||||
settings in RPC devices.<br/>
|
||||
noAutoDetect - Do not detect any device (only for development and testing)<br/>
|
||||
nonBlocking - Use non blocking (asynchronous) CCU requests<br/>
|
||||
noReadings - Do not create or update readings<br/>
|
||||
procrpc - Use external RPC server provided by module HMCCPRPCPROC. During first RPC
|
||||
server start HMCCU will create a HMCCURPCPROC device for each interface confiugured
|
||||
in attribute 'rpcinterface'<br/>
|
||||
reconnect - Automatically reconnect to CCU when events timeout occurred.<br/>
|
||||
unknownDeviceRoles - Command createDev will create HMCCUDEV or HMCCUCHN devices even if none of the device roles are known by HMCCU. This will become the default in a future version.<br/>
|
||||
updGroupMembers - Update readings of group members in virtual devices.
|
||||
</li><br/>
|
||||
<li><b>ccuget {State | <u>Value</u>}</b><br/>
|
||||
|
@ -30,7 +30,7 @@ sub HMCCUCHN_Set ($@);
|
||||
sub HMCCUCHN_Get ($@);
|
||||
sub HMCCUCHN_Attr ($@);
|
||||
|
||||
my $HMCCUCHN_VERSION = '5.0 222930908';
|
||||
my $HMCCUCHN_VERSION = '5.0 232641921';
|
||||
|
||||
######################################################################
|
||||
# Initialize module
|
||||
@ -51,7 +51,7 @@ sub HMCCUCHN_Initialize ($)
|
||||
$hash->{parseParams} = 1;
|
||||
|
||||
$hash->{AttrList} = 'IODev ccucalculate '.
|
||||
'ccuflags:multiple-strict,hideStdReadings,replaceStdReadings,noBoundsChecking,ackState,logCommand,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
|
||||
'ccuflags:multiple-strict,hideStdReadings,replaceStdReadings,noBoundsChecking,ackState,logCommand,noAutoSubstitute,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
|
||||
'ccureadingfilter:textField-long statedatapoint controldatapoint '.
|
||||
'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
|
||||
'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix '.
|
||||
@ -765,6 +765,7 @@ sub HMCCUCHN_Get ($@)
|
||||
replaceStdReadings: Replace original readings like 'ACTUAL_TEMPERATURE' by standard readings like 'measured-temp' instead of adding standard readings<br/>
|
||||
logCommand: Write get and set commands to FHEM log with verbose level 3.<br/>
|
||||
noBoundsChecking: Datapoint values are not checked for min/max boundaries<br/>
|
||||
noAutoSubstitute - Do not substitute reading values by names. This local flag affects only the current device. You can turn off all substitutes by setting this flag in I/O device.<br/>
|
||||
noReadings: Do not update readings<br/>
|
||||
simulate: Do not execute set datapoint commands. Use this flag together with 'trace'<br/>
|
||||
showDeviceReadings: Show readings of device and channel 0.<br/>
|
||||
|
@ -31,7 +31,7 @@ sub HMCCUDEV_Set ($@);
|
||||
sub HMCCUDEV_Get ($@);
|
||||
sub HMCCUDEV_Attr ($@);
|
||||
|
||||
my $HMCCUDEV_VERSION = '5.0 222930908';
|
||||
my $HMCCUDEV_VERSION = '5.0 232641921';
|
||||
|
||||
######################################################################
|
||||
# Initialize module
|
||||
@ -52,7 +52,7 @@ sub HMCCUDEV_Initialize ($)
|
||||
$hash->{parseParams} = 1;
|
||||
|
||||
$hash->{AttrList} = 'IODev ccuaggregate:textField-long ccucalculate:textField-long '.
|
||||
'ccuflags:multiple-strict,ackState,hideStdReadings,replaceStdReadings,noBoundsChecking,logCommand,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
|
||||
'ccuflags:multiple-strict,ackState,hideStdReadings,replaceStdReadings,noAutoSubstitute,noBoundsChecking,logCommand,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
|
||||
'ccureadingfilter:textField-long '.
|
||||
'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
|
||||
'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix devStateFlags '.
|
||||
|
@ -8,7 +8,7 @@
|
||||
#
|
||||
# Subprocess based RPC Server module for HMCCU.
|
||||
#
|
||||
# (c) 2022 by zap (zap01 <at> t-online <dot> de)
|
||||
# (c) 2023 by zap (zap01 <at> t-online <dot> de)
|
||||
#
|
||||
##############################################################################
|
||||
#
|
||||
@ -39,7 +39,7 @@ use SetExtensions;
|
||||
######################################################################
|
||||
|
||||
# HMCCURPC version
|
||||
my $HMCCURPCPROC_VERSION = '5.0 222930908';
|
||||
my $HMCCURPCPROC_VERSION = '5.0 232641921';
|
||||
|
||||
# Maximum number of events processed per call of Read()
|
||||
my $HMCCURPCPROC_MAX_EVENTS = 100;
|
||||
@ -446,7 +446,7 @@ sub HMCCURPCPROC_InitDevice ($$)
|
||||
$devHash->{hmccu}{rpc}{methods} =~ /(system\.multicall)/i)
|
||||
{
|
||||
$devHash->{hmccu}{rpc}{multicall} = $1;
|
||||
HMCCU_Log ($devHash, 2, "CCU interface $ifname supports RPC multicalls");
|
||||
HMCCU_Log ($devHash, 5, "CCU interface $ifname supports RPC multicalls");
|
||||
}
|
||||
else {
|
||||
HMCCU_Log ($devHash, 2, "CCU interface $ifname doesn't support RPC multicalls");
|
||||
@ -461,6 +461,7 @@ sub HMCCURPCPROC_InitDevice ($$)
|
||||
# Set some attributes
|
||||
if ($init_done) {
|
||||
$attr{$name}{stateFormat} = 'rpcstate/state';
|
||||
$attr{$name}{room} = 'Homematic';
|
||||
$attr{$name}{verbose} = 2;
|
||||
}
|
||||
|
||||
@ -1381,13 +1382,14 @@ sub HMCCURPCPROC_RegisterCallback ($$)
|
||||
if ($force == 2 && !HMCCU_TCPConnect ($hash->{host}, $port));
|
||||
|
||||
my $cburl = HMCCU_GetRPCCallbackURL ($ioHash, $localaddr, $hash->{hmccu}{rpc}{cbport}, $clkey, $port);
|
||||
my $clurl = HMCCU_BuildURL ($ioHash, $port);
|
||||
my ($clurl, $auth) = HMCCU_BuildURL ($ioHash, $port);
|
||||
my ($rpctype) = HMCCU_GetRPCServerInfo ($ioHash, $port, 'type');
|
||||
return (0, "Can't get RPC parameters for ID $clkey")
|
||||
if (!defined($cburl) || !defined($clurl) || !defined($rpctype));
|
||||
|
||||
$hash->{hmccu}{rpc}{port} = $port;
|
||||
$hash->{hmccu}{rpc}{clurl} = $clurl;
|
||||
$hash->{hmccu}{rpc}{auth} = $auth;
|
||||
$hash->{hmccu}{rpc}{cburl} = $cburl;
|
||||
|
||||
HMCCU_Log ($hash, 2, "Registering callback $cburl of type $rpctype with ID $clkey at $clurl");
|
||||
@ -1416,6 +1418,7 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
|
||||
my $localaddr = $hash->{hmccu}{localaddr};
|
||||
my $cburl = '';
|
||||
my $clurl = '';
|
||||
my $auth = '';
|
||||
my $rpchash = \%{$hash->{hmccu}{rpc}};
|
||||
|
||||
return (0, "RPC server $clkey not in state registered or running")
|
||||
@ -1423,8 +1426,9 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
|
||||
|
||||
$cburl = $rpchash->{cburl} if (exists($rpchash->{cburl}));
|
||||
$clurl = $rpchash->{clurl} if (exists($rpchash->{clurl}));
|
||||
$auth = $rpchash->{auth} if (exists($rpchash->{auth}));
|
||||
$cburl = HMCCU_GetRPCCallbackURL ($ioHash, $localaddr, $rpchash->{cbport}, $clkey, $port) if ($cburl eq '');
|
||||
$clurl = HMCCU_BuildURL ($ioHash, $port) if ($clurl eq '');
|
||||
($clurl, $auth) = HMCCU_BuildURL ($ioHash, $port) if ($clurl eq '');
|
||||
return (0, "Can't get RPC parameters for ID $clkey") if ($cburl eq '' || $clurl eq '');
|
||||
|
||||
HMCCU_Log ($hash, 1, "Deregistering RPC server $cburl with ID $clkey at $clurl");
|
||||
@ -1440,6 +1444,7 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
|
||||
|
||||
$rpchash->{cburl} = '';
|
||||
$rpchash->{clurl} = '';
|
||||
$rpchash->{auth} = '';
|
||||
$rpchash->{cbport} = 0;
|
||||
|
||||
return (1, 'working');
|
||||
@ -1926,20 +1931,24 @@ sub HMCCURPCPROC_Connect ($;$)
|
||||
|
||||
if (HMCCU_IsRPCType ($ioHash, $hash->{rpcport}, 'A')) {
|
||||
# Build the request URL
|
||||
my $clurl = HMCCU_BuildURL ($ioHash, $hash->{rpcport});
|
||||
return HMCCU_Log ($hash, 2, "Can't get RPC client URL for port $hash->{rpcport}", 0) if (!defined($clurl));
|
||||
my ($clurl, $auth) = HMCCU_BuildURL ($ioHash, $hash->{rpcport});
|
||||
HMCCU_Log ($hash, 5, "Connecting to " . $clurl);
|
||||
return HMCCU_Log ($hash, 1, "Can't get RPC client URL for port $hash->{rpcport}", 0) if (!defined($clurl));
|
||||
|
||||
my $header = HTTP::Headers->new ('Connection' => 'Keep-Alive');
|
||||
$header->header('Authorization' => "Basic $auth") if ($auth) ne '';
|
||||
$hash->{hmccu}{rpc}{connection} = RPC::XML::Client->new ($clurl,
|
||||
useragent => [
|
||||
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 },
|
||||
default_headers => $header
|
||||
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 }
|
||||
]
|
||||
);
|
||||
$hash->{hmccu}{rpc}{connection}->useragent->default_headers($header);
|
||||
$hash->{hmccu}{rpc}{clurl} = $clurl;
|
||||
$hash->{hmccu}{rpc}{auth} = $auth;
|
||||
}
|
||||
elsif (HMCCU_IsRPCType ($ioHash, $hash->{rpcport}, 'B')) {
|
||||
my ($serveraddr) = HMCCU_GetRPCServerInfo ($ioHash, $hash->{rpcport}, 'host');
|
||||
return HMCCU_Log ($ioHash, 2, "Can't get server address for port $hash->{rpcport}", 0) if (!defined($serveraddr));
|
||||
return HMCCU_Log ($ioHash, 1, "Can't get server address for port $hash->{rpcport}", 0) if (!defined($serveraddr));
|
||||
|
||||
$hash->{hmccu}{rpc}{connection} = IO::Socket::INET->new (
|
||||
PeerHost => $serveraddr, PeerPort => $hash->{rpcport}, Proto => 'tcp', Timeout => 3
|
||||
@ -1950,7 +1959,7 @@ sub HMCCURPCPROC_Connect ($;$)
|
||||
}
|
||||
}
|
||||
|
||||
return HMCCU_Log ($hash, 2, "Can't connect to RPC interface", 0) if (!defined($hash->{hmccu}{rpc}{connection}));
|
||||
return HMCCU_Log ($hash, 1, "Can't connect to RPC interface", 0) if (!defined($hash->{hmccu}{rpc}{connection}));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1972,6 +1981,8 @@ sub HMCCURPCPROC_Disconnect ($;$)
|
||||
}
|
||||
|
||||
delete $hash->{hmccu}{rpc}{connection};
|
||||
$hash->{hmccu}{rpc}{clurl} = '';
|
||||
$hash->{hmccu}{rpc}{auth} = '';
|
||||
}
|
||||
|
||||
######################################################################
|
||||
@ -2171,12 +2182,13 @@ sub HMCCURPCPROC_SendXMLRequest ($@)
|
||||
my $re = ':('.join('|', keys(%BINRPC_TYPE_MAPPING)).')';
|
||||
|
||||
# Build the request URL
|
||||
my $clurl = HMCCU_BuildURL ($ioHash, $port);
|
||||
if (!defined($clurl)) {
|
||||
HMCCU_Log ($hash, 2, "Can't get RPC client URL for port $port");
|
||||
return (undef, "Can't get RPC client URL for port $port");
|
||||
}
|
||||
HMCCU_Log ($hash, 4, "Send ASCII XML RPC request $request to $clurl");
|
||||
# my $clurl = HMCCU_BuildURL ($ioHash, $port);
|
||||
# if (!defined($clurl)) {
|
||||
# HMCCU_Log ($hash, 2, "Can't get RPC client URL for port $port");
|
||||
# return (undef, "Can't get RPC client URL for port $port");
|
||||
# }
|
||||
# HMCCU_Log ($hash, 1, stacktraceAsString(undef));
|
||||
# HMCCU_Log ($hash, 1, "Send ASCII XML RPC request $request to " . $hash->{hmccu}{rpc}{clurl});
|
||||
|
||||
# my $rpcclient = RPC::XML::Client->new ($clurl, useragent => [
|
||||
# ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 }
|
||||
@ -2185,6 +2197,7 @@ sub HMCCURPCPROC_SendXMLRequest ($@)
|
||||
my @rpcParam = map { HMCCURPCPROC_XMLEncValue ($_) } @param;
|
||||
|
||||
# Submit RPC request
|
||||
# HMCCU_Log($hash, 2, Dumper($hash->{hmccu}{rpc}{connection}));
|
||||
my $resp = $hash->{hmccu}{rpc}{connection}->simple_request ($request, @rpcParam);
|
||||
if (!defined($resp)) {
|
||||
HMCCU_Log ($hash, 2, "RPC request $request failed: ".$RPC::XML::ERROR);
|
||||
@ -2217,6 +2230,8 @@ sub HMCCURPCPROC_SendBINRequest ($@)
|
||||
# return (undef, "Can't get server address for port $port");
|
||||
# }
|
||||
|
||||
# HMCCU_Log ($hash, 1, "Send BIN XML RPC request $request");
|
||||
|
||||
my $timeoutRead = AttrVal ($name, 'rpcReadTimeout', $HMCCURPCPROC_TIMEOUT_READ);
|
||||
my $timeoutWrite = AttrVal ($name, 'rpcWriteTimeout', $HMCCURPCPROC_TIMEOUT_WRITE);
|
||||
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
|
||||
|
@ -192,7 +192,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
|
||||
},
|
||||
'SWITCH' => {
|
||||
F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false', P => 2
|
||||
},
|
||||
},
|
||||
'SWITCH_PANIC' => {
|
||||
F => 3, S => 'STATE', C => 'STATE', V => 'on:true,off:false', P => 2
|
||||
},
|
||||
@ -314,7 +314,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
|
||||
'^([0-9]{1,2}\.)?ACTUAL_HUMIDITY$:+humidity'
|
||||
);
|
||||
|
||||
######################################################################
|
||||
#######################################################################################
|
||||
# Set commands related to channel role
|
||||
# Role => { Command-Definition, ... }
|
||||
# Command-Defintion:
|
||||
@ -325,11 +325,12 @@ $HMCCU_CONFIG_VERSION = '5.0';
|
||||
# Function:
|
||||
# A Perl function name
|
||||
# Datapoint-Def:
|
||||
# Paramset:Datapoints:[Parameter=]FixedValue
|
||||
# Paramset:Datapoints:?Parameter
|
||||
# Paramset:Datapoints:?Parameter=Default-Value
|
||||
# Paramset:Datapoints:#Parameter[=FixedValue,[...]]
|
||||
# Paramset:Datapoints:*Parameter=Default-Value
|
||||
# No parameters: Paramset:Datapoints:[Parameter=]FixedValue[,...]
|
||||
# Toggle command: Paramset:Datapoints
|
||||
# One parameter: Paramset:Datapoints:?Parameter
|
||||
# Optional parameter with default: Paramset:Datapoints:?Parameter=Default-Value
|
||||
# List of values: Paramset:Datapoints:#Parameter[=FixedValue[,...]]
|
||||
# Internal value (paramset "I"): Paramset:Datapoints:*Parameter=Default-Value
|
||||
# Paramset:
|
||||
# V=VALUES, M=MASTER (channel), D=MASTER (device), I=INTERNAL
|
||||
# Datapoints:
|
||||
@ -340,6 +341,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
|
||||
# parameter set description. Otherwise a list of values must
|
||||
# be specified after '='.
|
||||
# * = internal value $hash->{hmccu}{values}{parameterName}
|
||||
# See also paramset "I"
|
||||
# FixedValue: Parameter values are detected in the following order:
|
||||
# 1. If command parameter name is identical with controldatapoint,
|
||||
# option values are taken from controldatapoint definition {V}. The
|
||||
@ -351,7 +353,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
|
||||
# 3. As a fallback command options and option values are identical.
|
||||
# If Default-Value is preceeded by + or -, value is added to or
|
||||
# subtracted from current datapoint value
|
||||
######################################################################
|
||||
#######################################################################################
|
||||
|
||||
%HMCCU_ROLECMDS = (
|
||||
'ALARM_SWITCH_VIRTUAL_RECEIVER' => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user