2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-16 10:46:03 +00:00

HMCCU: Update for version 4.4 beta

git-svn-id: https://svn.fhem.de/fhem/trunk@20988 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-01-15 18:17:54 +00:00
parent e105e07514
commit be9bc8d368
4 changed files with 457 additions and 216 deletions

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCU.pm 18745 2019-02-26 17:33:23Z zap $
#
# Version 4.4.000
# Version 4.4.002
#
# Module for communication between FHEM and Homematic CCU2/3.
#
@ -52,7 +52,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.4.000';
my $HMCCU_VERSION = '4.4.002';
# Constants and default values
my $HMCCU_MAX_IOERRORS = 100;
@ -222,9 +222,9 @@ sub HMCCU_SetRPCState ($@);
# Filter and modify readings
sub HMCCU_FilterReading ($$$);
sub HMCCU_FormatReadingValue ($$$);
sub HMCCU_GetReadingName ($$$$$$$);
sub HMCCU_GetReadingName ($$$$$$$;$);
sub HMCCU_ScaleValue ($$$$$);
sub HMCCU_Substitute ($$$$$);
sub HMCCU_Substitute ($$$$$;$);
sub HMCCU_SubstRule ($$$);
sub HMCCU_SubstVariables ($$$);
@ -284,6 +284,7 @@ sub HMCCU_AddDeviceModel ($$$$$$);
sub HMCCU_CreateDevice ($$$$$);
sub HMCCU_DeleteDevice ($);
sub HMCCU_ExistsDeviceModel ($$$;$);
sub HMCCU_FindParamDef ($$$);
sub HMCCU_FormatDeviceInfo ($);
sub HMCCU_GetAddress ($$$$);
sub HMCCU_GetAffectedAddresses ($);
@ -406,7 +407,7 @@ sub HMCCU_Initialize ($)
" ccudef-hmstatevals:textField-long ccudef-substitute:textField-long".
" ccudef-readingname:textField-long ccudef-readingfilter:textField-long".
" ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc".
" ccudef-stripnumber".
" ccudef-stripnumber ccuReadingPrefix".
" ccuflags:multiple-strict,procrpc,dptnocheck,logCommand,noagg,nohmstate,".
"logEvents,noEvents,noInitialUpdate,noReadings,nonBlocking,reconnect,logPong,trace".
" ccuReqTimeout ccuGetVars rpcinterval:2,3,5,7,10 rpcqueue rpcPingCCU".
@ -2365,24 +2366,25 @@ sub HMCCU_FilterReading ($$$)
my $hmccu_hash = HMCCU_GetHash ($hash);
return 1 if (!defined ($hmccu_hash));
my $grf = AttrVal ($hmccu_hash->{NAME}, 'ccudef-readingfilter', '.*');
my $rf = AttrVal ($name, 'ccureadingfilter', $grf);
$rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*');
# my $grf = AttrVal ($hmccu_hash->{NAME}, 'ccudef-readingfilter', '.*');
# my $rf = AttrVal ($name, 'ccureadingfilter', $grf);
# $rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*');
my $rf = AttrVal ($name, 'ccureadingfilter', '.*');
my $chnnam = '';
my $chnnum = '';
my $devadd = '';
# my $chnnum = '';
# my $devadd = '';
# Get channel name and channel number
if (HMCCU_IsValidChannel ($hmccu_hash, $chn, $HMCCU_FL_ADDRESS)) {
my ($devadd, $chnnum) = HMCCU_SplitChnAddr ($chn);
if ($chnnum ne 'd') {
# Get channel name and channel number
$chnnam = HMCCU_GetChannelName ($hmccu_hash, $chn, '');
($devadd, $chnnum) = HMCCU_SplitChnAddr ($chn);
if ($chnnam eq '') {
($devadd, $chnnum) = HMCCU_GetAddress ($hash, $chn, '', '');
$chnnam = $chn;
}
}
else {
($devadd, $chnnum) = HMCCU_GetAddress ($hash, $chn, '', '');
$chnnam = $chn;
}
HMCCU_Trace ($hash, 2, $fnc, "chn=$chn, chnnam=$chnnam chnnum=$chnnum dpt=$dpt, rules=$rf");
foreach my $r (split (';', $rf)) {
@ -2420,11 +2422,12 @@ sub HMCCU_FilterReading ($$$)
(
($cn ne '' && "$chnnum" eq "$cn") ||
($c ne '' && $chnnam =~ /$c/) ||
($cn eq '' && $c eq '')
($cn eq '' && $c eq '') ||
($chnnum eq 'd')
) && $dpt =~ /$f/
)
);
# Negate filter
# Negative filter
return 1 if (
!$rm && (
($cn ne '' && "$chnnum" ne "$cn") ||
@ -2443,7 +2446,7 @@ sub HMCCU_FilterReading ($$$)
#
# Parameters:
#
# Interface,Address,ChannelNo,Datapoint,ChannelNam,Format
# Interface,Address,ChannelNo,Datapoint,ChannelNam,Format,Paramset
# Format := { name[lc] | datapoint[lc] | address[lc] | formatStr }
# formatStr := Any text containing at least one format pattern
# pattern := { %a, %c, %n, %d, %A, %C, %N, %D }
@ -2456,17 +2459,20 @@ sub HMCCU_FilterReading ($$$)
#
# Reading names can be modified or new readings can be added by
# setting attribut ccureadingname.
# Returns list of readings names.
# Returns list of readings names. Return empty list on error.
######################################################################
sub HMCCU_GetReadingName ($$$$$$$)
sub HMCCU_GetReadingName ($$$$$$$;$)
{
my ($hash, $i, $a, $c, $d, $n, $rf) = @_;
my ($hash, $i, $a, $c, $d, $n, $rf, $ps) = @_;
my $name = $hash->{NAME};
my %prefix = ( 'MASTER' => 'R-', 'LINK' => 'L-', 'VALUES' => '', 'SERVICE' => 'S-' );
my $ioHash = HMCCU_GetHash ($hash);
return '' if (!defined ($ioHash));
return () if (!defined ($ioHash) || !defined($d) || $d eq '');
$ps = 'VALUES' if (!defined($ps));
my $rn = '';
my @rnlist;
@ -2477,8 +2483,13 @@ sub HMCCU_GetReadingName ($$$$$$$)
my $sr = AttrVal ($name, 'ccureadingname', $gsr);
$sr .= ";".$gsr if ($sr ne $gsr && $gsr ne '');
# Datapoint is mandatory
return '' if ($d eq '');
# Get reading prefix definitions
my $readingPrefix = HMCCU_GetAttribute ($ioHash, $hash, 'ccuReadingPrefix', '');
foreach my $pd (split (',', $readingPrefix)) {
my ($rSet, $rPre) = split (':', $pd);
$prefix{$rSet} = $rPre if (defined($rPre) && exists($prefix{$rSet}));
}
my $rpf = exists($prefix{$ps}) ? $prefix{$ps} : '';
# Complete missing values
$c = '' if (!defined ($c));
@ -2499,11 +2510,11 @@ sub HMCCU_GetReadingName ($$$$$$$)
$rn = $c ne '' ? $c.'.'.$d : $d;
}
elsif ($rf eq 'name' || $rf =~ /^name(lc|uc)$/) {
return '' if ($n eq '');
return () if ($n eq '');
$rn = $n.'.'.$d;
}
elsif ($rf eq 'address' || $rf =~ /^address(lc|uc)$/) {
return '' if ($a eq '');
return () if ($a eq '');
my $t = $a;
$t = $i.'.'.$t if ($i ne '');
$t = $t.'.'.$c if ($c ne '');
@ -2521,7 +2532,7 @@ sub HMCCU_GetReadingName ($$$$$$$)
$rn =~ s/\%D/uc($d)/ge;
}
push (@rnlist, $rn);
push (@rnlist, $rpf.$rn);
# Rename and/or add reading names
if ($sr ne '') {
@ -2837,9 +2848,9 @@ sub HMCCU_SetRPCState ($@)
# mode: 0=Substitute regular expression, 1=Substitute text
######################################################################
sub HMCCU_Substitute ($$$$$)
sub HMCCU_Substitute ($$$$$;$)
{
my ($value, $substrule, $mode, $chn, $dpt) = @_;
my ($value, $substrule, $mode, $chn, $dpt, $type) = @_;
my $rc = 0;
my $newvalue;
@ -2853,26 +2864,34 @@ sub HMCCU_Substitute ($$$$$)
my @rulelist = split (';', $substrule);
foreach my $rule (@rulelist) {
my @ruletoks = split ('!', $rule);
if (@ruletoks == 2 && $dpt ne '' && $mode == 0) {
my @dptlist = split (',', $ruletoks[0]);
foreach my $d (@dptlist) {
my $c = -1;
if ($d =~ /^([0-9]{1,2})\.(.+)$/) {
($c, $d) = ($1, $2);
}
if ($d eq $dpt && ($c == -1 || !defined($chn) || $c == $chn)) {
($rc, $newvalue) = HMCCU_SubstRule ($value, $ruletoks[1], $mode);
return $newvalue;
if (scalar(@ruletoks) == 2 && $dpt ne '' && $mode == 0) {
my ($r, $f) = split (':', $ruletoks[0], 2);
if (!defined($f)) {
$f = $r;
$r = undef;
}
if (!defined($r) || (defined($type) && $r eq $type)) {
my @dptlist = split (',', $f);
foreach my $d (@dptlist) {
my $c = -1;
if ($d =~ /^([0-9]{1,2})\.(.+)$/) {
($c, $d) = ($1, $2);
}
if ($d eq $dpt && ($c == -1 || !defined($chn) || $c == $chn)) {
($rc, $newvalue) = HMCCU_SubstRule ($value, $ruletoks[1], $mode);
return $newvalue;
}
}
}
}
elsif (@ruletoks == 1) {
elsif (scalar(@ruletoks) == 1) {
return $value if ($value !~ /^[+-]?\d+$/ && $value =~ /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/);
($rc, $newvalue) = HMCCU_SubstRule ($value, $ruletoks[0], $mode);
return $newvalue if ($rc == 1);
}
}
# Original value not modified by rules. Use default conversion
return $value;
}
@ -3365,7 +3384,9 @@ sub HMCCU_AddDeviceDesc ($$$$)
$hash->{hmccu}{device}{$iface}{$k}{$p} = join(',', @{$desc->{$p}});
}
else {
$hash->{hmccu}{device}{$iface}{$k}{$p} = $desc->{$p};
my $d = $desc->{$p};
$d =~ s/ /,/g;
$hash->{hmccu}{device}{$iface}{$k}{$p} = $d;
}
}
@ -3392,7 +3413,8 @@ sub HMCCU_AddDeviceDesc ($$$$)
# Get device description.
# Parameters:
# $hash - Hash reference of IO device.
# $address - Address of device or channel.
# $address - Address of device or channel. Accepts a channel address
# with channel number 'd' as an alias for device address.
# $iface - Interface name.
# Return hash reference for device description or undef on error.
######################################################################
@ -3409,6 +3431,7 @@ sub HMCCU_GetDeviceDesc ($$;$)
push (@ifaceList, keys %${$hash->{hmccu}{device}});
}
$address =~ s/:d//;
foreach my $i (@ifaceList) {
return $hash->{hmccu}{device}{$i}{$address}
if (exists($hash->{hmccu}{device}{$i}{$address}));
@ -3589,19 +3612,12 @@ sub HMCCU_GetParamDef ($$$$)
{
my ($hash, $object, $paramset, $parameter) = @_;
my $devDesc;
if (ref($object) eq 'HASH') {
$devDesc = $object;
}
else {
$devDesc = HMCCU_GetDeviceDesc ($hash, $object);
}
my $devDesc = ref($object) eq 'HASH' ? $object : HMCCU_GetDeviceDesc ($hash, $object);
if (defined($devDesc)) {
# Build device address and channel number
my $address = $devDesc->{ADDRESS};
my ($devAddr, $chnNo) = ($address =~ /:[0-9]{1,2}$/) ?
HMCCU_SplitChnAddr ($address) : ($address, 'd');
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($model) && exists($model->{$paramset}) && exists($model->{$paramset}{$parameter})) {
@ -3612,6 +3628,39 @@ sub HMCCU_GetParamDef ($$$$)
return undef;
}
######################################################################
# Find parameter defintion of device model
# Parameters:
# $hash - Hash reference of IO device.
# $object - Device or channel address or device description
# reference.
# $parameter - Parameter name.
# Returns (undef,undef) on error. Otherwise parameter set name and
# reference to the parameter definition.
######################################################################
sub HMCCU_FindParamDef ($$$)
{
my ($hash, $object, $parameter) = @_;
my $devDesc = ref($object) eq 'HASH' ? $object : HMCCU_GetDeviceDesc ($hash, $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);
if (defined($model)) {
foreach my $ps (keys %$model) {
return ($ps, $model->{$ps}{$parameter}) if (exists($model->{$ps}{$parameter}));
}
}
}
return (undef, undef);
}
######################################################################
# Convert parameter value
# Parameters:
@ -3635,7 +3684,6 @@ sub HMCCU_GetParamValue ($$$$$)
my $paramDef = HMCCU_GetParamDef ($hash, $object, $paramset, $parameter);
if (defined($paramDef)) {
my $type = $paramDef->{TYPE};
HMCCU_Log ($hash, 2, "Checking type $type");
return $ct{$type}{$value} if (exists($ct{$type}) && exists($ct{$type}{$value}));
@ -3715,6 +3763,138 @@ sub HMCCU_UpdateSingleDatapoint ($$$$)
return (ref ($rc)) ? $rc->{$devaddr}{$chn}{$dpt} : $value;
}
######################################################################
# Update readings of client device.
# Parameter objects is a hash reference which contains updated data
# for devices:
# {devaddr}{channelno}{paramset}{parameter} = value
# channelno = 'd' for device parameters.
# Return hash reference for results or undef on error.
######################################################################
sub HMCCU_UpdateParamsetReadings ($$$;$)
{
my ($ioHash, $clHash, $objects, $addListRef) = @_;
my $clName = $clHash->{NAME};
my $clType = $clHash->{TYPE};
return undef if (!defined($clHash->{IODev}) || !defined($clHash->{ccuaddr}) ||
$clHash->{IODev} != $ioHash);
# Store the resulting readings
my %results;
# Updated internal values
my @chKeys = ();
# Check if update of device allowed
my $disable = AttrVal ($clName, 'disable', 0);
my $update = AttrVal ($clName, 'ccureadings', 1);
return undef if ($update == 0 || $disable == 1 || $clHash->{ccudevstate} ne 'active');
# Build list of affected addresses
my ($devAddr, $chnNo) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
my @addList = defined ($addListRef) ? @$addListRef : ($devAddr);
# Determine virtual device flag
my $vg = (($clHash->{ccuif} eq 'VirtualDevices' || $clHash->{ccuif} eq 'fhem') &&
exists($clHash->{ccugroup})) ? 1 : 0;
# Get attributes considering default attributes in IO device
my $substitute = HMCCU_GetAttrSubstitute ($clHash, $ioHash);
# Get client device attributes
my $clFlags = HMCCU_GetFlags ($clName);
my $clRF = HMCCU_GetAttrReadingFormat ($clHash, $ioHash);
my $peer = AttrVal ($clName, 'peer', 'null');
my $clInt = $clHash->{ccuif};
my ($sc, $sd, $cc, $cd, $ss, $cs) = HMCCU_GetSpecialDatapoints ($clHash, '', 'STATE', '', '');
readingsBeginUpdate ($clHash);
# Loop over all addresses
foreach my $a (@addList) {
# Loop over all channels of device, including channel 'd'
foreach my $c (keys %{$objects->{$a}}) {
next if (($clType eq 'HMCCUCHN' && "$c" ne "$chnNo" && "$c" ne "0" && "$c" ne "d") ||
("$c" eq "0" && $clFlags =~ /nochn0/));
my $chnAddr = "$devAddr:$c";
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $chnAddr, $clHash->{ccuif});
my $chnType = defined($devDesc) ? $devDesc->{TYPE} : undef;
# Loop over all parameter sets
foreach my $ps (keys %{$objects->{$a}{$c}}) {
# Loop over all parameters
foreach my $p (keys %{$objects->{$a}{$c}{$ps}}) {
my $v = $objects->{$a}{$c}{$ps}{$p};
next if (!defined($v) || !HMCCU_FilterReading ($clHash, $chnAddr, $p));
my $fv = $v;
my $cv = $v;
my $sv;
# Key for storing values in client device hash. Indirect updates of virtual
# devices are stored with device address in key.
my $chKey = $devAddr ne $a ? "$chnAddr.$p" : "$c.$p";
# Store raw value in client device hash
HMCCU_UpdateInternalValues ($clHash, $chKey, 'VAL', $v) if ($ps eq 'VALUES');
# Store the resulting value after scaling, formatting and substitution
if ($ps eq 'VALUES') {
# Modify value: scale, format, substitute
$sv = HMCCU_ScaleValue ($clHash, $c, $p, $v, 0);
$fv = HMCCU_FormatReadingValue ($clHash, $sv, $p);
$cv = HMCCU_Substitute ($fv, $substitute, 0, $c, $p, $chnType);
if ("$cv" eq "$fv") {
# If value has not been changed by rules, use default conversion
$cv = HMCCU_GetParamValue ($ioHash, $devDesc, $ps, $p, $fv);
}
HMCCU_UpdateInternalValues ($clHash, $chKey, 'SVAL', $cv);
push @chKeys, $chKey;
# Update 'state' and 'control'
HMCCU_BulkUpdate ($clHash, 'control', $fv, $cv)
if ($cd ne '' && $p eq $cd && $c eq $cc);
HMCCU_BulkUpdate ($clHash, 'state', $fv, $cv)
if ($p eq $sd && ($sc eq '' || $sc eq $c));
# Update peers
HMCCU_UpdatePeers ($clHash, "$c.$p", $cv, $peer) if (!$vg && $peer ne 'null');
}
else {
$fv = $v;
$cv = HMCCU_GetParamValue ($ioHash, $devDesc, $ps, $p, $v);
}
# Store result, but not for indirect updates of virtual devices
$results{$devAddr}{$c}{$p} = $cv if ($devAddr eq $a);
# Update readings
my @rnList = HMCCU_GetReadingName ($clHash, $clInt, $a, $c, $p, '', $clRF, $ps);
foreach my $rn (@rnList) {
HMCCU_BulkUpdate ($clHash, $rn, $fv, $cv);
}
}
}
}
}
# Calculate additional readings
if (scalar (@chKeys) > 0) {
my %calc = HMCCU_CalculateReading ($clHash, \@chKeys);
foreach my $cr (keys %calc) {
HMCCU_BulkUpdate ($clHash, $cr, $calc{$cr}, $calc{$cr});
}
}
readingsEndUpdate ($clHash, 1);
return \%results;
}
######################################################################
# Update readings of client device.
# Parameter objects is a hash reference which contains updated data
@ -3744,7 +3924,7 @@ sub HMCCU_UpdateSingleDevice ($$$$)
# Check if update of device allowed
my $disable = AttrVal ($cltname, 'disable', 0);
my $update = AttrVal ($cltname, 'ccureadings', 1);
next if ($update == 0 || $disable == 1 || $clthash->{ccudevstate} ne 'active');
return 0 if ($update == 0 || $disable == 1 || $clthash->{ccudevstate} ne 'active');
# Get device parameters and attributes
my $ccuflags = HMCCU_GetFlags ($ccuname);
@ -5991,10 +6171,10 @@ sub HMCCU_GetHash ($@)
sub HMCCU_GetAttribute ($$$$)
{
my ($hmccu_hash, $cl_hash, $attr_name, $attr_def) = @_;
my ($ioHash, $clHash, $attrName, $attrDefault) = @_;
my $value = AttrVal ($cl_hash->{NAME}, $attr_name, '');
$value = AttrVal ($hmccu_hash->{NAME}, $attr_name, $attr_def) if ($value eq '');
my $value = AttrVal ($clHash->{NAME}, $attrName, '');
$value = AttrVal ($ioHash->{NAME}, $attrName, $attrDefault) if ($value eq '');
return $value;
}
@ -7403,7 +7583,8 @@ sub HMCCU_RPCRequest ($$$$$;$)
my $type = $clHash->{TYPE};
my $fnc = "RPCRequest";
my $reqMethod = $method eq 'listParamset' || $method eq 'listRawParamset' ? 'getParamset' : $method;
my $reqMethod = $method eq 'listParamset' || $method eq 'listRawParamset' ||
$method eq 'getRawParamset' ? 'getParamset' : $method;
$filter = '.*' if (!defined ($filter));
my $addr = '';
my $result = '';
@ -7437,10 +7618,19 @@ sub HMCCU_RPCRequest ($$$$$;$)
# Build parameter array: (Address, Paramset [, Parameter ...])
# Paramset := VALUE | MASTER | LINK or any paramset supported by device
# Parameter := Name=Value
# Parameter := Name=Value[:Type]
my @parArray = ($addr, $paramset);
if (defined ($parref)) {
foreach my $k (keys %{$parref}) { push @parArray, "$k=$parref->{$k}"; };
if (defined($parref)) {
foreach my $k (keys %{$parref}) {
my ($pv, $pt) = split (':', $parref->{$k});
if (!defined($pt)) {
my $paramDef = HMCCU_GetParamDef ($ioHash, $addr, $paramset, $k);
$pt = defined($paramDef) && defined($paramDef->{TYPE}) && $paramDef->{TYPE} ne '' ?
$paramDef->{TYPE} : "STRING";
}
$pv .= ":$pt";
push @parArray, "$k=$pv";
};
}
# Submit RPC request
@ -7469,7 +7659,7 @@ sub HMCCU_RPCRequest ($$$$$;$)
if ($method eq 'listParamset') {
$result = join ("\n", map { $_ =~ /$filter/ ? $_.'='.$reqResult->{$_} : () } keys %$reqResult);
}
elsif ($method eq 'listRawParamset') {
elsif ($method eq 'listRawParamset' || $method eq 'getRawParamset') {
$result = $reqResult;
}
elsif ($method eq 'getDeviceDescription') {

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.4.001
# Version 4.4.002
#
# (c) 2020 zap (zap01 <at> t-online <dot> de)
#
@ -45,7 +45,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{AttrList} = "IODev ccucalculate ".
"ccuflags:multiple-strict,ackState,logCommand,nochn0,trace ccureadingfilter ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
"ccureadingname:textField-long ccuSetOnChange ".
"ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix".
"ccureadings:0,1 ccuscaleval ccuverify:0,1,2 ccuget:State,Value controldatapoint ".
"disable:0,1 hmstatevals:textField-long statedatapoint statevals substitute:textField-long ".
"substexcl stripnumber peer:textField-long ". $readingFnAttributes;
@ -67,7 +67,7 @@ sub HMCCUCHN_Define ($@)
my $devtype = shift @$a;
my $devspec = shift @$a;
my $hmccu_hash = undef;
my $ioHash = undef;
# Store some definitions for delayed initialization
$hash->{hmccu}{devspec} = $devspec;
@ -93,16 +93,16 @@ sub HMCCUCHN_Define ($@)
return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists ($defs{$h->{iodev}}));
return "Specified IO Device ".$h->{iodev}." is not a HMCCU device"
if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
$hmccu_hash = $defs{$h->{iodev}};
$ioHash = $defs{$h->{iodev}};
}
else {
# The following call will fail during FHEM start if CCU is not ready
$hmccu_hash = HMCCU_FindIODevice ($devspec);
$ioHash = HMCCU_FindIODevice ($devspec);
}
if ($init_done) {
# Interactive define command while CCU not ready or no IO device defined
if (!defined ($hmccu_hash)) {
if (!defined ($ioHash)) {
my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
if ($ccuinactive > 0) {
return "CCU and/or IO device not ready. Please try again later";
@ -114,7 +114,7 @@ sub HMCCUCHN_Define ($@)
}
else {
# CCU not ready during FHEM start
if (!defined ($hmccu_hash) || $hmccu_hash->{ccustate} ne 'active') {
if (!defined ($ioHash) || $ioHash->{ccustate} ne 'active') {
Log3 $name, 2, "HMCCUCHN: [$devname] Cannot detect IO device, maybe CCU not ready. Trying later ...";
# readingsSingleUpdate ($hash, "state", "Pending", 1);
$hash->{ccudevstate} = 'pending';
@ -123,9 +123,9 @@ sub HMCCUCHN_Define ($@)
}
# Initialize FHEM device, set IO device
my $rc = HMCCUCHN_InitDevice ($hmccu_hash, $hash);
my $rc = HMCCUCHN_InitDevice ($ioHash, $hash);
return "Invalid or unknown CCU channel name or address" if ($rc == 1);
return "Can't assign I/O device ".$hmccu_hash->{NAME} if ($rc == 2);
return "Can't assign I/O device ".$ioHash->{NAME} if ($rc == 2);
return undef;
}
@ -223,7 +223,7 @@ sub HMCCUCHN_Set ($@)
return "No set command specified" if (!defined ($opt));
my $rocmds = "clear defaults:noArg";
my $rwcmds = "clear config control datapoint defaults:noArg paramset devstate";
my $rwcmds = "clear config control datapoint defaults:noArg paramset link devstate values";
# Get I/O device, check device state
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
@ -234,9 +234,9 @@ sub HMCCUCHN_Set ($@)
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME};
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?');
return "HMCCUCHN: CCU busy";
}
@ -419,20 +419,31 @@ sub HMCCUCHN_Set ($@)
HMCCU_DeleteReadings ($hash, $rnexp);
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'paramset' || $opt eq 'rpcparameter' || $opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name rpcparameter [device] [paramset] {parameter}={value}[:{type}] [...]")
elsif ($opt =~ /^(paramset|rpcparameter|config|link|values)$/) {
my %parSets = ('config' => 'MASTER', 'links' => 'LINK', 'values' => 'VALUES');
my $paramset = '';
return HMCCU_SetError ($hash, "Usage: set $name $opt [device] [paramset] {parameter}={value}[:{type}] [...]")
if ((scalar keys %{$h}) < 1);
if (exists($parSets{$opt})) {
$paramset = $parSets{$opt};
}
my $ccuobj = $ccuaddr;
my $p = shift @$a;
if (defined($p) && $p eq 'device') {
($ccuobj, undef) = HMCCU_SplitChnAddr ($ccuaddr);
$p = shift @$a;
}
my $paramset = defined($p) ? uc($p) : ($opt eq 'config' ? 'MASTER' : 'VALUES');
my $devDesc = HMCCU_GetDeviceDesc ($hmccu_hash, $ccuobj, $ccuif);
if ($opt =~ /(paramset|rpcparameter)/) {
return HMCCU_SetError ($hash, "Command $opt requires a parameter set")
if (!defined($p));
$paramset = $p;
}
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuobj, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description")
if (!defined($devDesc));
return HMCCU_SetError ($hash, "Paramset $paramset not supported by device")
@ -492,9 +503,9 @@ sub HMCCUCHN_Get ($@)
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME};
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME};
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?');
return "HMCCUCHN: CCU busy";
}
@ -552,67 +563,77 @@ sub HMCCUCHN_Get ($@)
return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result);
}
elsif ($opt eq 'config' || $opt eq 'configlist') {
my $ccuobj = $ccuaddr;
my $method = $opt eq 'config' ? 'getParamset' : 'listRawParamset';
elsif ($opt =~ /^(paramset|paramsetlist|config|links|values)$/) {
my $defParamset = '';
my $method = $opt =~ /list$/ ? 'listRawParamset' : 'getRawParamset';
my %parSets = ('config' => 'MASTER', 'links' => 'LINK', 'values' => 'VALUES',
'configlist' => 'MASTER');
my ($devAddr, undef) = HMCCU_SplitChnAddr ($ccuaddr);
my @addList = ();
my @addList = ($devAddr, "$devAddr:0", $ccuaddr);
my $par = shift @$a;
if (defined ($par)) {
if ($par eq 'device') {
push (@addList, $devAddr);
$par = shift @$a;
}
elsif ($par eq 'channel') {
$par = shift @$a;
}
}
if (scalar(@addList) == 0) {
push (@addList, "$devAddr:0", $ccuaddr);
if (exists($parSets{$opt})) {
$defParamset = $parSets{$opt};
}
my $paramset = 'ALL';
if (defined($par)) {
$paramset = $par;
$par = shift @$a;
else {
if (defined($par)) {
$defParamset = $par;
$par = shift @$a;
}
}
$par = '.*' if (!defined ($par));
my $res = '';
my %objects;
foreach my $a (@addList) {
my $devDesc = HMCCU_GetDeviceDesc ($hmccu_hash, $a, $ccuif);
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
my $paramset = $defParamset eq '' ? $devDesc->{PARAMSETS} : $defParamset;
my ($da, $dc) = HMCCU_SplitChnAddr ($a);
$dc = 'd' if ($dc eq '');
$res .= $a eq $devAddr ? "Device $a\n" : "Channel $a\n";
foreach my $ps (split (',', $devDesc->{PARAMSETS})) {
next if (($ps ne $paramset && $paramset ne 'ALL') || ($ps ne 'MASTER' && $ps ne 'LINK'));
foreach my $ps (split (',', $paramset)) {
next if ($devDesc->{PARAMSETS} !~ /$ps/);
$res .= " Paramset $ps\n";
($rc, $result) = HMCCU_RPCRequest ($hash, $method, $a, $ps, undef, $par);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
$res .= $opt eq 'config' ?
$result :
join ("\n", map { $_ =~ /$par/ ?
" ".$_.' = '.HMCCU_GetParamValue ($hmccu_hash, $devDesc, $ps, $_, $result->{$_}) : ()
} sort keys %$result)."\n";
if ($opt =~ /list$/) {
$res .= join ("\n", map { $_ =~ /$par/ ?
" ".$_.' = '.HMCCU_GetParamValue ($ioHash, $devDesc, $ps, $_, $result->{$_}) : ()
} sort keys %$result)."\n";
}
else {
foreach my $p (keys %$result) { $objects{$da}{$dc}{$ps}{$p} = $result->{$p}; }
}
}
}
return $ccureadings && $opt eq 'config' ? undef : $res;
if ($opt !~ /list$/ && scalar(keys %objects) > 0) {
my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $hash, \%objects);
if (defined($convRes)) {
$res .= join ("\n", map { $_ =~ /$par/ ?
" ".$_.' = '.$convRes->{$_} : ()
} sort keys %$convRes)."\n";
}
}
return (!$ccureadings || $opt =~ /list$/) ? $res : undef;
}
elsif ($opt eq 'paramsetdesc') {
my $ccuobj = $ccuaddr;
my $par = shift @$a;
my ($devAddr, $chnNo) = HMCCU_SplitChnAddr ($ccuaddr);
$chnNo = 'd' if (defined ($par) && $par eq 'device');
my $model = HMCCU_GetClientDeviceModel ($hash);
return HMCCU_SetError ($hash, "Can't get device model") if (!defined($model));
my $res = '';
foreach my $c (sort keys %{$model}) {
next if (($chnNo eq 'd' && $c ne 'd') || ($chnNo ne 'd' && $c ne '0' && $c ne $chnNo));
# my @chnList = sort keys %{$model};
my @chnList = ('d', 0, $chnNo);
# unshift (@chnList, pop(@chnList)) if (exists($model->{'d'}));
foreach my $c (@chnList) {
$res .= $c eq 'd' ? "Device\n" : "Channel $c\n";
foreach my $ps (sort keys %{$model->{$c}}) {
$res .= " Paramset $ps\n";
@ -633,26 +654,20 @@ sub HMCCUCHN_Get ($@)
elsif ($opt eq 'devicedesc') {
my $ccuobj = $ccuaddr;
my $par = shift @$a;
my @addList = ();
my ($devAddr, $chnNo) = HMCCU_SplitChnAddr ($ccuaddr);
if (defined($par) && $par eq 'device') {
push (@addList, $devAddr);
}
else {
push (@addList, "$devAddr:0");
push (@addList, $ccuaddr);
}
my @addList = ($devAddr, "$devAddr:0", $ccuaddr);
$result = '';
foreach my $a (@addList) {
my $devDesc = HMCCU_GetDeviceDesc ($hmccu_hash, $a, $ccuif);
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description")
if (!defined($devDesc));
$result .= $a eq $devAddr ? "Device $a\n" : "Channel $a\n";
$result .= $a eq $devAddr ? "Device $a" : "Channel $a";
$result .= " $devDesc->{_name} [$devDesc->{TYPE}]\n";
foreach my $n (sort keys %{$devDesc}) {
next if ($n =~ /^_/);
next if ($n =~ /^_/ || $n eq 'ADDRESS' || $n eq 'TYPE' ||
!defined($devDesc->{$n}) || $devDesc->{$n} eq '');
$result .= " $n: ".HMCCU_FlagsToStr ('device', $n, $devDesc->{$n}, ',', '')."\n";
}
}
@ -669,8 +684,8 @@ sub HMCCUCHN_Get ($@)
my @valuelist;
my $valuecount = HMCCU_GetValidDatapoints ($hash, $hash->{ccutype}, $c, 1, \@valuelist);
$retmsg .= ":".join(",",@valuelist) if ($valuecount > 0);
$retmsg .= " update:noArg deviceinfo:noArg config configlist:channel,device".
" devicedesc:channel,device paramsetdesc:channel,device";
$retmsg .= " update:noArg deviceinfo:noArg config links".
" devicedesc:noArg paramset paramsetlist paramsetdesc:noArg values";
return $retmsg;
}
@ -720,7 +735,7 @@ sub HMCCUCHN_Get ($@)
Readings 'state' and 'control' are not deleted.
</li><br/>
<li><b>set &lt;name&gt; config</b><br/>
Alias for command 'set paramset' with default value for parameter set = 'MASTER'.
Alias for command 'set paramset' for parameter set MASTER.
</li><br/>
<li><b>set &lt;name&gt; datapoint &lt;datapoint&gt; &lt;value&gt; [...]</b><br/>
Set datapoint values of a CCU channel. If parameter <i>value</i> contains special
@ -745,6 +760,9 @@ sub HMCCUCHN_Get ($@)
Decrement value of datapoint LEVEL. This command is only available if channel contains
a datapoint LEVEL. Default for <i>value</i> is 10.
</li><br/>
<li><b>set &lt;name&gt; link</b><br/>
Alias for command 'set paramset' for parameter set LINK.
</li><br/>
<li><b>set &lt;name&gt; &lt;statevalue&gt;</b><br/>
Set state of a CCU device channel to <i>StateValue</i>. The state datapoint of a channel
must be defined by setting attribute 'statedatapoint'. The available state values must
@ -781,7 +799,8 @@ sub HMCCUCHN_Get ($@)
Parameter <i>paramset</i> is a valid parameter set name (i.e. MASTER, LINK, ...). The
default parameter set is 'VALUES'.
Supports attribute 'ccuscaleval' for datapoints. Parameter <i>parameter</i> must be a valid
datapoint or config parameter name. The default <i>type</i> is STRING.
datapoint or config parameter name. If <i>type</i> is not specified, it's taken from
parameter set definition. The default <i>type</i> is STRING.
Valid types are STRING, BOOL, INTEGER, FLOAT, DOUBLE.
</li><br/>
<li><b>set &lt;name&gt; pct &lt;value&gt; [&lt;ontime&gt; [&lt;ramptime&gt;]]</b><br/>
@ -818,21 +837,17 @@ sub HMCCUCHN_Get ($@)
Increment value of datapoint LEVEL. This command is only available if channel contains
a datapoint LEVEL. Default for <i>value</i> is 10.
</li><br/>
<li><b>set &lt;name&gt; values</b><br/>
Alias for command 'set paramset' for parameter set VALUES.
</li>
</ul>
<br/>
<a name="HMCCUCHNget"></a>
<b>Get</b><br/><br/>
<ul>
<li><b>get &lt;name&gt; config [<u>channel</u>|device] [&lt;paramset&gt;|<u>ALL</u>] [&lt;filter-expr&gt;]</b><br/>
Get configuration parameters of CCU channel. If attribute 'ccureadings' is 0 results
are displayed in browser window. Otherwise they are stored as readings beginning with "R_".
Parameters can be filtered by <i>filter-expr</i>.
If option 'device' is specified parameters of device are read. Without option 'device'
parameters of current channel and channel 0 are read.
</li><br/>
<li><b>get &lt;name&gt; configlist [<u>channel</u>|device] [&lt;paramset&gt;|<u>ALL</u>] [&lt;filter-expr&gt;]</b><br/>
Same as 'get config' without storing parameters as readings.
<li><b>get &lt;name&gt; config [&lt;filter-expr&gt;]</b><br/>
Same as 'get paramset', but read only parameter set MASTER.
</li><br/>
<li><b>get &lt;name&gt; datapoint &lt;datapoint&gt;</b><br/>
Get value of a CCU channel datapoint.
@ -840,7 +855,7 @@ sub HMCCUCHN_Get ($@)
<li><b>get &lt;name&gt; defaults</b><br/>
Display default attributes for CCU device type.
</li><br/>
<li><b>get &lt;name&gt; devicedesc [<u>channel</u>|device]</b><br/>
<li><b>get &lt;name&gt; devicedesc</b><br/>
Display device or channel description. A channel description always includes channel 0.
</li><br/>
<li><b>get &lt;name&gt; deviceinfo</b><br/>
@ -851,12 +866,32 @@ sub HMCCUCHN_Get ($@)
attribute 'statedatapoint'. Command will fail if state datapoint does not exist in
channel.
</li><br/>
<li><b>get &lt;name&gt; paramsetdesc [<u>channel</u>|device]</b><br/>
Display description of parameter sets of CCU channel or device.
<li><b>get &lt;name&gt; links [&lt;filter-expr&gt;]</b><br/>
Same as 'get paramset', but read only parameter set LINK.
</li><br/>
<li><b>get &lt;name&gt; paramset [&lt;paramset&gt;[,...]] [&lt;filter-expr&gt;]</b><br/>
Get parameters from all or specific parameter sets of device and channel.
If attribute 'ccureadings' is 0 results are displayed in browser window. Otherwise
they are stored as readings beginning with "R-" for MASTER parameters and "L-" for
LINK parameters. Values from other parameter sets are stored without prefix.
Prefixes can be modified with attribute 'ccuReadingPrefix'. If no <i>paramset</i>
is specified, all parameter sets will be read.
Parameters can be filtered by <i>filter-expr</i>. If option 'device' is specified parameters
of device are read. Without option 'device' parameters of current channel and channel 0 are read.
</li><br/>
<li><b>get &lt;name&gt; paramsetdesc</b><br/>
Display description of parameter sets of channel and device.
</li><br/>
<li><b>get &lt;name&gt; paramsetlist [&lt;paramset&gt;[,...]] [&lt;filter-expr&gt;]</b><br/>
Same as 'get paramset' without storing parameters as readings.
</li><br/>
<li><b>get &lt;name&gt; update [{State | <u>Value</u>}]</b><br/>
Update all datapoints / readings of channel. With option 'State' the device is queried.
This request method is more accurate but slower then 'Value'.
</li><br/>
<li><b>get &lt;name&gt; values [&lt;filter-expr&gt;]</b><br/>
Same as 'get update' but using RPC instead of ReGa. Datapoint read from CCU can be
filtered by <i>filter-expr</i>.
</li>
</ul>
<br/>
@ -955,6 +990,9 @@ sub HMCCUCHN_Get ($@)
attr mydev ccureadingname [1-4].PRESSED_SHORT:+pressed
</code>
</li><br/>
<li><b>ccuReadingPrefix &lt;paramset&gt;:&lt;prefix&gt;[,...]</b><br/>
Set reading name prefix for parameter sets.
</li><br/>
<li><b>ccuscaleval &lt;[channelno.]datapoint&gt;:&lt;factor&gt;[,...]</b><br/>
<b>ccuscaleval &lt;[!][channelno.]datapoint&gt;:&lt;min&gt;:&lt;max&gt;:&lt;minn&gt;:&lt;maxn&gt;[,...]
</b><br/>
@ -1082,8 +1120,9 @@ sub HMCCUCHN_Get ($@)
</li><br/>
<li><b>substitute &lt;subst-rule&gt;[;...]</b><br/>
Define substitutions for datapoint/reading values. Syntax of <i>subst-rule</i> is<br/><br/>
[[&lt;channelno&gt;.]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
[[&lt;type&gt;:][&lt;channelno&gt;.]&lt;datapoint&gt;[,...]!]&lt;{#n1-m1|regexp}&gt;:&lt;text&gt;[,...]
<br/><br/>
Parameter <i>type</i> is a valid channel type, i.e. "SHUTTER_CONTACT".
Parameter <i>text</i> can contain variables in format ${<i>varname</i>}. The variable
${value} is
substituted by the original datapoint value. All other variables must match with a valid

View File

@ -83,7 +83,7 @@ sub HMCCUDEV_Define ($@)
my $devtype = shift @$a;
my $devspec = shift @$a;
my $hmccu_hash = undef;
my $ioHash = undef;
# Store some definitions for delayed initialization
$hash->{hmccu}{devspec} = $devspec;
@ -120,16 +120,16 @@ sub HMCCUDEV_Define ($@)
return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists ($defs{$h->{iodev}}));
return "Specified IO Device ".$h->{iodev}." is not a HMCCU device"
if ($defs{$h->{iodev}}->{TYPE} ne 'HMCCU');
$hmccu_hash = $defs{$h->{iodev}};
$ioHash = $defs{$h->{iodev}};
}
else {
# The following call will fail for non virtual devices during FHEM start if CCU is not ready
$hmccu_hash = $devspec eq 'virtual' ? HMCCU_GetHash (0) : HMCCU_FindIODevice ($devspec);
$ioHash = $devspec eq 'virtual' ? HMCCU_GetHash (0) : HMCCU_FindIODevice ($devspec);
}
if ($init_done) {
# Interactive define command while CCU not ready
if (!defined ($hmccu_hash)) {
if (!defined ($ioHash)) {
my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
if ($ccuinactive > 0) {
return "CCU and/or IO device not ready. Please try again later";
@ -141,7 +141,7 @@ sub HMCCUDEV_Define ($@)
}
else {
# CCU not ready during FHEM start
if (!defined ($hmccu_hash) || $hmccu_hash->{ccustate} ne 'active') {
if (!defined ($ioHash) || $ioHash->{ccustate} ne 'active') {
Log3 $name, 2, "HMCCUDEV: [$devname] Cannot detect IO device, maybe CCU not ready. Trying later ...";
# readingsSingleUpdate ($hash, "state", "Pending", 1);
$hash->{ccudevstate} = 'pending';
@ -150,7 +150,7 @@ sub HMCCUDEV_Define ($@)
}
# Initialize FHEM device, set IO device
my $rc = HMCCUDEV_InitDevice ($hmccu_hash, $hash);
my $rc = HMCCUDEV_InitDevice ($ioHash, $hash);
return $errmsg[$rc] if ($rc > 0);
return undef;
@ -171,7 +171,7 @@ sub HMCCUDEV_Define ($@)
sub HMCCUDEV_InitDevice ($$)
{
my ($hmccu_hash, $dev_hash) = @_;
my ($ioHash, $dev_hash) = @_;
my $name = $dev_hash->{NAME};
my $devspec = $dev_hash->{hmccu}{devspec};
my $gdcount = 0;
@ -187,7 +187,7 @@ sub HMCCUDEV_InitDevice ($$)
# Search for free address. Maximum of 10000 virtual devices allowed.
for (my $i=1; $i<=10000; $i++) {
my $va = sprintf ("VIR%07d", $i);
if (!HMCCU_IsValidDevice ($hmccu_hash, $va, 1)) {
if (!HMCCU_IsValidDevice ($ioHash, $va, 1)) {
$no = $i;
last;
}
@ -200,9 +200,9 @@ sub HMCCUDEV_InitDevice ($$)
$dev_hash->{ccuname} = $name;
}
else {
return 1 if (!HMCCU_IsValidDevice ($hmccu_hash, $devspec, 7));
return 1 if (!HMCCU_IsValidDevice ($ioHash, $devspec, 7));
my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($hmccu_hash, $devspec);
my ($di, $da, $dn, $dt, $dc) = HMCCU_GetCCUDeviceParam ($ioHash, $devspec);
return 1 if (!defined ($da));
$gdname = $dn;
@ -218,7 +218,7 @@ sub HMCCUDEV_InitDevice ($$)
my @devlist = ();
if (exists ($dev_hash->{hmccu}{groupexp})) {
# Group devices specified by name expression
$gdcount = HMCCU_GetMatchingDevices ($hmccu_hash, $dev_hash->{hmccu}{groupexp}, 'dev', \@devlist);
$gdcount = HMCCU_GetMatchingDevices ($ioHash, $dev_hash->{hmccu}{groupexp}, 'dev', \@devlist);
return 4 if ($gdcount == 0);
}
elsif (exists ($dev_hash->{hmccu}{group})) {
@ -228,9 +228,9 @@ sub HMCCUDEV_InitDevice ($$)
foreach my $gd (@gdevlist) {
my ($gda, $gdc, $gdo) = ('', '', '', '');
return 1 if (!HMCCU_IsValidDevice ($hmccu_hash, $gd, 7));
return 1 if (!HMCCU_IsValidDevice ($ioHash, $gd, 7));
($gda, $gdc) = HMCCU_GetAddress ($hmccu_hash, $gd, '', '');
($gda, $gdc) = HMCCU_GetAddress ($ioHash, $gd, '', '');
$gdo = $gda;
$gdo .= ':'.$gdc if ($gdc ne '');
push @devlist, $gdo;
@ -239,7 +239,7 @@ sub HMCCUDEV_InitDevice ($$)
}
else {
# Group specified by CCU virtual group name
@devlist = HMCCU_GetGroupMembers ($hmccu_hash, $gdname);
@devlist = HMCCU_GetGroupMembers ($ioHash, $gdname);
$gdcount = scalar (@devlist);
}
@ -248,10 +248,10 @@ sub HMCCUDEV_InitDevice ($$)
$dev_hash->{ccugroup} = join (',', @devlist);
if ($devspec eq 'virtual') {
my $dev = shift @devlist;
my $devtype = HMCCU_GetDeviceType ($hmccu_hash, $dev, 'n/a');
my $devtype = HMCCU_GetDeviceType ($ioHash, $dev, 'n/a');
my $devna = $devtype eq 'n/a' ? 1 : 0;
for my $d (@devlist) {
if (HMCCU_GetDeviceType ($hmccu_hash, $d, 'n/a') ne $devtype) {
if (HMCCU_GetDeviceType ($ioHash, $d, 'n/a') ne $devtype) {
$devna = 1;
last;
}
@ -261,11 +261,11 @@ sub HMCCUDEV_InitDevice ($$)
if ($devna) {
$dev_hash->{ccutype} = 'n/a';
$dev_hash->{statevals} = 'readonly';
$rc = HMCCU_CreateDevice ($hmccu_hash, $dev_hash->{ccuaddr}, $name, undef, $dev);
$rc = HMCCU_CreateDevice ($ioHash, $dev_hash->{ccuaddr}, $name, undef, $dev);
}
else {
$dev_hash->{ccutype} = $devtype;
$rc = HMCCU_CreateDevice ($hmccu_hash, $dev_hash->{ccuaddr}, $name, $devtype, $dev);
$rc = HMCCU_CreateDevice ($ioHash, $dev_hash->{ccuaddr}, $name, $devtype, $dev);
}
return $rc+4 if ($rc > 0);
@ -275,7 +275,7 @@ sub HMCCUDEV_InitDevice ($$)
}
# Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($dev_hash, $hmccu_hash->{NAME}, undef));
return 2 if (!HMCCU_AssignIODevice ($dev_hash, $ioHash->{NAME}, undef));
# readingsSingleUpdate ($dev_hash, "state", "Initialized", 1);
$dev_hash->{ccudevstate} = 'active';
@ -347,8 +347,8 @@ sub HMCCUDEV_Set ($@)
# Get I/O device, check device state
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME};
my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME};
# Handle read only and disabled devices
return undef if ($hash->{statevals} eq 'readonly' && $opt ne '?'
@ -357,7 +357,7 @@ sub HMCCUDEV_Set ($@)
return undef if ($disable == 1);
# Check if CCU is busy
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?');
return "HMCCUDEV: CCU busy";
}
@ -670,15 +670,15 @@ sub HMCCUDEV_Get ($@)
# Get I/O device
return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME};
my $ioHash = $hash->{IODev};
my $hmccu_name = $ioHash->{NAME};
# Handle disabled devices
my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1);
# Check if CCU is busy
if (HMCCU_IsRPCStateBlocking ($hmccu_hash)) {
if (HMCCU_IsRPCStateBlocking ($ioHash)) {
return undef if ($opt eq '?');
return "HMCCUDEV: CCU busy";
}
@ -816,43 +816,55 @@ sub HMCCUDEV_Get ($@)
}
return $res;
}
elsif ($opt eq 'configdesc') {
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par)) {
if ($par =~ /^([0-9]{1,2})$/) {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
$ccuobj .= ':'.$1;
}
else {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
elsif ($opt eq 'paramsetdesc') {
my ($devAddr, $chnNo) = HMCCU_SplitChnAddr ($ccuaddr);
my $model = HMCCU_GetClientDeviceModel ($hash);
return HMCCU_SetError ($hash, "Can't get device model") if (!defined($model));
my $res = '';
my @chnList = sort keys %{$model};
unshift (@chnList, pop(@chnList)) if (exists($model->{'d'}));
foreach my $c (@chnList) {
$res .= $c eq 'd' ? "Device\n" : "Channel $c\n";
foreach my $ps (sort keys %{$model->{$c}}) {
$res .= " Paramset $ps\n";
$result = join ("\n", map {
" ".$_.": ".
$model->{$c}{$ps}{$_}{TYPE}.
" [".HMCCU_FlagsToStr ('model', 'OPERATIONS', $model->{$c}{$ps}{$_}{OPERATIONS}, ',', '')."]".
" [".HMCCU_FlagsToStr ('model', 'FLAGS', $model->{$c}{$ps}{$_}{FLAGS}, ',', '')."]".
" RANGE=".$model->{$c}{$ps}{$_}{MIN}."-".$model->{$c}{$ps}{$_}{MAX}.
" DFLT=".$model->{$c}{$ps}{$_}{DEFAULT}.
" UNIT=".$model->{$c}{$ps}{$_}{UNIT}
} sort keys %{$model->{$c}{$ps}});
$res .= "$result\n";
}
}
my $res = "MASTER:\n";
($rc, $result) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
$res .= "$result\nLINK:\n";
($rc, $result) = HMCCU_RPCRequest ($hash, "getParamsetDescription", $ccuobj, "MASTER", undef);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
return $res.$result;
return $res;
}
elsif ($opt eq 'devicedesc') {
my $ccuobj = $ccuaddr;
my $par = shift @$a;
if (defined ($par)) {
if ($par =~ /^([0-9]{1,2})$/) {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
$ccuobj .= ':'.$1;
}
else {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{channels});
}
}
my $devDesc = HMCCU_GetDeviceDesc ($ioHash, $ccuaddr, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
my @addList = ();
push (@addList, split (',', $devDesc->{CHILDREN}))
if (defined($devDesc->{CHILDREN}) && $devDesc->{CHILDREN} ne '');
($rc, $result) = HMCCU_RPCRequest ($hash, "getDeviceDescription", $ccuobj, "MASTER", undef);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
my $a = $ccuaddr;
$result = '';
while (1) {
$result .= $a eq $ccuaddr ? "Device $a" : "Channel $a";
$result .= " $devDesc->{_name} [$devDesc->{TYPE}]\n";
foreach my $n (sort keys %{$devDesc}) {
next if ($n =~ /^_/ || $n eq 'ADDRESS' || $n eq 'TYPE' ||
!defined($devDesc->{$n}) || $devDesc->{$n} eq '');
$result .= " $n: ".HMCCU_FlagsToStr ('device', $n, $devDesc->{$n}, ',', '')."\n";
}
$a = shift (@addList);
last if (!defined($a));
$devDesc = HMCCU_GetDeviceDesc ($ioHash, $a, $ccuif);
return HMCCU_SetError ($hash, "Can't get device description") if (!defined($devDesc));
}
return $result;
}
elsif ($opt eq 'defaults') {
@ -866,7 +878,7 @@ sub HMCCUDEV_Get ($@)
my $valuecount = HMCCU_GetValidDatapoints ($hash, $ccutype, -1, 1, \@valuelist);
$retmsg .= ":".join(",", @valuelist) if ($valuecount > 0);
$retmsg .= " defaults:noArg update:noArg config configlist configdesc devicedesc".
$retmsg .= " defaults:noArg update:noArg config configlist paramsetdesc:noArg devicedesc:noArg".
" deviceinfo:noArg";
$retmsg .= ' devstate:noArg' if ($sc ne '');

View File

@ -404,13 +404,13 @@ sub HMCCURPCPROC_InitDevice ($$) {
}
# Read RPC device descriptions
if ($dev_hash->{rpcinterface} ne 'CUxD') {
HMCCU_Log ($dev_hash, 1, "Updating internal device tables");
HMCCU_ResetDeviceTables ($hmccu_hash, $dev_hash->{rpcinterface});
my $cd = HMCCURPCPROC_GetDeviceDesc ($dev_hash);
my $cm = HMCCURPCPROC_GetParamsetDesc ($dev_hash);
HMCCU_Log ($dev_hash, 1, "Read $cd channel and device descriptions and $cm device models from CCU");
}
if ($dev_hash->{rpcinterface} ne 'CUxD') {
HMCCU_Log ($dev_hash, 1, "Updating internal device tables");
HMCCU_ResetDeviceTables ($hmccu_hash, $dev_hash->{rpcinterface});
my $cd = HMCCURPCPROC_GetDeviceDesc ($dev_hash);
my $cm = HMCCURPCPROC_GetParamsetDesc ($dev_hash);
HMCCU_Log ($dev_hash, 1, "Read $cd channel and device descriptions and $cm device models from CCU");
}
# RPC device ready
HMCCURPCPROC_ResetRPCState ($dev_hash);