2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

HMCCU: Update for version 4.4 beta

git-svn-id: https://svn.fhem.de/fhem/trunk@21618 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2020-04-07 18:45:11 +00:00
parent c44ddf34df
commit 7c38251b57
5 changed files with 526 additions and 540 deletions

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCU.pm 18745 2019-02-26 17:33:23Z zap $
#
# Version 4.4.014
# Version 4.4.016
#
# Module for communication between FHEM and Homematic CCU2/3.
#
@ -56,7 +56,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.4.014';
my $HMCCU_VERSION = '4.4.016';
# Constants and default values
my $HMCCU_MAX_IOERRORS = 100;
@ -210,7 +210,6 @@ sub HMCCU_AggregationRules ($$);
# Handling of default attributes
sub HMCCU_DetectDefaults ($$);
sub HMCCU_ExportDefaults ($$);
sub HMCCU_ExportDefaultsCSV ($$);
sub HMCCU_ImportDefaults ($);
sub HMCCU_FindDefaults ($$);
sub HMCCU_GetDefaults ($$);
@ -246,7 +245,7 @@ sub HMCCU_UpdateMultipleDevices ($$);
sub HMCCU_UpdatePeers ($$$$);
sub HMCCU_UpdateParamsetReadings ($$$;$);
sub HMCCU_UpdateSingleDatapoint ($$$$);
sub HMCCU_UpdateSingleDevice ($$$$);
# sub HMCCU_UpdateSingleDevice ($$$$);
# RPC functions
sub HMCCU_EventsTimedOut ($);
@ -343,7 +342,7 @@ sub HMCCU_GetDatapointAttr ($$$$$);
sub HMCCU_GetDatapointCount ($$$);
sub HMCCU_GetDatapointList ($$$);
sub HMCCU_GetSpecialCommands ($$);
sub HMCCU_GetSpecialDatapoints ($$$$$);
sub HMCCU_GetSpecialDatapoints ($);
sub HMCCU_GetStateValues ($$;$);
sub HMCCU_GetSwitchDatapoint ($$$);
sub HMCCU_GetValidDatapoints ($$$$$);
@ -392,7 +391,9 @@ sub HMCCU_GetHMState ($$$);
sub HMCCU_GetIdFromIP ($$);
sub HMCCU_GetTimeSpec ($);
sub HMCCU_FlagsToStr ($$$;$$);
sub HMCCU_Max ($$);
sub HMCCU_MaxHashEntries ($$);
sub HMCCU_Min ($$);
sub HMCCU_RefToString ($);
sub HMCCU_ResolveName ($$);
sub HMCCU_TCPConnect ($$);
@ -434,10 +435,10 @@ sub HMCCU_Initialize ($)
$hash->{AttrList} = "stripchar stripnumber ccuaggregate:textField-long".
" ccudefaults rpcinterfaces:multiple-strict,".join(',',sort keys %HMCCU_RPC_PORT).
" ccudef-hmstatevals:textField-long ccudef-substitute:textField-long".
" ccudef-readingname:textField-long ccudef-readingfilter:textField-long".
" ccudef-readingfilter:textField-long".
" ccudef-readingformat:name,namelc,address,addresslc,datapoint,datapointlc".
" ccudef-stripnumber ccuReadingPrefix".
" ccuflags:multiple-strict,procrpc,dptnocheck,logCommand,noagg,nohmstate,".
" ccuflags:multiple-strict,procrpc,dptnocheck,logCommand,noagg,nohmstate,updGroupMembers,".
"logEvents,noEvents,noInitialUpdate,noReadings,nonBlocking,reconnect,logPong,trace".
" ccuReqTimeout ccuGetVars rpcinterval:2,3,5,7,10 rpcqueue rpcPingCCU".
" rpcport:multiple-strict,".join(',',sort keys %HMCCU_RPC_NUMPORT).
@ -907,80 +908,6 @@ sub HMCCU_ExportDefaults ($$)
return 1;
}
######################################################################
# Export default attributes as CSV file.
######################################################################
sub HMCCU_ExportDefaultsCSV ($$)
{
my ($filename, $all) = @_;
my %attrlist = (
'_type' => '', '_description' => '', '_channels' => '',
'ccureadingfilter' => '', 'ccureadingname' => '', 'ccuscaleval' => '', 'cmdIcon' => '', 'controldatapoint' => '',
'eventMap' => '', 'event-on-change-reading' => '', 'event-on-update-reading' => '',
'genericDeviceType' => '',
'hmstatevals' => '',
'statedatapoint' => '', 'statevals' => '', 'stripnumber' => '', 'substexcl' => '', 'substitute' => '',
'webCmd' => '', 'widgetOverride' => ''
);
return 0 if (!open (DEFFILE, ">$filename"));
# Write header
print DEFFILE "_flag,".join (',', sort keys %attrlist)."\n";
# Write channel configurations
foreach my $t (keys %{$HMCCU_CHN_DEFAULTS}) {
print DEFFILE "C";
$attrlist{'_type'} = $t;
foreach $a (sort keys %attrlist) {
my $v = exists ($HMCCU_CHN_DEFAULTS->{$t}{$a}) ? $HMCCU_CHN_DEFAULTS->{$t}{$a} : $attrlist{$a};
print DEFFILE ",\"$v\"";
}
print DEFFILE "\n";
}
# Write device configurations
foreach my $t (keys %{$HMCCU_DEV_DEFAULTS}) {
print DEFFILE "D";
$attrlist{'_type'} = $t;
foreach $a (sort keys %attrlist) {
my $v = exists ($HMCCU_DEV_DEFAULTS->{$t}{$a}) ? $HMCCU_DEV_DEFAULTS->{$t}{$a} : $attrlist{$a};
print DEFFILE ",\"$v\"";
}
print DEFFILE "\n";
}
if ($all) {
# Write channel configurations
foreach my $t (keys %HMCCU_CUST_CHN_DEFAULTS) {
print DEFFILE "C";
$attrlist{'_type'} = $t;
foreach $a (sort keys %attrlist) {
my $v = exists ($HMCCU_CUST_CHN_DEFAULTS{$t}{$a}) ? $HMCCU_CUST_CHN_DEFAULTS{$t}{$a} : $attrlist{$a};
print DEFFILE ",\"$v\"";
}
print DEFFILE "\n";
}
# Write device configurations
foreach my $t (keys %HMCCU_CUST_DEV_DEFAULTS) {
print DEFFILE "D";
$attrlist{'_type'} = $t;
foreach $a (sort keys %attrlist) {
my $v = exists ($HMCCU_CUST_DEV_DEFAULTS{$t}{$a}) ? $HMCCU_CUST_DEV_DEFAULTS{$t}{$a} : $attrlist{$a};
print DEFFILE ",\"$v\"";
}
print DEFFILE "\n";
}
}
close (DEFFILE);
return 1;
}
######################################################################
# Import customer default attributes
# Returns 1 on success. Returns negative line number on syntax errors.
@ -1451,7 +1378,7 @@ sub HMCCU_DelayedShutdown ($)
# HMCCU_Log ($hash, 3, "DelayedShutdown()");
my $delay = max (AttrVal ("global", "maxShutdownDelay", 10)-2, 0);
my $delay = HMCCU_Max (AttrVal ("global", "maxShutdownDelay", 10)-2, 0);
# Shutdown RPC server
if (!exists ($hash->{hmccu}{delayedShutdown})) {
@ -1657,7 +1584,7 @@ sub HMCCU_Set ($@)
foreach my $devName (@devList) {
my $dh = $defs{$devName};
my $ccuif = $dh->{ccuif};
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($dh, '', '', '', '');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($dh);
my $stateVals = HMCCU_GetStateValues ($dh, $cd, $cc);
if ($dh->{TYPE} eq 'HMCCUCHN') {
@ -2158,19 +2085,14 @@ sub HMCCU_Get ($@)
}
elsif ($opt eq 'exportdefaults') {
my $filename = shift @$a;
$usage = "Usage: get $name $opt filename ['all'] ['csv']";
my $csv = 0;
$usage = "Usage: get $name $opt filename ['all']";
my $all = 0;
foreach my $defopt (@$a) {
if ($defopt eq 'csv') { $csv = 1; }
elsif ($defopt eq 'all') { $all = 1; }
else { return HMCCU_SetError ($hash, $usage); }
}
my $defopt = shift @$a;
$all = 1 if (defined($defopt) && $defopt eq 'all');
return HMCCU_SetError ($hash, $usage) if (!defined ($filename));
my $rc = $csv ? HMCCU_ExportDefaultsCSV ($filename, $all) : HMCCU_ExportDefaults ($filename, $all);
my $rc = HMCCU_ExportDefaults ($filename, $all);
return HMCCU_SetError ($hash, -16) if ($rc == 0);
return HMCCU_SetState ($hash, "OK", "Default attributes written to $filename");
}
@ -2559,9 +2481,10 @@ sub HMCCU_GetReadingName ($$$$$$$;$)
# Log3 $name, 1, "HMCCU: ChannelNo undefined: Addr=".$a if (!defined ($c));
$rf = HMCCU_GetAttrReadingFormat ($hash, $ioHash) if (!defined ($rf));
my $gsr = AttrVal ($ioHash->{NAME}, 'ccudef-readingname', '');
my $sr = AttrVal ($name, 'ccureadingname', $gsr);
$sr .= ";".$gsr if ($sr ne $gsr && $gsr ne '');
my $sr = 'LEVEL$:pct;SET_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$measured-temp;'.
'SET_POINT_TEMPERATURE$:desired-temp';
my $asr = AttrVal ($name, 'ccureadingname', '');
$sr .= ';'.$asr if ($asr ne '');
# Complete missing values
if ($n eq '' && $a ne '') {
@ -3708,7 +3631,11 @@ sub HMCCU_GetChannelRole ($;$)
return $clHash->{hmccu}{role};
}
elsif ($clHash->{TYPE} eq 'HMCCUDEV') {
if (defined($chnNo)) {
if (!defined($chnNo)) {
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($clHash);
$chnNo = $cc;
}
if ($chnNo ne '') {
foreach my $role (split(',', $clHash->{hmccu}{role})) {
my ($c, $r) = split(':', $role);
return $r if (defined($r) && "$c" eq "$chnNo");
@ -4479,7 +4406,7 @@ sub HMCCU_UpdateParamsetReadings ($$$;$)
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', '', '');
my ($sc, $sd, $cc, $cd, $ss, $cs) = HMCCU_GetSpecialDatapoints ($clHash);
readingsBeginUpdate ($clHash);
@ -4620,141 +4547,141 @@ sub HMCCU_RefreshReadings ($)
# {devaddr}{datapoint} = value
######################################################################
sub HMCCU_UpdateSingleDevice ($$$$)
{
my ($ccuhash, $clthash, $objects, $alref) = @_;
my $ccuname = $ccuhash->{NAME};
my $cltname = $clthash->{NAME};
my $clttype = $clthash->{TYPE};
my $fnc = "UpdateSingleDevice";
return 0 if (!defined ($clthash->{IODev}) || !defined ($clthash->{ccuaddr}));
return 0 if ($clthash->{IODev} != $ccuhash);
# Build list of relevant addresses in object data hash
my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clthash->{ccuaddr});
my @addlist = defined ($alref) ? @$alref : ($devaddr);
# Check if update of device allowed
my $disable = AttrVal ($cltname, 'disable', 0);
my $update = AttrVal ($cltname, 'ccureadings', HMCCU_IsFlag ($cltname, 'noReadings') ? 0 : 1);
return 0 if ($update == 0 || $disable == 1 || $clthash->{ccudevstate} ne 'active');
# Get device parameters and attributes
my $ccuflags = HMCCU_GetFlags ($ccuname);
my $cf = HMCCU_GetFlags ($cltname);
my $peer = AttrVal ($cltname, 'peer', 'null');
my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash);
my ($sc, $st, $cc, $cd, $ss, $cs) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
# Virtual device flag
my $vg = 0;
$vg = 1 if (($clthash->{ccuif} eq 'VirtualDevices' || $clthash->{ccuif} eq 'fhem') &&
exists ($clthash->{ccugroup}));
HMCCU_Trace ($clthash, 2, $fnc, "$cltname Objects = ".join(',', @addlist));
# Store the resulting readings
my %results;
# Updated internal values
my @chkeys = ();
# Update readings of client device with data from address list
readingsBeginUpdate ($clthash);
foreach my $addr (@addlist) {
next if (!exists ($objects->{$addr}));
HMCCU_Trace ($clthash, 2, $fnc, "Processing object $addr");
# Update channels of device
foreach my $chnnum (keys (%{$objects->{$addr}})) {
next if ($clttype eq 'HMCCUCHN' && "$chnnum" ne "$cnum" && "$chnnum" ne "0");
next if ("$chnnum" eq "0" && $cf =~ /nochn0/);
my $chnadd = "$addr:$chnnum";
my $devDesc = HMCCU_GetDeviceDesc ($ccuhash, $chnadd, $clthash->{ccuif});
my $chnType = defined($devDesc) ? $devDesc->{TYPE} : HMCCU_GetChannelRole ($clthash, $chnnum);
# Update datapoints of channel
foreach my $dpt (keys (%{$objects->{$addr}{$chnnum}})) {
my $value = $objects->{$addr}{$chnnum}{$dpt};
next if (!defined ($value));
# Key for storing values in client hash. Indirect updates of virtual devices
# are stored with device address in key.
my $chkey = $devaddr ne $addr ? "$chnadd.$dpt" : "$chnnum.$dpt";
# Store datapoint raw value in device hash
HMCCU_UpdateInternalValues ($clthash, $chkey, 'VALUES', 'VAL', $value);
HMCCU_Trace ($clthash, 2, $fnc, "dev=$cltname, chnadd/object=$chnadd, dpt=$dpt, key=$chkey, value=$value");
if (HMCCU_FilterReading ($clthash, $chnadd, $dpt)) {
# Modify reading name and value
my @readings = HMCCU_GetReadingName ($clthash, '', $addr, $chnnum, $dpt, '', $crf);
my $svalue = HMCCU_ScaleValue ($clthash, $chnnum, $dpt, $value, 0);
my $fvalue = HMCCU_FormatReadingValue ($clthash, $svalue, $dpt);
my $cvalue = HMCCU_Substitute ($fvalue, $clthash, 0, $chnnum, $dpt, $chnType, $devDesc);
$cvalue = HMCCU_GetParamValue ($ccuhash, $devDesc, 'VALUES', $dpt, $fvalue) if ("$fvalue" eq "$cvalue");
# my %calcs = HMCCU_CalculateReading ($clthash, $chkey);
# Store the resulting value after scaling, formatting and substitution
HMCCU_UpdateInternalValues ($clthash, $chkey, 'VALUES', 'SVAL', $cvalue);
push @chkeys, $chkey;
# Store result, but not for indirect updates of virtual devices
$results{$devaddr}{$chnnum}{$dpt} = $cvalue if ($devaddr eq $addr);
HMCCU_Trace ($clthash, 2, $fnc,
"device=$cltname, readings=".join(',', @readings).
", orgvalue=$value value=$cvalue peer=$peer");
# Update readings
if ("$chnnum" ne "0" || $cf =~ /devState/) {
foreach my $rn (@readings) {
HMCCU_BulkUpdate ($clthash, $rn, $fvalue, $cvalue) if ($rn ne '');
}
}
# foreach my $clcr (keys %calcs) {
# HMCCU_BulkUpdate ($clthash, $clcr, $calcs{$clcr}, $calcs{$clcr});
# sub HMCCU_UpdateSingleDevice ($$$$)
# {
# my ($ccuhash, $clthash, $objects, $alref) = @_;
# my $ccuname = $ccuhash->{NAME};
# my $cltname = $clthash->{NAME};
# my $clttype = $clthash->{TYPE};
# my $fnc = "UpdateSingleDevice";
#
# return 0 if (!defined ($clthash->{IODev}) || !defined ($clthash->{ccuaddr}));
# return 0 if ($clthash->{IODev} != $ccuhash);
#
# # Build list of relevant addresses in object data hash
# my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clthash->{ccuaddr});
# my @addlist = defined ($alref) ? @$alref : ($devaddr);
#
# # Check if update of device allowed
# my $disable = AttrVal ($cltname, 'disable', 0);
# my $update = AttrVal ($cltname, 'ccureadings', HMCCU_IsFlag ($cltname, 'noReadings') ? 0 : 1);
# return 0 if ($update == 0 || $disable == 1 || $clthash->{ccudevstate} ne 'active');
#
# # Get device parameters and attributes
# my $ccuflags = HMCCU_GetFlags ($ccuname);
# my $cf = HMCCU_GetFlags ($cltname);
# my $peer = AttrVal ($cltname, 'peer', 'null');
# my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash);
# my ($sc, $st, $cc, $cd, $ss, $cs) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
#
# # Virtual device flag
# my $vg = 0;
# $vg = 1 if (($clthash->{ccuif} eq 'VirtualDevices' || $clthash->{ccuif} eq 'fhem') &&
# exists ($clthash->{ccugroup}));
#
# HMCCU_Trace ($clthash, 2, $fnc, "$cltname Objects = ".join(',', @addlist));
#
# # Store the resulting readings
# my %results;
#
# # Updated internal values
# my @chkeys = ();
#
# # Update readings of client device with data from address list
# readingsBeginUpdate ($clthash);
#
# foreach my $addr (@addlist) {
# next if (!exists ($objects->{$addr}));
#
# HMCCU_Trace ($clthash, 2, $fnc, "Processing object $addr");
#
# # Update channels of device
# foreach my $chnnum (keys (%{$objects->{$addr}})) {
# next if ($clttype eq 'HMCCUCHN' && "$chnnum" ne "$cnum" && "$chnnum" ne "0");
# next if ("$chnnum" eq "0" && $cf =~ /nochn0/);
# my $chnadd = "$addr:$chnnum";
#
# my $devDesc = HMCCU_GetDeviceDesc ($ccuhash, $chnadd, $clthash->{ccuif});
# my $chnType = defined($devDesc) ? $devDesc->{TYPE} : HMCCU_GetChannelRole ($clthash, $chnnum);
#
# # Update datapoints of channel
# foreach my $dpt (keys (%{$objects->{$addr}{$chnnum}})) {
# my $value = $objects->{$addr}{$chnnum}{$dpt};
# next if (!defined ($value));
#
# # Key for storing values in client hash. Indirect updates of virtual devices
# # are stored with device address in key.
# my $chkey = $devaddr ne $addr ? "$chnadd.$dpt" : "$chnnum.$dpt";
#
# # Store datapoint raw value in device hash
# HMCCU_UpdateInternalValues ($clthash, $chkey, 'VALUES', 'VAL', $value);
#
# HMCCU_Trace ($clthash, 2, $fnc, "dev=$cltname, chnadd/object=$chnadd, dpt=$dpt, key=$chkey, value=$value");
#
# if (HMCCU_FilterReading ($clthash, $chnadd, $dpt)) {
# # Modify reading name and value
# my @readings = HMCCU_GetReadingName ($clthash, '', $addr, $chnnum, $dpt, '', $crf);
# my $svalue = HMCCU_ScaleValue ($clthash, $chnnum, $dpt, $value, 0);
# my $fvalue = HMCCU_FormatReadingValue ($clthash, $svalue, $dpt);
# my $cvalue = HMCCU_Substitute ($fvalue, $clthash, 0, $chnnum, $dpt, $chnType, $devDesc);
# $cvalue = HMCCU_GetParamValue ($ccuhash, $devDesc, 'VALUES', $dpt, $fvalue) if ("$fvalue" eq "$cvalue");
# # my %calcs = HMCCU_CalculateReading ($clthash, $chkey);
#
# # Store the resulting value after scaling, formatting and substitution
# HMCCU_UpdateInternalValues ($clthash, $chkey, 'VALUES', 'SVAL', $cvalue);
# push @chkeys, $chkey;
#
# # Store result, but not for indirect updates of virtual devices
# $results{$devaddr}{$chnnum}{$dpt} = $cvalue if ($devaddr eq $addr);
#
# HMCCU_Trace ($clthash, 2, $fnc,
# "device=$cltname, readings=".join(',', @readings).
# ", orgvalue=$value value=$cvalue peer=$peer");
#
# # Update readings
# if ("$chnnum" ne "0" || $cf =~ /devState/) {
# foreach my $rn (@readings) {
# HMCCU_BulkUpdate ($clthash, $rn, $fvalue, $cvalue) if ($rn ne '');
# }
# }
HMCCU_BulkUpdate ($clthash, 'control', $fvalue, $cvalue)
if ($cd ne '' && $dpt eq $cd && $chnnum eq $cc);
HMCCU_BulkUpdate ($clthash, 'state', $fvalue, $cvalue)
if ($dpt eq $st && ($sc eq '' || $sc eq $chnnum));
# Update peers
HMCCU_UpdatePeers ($clthash, "$chnnum.$dpt", $cvalue, $peer) if (!$vg && $peer ne 'null');
}
}
}
}
if (scalar (@chkeys) > 0) {
my %calcs = HMCCU_CalculateReading ($clthash, \@chkeys);
foreach my $clcr (keys %calcs) {
HMCCU_BulkUpdate ($clthash, $clcr, $calcs{$clcr}, $calcs{$clcr});
}
}
# Update device states
my ($devState, $battery, $activity) = HMCCU_GetDeviceStates ($clthash);
HMCCU_BulkUpdate ($clthash, 'battery', $battery, $battery);
HMCCU_BulkUpdate ($clthash, 'activity', $activity, $activity);
HMCCU_BulkUpdate ($clthash, 'devstate', $devState, $devState);
# Calculate and update HomeMatic state
if ($ccuflags !~ /nohmstate/) {
my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cltname, $ccuname, undef);
HMCCU_BulkUpdate ($clthash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
}
readingsEndUpdate ($clthash, 1);
return \%results;
}
# # foreach my $clcr (keys %calcs) {
# # HMCCU_BulkUpdate ($clthash, $clcr, $calcs{$clcr}, $calcs{$clcr});
# # }
# HMCCU_BulkUpdate ($clthash, 'control', $fvalue, $cvalue)
# if ($cd ne '' && $dpt eq $cd && $chnnum eq $cc);
# HMCCU_BulkUpdate ($clthash, 'state', $fvalue, $cvalue)
# if ($dpt eq $st && ($sc eq '' || $sc eq $chnnum));
#
# # Update peers
# HMCCU_UpdatePeers ($clthash, "$chnnum.$dpt", $cvalue, $peer) if (!$vg && $peer ne 'null');
# }
# }
# }
# }
#
# if (scalar (@chkeys) > 0) {
# my %calcs = HMCCU_CalculateReading ($clthash, \@chkeys);
# foreach my $clcr (keys %calcs) {
# HMCCU_BulkUpdate ($clthash, $clcr, $calcs{$clcr}, $calcs{$clcr});
# }
# }
#
# # Update device states
# my ($devState, $battery, $activity) = HMCCU_GetDeviceStates ($clthash);
# HMCCU_BulkUpdate ($clthash, 'battery', $battery, $battery);
# HMCCU_BulkUpdate ($clthash, 'activity', $activity, $activity);
# HMCCU_BulkUpdate ($clthash, 'devstate', $devState, $devState);
#
# # Calculate and update HomeMatic state
# if ($ccuflags !~ /nohmstate/) {
# my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cltname, $ccuname, undef);
# HMCCU_BulkUpdate ($clthash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
# }
#
# readingsEndUpdate ($clthash, 1);
#
# return \%results;
# }
######################################################################
# Store datapoint values in device hash.
@ -4822,21 +4749,25 @@ sub HMCCU_UpdateMultipleDevices ($$)
######################################################################
# Get list of device addresses including group device members.
# For virtual devices group members are only returned if ccuflag
# updGroupMembers is set.
######################################################################
sub HMCCU_GetAffectedAddresses ($)
{
my ($clthash) = @_;
my ($clHash) = @_;
my @addlist = ();
if ($clthash->{TYPE} eq 'HMCCUDEV' || $clthash->{TYPE} eq 'HMCCUCHN') {
if (exists ($clthash->{ccuaddr})) {
my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clthash->{ccuaddr});
if ($clHash->{TYPE} eq 'HMCCUDEV' || $clHash->{TYPE} eq 'HMCCUCHN') {
my $ioHash = HMCCU_GetHash ($clHash);
my $ccuFlags = defined($ioHash) ? HMCCU_GetFlags ($ioHash) : 'null';
if (exists($clHash->{ccuaddr})) {
my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clHash->{ccuaddr});
push @addlist, $devaddr;
}
if (($clthash->{ccuif} eq 'VirtualDevices' || $clthash->{ccuif} eq 'fhem') &&
exists ($clthash->{ccugroup})) {
push @addlist, split (',', $clthash->{ccugroup});
if ((($clHash->{ccuif} eq 'VirtualDevices' && $ccuFlags =~ /updGroupMembers/) ||
$clHash->{ccuif} eq 'fhem') && exists($clHash->{ccugroup})) {
push @addlist, split (',', $clHash->{ccugroup});
}
}
@ -6666,6 +6597,7 @@ sub HMCCU_FindClientDevices ($$$$)
######################################################################
# Check if client device already exists
# Return name of existing device or empty string.
######################################################################
sub HMCCU_ExistsClientDevice ($$)
@ -6680,7 +6612,7 @@ sub HMCCU_ExistsClientDevice ($$)
);
}
return undef;
return '';
}
######################################################################
@ -6927,7 +6859,9 @@ sub HMCCU_SetDefaultAttributes ($;$)
my $clName = $clHash->{NAME};
my $role = HMCCU_GetChannelRole ($clHash, $ctrlChn);
HMCCU_Log ($clHash, 2, "SetDefaultAttributes: role=$role");
if ($role ne '' && exists($HMCCU_ATTR->{$role})) {
HMCCU_Log ($clHash, 2, "SetDefaultAttributes: attributes found");
foreach my $a (keys %{$HMCCU_ATTR->{$role}}) {
CommandAttr (undef, "$clName $a ".$HMCCU_ATTR->{$role}{$a});
}
@ -6984,80 +6918,108 @@ sub HMCCU_GetSpecialCommands ($$)
# Return (sc, sd, cc, cd)
######################################################################
sub HMCCU_GetSpecialDatapoints ($$$$$)
sub HMCCU_GetSpecialDatapoints ($)
{
my ($hash, $sc, $sd, $cc, $cd) = @_;
my ($hash) = @_;
my $name = $hash->{NAME};
my $type = $hash->{TYPE};
my $ccutype = $hash->{ccutype};
my ($sc, $sd, $cc, $cd) = ('', '', '', '');
my $statedatapoint = AttrVal ($name, 'statedatapoint', '');
my $statechannel = AttrVal ($name, 'statechannel', '');
my $controldatapoint = AttrVal ($name, 'controldatapoint', $statedatapoint);
my $controldatapoint = AttrVal ($name, 'controldatapoint', '');
my ($da, $dc) = HMCCU_SplitChnAddr ($hash->{ccuaddr});
# If attribute statedatapoint is specified, use it
# Attributes controlchannel and statechannel are only valid for HMCCUDEV devices
if ($type eq 'HMCCUDEV') {
$sc = AttrVal ($name, 'statechannel', '');
$cc = AttrVal ($name, 'controlchannel', '');
}
else {
$sc = $dc;
$cc = $dc;
}
# If attribute statedatapoint is specified, use it. Attribute statechannel overrides
# channel specification in statedatapoint
if ($statedatapoint ne '') {
if ($statedatapoint =~ /^([0-9]+)\.(.+)$/) {
($sc, $sd) = ($1, $2);
($sc, $sd) = $sc eq '' ? ($1, $2) : ($sc, $2);
}
else {
$sd = $statedatapoint;
if ($statechannel eq '') {
if ($sc eq '') {
# Try to find state channel
my $c = HMCCU_FindDatapoint ($hash, $type, -1, $sd, 3);
$sc = $c if ($c >= 0);
}
else {
$sc = $statechannel;
}
}
}
# If attribute controldatapoint is specified, use it
# If attribute controldatapoint is specified, use it. Attribute controlchannel overrides
# channel specification in controldatapoint
if ($controldatapoint ne '') {
if ($controldatapoint =~ /^([0-9]+)\.(.+)$/) {
($cc, $cd) = ($1, $2);
}
else {
$cd = $controldatapoint;
# Try to find control channel
my $c = HMCCU_FindDatapoint ($hash, $type, -1, $cd, 3);
$cc = $c if ($c >= 0);
if ($cc eq '') {
# Try to find control channel
my $c = HMCCU_FindDatapoint ($hash, $type, -1, $cd, 3);
$cc = $c if ($c >= 0);
}
}
}
# Detect by role, but do not override values defined as attributes
if (exists($hash->{hmccu}{role})) {
my $ccuRole = $hash->{hmccu}{role};
if ($type eq 'HMCCUCHN') {
my ($da, $dc) = HMCCU_SplitChnAddr ($hash->{ccuaddr});
$sc = $dc;
$cc = $dc;
if (exists($HMCCU_STATECONTROL->{$ccuRole}) && $HMCCU_STATECONTROL->{$ccuRole}{F} & 1) {
$sd = $HMCCU_STATECONTROL->{$ccuRole}{S} if ($HMCCU_STATECONTROL->{$ccuRole}{S} ne '');
$cd = $HMCCU_STATECONTROL->{$ccuRole}{C} if ($HMCCU_STATECONTROL->{$ccuRole}{C} ne '');
$sd = $HMCCU_STATECONTROL->{$ccuRole}{S} if ($HMCCU_STATECONTROL->{$ccuRole}{S} ne '' && $sd eq '');
$cd = $HMCCU_STATECONTROL->{$ccuRole}{C} if ($HMCCU_STATECONTROL->{$ccuRole}{C} ne '' && $cd eq '');
}
}
elsif ($type eq 'HMCCUDEV') {
my ($rsdCnt, $rcdCnt) = (0, 0);
my ($rsc, $rsd, $rcc, $rcd) = ('', '', '', '');
foreach my $roleDef (split(',', $ccuRole)) {
my ($dc, $role) = split(':', $roleDef);
if (exists($HMCCU_STATECONTROL->{$role}) && $HMCCU_STATECONTROL->{$role}{F} & 2) {
if ($HMCCU_STATECONTROL->{$role}{S} ne '' && $sd eq '') {
$sd = $HMCCU_STATECONTROL->{$role}{S};
$sc = $dc;
my ($rc, $role) = split(':', $roleDef);
if (defined($role) && exists($HMCCU_STATECONTROL->{$role}) && $HMCCU_STATECONTROL->{$role}{F} & 2) {
if ($sd eq '' && $HMCCU_STATECONTROL->{$role}{S} ne '') {
if ($sc ne '' && $rc eq $sc) {
$sd = $HMCCU_STATECONTROL->{$role}{S};
}
else {
$rsc = $rc;
$rsd = $HMCCU_STATECONTROL->{$role}{S};
$rsdCnt++;
}
}
if ($HMCCU_STATECONTROL->{$role}{C} ne '' && $cd eq '') {
$cd = $HMCCU_STATECONTROL->{$role}{C} ;
$cc = $dc;
if ($cd eq '' && $HMCCU_STATECONTROL->{$role}{C} ne '') {
if ($cc ne '' && $rc eq $cc) {
$cd = $HMCCU_STATECONTROL->{$role}{C};
}
else {
$rcc = $rc;
$rcd = $HMCCU_STATECONTROL->{$role}{C};
$rcdCnt++;
}
}
}
last if ($sd ne '' && $cd ne '');
}
($sc, $sd) = ($rsc, $rsd) if ($rsdCnt == 1 && $sd eq '');
($cc, $cd) = ($rcc, $rcd) if ($rcdCnt == 1 && $cd eq '');
}
}
# By default set control channel and datapoint to state channel and datapoint
$cc = $sc if ($cc eq '');
$cd = $sd if ($cd eq '');
$cc = $sc if ($cc eq '' && $sc ne '');
$sc = $cc if ($sc eq '' && $cc ne '');
$cd = $sd if ($cd eq '' && $sd ne '');
$sd = $cd if ($sd eq '' && $cd ne '');
$hash->{hmccu}{state}{dpt} = $sd;
$hash->{hmccu}{state}{chn} = $sc;
$hash->{hmccu}{control}{dpt} = $cd;
@ -7788,8 +7750,7 @@ sub HMCCU_GetDatapoint ($@)
my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $io_hash);
my $substitute = HMCCU_GetAttrSubstitute ($cl_hash, $io_hash);
my ($statechn, $statedpt, $controlchn, $controldpt) = HMCCU_GetSpecialDatapoints (
$cl_hash, '', 'STATE', '', '');
my ($statechn, $statedpt, $controlchn, $controldpt) = HMCCU_GetSpecialDatapoints ($cl_hash);
my $ccuget = HMCCU_GetAttribute ($io_hash, $cl_hash, 'ccuget', 'Value');
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
@ -7829,8 +7790,9 @@ sub HMCCU_GetDatapoint ($@)
######################################################################
# Set multiple values of parameter set.
# Parameter params is a hash reference. Keys are datapoint names.
# Parameter address must be a channel address.
# Parameter params is a hash reference. Keys are parameter names.
# Parameter address must be a device or a channel address.
# If no paramSet is specified, VALUES is used by default.
######################################################################
sub HMCCU_SetMultipleParameters ($$$;$)
@ -7839,14 +7801,14 @@ sub HMCCU_SetMultipleParameters ($$$;$)
$paramSet = 'VALUES' if (!defined($paramSet));
my ($add, $chn) = HMCCU_SplitChnAddr ($address);
return -1 if (!defined ($chn));
return -1 if ($paramSet eq 'VALUES' && !defined ($chn));
foreach my $p (sort keys %$params) {
return -8 if ($paramSet eq 'VALUES' && !HMCCU_IsValidDatapoint ($clHash, $clHash->{ccutype}, $chn, $p, 2));
return -8 if ($paramSet eq 'MASTER' && !HMCCU_IsValidParameter ($clHash, $address, $paramSet, $p));
$params->{$p} = HMCCU_ScaleValue ($clHash, $chn, $p, $params->{$p}, 1);
}
return HMCCU_RPCRequest ($clHash, "putParamset", $address, $paramSet, $params);
}
@ -8136,7 +8098,7 @@ sub HMCCU_ScaleValue ($$$$$)
}
if ($dpt eq 'LEVEL') {
return ($mode == 0) ? min($value,100.0)/100.0 : min($value,1.0)*100.0;
return ($mode == 0) ? HMCCU_Min($value,100.0)/100.0 : HMCCU_Min($value,1.0)*100.0;
}
elsif ($dpt =~ /^P[0-9]_ENDTIME/) {
if ($mode == 0) {
@ -8271,44 +8233,44 @@ sub HMCCU_SetVariable ($$$$$)
sub HMCCU_GetUpdate ($$$)
{
my ($cl_hash, $addr, $ccuget) = @_;
my $name = $cl_hash->{NAME};
my $type = $cl_hash->{TYPE};
my ($clHash, $addr, $ccuget) = @_;
my $name = $clHash->{NAME};
my $type = $clHash->{TYPE};
my $fnc = "GetUpdate";
my $disable = AttrVal ($name, 'disable', 0);
return 1 if ($disable == 1);
my $hmccu_hash = HMCCU_GetHash ($cl_hash);
return -3 if (!defined ($hmccu_hash));
return -4 if ($type ne 'HMCCU' && $cl_hash->{ccudevstate} eq 'deleted');
my $ioHash = HMCCU_GetHash ($clHash);
return -3 if (!defined ($ioHash));
return -4 if ($type ne 'HMCCU' && $clHash->{ccudevstate} eq 'deleted');
my $nam = '';
my $list = '';
my $script = '';
$ccuget = HMCCU_GetAttribute ($hmccu_hash, $cl_hash, 'ccuget', 'Value') if ($ccuget eq 'Attr');
$ccuget = HMCCU_GetAttribute ($ioHash, $clHash, 'ccuget', 'Value') if ($ccuget eq 'Attr');
if (HMCCU_IsValidChannel ($hmccu_hash, $addr, $HMCCU_FL_ADDRESS)) {
$nam = HMCCU_GetChannelName ($hmccu_hash, $addr, '');
if (HMCCU_IsValidChannel ($ioHash, $addr, $HMCCU_FL_ADDRESS)) {
$nam = HMCCU_GetChannelName ($ioHash, $addr, '');
return -1 if ($nam eq '');
my ($stadd, $stchn) = split (':', $addr);
my $stnam = HMCCU_GetChannelName ($hmccu_hash, "$stadd:0", '');
my $stnam = HMCCU_GetChannelName ($ioHash, "$stadd:0", '');
$list = $stnam eq '' ? $nam : $stnam . "," . $nam;
$script = "!GetDatapointsByChannel";
}
elsif (HMCCU_IsValidDevice ($hmccu_hash, $addr, $HMCCU_FL_ADDRESS)) {
$nam = HMCCU_GetDeviceName ($hmccu_hash, $addr, '');
elsif (HMCCU_IsValidDevice ($ioHash, $addr, $HMCCU_FL_ADDRESS)) {
$nam = HMCCU_GetDeviceName ($ioHash, $addr, '');
return -1 if ($nam eq '');
$list = $nam if ($cl_hash->{ccuif} ne 'fhem');
$list = $nam if ($clHash->{ccuif} ne 'fhem');
$script = "!GetDatapointsByDevice";
# Consider members of group device
if ($type eq 'HMCCUDEV' &&
($cl_hash->{ccuif} eq 'VirtualDevices' || $cl_hash->{ccuif} eq 'fhem') &&
exists ($cl_hash->{ccugroup})) {
foreach my $gd (split (",", $cl_hash->{ccugroup})) {
$nam = HMCCU_GetDeviceName ($hmccu_hash, $gd, '');
(($clHash->{ccuif} eq 'VirtualDevices' && HMCCU_IsFlag ($ioHash, 'updGroupMembers'))||
$clHash->{ccuif} eq 'fhem') && exists($clHash->{ccugroup})) {
foreach my $gd (split (",", $clHash->{ccugroup})) {
$nam = HMCCU_GetDeviceName ($ioHash, $gd, '');
$list .= ','.$nam if ($nam ne '');
}
}
@ -8317,59 +8279,21 @@ sub HMCCU_GetUpdate ($$$)
return -1;
}
if (HMCCU_IsFlag ($hmccu_hash->{NAME}, 'nonBlocking')) {
HMCCU_HMScriptExt ($hmccu_hash, $script, { list => $list, ccuget => $ccuget },
if (HMCCU_IsFlag ($ioHash->{NAME}, 'nonBlocking')) {
HMCCU_HMScriptExt ($ioHash, $script, { list => $list, ccuget => $ccuget },
\&HMCCU_UpdateCB, undef);
return 1;
}
else {
my $response = HMCCU_HMScriptExt ($hmccu_hash, $script,
my $response = HMCCU_HMScriptExt ($ioHash, $script,
{ list => $list, ccuget => $ccuget }, undef, undef);
HMCCU_Trace ($cl_hash, 2, $fnc, "Addr=$addr Name=$nam Script=$script<br>".
HMCCU_Trace ($clHash, 2, $fnc, "Addr=$addr Name=$nam Script=$script<br>".
"Script response = \n".$response);
return -2 if ($response eq '' || $response =~ /^ERROR:.*/);
HMCCU_UpdateCB ({ ioHash => $hmccu_hash }, undef, $response);
HMCCU_UpdateCB ({ ioHash => $ioHash }, undef, $response);
return 1;
}
# my @dpdef = split /\n/, $response;
# my $count = pop (@dpdef);
# return -10 if (!defined ($count) || $count == 0);
#
# my %events = ();
# foreach my $dp (@dpdef) {
# my ($chnname, $dpspec, $value) = split /=/, $dp;
# next if (!defined ($value));
# my ($iface, $chnadd, $dpt) = split /\./, $dpspec;
# next if (!defined ($dpt));
# my ($add, $chn) = ('', '');
# if ($iface eq 'sysvar' && $chnadd eq 'link') {
# ($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $chnname, '', '');
# }
# else {
# ($add, $chn) = HMCCU_SplitChnAddr ($chnadd);
# }
# next if ($chn eq '');
# $events{$add}{$chn}{$dpt} = $value;
# }
# if ($cl_hash->{ccuif} eq 'fhem') {
# # Calculate datapoints of virtual group device
# if ($cl_hash->{ccutype} ne 'n/a') {
# foreach my $da (split (",", $cl_hash->{ccugroup})) {
# foreach my $cn (keys %{$events{$da}}) {
# foreach my $dp (keys %{$events{$da}{$cn}}) {
# if (defined ($events{$da}{$cn}{$dp})) {
# $events{$cl_hash->{ccuaddr}}{$cn}{$dp} = $events{$da}{$cn}{$dp}
# }
# }
# }
# }
# }
# }
# HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events);
return 1;
}
@ -8420,7 +8344,7 @@ sub HMCCU_UpdateCB ($$$)
my $c_ok = HMCCU_UpdateMultipleDevices ($hash, \%events);
my $c_err = 0;
$c_err = max($param->{devCount}-$c_ok, 0) if (exists ($param->{devCount}));
$c_err = HMCCU_Max($param->{devCount}-$c_ok, 0) if (exists ($param->{devCount}));
HMCCU_Log ($hash, 2, "Update success=$c_ok failed=$c_err") if ($logcount);
}
@ -8857,6 +8781,28 @@ sub HMCCU_GetTimeSpec ($)
return ($s-$cs);
}
######################################################################
# Get minimum of 2 values
######################################################################
sub HMCCU_Min ($$)
{
my ($a, $b) = @_;
return $a < $b ? $a : $b;
}
######################################################################
# Get maximum of 2 values
######################################################################
sub HMCCU_Max ($$)
{
my ($a, $b) = @_;
return $a > $b ? $a : $b;
}
######################################################################
# Build ReGa or RPC client URL
# Parameter backend specifies type of URL, 'rega' or name or port of
@ -9991,7 +9937,7 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
iface_conn_n = interface connection state (1=connected, 0=disconnected)<br/>
iface_ducy_n = duty cycle of interface (0-100)
</li><br/>
<li><b>get &lt;name&gt; exportdefaults &lt;filename&gt; [csv] [all]</b><br/>
<li><b>get &lt;name&gt; exportdefaults &lt;filename&gt; [all]</b><br/>
Export default attributes into file. If option <i>all</i> is specified, also defaults imported
by customer will be exported.
</li><br/>
@ -10084,11 +10030,6 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
Set global reading format. This format is the default for all readings except readings
of virtual device groups.
</li><br/>
<li><b>ccudef-readingname &lt;old-readingname-expr&gt;:[+]&lt;new-readingname&gt;
[;...]</b><br/>
Set global rules for reading name substitution. These rules are added to the rules
specified by client device attribute 'ccureadingname'.
</li><br/>
<li><b>ccudef-stripnumber [&lt;datapoint-expr&gt;!]{0|1|2|-n|%fmt}[;...]</b><br/>
Set global formatting rules for numeric datapoint or config parameter values.
Default value is 2 (strip trailing zeroes).<br/>
@ -10121,7 +10062,8 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
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.
reconnect - Automatically reconnect to CCU when events timeout occurred.<br/>
updGroupMembers - Update readings of group members in virtual devices.
</li><br/>
<li><b>ccuget {State | <u>Value</u>}</b><br/>
Set read access method for CCU channel datapoints. Method 'State' is slower than

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCUCHN.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.4.014
# Version 4.4.016
#
# (c) 2020 zap (zap01 <at> t-online <dot> de)
#
@ -66,17 +66,16 @@ sub HMCCUCHN_Define ($@)
my ($hash, $a, $h) = @_;
my $name = $hash->{NAME};
my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['noDefaults'] [iodev={iodevname}]";
my $usage = "Usage: define $name HMCCUCHN {device} ['readonly'] ['noDefaults'|'defaults'] [iodev={iodevname}]";
return $usage if (@$a < 3);
my $devname = shift @$a;
my $devtype = shift @$a;
my $devspec = shift @$a;
my $ioHash = undef;
my $ioHash;
my $existDev = HMCCU_ExistsClientDevice ($devspec, $devtype);
return "FHEM device $existDev for CCU device $devspec already exists" if (defined($existDev));
return "FHEM device $existDev for CCU device $devspec already exists" if ($existDev ne '');
# Store some definitions for delayed initialization
$hash->{hmccu}{devspec} = $devspec;
@ -87,19 +86,18 @@ sub HMCCUCHN_Define ($@)
# Parse optional command line parameters
my $n = 0;
my $arg = shift @$a;
while (defined ($arg)) {
while (my $arg = shift @$a) {
return $usage if ($n == 3);
if ($arg eq 'readonly') { $hash->{readonly} = "yes"; }
elsif ($arg ne 'noDefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; }
else { return $usage; }
$n++;
$arg = shift @$a;
}
# IO device can be set by command line parameter iodev, otherwise try to detect IO device
if (exists ($h->{iodev})) {
return "Specified IO Device ".$h->{iodev}." does not exist" if (!exists ($defs{$h->{iodev}}));
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');
$ioHash = $defs{$h->{iodev}};
@ -111,7 +109,7 @@ sub HMCCUCHN_Define ($@)
if ($init_done) {
# Interactive define command while CCU not ready or no IO device defined
if (!defined ($ioHash)) {
if (!defined($ioHash)) {
my ($ccuactive, $ccuinactive) = HMCCU_IODeviceStates ();
if ($ccuinactive > 0) {
return "CCU and/or IO device not ready. Please try again later";
@ -125,7 +123,6 @@ sub HMCCUCHN_Define ($@)
# CCU not ready during FHEM start
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';
return undef;
}
@ -171,7 +168,7 @@ sub HMCCUCHN_InitDevice ($$)
HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME});
HMCCU_UpdateDevice ($ioHash, $devHash);
HMCCU_UpdateDeviceRoles ($ioHash, $devHash);
if (!exists($devHash->{hmccu}{nodefaults})) {
if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) {
if (!HMCCU_SetDefaultAttributes ($devHash)) {
HMCCU_SetDefaults ($devHash);
}
@ -193,6 +190,8 @@ sub HMCCUCHN_Undef ($$)
if (defined($hash->{IODev})) {
HMCCU_RemoveDevice ($hash->{IODev}, $hash->{ccuif}, $hash->{ccuaddr}, $hash->{NAME});
}
return undef;
}
######################################################################
@ -270,7 +269,7 @@ sub HMCCUCHN_Set ($@)
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
# Get state and control datapoints
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', '', '', '');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Get additional commands (including state commands)
my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc);
@ -354,7 +353,7 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
@ -385,7 +384,7 @@ sub HMCCUCHN_Set ($@)
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$cd" => $stateCmds{$newState} }
);
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif (defined($roleCmds) && exists($roleCmds->{$opt})) {
my $value;
@ -472,11 +471,11 @@ sub HMCCUCHN_Set ($@)
if (scalar(keys %dpval) > 0) {
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
if (scalar(keys %cfval) > 0) {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, 'MASTER');
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
}
elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') {
@ -502,7 +501,7 @@ sub HMCCUCHN_Set ($@)
"001.$ccuif.$ccuaddr.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr.$cd" => $stateCmds{"on"}
});
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'clear') {
my $rnexp = shift @$a;
@ -541,7 +540,7 @@ sub HMCCUCHN_Set ($@)
}
if ($paramset eq 'VALUES' || $paramset eq 'MASTER') {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, $paramset);
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuobj, $h, $paramset);
}
else {
if (exists($defs{$receiver}) && defined($defs{$receiver}->{TYPE})) {
@ -571,7 +570,7 @@ sub HMCCUCHN_Set ($@)
($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $receiver, $h);
}
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'defaults') {
$rc = HMCCU_SetDefaultAttributes ($hash);
@ -581,12 +580,11 @@ sub HMCCUCHN_Set ($@)
else {
my $retmsg = "clear defaults:noArg";
if ($hash->{readonly} ne 'yes') {
$retmsg .= " config";
$retmsg .= ':'.join(',', @states) if (scalar(@states) > 0);
$retmsg .= " datapoint".$cmdList;
$retmsg .= " config datapoint".$cmdList;
# $retmsg .= ':'.join(',', @states) if (scalar(@states) > 0);
$retmsg .= ' toggle:noArg' if (scalar(@states) > 0);
$retmsg .= " on-for-timer on-till"
if ($sc ne '' && HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "ON_TIME", 2));
if ($cc ne '' && HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, "ON_TIME", 2));
}
return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a);
}
@ -656,8 +654,9 @@ sub HMCCUCHN_Get ($@)
elsif ($opt eq 'deviceinfo') {
my ($a, $c) = HMCCU_SplitChnAddr ($ccuaddr);
$result = HMCCU_GetDeviceInfo ($hash, $a);
return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result);
return HMCCU_SetError ($hash, -2) if ($result eq '');
my $devInfo = HMCCU_FormatDeviceInfo ($result);
return $devInfo;
}
elsif ($opt =~ /^(config|values)$/) {
my %parSets = ('config' => 'MASTER,LINK', 'values' => 'VALUES');
@ -759,7 +758,7 @@ sub HMCCUCHN_Get ($@)
<b>Define</b><br/><br/>
<ul>
<code>define &lt;name&gt; HMCCUCHN {&lt;channel-name&gt; | &lt;channel-address&gt;}
[readonly] [noDefaults] [iodev=&lt;iodev-name&gt;]</code>
[readonly] [<u>defaults</u>|noDefaults] [iodev=&lt;iodev-name&gt;]</code>
<br/><br/>
If option 'readonly' is specified no set command will be available. With option 'noDefaults'
no default attributes will be set during interactive device definition. <br/>

View File

@ -4,7 +4,7 @@
#
# $Id: 88_HMCCUDEV.pm 18552 2019-02-10 11:52:28Z zap $
#
# Version 4.4.008
# Version 4.4.016
#
# (c) 2020 zap (zap01 <at> t-online <dot> de)
#
@ -52,7 +52,7 @@ sub HMCCUDEV_Initialize ($)
"ccureadingname:textField-long ".
"ccuget:State,Value ccuscaleval ccuSetOnChange ccuverify:0,1,2 disable:0,1 ".
"hmstatevals:textField-long statevals substexcl substitute:textField-long statechannel ".
"statedatapoint controldatapoint stripnumber peer:textField-long ".
"controlchannel statedatapoint controldatapoint stripnumber peer:textField-long ".
$readingFnAttributes;
}
@ -65,8 +65,8 @@ sub HMCCUDEV_Define ($@)
my ($hash, $a, $h) = @_;
my $name = $hash->{NAME};
my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [state-channel] ".
"['readonly'] ['noDefaults'] [iodev={iodev-name}] [address={virtual-device-no}]".
my $usage = "Usage: define $name HMCCUDEV {device|'virtual'} [control-channel] ".
"['readonly'] ['noDefaults'|'defaults'] [iodev={iodev-name}] [address={virtual-device-no}]".
"[{groupexp=regexp|group={device|channel}[,...]]";
return $usage if (scalar (@$a) < 3);
@ -111,8 +111,9 @@ sub HMCCUDEV_Define ($@)
# Parse optional command line parameters
foreach my $arg (@$a) {
if ($arg eq 'readonly') { $hash->{readonly} = 'yes'; }
elsif ($arg ne 'noDefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif ($arg =~ /^[0-9]+$/) { $attr{$name}{statechannel} = $arg; }
elsif (lc($arg) eq 'nodefaults' && $init_done) { $hash->{hmccu}{nodefaults} = 1; }
elsif ($arg eq 'defaults' && $init_done) { $hash->{hmccu}{nodefaults} = 0; }
elsif ($arg =~ /^[0-9]+$/) { $attr{$name}{controlchannel} = $arg; }
else { return $usage; }
}
@ -177,7 +178,7 @@ sub HMCCUDEV_InitDevice ($$)
my $devspec = $devHash->{hmccu}{devspec};
my $gdcount = 0;
my $gdname = $devspec;
if ($devspec eq 'virtual') {
my $no = 0;
if (exists ($devHash->{hmccu}{address})) {
@ -196,9 +197,14 @@ sub HMCCUDEV_InitDevice ($$)
return 7 if ($no == 0);
$devHash->{DEF} .= " address=$no";
}
# Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef));
$devHash->{ccuif} = 'fhem';
$devHash->{ccuaddr} = sprintf ("VIR%07d", $no);
$devHash->{ccuname} = $name;
$devHash->{ccudevstate} = 'active';
}
else {
return 1 if (!HMCCU_IsValidDevice ($ioHash, $devspec, 7));
@ -207,10 +213,14 @@ sub HMCCUDEV_InitDevice ($$)
return 1 if (!defined ($da));
$gdname = $dn;
# Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef));
$devHash->{ccuif} = $di;
$devHash->{ccuaddr} = $da;
$devHash->{ccuname} = $dn;
$devHash->{ccutype} = $dt;
$devHash->{ccudevstate} = 'active';
$devHash->{hmccu}{channels} = $dc;
if ($init_done) {
@ -218,7 +228,7 @@ sub HMCCUDEV_InitDevice ($$)
HMCCU_AddDevice ($ioHash, $di, $da, $devHash->{NAME});
HMCCU_UpdateDevice ($ioHash, $devHash);
HMCCU_UpdateDeviceRoles ($ioHash, $devHash);
if (!exists($devHash->{hmccu}{nodefaults})) {
if (!exists($devHash->{hmccu}{nodefaults}) || $devHash->{hmccu}{nodefaults} == 0) {
if (!HMCCU_SetDefaultAttributes ($devHash)) {
HMCCU_SetDefaults ($devHash);
}
@ -288,11 +298,6 @@ sub HMCCUDEV_InitDevice ($$)
}
}
# Inform HMCCU device about client device
return 2 if (!HMCCU_AssignIODevice ($devHash, $ioHash->{NAME}, undef));
$devHash->{ccudevstate} = 'active';
return 0;
}
@ -310,6 +315,8 @@ sub HMCCUDEV_Undef ($$)
HMCCU_DeleteDevice ($hash->{IODev});
}
}
return undef;
}
######################################################################
@ -389,28 +396,41 @@ sub HMCCUDEV_Set ($@)
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
# Get state and control datapoints
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', '', '', '');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
# Get additional commands (including state commands)
my $roleCmds = HMCCU_GetSpecialCommands ($hash, $cc);
my %pset = ('V' => 'VALUES', 'M' => 'MASTER', 'D' => 'MASTER');
my $cmdList = '';
my %valLookup;
foreach my $cmd (keys %$roleCmds) {
$cmdList .= " $cmd";
my @setList = split (/\s+/, $roleCmds->{$cmd});
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
if ($par !~ /^\?/) {
my @argList = split (',', $par);
$cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg";
my @argList = ();
if ($par =~ /^#/) {
my $paramDef = HMCCU_GetParamDef ($ioHash, $ccuaddr, $pset{$ps}, $dpt);
if (defined($paramDef)) {
if ($paramDef->{TYPE} eq 'ENUM' && defined($paramDef->{VALUE_LIST})) {
$par = $paramDef->{VALUE_LIST};
$par =~ s/[ ]+/-/g;
@argList = split (',', $par);
while (my ($i, $e) = each(@argList)) { $valLookup{$pset{$ps}}{$dpt}{$e} = $i; }
}
}
}
elsif ($par !~ /^\?/) {
@argList = split (',', $par);
}
$cmdList .= scalar(@argList) > 1 ? ":$par" : ":noArg";
}
}
# Get state values related to control command and datapoint
my $stateVals = HMCCU_GetStateValues ($hash, $cd, $cc);
my @stateCmdList = split (/[:,]/, $stateVals);
my %stateCmds = @stateCmdList;
my @states = keys %stateCmds;
@ -449,8 +469,8 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, -7) if ($chn >= $hash->{hmccu}{channels});
}
else {
return HMCCU_SetError ($hash, -11) if ($sc eq '');
$objname = $sc.'.'.$objname;
return HMCCU_SetError ($hash, -11) if ($cc eq '');
$objname = $cc.'.'.$objname;
}
my $no = sprintf ("%03d", $i);
@ -461,38 +481,12 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, min(0, $rc));
}
elsif ($opt eq 'control') {
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -7) if ($cc >= $hash->{hmccu}{channels});
my $objvalue = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue));
$objvalue =~ s/\\_/%20/g;
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($objvalue, $stateVals, 1, undef, '') }
);
return HMCCU_SetError ($hash, min(0, $rc));
}
elsif (exists($stateCmds{$opt})) {
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $cd, 2));
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => $stateCmds{$opt} }
);
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'toggle') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, -15) if ($stateVals eq '');
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
@ -518,76 +512,113 @@ sub HMCCUDEV_Set ($@)
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => $stateCmds{$newState} }
);
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'pct' || $opt eq 'up' || $opt eq 'down') {
return HMCCU_SetError ($hash, -11) if ($sc eq '' && $cc eq '');
my $chn;
if (HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, "LEVEL", 2)) {
$chn = $cc;
}
elsif (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "LEVEL", 2)) {
$chn = $sc;
}
else {
return HMCCU_SetError ($hash, "Can't find LEVEL datapoint for device type $ccutype")
}
elsif (defined($roleCmds) && exists($roleCmds->{$opt})) {
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
my $value;
my %dpval;
my %cfval;
if ($opt eq 'pct') {
my $objname = '';
my $objvalue = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name pct {value} [{ontime} [{ramptime}]]")
if (!defined ($objvalue));
my @setList = split (/\s+/, $roleCmds->{$opt});
my $i = 0;
foreach my $set (@setList) {
my ($ps, $dpt, $par) = split(/:/, $set);
my $timespec = shift @$a;
my $ramptime = shift @$a;
my %dpval;
# Set on time
if (defined ($timespec)) {
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $chn, "ON_TIME", 2));
if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
$dpval{"001.$ccuif.$ccuaddr:$chn.ON_TIME"} = $timespec if ($timespec > 0);
return HMCCU_SetError ($hash, "Syntax error in definition of command $opt")
if (!defined($par));
if (!HMCCU_IsValidParameter ($hash, $ccuaddr, $pset{$ps}, $dpt)) {
HMCCU_Trace ($hash, 2, "Set", "Invalid parameter $ps $dpt");
return HMCCU_SetError ($hash, -8);
}
# Set ramp time
$dpval{"002.$ccuif.$ccuaddr:$chn.RAMP_TIME"} = $ramptime if (defined ($ramptime));
# Set level
$dpval{"003.$ccuif.$ccuaddr:$chn.LEVEL"} = $objvalue;
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
}
else {
my $delta = shift @$a;
$delta = 10 if (!defined ($delta));
$delta = -$delta if ($opt eq 'down');
my $objname = "$ccuif.$ccuaddr:$chn.LEVEL";
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 1);
Log3 $name, 2, "HMCCU: set $opt: GetDatapoint returned $rc, $result"
if ($ccuflags =~ /trace/);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
# Set level
my $objvalue = min(max($result+$delta,0),100);
$rc = HMCCU_SetMultipleDatapoints ($hash, { "001.$objname" => $objvalue });
}
# Check if parameter is required
if ($par =~ /^\?(.+)$/) {
$par = $1;
# Consider default value for parameter
my ($parName, $parDef) = split ('=', $par);
$value = shift @$a;
if (!defined($value) && defined($parDef)) {
if ($parDef =~ /^[+-][0-9]+$/) {
return HMCCU_SetError ($hash, "Current value of $cc.$dpt not available")
if (!defined($hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}));
$value = $hash->{hmccu}{dp}{"$cc.$dpt"}{$pset{$ps}}{SVAL}+int($parDef);
}
else {
$value = $parDef;
}
}
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, "Missing parameter $parName")
if (!defined($value));
}
else {
if (exists($valLookup{$ps}{$dpt})) {
return HMCCU_SetError ($hash, "Illegal value $par. Use one of ".join(',', keys %{$valLookup{$ps}{$dpt}}))
if (!exists($valLookup{$ps}{$dpt}{$par}));
$value = $valLookup{$ps}{$dpt}{$par};
}
else {
$value = $par;
}
}
if ($opt eq 'pct' || $opt eq 'level') {
my $timespec = shift @$a;
my $ramptime = shift @$a;
# Set on time
if (defined ($timespec)) {
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "ON_TIME", 2));
if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
$dpval{"001.$ccuif.$ccuaddr.$cc.ON_TIME"} = $timespec if ($timespec > 0);
}
# Set ramp time
if (defined($ramptime)) {
return HMCCU_SetError ($hash, "Can't find RAMP_TIME datapoint for device type $ccutype")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, "RAMP_TIME", 2));
$dpval{"002.$ccuif.$ccuaddr.$cc.RAMP_TIME"} = $ramptime if (defined ($ramptime));
}
$dpval{"003.$ccuif.$ccuaddr.$cc.$dpt"} = $value;
last;
}
else {
if ($ps eq 'V') {
my $no = sprintf ("%03d", $i);
$dpval{"$i.$ccuif.$ccuaddr.$cc.$dpt"} = $value;
$i++;
}
else {
$cfval{$dpt} = $value;
}
}
}
if (scalar(keys %dpval) > 0) {
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
if (scalar(keys %cfval) > 0) {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuaddr, $h, 'MASTER');
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
}
elsif ($opt eq 'on-for-timer' || $opt eq 'on-till') {
return HMCCU_SetError ($hash, -15) if ($stateVals eq '' || !exists($hash->{hmccu}{statevals}));
return HMCCU_SetError ($hash, "No state value for 'on' defined")
if ("on" !~ /($hash->{hmccu}{statevals})/);
return HMCCU_SetError ($hash, -11) if ($sc eq '');
return HMCCU_SetError ($hash, -13) if ($sd eq '');
return HMCCU_SetError ($hash, -12) if ($cc eq '');
return HMCCU_SetError ($hash, -14) if ($cd eq '');
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "ON_TIME", 2));
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, "ON_TIME", 2));
my $timespec = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name $opt {ontime-spec}")
@ -599,66 +630,85 @@ sub HMCCUDEV_Set ($@)
}
$rc = HMCCU_SetMultipleDatapoints ($hash, {
"001.$ccuif.$ccuaddr:$sc.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ("on", $stateVals, 1, undef, '')
"001.$ccuif.$ccuaddr:$cc.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ("on", $stateVals, 1, undef, '')
});
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'clear') {
my $rnexp = shift @$a;
HMCCU_DeleteReadings ($hash, $rnexp);
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]")
if ((scalar keys %{$h}) < 1);
my $objname = $ccuaddr;
elsif ($opt =~ /^(config|values)$/) {
my %parSets = ('config' => 'MASTER', 'values' => 'VALUES');
my $paramset = $parSets{$opt};
my $receiver = '';
my $ccuobj = $ccuaddr;
# Channel number is optional because parameter can be related to device or channel
if ((scalar @$a) > 0 && $$a[0] =~ /^([0-9]{1,2})$/) {
return HMCCU_SetError ($hash, -7) if ($1 >= $hash->{hmccu}{channels});
$objname .= ':'.$1;
}
my ($rc, $res) = HMCCU_RPCRequest ($hash, "putParamset", $objname, "MASTER", $h);
return HMCCU_SetError ($hash, min(0, $rc));
}
elsif ($opt eq 'rpcparameter') {
return HMCCU_SetError ($hash, "Usage: set $name rpcparameter [channel] [MASTER|VALUES|LINK] {parameter}={value} [...]")
return HMCCU_SetError ($hash, "No parameter specified")
if ((scalar keys %{$h}) < 1);
my $key;
my $chn;
while (my $p = shift @$a) {
if (uc($p) =~ /^(MASTER|VALUES|LINK)$/ && !defined ($key)) {
$key = uc($p);
# Channel number is optional because parameter can be related to device or channel
my $p = shift @$a;
if (defined($p)) {
if ($p =~ /^([0-9]{1,2})$/) {
return HMCCU_SetError ($hash, -7) if ($p >= $hash->{hmccu}{channels});
$ccuobj .= ':'.$p;
}
elsif ($p =~ /^([0-9]+)$/ && !defined ($chn)) {
HMCCU_SetError ($hash, -7) if ($p >= $hash->{hmccu}{channels});
$chn = $p;
else {
$receiver = $p;
$paramset = 'LINK';
}
}
$key = 'VALUES' if (!defined ($key));
return HMCCU_SetError ($hash, -7) if (!defined ($chn) && ($key eq 'VALUES' || $key eq 'LINK'));
my $addr = defined ($chn) ? "$ccuaddr:$chn" : $ccuaddr;
if ($key eq 'VALUES') {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $addr, $h);
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 or channel")
if ($devDesc->{PARAMSETS} !~ /$paramset/);
if (!HMCCU_IsValidParameter ($ioHash, $devDesc, $paramset, $h)) {
my @parList = HMCCU_GetParamDef ($ioHash, $devDesc, $paramset);
return HMCCU_SetError ($hash, "Invalid parameter specified. Valid parameters are ".
join(',', @parList));
}
elsif ($key eq 'MASTER' || $key eq 'LINK') {
($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $addr, $key, $h);
if ($paramset eq 'VALUES' || $paramset eq 'MASTER') {
($rc, $result) = HMCCU_SetMultipleParameters ($hash, $ccuobj, $h, $paramset);
}
else {
return HMCCU_SetError ($hash, "Key must be MASTER, LINK or VALUES");
if (exists($defs{$receiver}) && defined($defs{$receiver}->{TYPE})) {
my $clHash = $defs{$receiver};
if ($clHash->{TYPE} eq 'HMCCUDEV') {
my $chnNo = shift @$a;
return HMCCU_SetError ($hash, "Channel number required for link receiver")
if (!defined($chnNo) || $chnNo !~ /^[0-9]{1,2}$/);
$receiver = $clHash->{ccuaddr}.":$chnNo";
}
elsif ($clHash->{TYPE} eq 'HMCCUCHN') {
$receiver = $clHash->{ccuaddr};
}
else {
return HMCCU_SetError ($hash, "Receiver $receiver is not a HMCCUCHN or HMCCUDEV device");
}
}
elsif (!HMCCU_IsChnAddr ($receiver, 0)) {
my ($rcvAdd, $rcvChn) = HMCCU_GetAddress ($ioHash, $receiver, '', '');
return HMCCU_SetError ($hash, "$receiver is not a valid CCU channel name")
if ($rcvAdd eq '' || $rcvChn eq '');
$receiver = "$rcvAdd:$rcvChn";
}
return HMCCU_SetError ($hash, "$receiver is not a link receiver of $name")
if (!HMCCU_IsValidReceiver ($ioHash, $ccuaddr, $ccuif, $receiver));
($rc, $result) = HMCCU_RPCRequest ($hash, "putParamset", $ccuaddr, $receiver, $h);
}
return HMCCU_SetError ($hash, min(0, $rc));
return HMCCU_SetError ($hash, HMCCU_Min(0, $rc));
}
elsif ($opt eq 'defaults') {
my $rc = HMCCU_SetDefaults ($hash);
$rc = HMCCU_SetDefaultAttributes ($hash, $cc);
$rc = HMCCU_SetDefaults ($hash) if (!$rc);
return HMCCU_SetError ($hash, $rc == 0 ? "No default attributes found" : "OK");
}
else {
@ -667,12 +717,10 @@ sub HMCCUDEV_Set ($@)
if ($hash->{readonly} ne 'yes') {
$retmsg .= " datapoint rpcparameter";
if ($sc ne '') {
$retmsg .= " config control";
$retmsg .= ':'.join(',', @states) if (scalar(@states) > 0);
$retmsg .= $cmdList;
$retmsg .= " config datapoint".$cmdList;
$retmsg .= " toggle:noArg" if (scalar(@states) > 0);
$retmsg .= " on-for-timer on-till"
if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $sc, "ON_TIME", 2));
if ($cc ne '' && HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $cc, "ON_TIME", 2));
}
}
return AttrTemplate_Set ($hash, $retmsg, $name, $opt, @$a);
@ -712,7 +760,7 @@ sub HMCCUDEV_Get ($@)
my $ccuaddr = $hash->{ccuaddr};
my $ccuif = $hash->{ccuif};
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash, '', 'STATE', '', '');
my ($sc, $sd, $cc, $cd) = HMCCU_GetSpecialDatapoints ($hash);
my $result = '';
my $rc;
@ -791,7 +839,9 @@ sub HMCCUDEV_Get ($@)
}
$result = HMCCU_GetDeviceInfo ($hash, $ccuaddr, $ccuget);
return HMCCU_SetError ($hash, -2) if ($result eq '');
return HMCCU_FormatDeviceInfo ($result);
my $devInfo = HMCCU_FormatDeviceInfo ($result);
$devInfo .= "StateDatapoint = $sc.$sd\nControlDatapoint = $cc.$cd";
return $devInfo;
}
elsif ($opt =~ /^(paramset|config|values)$/) {
my $par = shift @$a;
@ -909,14 +959,14 @@ sub HMCCUDEV_Get ($@)
<a name="HMCCUDEVdefine"></a>
<b>Define</b><br/><br/>
<ul>
<code>define &lt;name&gt; HMCCUDEV {&lt;device&gt; | 'virtual'} [&lt;statechannel&gt;]
[readonly] [defaults] [{group={device|channel}[,...]|groupexp=regexp]
<code>define &lt;name&gt; HMCCUDEV {&lt;device&gt; | 'virtual'} [&lt;controlchannel&gt;]
[readonly] [<u>defaults</u>|noDefaults] [{group={device|channel}[,...]|groupexp=regexp]
[iodev=&lt;iodev-name&gt;]</code>
<br/><br/>
If option 'readonly' is specified no set command will be available. With option 'defaults'
some default attributes depending on CCU device type will be set. Default attributes are only
available for some device types. The option is ignored during FHEM start.
Parameter <i>statechannel</i> corresponds to attribute 'statechannel'.<br/>
Parameter <i>controlchannel</i> corresponds to attribute 'controlchannel'.<br/>
A HMCCUDEV device supports CCU group devices. The CCU devices or channels related to a group
device are specified by using options 'group' or 'groupexp' followed by the names or
addresses of the CCU devices or channels. By using 'groupexp' one can specify a regular
@ -1111,6 +1161,9 @@ sub HMCCUDEV_Get ($@)
<li><b>ccuverify {0 | 1 | 2}</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>controlchannel &lt;channel-number&gt;</b><br/>
Channel used for setting device states.
</li><br/>
<li><b>controldatapoint &lt;channel-number.datapoint&gt;</b><br/>
Set channel number and datapoint for device control.
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
@ -1126,8 +1179,7 @@ sub HMCCUDEV_Get ($@)
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>statechannel &lt;channel-number&gt;</b><br/>
Channel for setting device state by devstate command. Deprecated, use attribute
'statedatapoint' instead.
Channel for getting device state. Deprecated, use attribute 'statedatapoint' instead.
</li><br/>
<li><b>statedatapoint [&lt;channel-number&gt;.]&lt;datapoint&gt;</b><br/>
Set state channel and state datapoint for setting device state by devstate command.

View File

@ -445,7 +445,7 @@ sub HMCCURPCPROC_DelayedShutdown ($)
my $hmccu_hash = $hash->{IODev};
my $ifname = $hash->{rpcinterface};
my $delay = max (AttrVal ("global", "maxShutdownDelay", 10)-2, 0);
my $delay = HMCCU_Max (AttrVal ("global", "maxShutdownDelay", 10)-2, 0);
# Shutdown RPC server
if (defined ($hmccu_hash) && exists ($hmccu_hash->{hmccu}{interfaces}{$ifname}{manager}) &&

View File

@ -205,17 +205,14 @@ use vars qw(%HMCCU_SCRIPTS);
%HMCCU_ATTR = (
'BLIND' => {
'ccureadingname' => 'LEVEL$:pct',
'webCmd' => 'up:down:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'BLIND_VIRTUAL_RECEIVER' => {
'ccureadingname' => 'LEVEL$:pct',
'webCmd' => 'up:down:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
'SHUTTER_VIRTUAL_RECEIVER' => {
'ccureadingname' => 'LEVEL$:pct',
'webCmd' => 'up:down:stop:pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
@ -228,7 +225,6 @@ use vars qw(%HMCCU_SCRIPTS);
'widgetOverride' => 'toggle:uzsuToggle,off,on'
},
'DIMMER' => {
'ccureadingname' => 'LEVEL$:pct',
'webCmd' => 'pct',
'widgetOverride' => 'pct:slider,0,10,100'
},
@ -238,19 +234,16 @@ use vars qw(%HMCCU_SCRIPTS);
'widgetOverride' => 'pct:slider,0,10,100'
},
'THERMALCONTROL_TRANSMIT' => {
'ccureadingname' => 'SET_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost:on:off',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
},
'CLIMATECONTROL_RT_TRANSCEIVER' => {
'ccureadingname' => 'SET_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'
},
'HEATING_CLIMATECONTROL_TRANSCEIVER' => {
'ccureadingname' => 'SET_POINT_TEMPERATURE$:desired-temp;ACTUAL_TEMPERATURE$:measured-temp',
'cmdIcon' => 'auto:sani_heating_automatic manu:sani_heating_manual boost:sani_heating_boost on:general_an off:general_aus',
'webCmd' => 'desired-temp:auto:manu:boost',
'widgetOverride' => 'desired-temp:slider,4.5,0.5,30.5,1'