2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

HMCCU: Support for CCU firmware 3.41.7

git-svn-id: https://svn.fhem.de/fhem/trunk@17672 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2018-11-04 12:40:18 +00:00
parent dca4508007
commit 28012b5c5a
5 changed files with 299 additions and 221 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- bugfix: 88_HMCCU: support for CCU firmware 3.41.7
- bugfix: 38_netatmo: fixed ignored values after 'dead' state
- feature: 72_XiaomiDevice: load_power reading for power plug
- feature: 34_ESPEasy: added set cmds: active/inactive/reopen, shutdown tcp

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.3.005
# Version 4.3.006
#
# Module for communication between FHEM and Homematic CCU2/3.
#
@ -108,7 +108,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.3.005';
my $HMCCU_VERSION = '4.3.006';
# Default RPC port (BidCos-RF)
my $HMCCU_RPC_PORT_DEFAULT = 2001;
@ -255,6 +255,7 @@ sub HMCCU_GetDefaults ($$);
# Status and logging functions
sub HMCCU_Trace ($$$$);
sub HMCCU_Log ($$$$);
sub HMCCU_LogError ($$$);
sub HMCCU_SetError ($@);
sub HMCCU_SetState ($@);
sub HMCCU_SetRPCState ($@);
@ -349,6 +350,7 @@ sub HMCCU_GetSwitchDatapoint ($$$);
sub HMCCU_GetValidDatapoints ($$$$$);
sub HMCCU_IsValidDatapoint ($$$$$);
sub HMCCU_SetDatapoint ($$$);
sub HMCCU_SetMultipleDatapoints ($$);
# Internal RPC server functions
sub HMCCU_ResetRPCQueue ($$);
@ -1425,7 +1427,7 @@ sub HMCCU_Set ($@)
my $name = shift @$a;
my $opt = shift @$a;
my $options = "var delete execute hmscript cleardefaults:noArg defaults:noArg ".
"importdefaults rpcregister:all rpcserver:on,off,restart datapoint ackmessages:noArg";
"importdefaults rpcregister:all rpcserver:on,off,restart ackmessages:noArg";
my @ifList = HMCCU_GetRPCInterfaceList ($hash);
if (scalar (@ifList) > 0) {
my $ifStr = join (',', @ifList);
@ -1478,16 +1480,7 @@ sub HMCCU_Set ($@)
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'datapoint') {
my $objname = shift @$a;
my $objvalue = shift @$a;
$usage = "Usage: set $name $opt {ccuobject|'hmccu':fhemobject} value";
return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue));
my $rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
return HMCCU_SetError ($hash, "Command set datapoint is no longer supported by I/O device");
}
elsif ($opt eq 'delete') {
my $objname = shift @$a;
@ -2096,6 +2089,20 @@ sub HMCCU_ParseObject ($$$)
my ($i, $a, $c, $d, $n, $f) = ('', '', '', '', '', '', 0);
my $extaddr;
# "ccu:" is default. Remove it.
$object =~ s/^ccu://g;
# Check for FHEM device
if ($object =~ /^hmccu:/) {
my ($hmccu, $fhdev, $fhcdp) = split(':', $object);
return ($i, $a, $c, $d, $n, $f) if (!defined ($fhdev));
my $cl_hash = $defs{$fhdev};
return ($i, $a, $c, $d, $n, $f) if (!defined ($cl_hash) ||
($cl_hash->{TYPE} ne 'HMCCUDEV' && $cl_hash->{TYPE} ne 'HMCCUCHN'));
$object = $cl_hash->{ccuaddr};
$object .= ":$fhcdp" if (defined ($fhcdp));
}
# Check if address is already known by HMCCU. Substitute device address by ZZZ0000000
# to allow external addresses like HVL
if ($object =~ /^.+\.(.+):[0-9]{1,2}\..+$/ ||
@ -2473,10 +2480,24 @@ sub HMCCU_Log ($$$$)
return $rc;
}
######################################################################
# Log message and return message preceded by string "ERROR: ".
######################################################################
sub HMCCU_LogError ($$$)
{
my ($hash, $level, $msg) = @_;
HMCCU_Log ($hash, $level, $msg, undef);
return "ERROR: $msg";
}
######################################################################
# Set error state and write log file message
# Parameter text can be an error code (integer < 0) or an error text.
# Parameter addinfo is optional.
# Return error message.
######################################################################
sub HMCCU_SetError ($@)
@ -2504,7 +2525,8 @@ sub HMCCU_SetError ($@)
-16 => 'Cannot open file',
-17 => 'Cannot detect or create external RPC device',
-18 => 'Type of system variable not supported',
-19 => 'Device not initialized'
-19 => 'Device not initialized',
-20 => 'Invalid or unknown device interface'
);
$msg = exists ($errlist{$text}) ? $errlist{$text} : $text;
@ -2513,7 +2535,8 @@ sub HMCCU_SetError ($@)
$msg .= ". $addinfo";
}
Log3 $name, 1, $msg;
HMCCU_Log ($hash, 1, $msg, undef);
return HMCCU_SetState ($hash, "Error", $msg);
}
@ -3377,6 +3400,8 @@ sub HMCCU_UpdatePeers ($$$$)
my ($clt_hash, $chndpt, $val, $peerattr) = @_;
my $fnc = "UpdatePeers";
my $io_hash = HMCCU_GetHash ($clt_hash);
HMCCU_Trace ($clt_hash, 2, $fnc, "chndpt=$chndpt val=$val peer=$peerattr");
my @rules = split (/[;\n]+/, $peerattr);
@ -3413,7 +3438,10 @@ sub HMCCU_UpdatePeers ($$$$)
$aexp =~ s/\$value/$val/g;
$aexp = HMCCU_SubstVariables ($clt_hash, $aexp, $vars);
HMCCU_Trace ($clt_hash, 2, $fnc, "set $aobj to $aexp");
HMCCU_SetDatapoint ($clt_hash, "$type:$aobj", $aexp);
my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($io_hash, "$type:$aobj",
$HMCCU_FLAG_INTERFACE);
next if ($flags != $HMCCU_FLAGS_IACD && $flags != $HMCCU_FLAGS_NCD);
HMCCU_SetMultipleDatapoints ($clt_hash, { "001.$int.$add:$chn.$dpt" => $aexp });
}
elsif ($type eq 'fhem') {
$act =~ s/\$value/$val/g;
@ -4290,6 +4318,10 @@ sub HMCCU_GetDeviceList ($)
if ($ifurl =~ /^([^:]+):\/\/([^:]+):([0-9]+)/) {
my ($prot, $ipaddr, $port) = ($1, $2, $3);
next if (!defined ($port) || $port eq '');
if ($port >= 10000) {
$port -= 30000;
$ifurl =~ s/:3$port/:$port/;
}
if ($hash->{ccuip} ne 'N/A') {
$ifurl =~ s/127\.0\.0\.1/$hash->{ccuip}/;
$ipaddr =~ s/127\.0\.0\.1/$hash->{ccuip}/;
@ -4313,7 +4345,7 @@ sub HMCCU_GetDeviceList ($)
$hash->{hmccu}{interfaces}{$hmdata[1]}{host} = $ipaddr;
$hash->{hmccu}{interfaces}{$hmdata[1]}{state} = 'inactive';
$hash->{hmccu}{interfaces}{$hmdata[1]}{manager} = 'null';
$hash->{hmccu}{interfaces}{$hmdata[1]}{flags} = $HMCCU_RPC_FLAG{$port};
$hash->{hmccu}{interfaces}{$hmdata[1]}{flags} = $HMCCU_RPC_FLAG{$port};
$hash->{hmccu}{ifports}{$port} = $hmdata[1];
$ifcount++;
}
@ -4731,11 +4763,9 @@ sub HMCCU_IsValidDatapoint ($$$$$)
my $chnno;
if (defined ($chn)) {
if ($chn =~ /^[0-9]{1,2}$/) {
HMCCU_Trace ($hash, 2, $fnc, "$chn is a channel number");
$chnno = $chn;
}
elsif (HMCCU_IsValidChannel ($hmccu_hash, $chn, $HMCCU_FL_ADDRESS)) {
HMCCU_Trace ($hash, 2, $fnc, "$chn is a valid channel address");
my ($a, $c) = split(":",$chn);
$chnno = $c;
}
@ -4747,17 +4777,18 @@ sub HMCCU_IsValidDatapoint ($$$$$)
elsif ($dpt =~ /^([0-9]{1,2})\.(.+)$/) {
$chnno = $1;
$dpt = $2;
HMCCU_Trace ($hash, 2, $fnc, "$dpt contains channel number");
}
else {
HMCCU_Trace ($hash, 2, $fnc, "channel number missing in datapoint $dpt");
return 0;
}
HMCCU_Trace ($hash, 2, $fnc, "devtype=$devtype, chnno=$chnno, dpt=$dpt");
return (exists ($hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chnno}{$dpt}) &&
my $v = (exists ($hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chnno}{$dpt}) &&
($hmccu_hash->{hmccu}{dp}{$devtype}{ch}{$chnno}{$dpt}{oper} & $oper)) ? 1 : 0;
HMCCU_Trace ($hash, 2, $fnc, "devtype=$devtype, chnno=$chnno, dpt=$dpt, valid=$v");
return $v;
}
######################################################################
@ -5804,24 +5835,26 @@ sub HMCCU_ReadRPCQueue ($)
sub HMCCU_HMCommand ($$$)
{
my ($hash, $cmd, $mode) = @_;
my $name = $hash->{NAME};
my ($cl_hash, $cmd, $mode) = @_;
my $cl_name = $cl_hash->{NAME};
my $fnc = "HMCommand";
my $ccureqtimeout = AttrVal ($name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$hash->{host}.":8181/do.exe?r1=".urlEncode($cmd);
my $io_hash = HMCCU_GetHash ($cl_hash);
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$io_hash->{host}.":8181/tclrega.exe";
my $value;
HMCCU_Trace ($hash, 2, $fnc, "URL=$url");
HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url, cmd=$cmd");
my $response = GetFileFromURL ($url, $ccureqtimeout);
my $response = GetFileFromURL ($url, $ccureqtimeout, $cmd);
if (defined ($response)) {
$response =~ m/<r1>(.*)<\/r1>/;
$value = $1;
HMCCU_Trace ($hash, 2, $fnc, "Response = $response");
$value = $response;
$value =~ s/<xml>(.*)<\/xml>//;
$value =~ s/\r//g;
HMCCU_Trace ($cl_hash, 2, $fnc, "Response=$response, Value=".(defined ($value) ? $value : "undef"));
}
else {
HMCCU_Trace ($hash, 2, $fnc, "Response undefined");
HMCCU_Trace ($cl_hash, 2, $fnc, "Response=undef");
}
if ($mode == 1) {
@ -5838,24 +5871,24 @@ sub HMCCU_HMCommand ($$$)
sub HMCCU_HMCommandNB ($$$)
{
my ($hash, $cmd, $cbfunc) = @_;
my $name = $hash->{NAME};
my ($cl_hash, $cmd, $cbfunc) = @_;
my $cl_name = $cl_hash->{NAME};
my $fnc = "HMCommandNB";
my $hmccu_hash = HMCCU_GetHash ($hash);
my $ccureqtimeout = AttrVal ($hmccu_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$hmccu_hash->{host}.":8181/do.exe?r1=".urlEncode($cmd);
my $io_hash = HMCCU_GetHash ($cl_hash);
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$io_hash->{host}.":8181/tclrega.exe";
HMCCU_Trace ($hash, 2, $fnc, "URL=$url");
HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url");
if (defined ($cbfunc)) {
my $param = { url => $url, timeout => $ccureqtimeout, method => "GET",
callback => $cbfunc, devhash => $hash };
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST",
callback => $cbfunc, devhash => $cl_hash };
HttpUtils_NonblockingGet ($param);
}
else {
my $param = { url => $url, timeout => $ccureqtimeout, method => "GET",
callback => \&HMCCU_HMCommandCB, devhash => $hash };
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST",
callback => \&HMCCU_HMCommandCB, devhash => $cl_hash };
HttpUtils_NonblockingGet ($param);
}
}
@ -5878,9 +5911,10 @@ sub HMCCU_HMCommandCB ($$$)
# Execute Homematic script on CCU.
# Parameters: device-hash, script-code or script-name, parameter-hash
# If content of hmscript starts with a ! the following text is treated
# as name of an internal HomeMatic script function.
# as name of an internal HomeMatic script function defined in
# HMCCUConf.pm.
# If content of hmscript is enclosed in [] the content is treated as
# HomeMatic script code.
# HomeMatic script code. Characters [] will be removed.
# Otherwise hmscript is the name of a file containing Homematic script
# code.
# Return script output or error message starting with "ERROR:".
@ -5890,25 +5924,24 @@ sub HMCCU_HMScriptExt ($$$)
{
my ($hash, $hmscript, $params) = @_;
my $name = $hash->{NAME};
my $host = $hash->{host};
my $code = $hmscript;
my $scrname = '';
if (!exists ($hash->{host})) {
Log3 $name, 2, "HMCCU: CCU host name not defined. Name=$name Type=".$hash->{TYPE};
return "ERROR: CCU host name not defined";
}
return HMCCU_LogError ($hash, 2, "CCU host name not defined") if (!exists ($hash->{host}));
my $host = $hash->{host};
# Check for internal script
if ($hmscript =~ /^!(.*)$/) {
# Internal script
$scrname = $1;
return "ERROR: Can't find internal script $scrname" if (!exists ($HMCCU_SCRIPTS->{$scrname}));
$code = $HMCCU_SCRIPTS->{$scrname}{code};
}
elsif ($hmscript =~ /^\[(.*)\]$/) {
# Script code
$code = $1;
}
else {
# Script file
if (open (SCRFILE, "<$hmscript")) {
my @lines = <SCRFILE>;
$code = join ("\n", @lines);
@ -5975,54 +6008,139 @@ sub HMCCU_BulkUpdate ($$$$)
######################################################################
# Get datapoint value from CCU and update reading.
# If parameter noupd is defined and > 0 no readings will be updated.
######################################################################
sub HMCCU_GetDatapoint ($@)
{
my ($hash, $param) = @_;
my $name = $hash->{NAME};
my ($cl_hash, $param, $noupd) = @_;
my $cl_name = $cl_hash->{NAME};
my $fnc = "GetDatapoint";
my $hmccu_hash;
my $value = '';
$hmccu_hash = HMCCU_GetHash ($hash);
return (-3, $value) if (!defined ($hmccu_hash));
return (-4, $value) if ($hash->{TYPE} ne 'HMCCU' && $hash->{ccudevstate} eq 'deleted');
my $io_hash = HMCCU_GetHash ($cl_hash);
return (-3, $value) if (!defined ($io_hash));
return (-4, $value) if ($cl_hash->{TYPE} ne 'HMCCU' && $cl_hash->{ccudevstate} eq 'deleted');
my $readingformat = HMCCU_GetAttrReadingFormat ($hash, $hmccu_hash);
my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $io_hash);
my ($statechn, $statedpt, $controlchn, $controldpt) = HMCCU_GetSpecialDatapoints (
$hash, '', 'STATE', '', '');
my $ccuget = HMCCU_GetAttribute ($hmccu_hash, $hash, 'ccuget', 'Value');
my $ccureqtimeout = AttrVal ($hmccu_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
$cl_hash, '', 'STATE', '', '');
my $ccuget = HMCCU_GetAttribute ($io_hash, $cl_hash, 'ccuget', 'Value');
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $cmd = '';
my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($hmccu_hash, $param,
my ($int, $add, $chn, $dpt, $nam, $flags) = HMCCU_ParseObject ($io_hash, $param,
$HMCCU_FLAG_INTERFACE);
return (-1, $value) if ($flags != $HMCCU_FLAGS_IACD && $flags != $HMCCU_FLAGS_NCD);
if ($flags == $HMCCU_FLAGS_IACD) {
$cmd = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).'.$ccuget.'()';
$cmd = 'Write((datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).'.$ccuget.'())';
}
elsif ($flags == $HMCCU_FLAGS_NCD) {
$cmd = '(dom.GetObject(ID_CHANNELS)).Get("'.$nam.'").DPByHssDP("'.$dpt.'").'.$ccuget.'()';
($add, $chn) = HMCCU_GetAddress ($hmccu_hash, $nam, '', '');
$cmd = 'Write((dom.GetObject(ID_CHANNELS)).Get("'.$nam.'").DPByHssDP("'.$dpt.'").'.$ccuget.'())';
($add, $chn) = HMCCU_GetAddress ($io_hash, $nam, '', '');
}
HMCCU_Trace ($hash, 2, $fnc, "CMD=$cmd, param=$param, ccuget=$ccuget");
HMCCU_Trace ($cl_hash, 2, $fnc, "CMD=$cmd, param=$param, ccuget=$ccuget");
$value = HMCCU_HMCommand ($hmccu_hash, $cmd, 1);
$value = HMCCU_HMCommand ($cl_hash, $cmd, 1);
if (defined ($value) && $value ne '' && $value ne 'null') {
$value = HMCCU_UpdateSingleDatapoint ($hash, $chn, $dpt, $value);
HMCCU_Trace ($hash, 2, $fnc, "Value of $chn.$dpt = $value");
if (defined ($value) && $value ne '' && $value ne 'null' &&
(!defined ($noupd) || $noupd == 0)) {
$value = HMCCU_UpdateSingleDatapoint ($cl_hash, $chn, $dpt, $value);
HMCCU_Trace ($cl_hash, 2, $fnc, "Value of $chn.$dpt = $value");
return (1, $value);
}
else {
HMCCU_Log ($hash, 1, "Error CMD = $cmd", 0);
HMCCU_Log ($cl_hash, 1, "Error CMD = $cmd", 0);
return (-2, '');
}
}
######################################################################
# Set multiple datapoints on CCU in a single request.
# Parameter params is a hash reference. Keys are full qualified CCU
# datapoint specifications in format:
# no.interface.address:channelno.datapoint
# Parameter no defines the command order.
######################################################################
sub HMCCU_SetMultipleDatapoints ($$) {
my ($cl_hash, $params) = @_;
my $fnc = "SetMultipleDatapoints";
my $type = $cl_hash->{TYPE};
my $io_hash = HMCCU_GetHash ($cl_hash);
return -3 if (!defined ($io_hash));
return -4 if (exists ($cl_hash->{ccudevstate}) && $cl_hash->{ccudevstate} eq 'deleted');
my $io_name = $io_hash->{NAME};
my $cl_name = $cl_hash->{NAME};
my $ccureqtimeout = AttrVal ($io_name, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $ccuflags = HMCCU_GetFlags ($io_name);
my $readingformat = HMCCU_GetAttrReadingFormat ($cl_hash, $io_hash);
my $ccuverify = AttrVal ($cl_name, 'ccuverify', 0);
my $ccuchange = AttrVal ($cl_name, 'ccuSetOnChange', 'null');
my $ccutype = $cl_hash->{ccutype};
# Build Homematic script
my @addrlist = $cl_hash->{ccuif} eq 'fhem' ? split (',', $cl_hash->{ccugroup}) : ($cl_hash->{ccuaddr});
my $cmd = '';
foreach my $a (@addrlist) {
foreach my $p (sort keys %$params) {
my $v = $params->{$p};
HMCCU_Trace ($cl_hash, 2, $fnc, "dpt=$p, value=$v");
# Check address
my ($no, $int, $addchn, $dpt) = split (/\./, $p);
return -1 if (!defined ($dpt));
my ($add, $chn) = split (/:/, $addchn);
return -1 if (!defined ($chn));
return -8 if (!HMCCU_IsValidDatapoint ($cl_hash, $ccutype, $chn, $dpt, 2));
# Override device interface and address if device is virtual
if ($cl_hash->{ccuif} eq 'fhem') {
$add = $a;
$int = HMCCU_GetDeviceInterface ($io_hash, $add, '');
return -20 if ($int eq '');
}
if ($ccutype eq 'HM-Dis-EP-WM55' && $dpt eq 'SUBMIT') {
$v = HMCCU_EncodeEPDisplay ($v);
}
else {
$v = HMCCU_ScaleValue ($cl_hash, $chn, $dpt, $v, 1);
}
my $dpttype = HMCCU_GetDatapointAttr ($io_hash, $ccutype, $chn, $dpt, 'type');
$v = "'".$v."'" if (defined ($dpttype) && $dpttype == $HMCCU_TYPE_STRING);
my $c = '(datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).State('.$v.");\n";
if ($dpt =~ /$ccuchange/) {
$cmd .= 'if((datapoints.Get("'.$int.'.'.$add.':'.$chn.'.'.$dpt.'")).Value() != '.$v.") {\n$c}\n";
}
else {
$cmd .= $c;
}
}
}
# Execute command (non blocking)
if ($ccuflags =~ /nonBlocking/) {
HMCCU_HMCommandNB ($cl_hash, $cmd, undef);
return 0;
}
# Execute command (blocking)
my $response = HMCCU_HMCommand ($cl_hash, $cmd, 1);
return -2 if (!defined ($response));
# Datapoint verification ???
return 0;
}
######################################################################
# Set datapoint on CCU.
# Parameter param is a valid CCU or FHEM datapoint specification:
@ -6107,7 +6225,7 @@ sub HMCCU_SetDatapoint ($$$)
}
# Execute command (blocking)
my $response = HMCCU_HMCommand ($hmccu_hash, $cmd, 1);
my $response = HMCCU_HMCommand ($hash, $cmd, 1);
HMCCU_Trace ($hash, 2, $fnc,
"Addr=$addr Name=$nam<br>".
"Script response = \n".(defined ($response) ? $response: 'undef')."<br>".
@ -6117,7 +6235,7 @@ sub HMCCU_SetDatapoint ($$$)
# Verify setting of datapoint value or update reading with new datapoint value
if (HMCCU_IsValidDatapoint ($hash, $hash->{ccutype}, $addr, $dpt, 1)) {
if ($ccuverify == 1) {
my ($rc, $result) = HMCCU_GetDatapoint ($hash, $param);
my ($rc, $result) = HMCCU_GetDatapoint ($hash, $param, 0);
return $rc;
}
elsif ($ccuverify == 2) {
@ -6821,8 +6939,6 @@ sub HMCCU_GetHMState ($$$)
$hmstatevals =~ s/^=[^;]*;//;
}
HMCCU_Trace ($clhash, 2, $fnc, "hmstatevals=$hmstatevals");
# Default hmstate is equal to state
$hmstate[3] = ReadingsVal ($name, 'state', undef) if (!defined ($defval));
@ -6834,7 +6950,7 @@ sub HMCCU_GetHMState ($$$)
my ($dptexpr, $subst) = split ('!', $rule, 2);
my $dp = '';
next if (!defined ($dptexpr) || !defined ($subst));
HMCCU_Trace ($clhash, 2, $fnc, "dptexpr=$dptexpr, subst=$subst");
HMCCU_Trace ($clhash, 2, $fnc, "rule=$rule, dptexpr=$dptexpr, subst=$subst");
foreach my $d (keys %{$clhash->{hmccu}{dp}}) {
HMCCU_Trace ($clhash, 2, $fnc, "Check $d match $dptexpr");
if ($d =~ /$dptexpr/) {
@ -7694,17 +7810,6 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<li><b>set &lt;name&gt; cleardefaults</b><br/>
Clear default attributes imported from file.
</li><br/>
<li><b>set &lt;name&gt; datapoint {&lt;[ccu:]ccuobject&gt;|&lt;hmccu:fhemobject&gt;}.
&lt;datapoint&gt; &lt;value&gt;</b><br/>
Set datapoint of CCU channel in "raw" mode. The value is not scaled or substituted. If
target object is preceded by string "hmccu:" the following parameter <i>fhemobject</i>
must be a FHEM device of type HMCCUDEV or HMCCUCHN. If device type is HMCCUDEV the device
name must be followed by a ':' and a valid channel number.<br/><br/>
Examples:<br/>
<code>set d_ccu datapoint ABC1234567:1.STATE true</code><br/>
<code>set d_ccu datapoint hmccu:mychndevice.STATE true</code><br/>
<code>set d_ccu datapoint hmccu:mydevdevice:1.STATE true</code>
</li><br/>
<li><b>set &lt;name&gt; defaults</b><br/>
Set default attributes for I/O device.
</li><br/>

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.3.002
# Version 4.3.003
#
# (c) 2018 zap (zap01 <at> t-online <dot> de)
#
@ -40,6 +40,7 @@
# attr <name> ccureadingfilter <filter-rule>[;...]
# attr <name> ccureadingformat { name[lc] | address[lc] | datapoint[lc] }
# attr <name> ccureadingname <oldname>:<newname>[;...]
# attr <name> ccuSetOnChange <expr>
# attr <name> ccuverify { 0 | 1 | 2 }
# attr <name> controldatapoint <datapoint>
# attr <name> disable { 0 | 1 }
@ -86,7 +87,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{AttrList} = "IODev ccucalculate ".
"ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
"ccureadingname:textField-long ".
"ccureadingname:textField-long ccuSetOnChange ".
"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;
@ -277,26 +278,25 @@ sub HMCCUCHN_Set ($@)
if ($opt eq 'datapoint') {
my $usage = "Usage: set $name datapoint {datapoint} {value} [...]";
my %dpval;
my $i = 0;
while (my $objname = shift @$a) {
my $objvalue = shift @$a;
$i += 1;
return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue));
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 2));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
$objname = $ccuif.'.'.$ccuaddr.'.'.$objname;
$dpval{$objname} = $objvalue;
my $no = sprintf ("%03d", $i);
$objvalue =~ s/\\_/%20/g;
$dpval{"$no.$ccuif.$ccuaddr.$objname"} = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
}
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
foreach my $dpt (keys %dpval) {
$rc = HMCCU_SetDatapoint ($hash, $dpt, $dpval{$dpt});
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
}
@ -307,10 +307,10 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
my $objname = $ccuif.'.'.$ccuaddr.'.'.$cd;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$cd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -325,11 +325,9 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr.$sd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -346,7 +344,7 @@ sub HMCCUCHN_Set ($@)
my $stc = scalar (@states);
my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 1);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
my $objvalue = '';
@ -364,8 +362,9 @@ sub HMCCUCHN_Set ($@)
return HMCCU_SetError ($hash, "Current device state doesn't match statevals")
if ($objvalue eq '');
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$objname" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -381,40 +380,25 @@ sub HMCCUCHN_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, $ccuaddr, "ON_TIME", 2));
if ($timespec =~ /^[0-9]{2}:[0-9]{2}/) {
my (undef, $h, $m, $s) = GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS")
if (!defined ($h));
$s += $h*3600+$m*60;
my @lt = localtime;
my $cs = $lt[2]*3600+$lt[1]*60+$lt[0];
$s += 86400 if ($cs > $s);
$timespec = $s-$cs;
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
if ($timespec > 0) {
$objname = $ccuif.'.'.$ccuaddr.'.ON_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 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));
$objname = $ccuif.'.'.$ccuaddr.'.RAMP_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $ramptime);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
$dpval{"001.$ccuif.$ccuaddr.ON_TIME"} = $timespec if ($timespec > 0);
}
# Set ramp time
$dpval{"002.$ccuif.$ccuaddr.RAMP_TIME"} = $ramptime if (defined ($ramptime));
# Set level
$objname = $ccuif.'.'.$ccuaddr.'.LEVEL';
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$dpval{"003.$ccuif.$ccuaddr.LEVEL"} = $objvalue;
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -434,25 +418,14 @@ sub HMCCUCHN_Set ($@)
if (!defined ($timespec));
if ($opt eq 'on-till') {
my (undef, $h, $m, $s) = GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM or HH:MM:SS")
if (!defined ($h));
$s += $h*3600+$m*60;
my @lt = localtime;
my $cs = $lt[2]*3600+$lt[1]*60+$lt[0];
$s += 86400 if ($cs > $s);
$timespec = $s-$cs;
$timespec = HMCCU_GetTimeSpec ($timespec);
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
# Set time
my $objname = $ccuif.'.'.$ccuaddr.'.ON_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# Set state
$objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
my $objvalue = HMCCU_Substitute ("on", $statevals, 1, undef, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash, {
"001.$ccuif.$ccuaddr.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr.$sd" => HMCCU_Substitute ("on", $statevals, 1, undef, '')
});
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -542,7 +515,7 @@ sub HMCCUCHN_Get ($@)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $sd, 1));
my $objname = $ccuif.'.'.$ccuaddr.'.'.$sd;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
return $ccureadings ? undef : $result;
}
@ -555,7 +528,7 @@ sub HMCCUCHN_Get ($@)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $ccuaddr, $objname, 1));
$objname = $ccuif.'.'.$ccuaddr.'.'.$objname;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
return $ccureadings ? undef : $result;
}
@ -812,10 +785,13 @@ sub HMCCUCHN_Get ($@)
<br/><br/>
<li><b>ccucalculate &lt;value-type&gt;:&lt;reading&gt;[:&lt;dp-list&gt;[;...]</b><br/>
Calculate special values like dewpoint based on datapoints specified in
<i>dp-list</i>. The result is stored in <i>reading</i>. The following <i>values</i>
are supported:<br/>
<i>dp-list</i>. The result is stored in <i>reading</i>. For datapoints in <i>dp-list</i>
also variable notation is supported (for more information on variables see documentation of
attribute 'peer').<br/>
The following <i>values</i> are supported:<br/>
dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
abshumidity = calculate absolute humidity, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
equ = compare datapoint values. Result is "n/a" if values are not equal.<br/>
inc = increment datapoint value considering reset of datapoint, <i>dp-list</i> = &lt;counter-datapoint&gt;<br/>
min = calculate minimum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
max = calculate maximum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
@ -893,6 +869,11 @@ sub HMCCUCHN_Get ($@)
attr myblind ccuscale !LEVEL:0:1:0:100
</code>
</li><br/>
<li><b>ccuSetOnChange &lt;expression&gt;</b><br/>
Check if datapoint value will be changed by set command before changing datapoint value.
This attribute can reduce the traffic between CCU and devices. It presumes that datapoint
state in CCU is current.
</li><br/>
<li><b>ccuverify {<u>0</u> | 1 | 2}</b><br/>
If set to 1 a datapoint is read for verification after set operation. If set to 2 the
corresponding reading will be set to the new value directly after setting a datapoint

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.3.004
# Version 4.3.005
#
# (c) 2018 zap (zap01 <at> t-online <dot> de)
#
@ -92,7 +92,7 @@ sub HMCCUDEV_Initialize ($)
"ccuflags:multiple-strict,ackState,nochn0,trace ccureadingfilter:textField-long ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ".
"ccureadingname:textField-long ".
"ccureadings:0,1 ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 ".
"ccureadings:0,1 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 ".
$readingFnAttributes;
@ -422,8 +422,11 @@ sub HMCCUDEV_Set ($@)
if ($opt eq 'datapoint') {
my $usage = "Usage: set $name datapoint [{channel-number}.]{datapoint} {value} [...]";
my %dpval;
my $i = 0;
while (my $objname = shift @$a) {
my $objvalue = shift @$a;
$i += 1;
if ($ccutype eq 'HM-Dis-EP-WM55' && !defined ($objvalue)) {
$objvalue = '';
@ -447,22 +450,16 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, -11) if ($sc eq '');
$objname = $sc.'.'.$objname;
}
return HMCCU_SetError ($hash, -8)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, undef, $objname, 2));
my $no = sprintf ("%03d", $i);
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
$objname = $ccuif.'.'.$ccuaddr.':'.$objname;
$dpval{$objname} = $objvalue;
$dpval{"$no.$ccuif.$ccuaddr:$objname"} = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
}
return HMCCU_SetError ($hash, $usage) if (scalar (keys %dpval) < 1);
foreach my $dpt (keys %dpval) {
$rc = HMCCU_SetDatapoint ($hash, $dpt, $dpval{$dpt});
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
}
@ -473,13 +470,12 @@ sub HMCCUDEV_Set ($@)
my $objvalue = shift @$a;
return HMCCU_SetError ($hash, "Usage: set $name control {value}") if (!defined ($objvalue));
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, $cd, 2));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
my $objname = $ccuif.'.'.$ccuaddr.':'.$cc.'.'.$cd;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$cc.$cd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -490,14 +486,12 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, -11) if ($sc eq '');
return HMCCU_SetError ($hash, -13) if ($sd eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, $sd, 2));
return HMCCU_SetError ($hash, "Usage: set $name devstate {value}") if (!defined ($objvalue));
$objvalue =~ s/\\_/%20/g;
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
my $objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.'.$sd;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -515,8 +509,8 @@ sub HMCCUDEV_Set ($@)
my $objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.'.$sd;
# Read current value of datapoint
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
# Read current value of datapoint without updating reading
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 1);
Log3 $name, 2, "HMCCU: set toggle: GetDatapoint returned $rc, $result"
if ($ccuflags =~ /trace/);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
@ -536,20 +530,21 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, "Current device state doesn't match statevals")
if ($objvalue eq '');
$objvalue = HMCCU_Substitute ($objvalue, $statevals, 1, undef, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash,
{ "001.$objname" => HMCCU_Substitute ($objvalue, $statevals, 1, undef, '') }
);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'pct') {
return HMCCU_SetError ($hash, -11) if ($sc eq '' && $cc eq '');
my $dp;
my $chn;
if (HMCCU_IsValidDatapoint ($hash, $ccutype, $cc, "LEVEL", 2)) {
$dp = "$cc.LEVEL";
$chn = $cc;
}
elsif (HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "LEVEL", 2)) {
$dp = "$sc.LEVEL";
$chn = $sc;
}
else {
return HMCCU_SetError ($hash, "Can't find LEVEL datapoint for device type $ccutype")
@ -562,34 +557,26 @@ sub HMCCUDEV_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, $sc, "ON_TIME", 2));
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);
}
if ($timespec > 0) {
$objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.ON_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
$dpval{"001.$ccuif.$ccuaddr:$chn.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, $sc, "RAMP_TIME", 2));
$objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.RAMP_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $ramptime);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
}
$dpval{"002.$ccuif.$ccuaddr:$chn.RAMP_TIME"} = $ramptime if (defined ($ramptime));
# Set level
$objname = $ccuif.'.'.$ccuaddr.':'.$dp;
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$dpval{"003.$ccuif.$ccuaddr:$chn.LEVEL"} = $objvalue;
$rc = HMCCU_SetMultipleDatapoints ($hash, \%dpval);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -600,7 +587,6 @@ sub HMCCUDEV_Set ($@)
if ("on" !~ /($hash->{statevals})/);
return HMCCU_SetError ($hash, -11) if ($sc eq '');
return HMCCU_SetError ($hash, -13) if ($sd eq '');
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, $sd, 2));
return HMCCU_SetError ($hash, "Can't find ON_TIME datapoint for device type")
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, "ON_TIME", 2));
@ -613,15 +599,10 @@ sub HMCCUDEV_Set ($@)
return HMCCU_SetError ($hash, "Wrong time format. Use HH:MM[:SS]") if ($timespec < 0);
}
# Set time
my $objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.ON_TIME';
$rc = HMCCU_SetDatapoint ($hash, $objname, $timespec);
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
# Set state
$objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.'.$sd;
my $objvalue = HMCCU_Substitute ("on", $statevals, 1, undef, '');
$rc = HMCCU_SetDatapoint ($hash, $objname, $objvalue);
$rc = HMCCU_SetMultipleDatapoints ($hash, {
"001.$ccuif.$ccuaddr:$sc.ON_TIME" => $timespec,
"002.$ccuif.$ccuaddr:$sc.$sd" => HMCCU_Substitute ("on", $statevals, 1, undef, '')
});
return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK");
@ -728,7 +709,7 @@ sub HMCCUDEV_Get ($@)
return HMCCU_SetError ($hash, -8) if (!HMCCU_IsValidDatapoint ($hash, $ccutype, $sc, $sd, 1));
my $objname = $ccuif.'.'.$ccuaddr.':'.$sc.'.'.$sd;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
return $ccureadings ? undef : $result;
@ -751,7 +732,7 @@ sub HMCCUDEV_Get ($@)
if (!HMCCU_IsValidDatapoint ($hash, $ccutype, undef, $objname, 1));
$objname = $ccuif.'.'.$ccuaddr.':'.$objname;
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname);
($rc, $result) = HMCCU_GetDatapoint ($hash, $objname, 0);
return HMCCU_SetError ($hash, $rc, $result) if ($rc < 0);
HMCCU_SetState ($hash, "OK") if (exists ($hash->{STATE}) && $hash->{STATE} eq "Error");
@ -1070,6 +1051,9 @@ sub HMCCUDEV_Get ($@)
ccuscaleval &lt;[!]datapoint&gt;:&lt;min&gt;:&lt;max&gt;:&lt;minn&gt;:&lt;maxn&gt;[,...]<br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>ccuSetOnChange &lt;expression&gt;</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>ccuverify {0 | 1 | 2}</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 1.1
# Version 1.2
#
# Subprocess based RPC Server module for HMCCU.
#
@ -35,7 +35,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
my $HMCCURPCPROC_VERSION = '1.0.007';
my $HMCCURPCPROC_VERSION = '1.2';
# Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100;
@ -199,7 +199,7 @@ sub HMCCURPCPROC_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = "ccuflags:multiple-strict,expert,reconnect,logEvents,ccuInit,queueEvents".
$hash->{AttrList} = "ccuflags:multiple-strict,expert,reconnect,logEvents,ccuInit,queueEvents,noEvents".
" rpcMaxEvents rpcQueueSend rpcQueueSize rpcMaxIOErrors".
" rpcServerAddr rpcServerPort rpcWriteTimeout rpcAcceptTimeout".
" rpcConnTimeout rpcStatistics rpcEventTimeout ".
@ -291,6 +291,8 @@ sub HMCCURPCPROC_Define ($$)
return "Invalid port or interface $iface" if ($rc == 1);
return "Can't assign I/O device $ioname" if ($rc == 2);
return "Invalid local IP address ".$hash->{hmccu}{localaddr} if ($rc == 3);
return "RPC device for CCU/port already exists" if ($rc == 4);
return "Cannot connect to CCU ".$hash->{host}." interface $iface" if ($rc == 5);
return undef;
}
@ -302,6 +304,8 @@ sub HMCCURPCPROC_Define ($$)
# 1 = Invalid port or interface
# 2 = Cannot assign IO device
# 3 = Invalid local IP address
# 4 = RPC device for CCU/port already exists
# 5 = Cannot connect to CCU
######################################################################
sub HMCCURPCPROC_InitDevice ($$) {
@ -319,14 +323,14 @@ sub HMCCURPCPROC_InitDevice ($$) {
my $dh = $defs{$d};
next if (!exists ($dh->{TYPE}) || !exists ($dh->{NAME}));
if ($dh->{TYPE} eq 'HMCCURPCPROC' && $dh->{NAME} ne $name && IsDisabled ($dh->{NAME}) != 1) {
return "RPC device for CCU/port already exists"
if ($dev_hash->{host} eq $dh->{host} && exists ($dh->{rpcport}) && $dh->{rpcport} == $ifport);
return 4 if ($dev_hash->{host} eq $dh->{host} && exists ($dh->{rpcport}) &&
$dh->{rpcport} == $ifport);
}
}
# Detect local IP address and check if CCU is reachable
my $localaddr = HMCCU_TCPConnect ($dev_hash->{host}, $ifport);
return "Can't connect to CCU ".$dev_hash->{host}." port $ifport" if ($localaddr eq '');
return 5 if ($localaddr eq '');
$dev_hash->{hmccu}{localaddr} = $localaddr;
$dev_hash->{hmccu}{defaultaddr} = $dev_hash->{hmccu}{localaddr};
@ -584,6 +588,7 @@ sub HMCCURPCPROC_Read ($)
# Get attributes
my $rpcmaxevents = AttrVal ($name, 'rpcMaxEvents', $HMCCURPCPROC_MAX_EVENTS);
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $hmccuflags = AttrVal ($hmccu_hash->{NAME}, 'ccuflags', 'null');
my $socktimeout = AttrVal ($name, 'rpcWriteTimeout', $HMCCURPCPROC_TIMEOUT_WRITE);
# Read events from queue
@ -641,7 +646,8 @@ sub HMCCURPCPROC_Read ($)
# Update device table and client device readings
HMCCU_UpdateDeviceTable ($hmccu_hash, \%devices) if ($devcount > 0);
HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events) if ($evcount > 0);
HMCCU_UpdateMultipleDevices ($hmccu_hash, \%events)
if ($evcount > 0 && $ccuflags !~ /noEvents/ && $hmccuflags !~ /noEvents/);
Log3 $name, 4, "HMCCURPCPROC: [$name] Read finished";
}
@ -2684,6 +2690,7 @@ sub HMCCURPCPROC_DecodeResponse ($)
This flag is not supported by interfaces CUxD and HVL.<br/>
expert - Activate expert mode<br/>
logEvents - Events are written into FHEM logfile if verbose is 4<br/>
noEvents - Ignore events from CCU, do not update client device readings.<br/>
queueEvents - Always write events into queue and send them asynchronously to FHEM.
Frequency of event transmission to FHEM depends on attribute rpcConnTimeout.<br/>
reconnect - Try to re-register at CCU if no events received for rpcEventTimeout seconds<br/>