2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-09 14:47:00 +00:00

HMCCU: Version 4.1

git-svn-id: https://svn.fhem.de/fhem/trunk@14693 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2017-07-12 14:22:34 +00:00
parent 6b435af21c
commit 64139e7db0
6 changed files with 620 additions and 407 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.
- update: 88_HMCCU: Version 4.1
- feature: 93_DbRep: V5.5.0, new command restoreMySQL, use new Internal
MODEL in DbLog since version 2.18.2
- feature: 98_fheminfo: do not show complete uniqueid in frontend

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
################################################################
######################################################################
#
# 88_HMCCUCHN.pm
#
# $Id$
#
# Version 4.0.002
# Version 4.1
#
# (c) 2017 zap (zap01 <at> t-online <dot> de)
#
################################################################
######################################################################
#
# define <name> HMCCUCHN <ccudev> [readonly] [defaults]
# [iodev=<iodevname>]
@ -44,15 +44,16 @@
# attr <name> ccuverify { 0 | 1 | 2 }
# attr <name> controldatapoint <datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> peer datapoints:condition:{hmccu:object=value|ccu:object=value|fhem:command}
# attr <name> hmstatevals <subst-rule>[;...]
# attr <name> statedatapoint <datapoint>
# attr <name> statevals <text1>:<subtext1>[,...]
# attr <name> substexcl <reading-expr>
# attr <name> substitute <subst-rule>[;...]
#
################################################################
######################################################################
# Requires modules 88_HMCCU.pm, HMCCUConf.pm
################################################################
######################################################################
package main;
@ -81,7 +82,12 @@ sub HMCCUCHN_Initialize ($)
$hash->{AttrFn} = "HMCCUCHN_Attr";
$hash->{parseParams} = 1;
$hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname 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 ". $readingFnAttributes;
$hash->{AttrList} = "IODev ccuackstate:0,1 ccucalculate ".
"ccuflags:multiple-strict,altread,nochn0,trace ccureadingfilter ".
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ".
"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;
}
##################################################
@ -873,6 +879,40 @@ sub HMCCUCHN_Get ($@)
Optionally the name of the HomeMatic state reading can be specified at the beginning of
the attribute in format =&lt;reading&gt;;. The default reading name is 'hmstate'.
</li><br/>
<li><b>peer [&lt;datapoints&gt;:&lt;condition&gt;:
{ccu:&lt;object&gt;=&lt;value&gt;|hmccu:&lt;object&gt;=&lt;value&gt;|
fhem:&lt;command&gt;}</b><br/>
Logically peer a datapoint of a HMCCUCHN or HMCCUDEV device with another device or any
FHEM command.<br/>
Parameter <i>datapoints</i> is a comma separated list of datapoints in format
<i>channelno.datapoint</i> which can trigger the action. If source device is of type HMCCUCHN
the parameter <i>channelno</i> is obsolete.<br/>
Parameter <i>condition</i> is a valid Perl expression which can contain
<i>channelno.datapoint</i> names as variables. Variables must start with a '$' or a '%'.
If a variable is preceded by a '$' the variable is substituted by the converted datapoint
value (i.e. "on" instead of "true"). If variable is preceded by a '%' the raw value
(i.e. "true") is used. If the special character is doubled the previous values will
be used.<br/>
If the result of this operation is true, the action specified after the second colon
is executed. Three types of actions are supported:<br/>
<b>hmccu</b>: Parameter <i>object</i> refers to a FHEM device/datapoint in format
&lt;device&gt;:&lt;channelno&gt;.&lt;datapoint&gt;<br/>
<b>ccu</b>: Parameter <i>object</i> refers to a CCU channel/datapoint in format
&lt;channel&gt;.&lt;datapoint&gt;. <i>channel</i> can be a channel name or address.<br/>
<b>fhem</b>: The specified <i>command</i> will be executed<br/>
If action contains the string $value it is substituted by the current value of the
datapoint which triggered the action. The attribute supports multiple peering rules
separated by semicolons and optionally by newline characters.<br/><br/>
Examples:<br/>
# Set FHEM device mydummy to value if formatted value of 1.STATE is 'on'<br/>
<code>attr mydev peer 1.STATE:'$1.STATE' eq 'on':fhem:set mydummy $value</code><br/>
# Set 2.LEVEL of device myBlind to 100 if raw value of 1.STATE is 1<br/>
<code>attr mydev peer 1.STATE:'%1.STATE' eq '1':hmccu:myBlind:2.LEVEL=100</code><br/>
# Set 1.STATE of device LEQ1234567 to true if 1.LEVEL < 100<br/>
<code>attr mydev peer 1.LEVEL:$1.LEVEL < 100:ccu:LEQ1234567:1.STATE=true</code><br/>
# Set 1.STATE of device LEQ1234567 to true if current level is different from old level<br/>
<code>attr mydev peer 1.LEVEL:$1.LEVEL != $$1.LEVEL:ccu:LEQ1234567:1.STATE=true</code><br/>
</li><br/>
<li><b>statedatapoint &lt;datapoint&gt;</b><br/>
Set state datapoint used by some commands like 'set devstate'.
</li><br/>

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.0.002
# Version 4.1
#
# (c) 2017 zap (zap01 <at> t-online <dot> de)
#
@ -37,7 +37,6 @@
# attr <name> ccucalculate <value>:<reading>[:<dp-list>][...]
# attr <name> ccuflags { altread, nochn0, trace }
# attr <name> ccuget { State | Value }
# attr <name> ccupeer [channel.]datapoint oper expr:{ hmccu:object=value | fhem:command }
# attr <name> ccureadings { 0 | 1 }
# attr <name> ccureadingformat { address[lc] | name[lc] | datapoint[lc] }
# attr <name> ccureadingfilter <filter-rule>[,...]
@ -46,6 +45,7 @@
# attr <name> ccuverify { 0 | 1 | 2}
# attr <name> controldatapoint <channel-number>.<datapoint>
# attr <name> disable { 0 | 1 }
# attr <name> peer datapoints:condition:{hmccu:object=value|ccu:object=value|fhem:command}
# attr <name> hmstatevals <subst-rule>[;...]
# attr <name> statechannel <channel>
# attr <name> statedatapoint [<channel-number>.]<datapoint>
@ -90,7 +90,7 @@ sub HMCCUDEV_Initialize ($)
"ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc ccureadingname ".
"ccureadings:0,1 ccuget:State,Value ccuscaleval ccuverify:0,1,2 disable:0,1 ".
"hmstatevals:textField-long statevals substexcl substitute:textField-long statechannel ".
"statedatapoint controldatapoint stripnumber ccupeer:textField-long ".$readingFnAttributes;
"statedatapoint controldatapoint stripnumber peer:textField-long ".$readingFnAttributes;
}
#####################################
@ -310,7 +310,7 @@ sub HMCCUDEV_Set ($@)
}
return HMCCU_SetError ($hash, "Usage: set $name datapoint [{channel-number}.]{datapoint} {value}")
if (!defined ($objname) || !defined ($objvalue) || $objvalue eq '');
if (!defined ($objvalue) || $objvalue eq '');
if ($objname =~ /^([0-9]+)\..+$/) {
my $chn = $1;
@ -500,7 +500,8 @@ sub HMCCUDEV_Set ($@)
}
}
elsif ($opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]") if ((scalar keys %{$h}) < 1);
return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]")
if ((scalar keys %{$h}) < 1);
my $objname = $ccuaddr;
# Channel number is optional because parameter can be related to device or channel
@ -947,6 +948,10 @@ sub HMCCUDEV_Get ($@)
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>hmstatevals &lt;subst-rule&gt;[;...]</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>peer [&lt;datapoints&gt;:&lt;condition&gt;:
{ccu:&lt;object&gt;=&lt;value&gt;|hmccu:&lt;object&gt;=&lt;value&gt;|fhem:&lt;command&gt;}</b><br/>
<a href="#HMCCUCHNattr">see HMCCUCHN</a>
</li><br/>
<li><b>statechannel &lt;channel-number&gt;</b><br/>

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 0.95 beta
# Version 0.96 beta
#
# Thread based RPC Server module for HMCCU.
#
@ -40,7 +40,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
my $HMCCURPC_VERSION = '0.95 beta';
my $HMCCURPC_VERSION = '0.96 beta';
# Maximum number of events processed per call of Read()
my $HMCCURPC_MAX_EVENTS = 50;
@ -66,6 +66,9 @@ my $HMCCURPC_TIMEOUT_WRITE = 0.001;
# Timeout for accepting incoming connections
my $HMCCURPC_TIMEOUT_ACCEPT = 1;
# Timeout for incoming CCU events
my $HMCCURPC_TIMEOUT_EVENT = 600;
# Send statistic information after specified amount of events
my $HMCCURPC_STATISTICS = 500;
@ -155,7 +158,7 @@ sub HMCCURPC_GetAttribute ($$$$);
sub HMCCURPC_GetRPCPortList ($);
sub HMCCURPC_ListDevices ($);
sub HMCCURPC_RegisterCallback ($);
sub HMCCURPC_RegisterSingleCallback ($$);
sub HMCCURPC_RegisterSingleCallback ($$$);
sub HMCCURPC_DeRegisterCallback ($);
sub HMCCURPC_InitRPCServer ($$$);
sub HMCCURPC_StartRPCServer ($);
@ -234,9 +237,10 @@ sub HMCCURPC_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = "rpcInterfaces:multiple-strict,".join(',',sort keys %HMCCURPC_RPC_PORT).
" ccuflags:multiple-strict,expert,keepThreads rpcMaxEvents rpcQueueSize rpcTriggerTime".
" ccuflags:multiple-strict,expert,keepThreads,reconnect".
" rpcMaxEvents rpcQueueSize rpcTriggerTime".
" rpcServer:on,off rpcServerAddr rpcServerPort rpcWriteTimeout rpcAcceptTimeout".
" rpcConnTimeout rpcWaitTime rpcStatistics ".
" rpcConnTimeout rpcWaitTime rpcStatistics rpcEventTimeout ".
$readingFnAttributes;
}
@ -483,7 +487,7 @@ sub HMCCURPC_Get ($@)
my $rc;
if ($opt eq 'rpcevents') {
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL", "TO");
$result = '';
foreach my $clkey (keys %{$hash->{hmccu}{rpc}}) {
next if ($clkey eq 'DATA');
@ -598,6 +602,7 @@ sub HMCCURPC_Read ($)
# Get attributes
my $rpcmaxevents = AttrVal ($name, 'rpcMaxEvents', $HMCCURPC_MAX_EVENTS);
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
# Data read from child socket is only a trigger for reading data from event queue
my $buffer = '';
@ -643,10 +648,17 @@ sub HMCCURPC_Read ($)
$devices{$par[0]}{newaddr} = $par[1];
$devcount++;
}
elsif ($et eq 'TO') {
if ($ccuflags =~ /reconnect/) {
Log3 $name, 2, "HMCCURPC: Reconnecting to CCU interface ".
HMCCURPC_RPC_NUMPORT{$par[0]};
HMCCURPC_RegisterSingleCallback ($hash, $par[0], 1);
}
}
$eventcount++;
if ($eventcount > $rpcmaxevents) {
Log3 $name, 4, "Read stopped after $rpcmaxevents events";
Log3 $name, 4, "HMCCURPC: Read stopped after $rpcmaxevents events";
last;
}
}
@ -807,7 +819,8 @@ sub HMCCURPC_ProcessEvent ($$)
"IN", 2,
"EX", 2,
"SL", 1,
"ST", 10
"TO", 1,
"ST", 11
);
# Parse event
@ -856,8 +869,9 @@ sub HMCCURPC_ProcessEvent ($$)
my $delay = $rh->{$clkey}{evtime}-$t[0];
$rh->{$clkey}{sumdelay} += $delay;
$rh->{$clkey}{avgdelay} = $rh->{$clkey}{sumdelay}/$rh->{$clkey}{rec}{$et};
Log3 $name, 2, "HMCCURPC: Received CENTRAL event. ".$t[2]."=".$t[3] if ($t[1] eq 'CENTRAL');
my ($add, $chn) = split (/:/, $t[1]);
return ($et, $clkey, $add, $chn, $t[2], $t[3]);
return defined ($chn) ? ($et, $clkey, $add, $chn, $t[2], $t[3]) : undef;
}
elsif ($et eq 'SL') {
#
@ -998,12 +1012,22 @@ sub HMCCURPC_ProcessEvent ($$)
my @res = ($et, $clkey);
push (@res, @t);
my $total = shift @t;
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
for (my $i=0; $i<9; $i++) {
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL", "TO");
for (my $i=0; $i<scalar(@eventtypes); $i++) {
$hash->{hmccu}{rpc}{$clkey}{snd}{$eventtypes[$i]} += $t[$i];
}
return @res;
}
elsif ($et eq 'TO') {
#
# Event timeout
# Input: TO|clkey|Time
# Output: TO, clkey, Port, Time
#
Log3 $name, 2, "HMCCU: Received no events from interface $clkey for ".$t[0]." seconds";
DoTrigger ($name, "No events from interface $clkey for ".$t[0]." seconds");
return ($et, $clkey, $hash->{hmccu}{rpc}{$clkey}{port}, $t[0]);
}
return undef;
}
@ -1084,19 +1108,22 @@ sub HMCCURPC_RegisterCallback ($)
my $regcount = 0;
foreach my $port (@rpcports) {
$regcount++ if (HMCCURPC_RegisterSingleCallback ($hash, $port));
$regcount++ if (HMCCURPC_RegisterSingleCallback ($hash, $port, 0));
}
return $regcount;
}
######################################################################
# Register single callback
# Register callback for specified CCU interface port.
# If parameter 'force' is 1 callback will be registered even if state
# is "running". State will not be modified.
# Return 0 on error.
######################################################################
sub HMCCURPC_RegisterSingleCallback ($$)
sub HMCCURPC_RegisterSingleCallback ($$$)
{
my ($hash, $port) = @_;
my ($hash, $port, $force) = @_;
my $name = $hash->{NAME};
my $serveraddr = $hash->{host};
@ -1104,8 +1131,8 @@ sub HMCCURPC_RegisterSingleCallback ($$)
my $rpcserveraddr = AttrVal ($name, 'rpcServerAddr', $localaddr);
my $clkey = 'CB'.$port;
return 0 if (!exists ($hash->{hmccu}{rpc}{$clkey}) ||
$hash->{hmccu}{rpc}{$clkey}{state} ne 'working');
return 0 if (!exists ($hash->{hmccu}{rpc}{$clkey}));
return 0 if ($hash->{hmccu}{rpc}{$clkey}{state} ne 'working' && $force == 0);
my $cburl = '';
if (HMCCURPC_IsAscRPCPort ($port)) {
@ -1114,32 +1141,33 @@ sub HMCCURPC_RegisterSingleCallback ($$)
else {
$cburl = "xmlrpc_bin://$rpcserveraddr:".$hash->{hmccu}{rpc}{$clkey}{cbport};
}
# The client URL is only relevant for ASCII RPC
my $clurl = "http://$serveraddr:$port/";
$clurl .= $HMCCURPC_RPC_URL{$port} if (exists ($HMCCURPC_RPC_URL{$port}));
$hash->{hmccu}{rpc}{$clkey}{port} = $port;
$hash->{hmccu}{rpc}{$clkey}{clurl} = $clurl;
$hash->{hmccu}{rpc}{$clkey}{cburl} = $cburl;
$hash->{hmccu}{rpc}{$clkey}{state} = 'registered';
Log3 $name, 1, "HMCCURPC: Registering callback $cburl with ID $clkey at $clurl";
# if ($HMCCURPC_RPC_PROT{$port} eq 'A') {
# my $rpcclient = RPC::XML::Client->new ($clurl);
# $rpcclient->send_request ("init", $cburl, $clkey);
# }
$hash->{hmccu}{rpc}{$clkey}{state} = 'registered' if ($force == 0);
Log3 $name, 2, "HMCCURPC: Registering callback $cburl with ID $clkey at $clurl";
my $rc;
if (HMCCURPC_IsAscRPCPort ($port)) {
HMCCURPC_SendRequest ($hash, $port, "init", $cburl, $clkey);
$rc = HMCCURPC_SendRequest ($hash, $port, "init", $cburl, $clkey);
}
else {
HMCCURPC_SendBinRequest ($hash, $port, "init",
$rc = HMCCURPC_SendBinRequest ($hash, $port, "init",
$BINRPC_STRING, $cburl, $BINRPC_STRING, $clkey);
}
Log3 $name, 1, "HMCCURPC: RPC callback with URL $cburl registered";
return 1;
if (defined ($rc)) {
Log3 $name, 1, "HMCCURPC: RPC callback with URL $cburl registered";
return 1;
}
else {
Log3 $name, 1, "HMCCURPC: Failed to register callback for ID $clkey";
return 0;
}
}
######################################################################
@ -1210,7 +1238,7 @@ sub HMCCURPC_InitRPCServer ($$$)
Log3 $name, 2, "HMCCURPC: Callback server $clkey created. Listening on port $callbackport";
# Callback for events
Log3 $name, 2, "HMCCURPC: Adding callback for events for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for events for server $clkey";
$server->add_method (
{ name=>"event",
signature=> ["string string string string int","string string string string double","string string string string boolean","string string string string i4"],
@ -1219,7 +1247,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Callback for new devices
Log3 $name, 2, "HMCCURPC: Adding callback for new devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for new devices for server $clkey";
$server->add_method (
{ name=>"newDevices",
signature=>["string string array"],
@ -1228,7 +1256,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Callback for deleted devices
Log3 $name, 2, "HMCCURPC: Adding callback for deleted devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for deleted devices for server $clkey";
$server->add_method (
{ name=>"deleteDevices",
signature=>["string string array"],
@ -1237,7 +1265,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Callback for modified devices
Log3 $name, 2, "HMCCURPC: Adding callback for modified devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for modified devices for server $clkey";
$server->add_method (
{ name=>"updateDevice",
signature=>["string string string int"],
@ -1246,7 +1274,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Callback for replaced devices
Log3 $name, 2, "HMCCURPC: Adding callback for replaced devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for replaced devices for server $clkey";
$server->add_method (
{ name=>"replaceDevice",
signature=>["string string string string"],
@ -1255,7 +1283,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Callback for readded devices
Log3 $name, 2, "HMCCURPC: Adding callback for readded devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for readded devices for server $clkey";
$server->add_method (
{ name=>"replaceDevice",
signature=>["string string array"],
@ -1264,7 +1292,7 @@ sub HMCCURPC_InitRPCServer ($$$)
);
# Dummy implementation, always return an empty array
Log3 $name, 2, "HMCCURPC: Adding callback for list devices for server $clkey";
Log3 $name, 4, "HMCCURPC: Adding callback for list devices for server $clkey";
$server->add_method (
{ name=>"listDevices",
signature=>["array string"],
@ -1305,6 +1333,7 @@ sub HMCCURPC_StartRPCServer ($)
$thrpar{socktimeout} = AttrVal ($name, 'rpcWriteTimeout', $HMCCURPC_TIMEOUT_WRITE);
$thrpar{conntimeout} = AttrVal ($name, 'rpcConnTimeout', $HMCCURPC_TIMEOUT_CONNECTION);
$thrpar{acctimeout} = AttrVal ($name, 'rpcAcceptTimeout', $HMCCURPC_TIMEOUT_ACCEPT);
$thrpar{evttimeout} = AttrVal ($name, 'rpcEventTimeout', $HMCCURPC_TIMEOUT_EVENT);
$thrpar{waittime} = AttrVal ($name, 'rpcWaitTime', $HMCCURPC_TIME_WAIT);
$thrpar{queuesize} = AttrVal ($name, 'rpcQueueSize', $HMCCURPC_MAX_QUEUESIZE);
$thrpar{triggertime} = AttrVal ($name, 'rpcTriggerTime', $HMCCURPC_TIME_TRIGGER);
@ -1313,7 +1342,7 @@ sub HMCCURPC_StartRPCServer ($)
my $ccunum = $hash->{CCUNum};
my $serveraddr = $hash->{host};
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL", "TO");
# Get or detect local IP address
if ($localaddr eq '') {
@ -1831,7 +1860,7 @@ sub HMCCURPC_HandleConnection ($$$$)
my $tid = threads->tid ();
my $clkey = 'CB'.$port;
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL", "TO");
# Initialize RPC server
my $iface = $HMCCURPC_RPC_NUMPORT{$port};
@ -1854,9 +1883,9 @@ sub HMCCURPC_HandleConnection ($$$$)
$rpcsrv->{hmccu}{queuesize} = $thrpar->{queuesize};
$rpcsrv->{hmccu}{statistics} = $thrpar->{statistics};
$rpcsrv->{hmccu}{running} = 0;
$rpcsrv->{hmccu}{evttime} = time ();
# Initialize statistic counters
$rpcsrv->{hmccu}{snd}{total} = 0;
foreach my $et (@eventtypes) {
$rpcsrv->{hmccu}{rec}{$et} = 0;
$rpcsrv->{hmccu}{snd}{$et} = 0;
@ -1872,6 +1901,9 @@ sub HMCCURPC_HandleConnection ($$$$)
$rpcsrv->{__daemon}->timeout ($thrpar->{acctimeout});
while ($run) {
my $difftime = time()-$rpcsrv->{hmccu}{evttime};
HMCCURPC_Write ($rpcsrv, "TO", $clkey, $difftime) if ($difftime >= $thrpar->{evttimeout});
# Next statement blocks for timeout seconds
my $connection = $rpcsrv->{__daemon}->accept ();
next if (! $connection);
@ -2034,6 +2066,8 @@ sub HMCCURPC_Write ($$$$)
if (defined ($server->{hmccu}{eventqueue})) {
my $queue = $server->{hmccu}{eventqueue};
$server->{hmccu}{evttime} = time ();
if (defined ($server->{hmccu}{queuesize}) &&
$queue->pending () >= $server->{hmccu}{queuesize}) {
Log3 $name, 1, "CCURPC: $cb maximum queue size reached";
@ -2060,7 +2094,7 @@ sub HMCCURPC_WriteStats ($$)
my ($server, $clkey) = @_;
my $name = $server->{hmccu}{name};
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL", "TO");
# Send statistic info
my $st = $server->{hmccu}{snd}{total};
@ -2746,6 +2780,7 @@ sub HMCCURPC_DecodeResponse ($)
Set flags for controlling device behaviour. Meaning of flags is:<br/>
expert - Activate expert mode<br/>
keepThreads - Do not delete thread objects after RPC server has been stopped<br/>
reconnect - Try to re-register at CCU if no events received for rpcEventTimeout seconds<br/>
</li><br/>
<li><b>rpcAcceptTimeout &lt;seconds&gt;</b><br/>
Specify timeout for accepting incoming connections. Default is 1 second. Increase this
@ -2754,6 +2789,10 @@ sub HMCCURPC_DecodeResponse ($)
<li><b>rpcConnTimeout &lt;seconds&gt;</b><br/>
Specify timeout of CCU connection handling. Default is 10 second.
</li><br/>
<li><b>rpcEventTimeout &lt;seconds&gt;</b><br/>
Specify timeout for CCU events. Default is 600 seconds. If timeout occurs an event
is triggered.
</li><br/>
<li><b>rpcInterfaces { BidCos-Wired, BidCos-RF, HmIP-RF, VirtualDevices, CUxD, Homegear }</b><br/>
Select RPC interfaces. If attribute is missing the corresponding attribute of I/O device
(HMCCU device) is used. Default is BidCos-RF.

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.0.002
# Version 4.1
#
# Configuration parameters for HomeMatic devices.
#
@ -113,7 +113,8 @@ use vars qw(%HMCCU_SCRIPTS);
substitute => "ERROR_REDUCED,ERROR_OVERHEAT!(0|false):no,(1|true):yes;LEVEL!#0-0:off,#1-100:on;DIRECTION!0:none,1:up,2:down,3:undefined",
webCmd => "control:on:off",
widgetOverride => "control:slider,0,10,100"
}, "HM-LC-Dim1T-Pl|HM-LC-Dim1T-CV|HM-LC-Dim1T-FM|HM-LC-Dim1T-CV-2|HM-LC-Dim2T-SM|HM-LC-Dim2T-SM-2|HM-LC-Dim1T-DR|HM-LC-Dim1T-FM-LF|HM-LC-Dim1T-FM-2|HM-LC-Dim1T-Pl-3|HM-LC-Dim1TPBU-FM|HM-LC-Dim1TPBU-FM-2" => {
},
"HM-LC-Dim1T-Pl|HM-LC-Dim1T-CV|HM-LC-Dim1T-FM|HM-LC-Dim1T-CV-2|HM-LC-Dim2T-SM|HM-LC-Dim2T-SM-2|HM-LC-Dim1T-DR|HM-LC-Dim1T-FM-LF|HM-LC-Dim1T-FM-2|HM-LC-Dim1T-Pl-3|HM-LC-Dim1TPBU-FM|HM-LC-Dim1TPBU-FM-2" => {
_description => "Funk-Abschnitt-Dimmaktor",
_channels => "1",
ccureadingfilter => "(^LEVEL\$|DIRECTION)",
@ -145,6 +146,22 @@ use vars qw(%HMCCU_SCRIPTS);
statevals => "press:true",
substitute => "PRESS!(1|true):pressed,(0|false):released"
},
"HM-PBI-4-FM" => {
_description => "Funk-Tasterschnittstelle",
_channels => "1,2,3,4",
ccureadingfilter => "PRESS",
statedatapoint => "PRESS_SHORT",
statevals => "press:true",
substitute => "PRESS_SHORT,PRESS_LONG,PRESS_CONT!(1|true):pressed,(0|false):released;PRESS_LONG_RELEASE!(0|false):no,(1|true):yes"
},
"HM-RC-Key4-2|HM-RC-Key4-3" => {
_description => "Funk-Handsender Key",
_channels => "1,2,3,4",
ccureadingfilter => "PRESS",
"event-on-update-reading" => ".*",
statedatapoint => "PRESS_SHORT",
substitute => "PRESS_SHORT,PRESS_LONG!(1|true):pressed"
},
"HM-LC-Sw1PBU-FM" => {
_description => "Unterputz Schaltaktor für Markenschalter",
_channels => "1",
@ -427,7 +444,8 @@ use vars qw(%HMCCU_SCRIPTS);
substitute => "ERROR_REDUCED,ERROR_OVERHEAT!(0|false):no,(1|true):yes;LEVEL!#0-0:off,#1-100:on;DIRECTION!0:none,1:up,2:down,3:undefined",
webCmd => "control:on:off",
widgetOverride => "control:slider,0,10,100"
}, "HM-LC-Dim1T-Pl|HM-LC-Dim1T-CV|HM-LC-Dim1T-FM|HM-LC-Dim1T-CV-2|HM-LC-Dim2T-SM|HM-LC-Dim2T-SM-2|HM-LC-Dim1T-DR|HM-LC-Dim1T-FM-LF|HM-LC-Dim1T-FM-2|HM-LC-Dim1T-Pl-3|HM-LC-Dim1TPBU-FM|HM-LC-Dim1TPBU-FM-2" => {
},
"HM-LC-Dim1T-Pl|HM-LC-Dim1T-CV|HM-LC-Dim1T-FM|HM-LC-Dim1T-CV-2|HM-LC-Dim2T-SM|HM-LC-Dim2T-SM-2|HM-LC-Dim1T-DR|HM-LC-Dim1T-FM-LF|HM-LC-Dim1T-FM-2|HM-LC-Dim1T-Pl-3|HM-LC-Dim1TPBU-FM|HM-LC-Dim1TPBU-FM-2" => {
_description => "Funk-Abschnitt-Dimmaktor",
ccureadingfilter => "(^LEVEL\$|DIRECTION)",
ccuscaleval => "LEVEL:0:1:0:100",
@ -453,6 +471,17 @@ use vars qw(%HMCCU_SCRIPTS);
statevals => "press:true",
substitute => "PRESS!(1|true):pressed,(0|false):released"
},
"HM-PBI-4-FM" => {
_description => "Funk-Tasterschnittstelle",
ccureadingfilter => "PRESS",
substitute => "PRESS_SHORT,PRESS_LONG,PRESS_CONT!(1|true):pressed,(0|false):released;PRESS_LONG_RELEASE!(0|false):no,(1|true):yes"
},
"HM-RC-Key4-2|HM-RC-Key4-3" => {
_description => "Funk-Handsender Key",
ccureadingfilter => "PRESS",
"event-on-update-reading" => ".*",
substitute => "PRESS_SHORT,PRESS_LONG!(1|true):pressed"
},
"HM-LC-Sw1PBU-FM" => {
_description => "Unterputz Schaltaktor für Markenschalter",
ccureadingfilter => "STATE",
@ -546,6 +575,16 @@ use vars qw(%HMCCU_SCRIPTS);
statedatapoint => "1.TEMPERATURE",
stripnumber => 1
},
"HM-Sen-RD-O" => {
_description => "Regensensor",
ccureadingfilter => "(STATE|WORKING)",
controldatapoint => "2.STATE",
eventMap => "/datapoint 2.STATE 1:on/datapoint 2.STATE 0:off/",
statedatapoint => "1.STATE",
substitute => "1.STATE!(0|false):dry,(1|true):rain;2.STATE!(0|false):off,(1|true):on",
webCmd => "control",
widgetOverride => "control:uzsuToggle,off,on"
},
"HM-WDS100-C6-O-2" => {
_description => "Funk-Kombisensor",
ccureadingfilter => "(HUMIDITY|TEMPERATURE|WIND|RAIN|SUNSHINE|BRIGHTNESS)",
@ -706,11 +745,11 @@ if (oPR) {
},
"CreateStringVariable" => {
description => "Create CCU system variable of type STRING",
syntax => "name, init, desc",
parameters => 3,
syntax => "name, unit, init, desc",
parameters => 4,
code => qq(
object oSV = dom.GetObject("\$name");
if (!oSV){
if (!oSV){
object oSysVars = dom.GetObject(ID_SYSTEM_VARIABLES);
oSV = dom.CreateObject(OT_VARDP);
oSysVars.Add(oSV.ID());
@ -718,7 +757,7 @@ if (!oSV){
oSV.ValueType(ivtString);
oSV.ValueSubType(istChar8859);
oSV.DPInfo("\$desc");
oSV.ValueUnit("");
oSV.ValueUnit("\$unit");
oSV.State("\$init");
oSV.Internal(false);
oSV.Visible(true);
@ -758,8 +797,8 @@ else {
},
"CreateBoolVariable" => {
description => "Create CCU system variable of type BOOL",
syntax => "name, init, desc, value1, value2",
parameters => 5,
syntax => "name, unit, init, desc, valtrue, valfalse",
parameters => 6,
code => qq(
object oSV = dom.GetObject("\$name");
if (!oSV){
@ -772,6 +811,7 @@ if (!oSV){
oSV.ValueName0("\$value1");
oSV.ValueName1("\$value2");
oSV.DPInfo("\$desc");
oSV.ValueUnit("\$unit");
oSV.State("\$init");
dom.RTUpdate(false);
}
@ -785,7 +825,7 @@ else {
syntax => "name, unit, init, desc, list",
parameters => 5,
code => qq(
object oSV = dom.GetObject("p2");
object oSV = dom.GetObject("\$name");
if (!oSV){
object oSysVars = dom.GetObject(ID_SYSTEM_VARIABLES);
oSV = dom.CreateObject(OT_VARDP);
@ -804,14 +844,16 @@ else {
}
)
},
"DeleteVariable" => {
description => "Delete CCU system variable",
syntax => "name",
parameters => 1,
"DeleteObject" => {
description => "Delete CCU object",
syntax => "name, type",
parameters => 2,
code => qq(
object oSV = dom.GetObject("\$name");
if (oSV) {
dom.DeleteObject(oSV.ID());
if (oSV.IsTypeOf(\$type)) {
dom.DeleteObject(oSV.ID());
}
}
)
},
@ -874,7 +916,7 @@ foreach(devid, root.Devices().EnumUsedIDs()) {
integer cc=0;
foreach (chnid, odev.Channels()) {
object ochn=dom.GetObject(chnid);
WriteLine("C;" # ochn.Address() # ";" # ochn.Name());
WriteLine("C;" # ochn.Address() # ";" # ochn.Name() # ";" # ochn.ChnDirection());
cc=cc+1;
}
WriteLine("D;" # intna # ";" # odev.Address() # ";" # odev.Name() # ";" # odev.HssType() # ";" # cc);
@ -938,6 +980,58 @@ foreach (sDevName, sDevList.Split(",")) {
}
WriteLine (c);
)
},
"GetDatapointList" => {
description => "Query datapoint information of device list",
syntax => "list",
parameters => 1,
code => qq(
string chnid;
string sDPId;
string sDevice;
string sDevList = "\$list";
foreach (sDevice, sDevList.Split(",")) {
object odev = dom.GetObject (sDevice);
if (odev) {
string sType = odev.HssType();
foreach (chnid, odev.Channels()) {
object ochn = dom.GetObject(chnid);
if (ochn) {
string sAddr = ochn.Address();
string sChnNo = sAddr.StrValueByIndex(":",1);
foreach(sDPId, ochn.DPs()) {
object oDP = dom.GetObject(sDPId);
if (oDP) {
string sDPName = oDP.Name().StrValueByIndex(".",2);
WriteLine (sAddr # ";" # sType # ";" # sChnNo # ";" # sDPName # ";" # oDP.ValueType() # ";" # oDP.Operations());
}
}
}
}
}
}
)
},
"GetChannel" => {
description => "Get datapoints of channel list",
syntax => "list, ccuget",
parameters => 2,
code => qq(
string sDPId;
string sChannel;
string sChnList = "\$list";
foreach (sChannel, sChnList.Split(",")) {
object oChannel = dom.GetObject (sChannel);
if (oChannel) {
foreach(sDPId, oChannel.DPs()) {
object oDP = dom.GetObject(sDPId);
if (oDP) {
WriteLine (sChannel # "=" # oDP.Name() # "=" # oDP.\$ccuget());
}
}
}
}
)
}
);