2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-27 20:34:52 +00:00

HMCCU: Features and bugfixes

git-svn-id: https://svn.fhem.de/fhem/trunk@28502 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2024-02-11 16:56:41 +00:00
parent 61ab9d1e23
commit 104b705e03
5 changed files with 570 additions and 578 deletions

File diff suppressed because it is too large Load Diff

@ -6,7 +6,7 @@
#
# Version 5.0
#
# (c) 2022 zap (zap01 <at> t-online <dot> de)
# (c) 2024 zap (zap01 <at> t-online <dot> de)
#
######################################################################
# Client device for Homematic channels.
@ -30,7 +30,7 @@ sub HMCCUCHN_Set ($@);
sub HMCCUCHN_Get ($@);
sub HMCCUCHN_Attr ($@);
my $HMCCUCHN_VERSION = '5.0 240121821';
my $HMCCUCHN_VERSION = '5.0 2024-02';
######################################################################
# Initialize module
@ -51,7 +51,7 @@ sub HMCCUCHN_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = 'IODev ccucalculate '.
'ccuflags:multiple-strict,hideStdReadings,replaceStdReadings,noBoundsChecking,ackState,logCommand,noAutoSubstitute,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
'ccuflags:multiple-strict,hideStdReadings,replaceStdReadings,noBoundsChecking,ackState,logCommand,noAutoSubstitute,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings '.
'ccureadingfilter:textField-long statedatapoint controldatapoint '.
'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix '.
@ -212,7 +212,7 @@ sub HMCCUCHN_InitDevice ($$)
$rc = -2;
}
HMCCU_GetUpdate ($devHash, $da);
HMCCU_ExecuteGetExtValuesCommand ($devHash, $da);
}
return $rc;
@ -352,9 +352,6 @@ sub HMCCUCHN_Set ($@)
elsif ($lcopt eq 'datapoint') {
return HMCCU_ExecuteSetDatapointCommand ($hash, $a, $h);
}
# elsif ($lcopt eq 'toggle') {
# return HMCCU_ExecuteToggleCommand ($hash);
# }
elsif (exists($hash->{hmccu}{roleCmds}{set}{$opt})) {
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'set', $opt, $a, $h);
}
@ -455,7 +452,7 @@ sub HMCCUCHN_Get ($@)
}
elsif ($lcopt eq 'extvalues') {
my $filter = shift @$a;
my $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $filter);
my $rc = HMCCU_ExecuteGetExtValuesCommand ($hash, $ccuaddr, $filter);
return $rc < 0 ? HMCCU_SetError ($hash, $rc) : 'OK';
}
elsif ($lcopt eq 'paramsetdesc') {
@ -526,6 +523,9 @@ sub HMCCUCHN_Get ($@)
<li><b>set &lt;name&gt; armState {DISARMED|EXTSENS_ARMED|ALLSENS_ARMED|ALARM_BLOCKED}</b><br/>
[alarm siren] Set arm state.
</li><br/>
<li><b>set &lt;name&gt; calibrate {START|STOP}</b><br/>
[blind] Run calibration.
</li><br/>
<li><b>set &lt;name&gt; clear [&lt;reading-exp&gt;|reset]</b><br/>
Delete readings matching specified reading name expression. Default expression is '.*'.
Readings 'state' and 'control' are not deleted. With option 'reset' all readings
@ -687,7 +687,6 @@ sub HMCCUCHN_Get ($@)
<li>showMasterReadings: Store configuration readings of parameter set 'MASTER' of current channel.</li>
<li>showDeviceReadings: Store configuration readings of device and value readings of channel 0.</li>
<li>showLinkReadings: Store readings of links.</li>
<li>showServiceReadings: Store readings of parameter set 'SERVICE'</li>
</ul>
If non of the flags is set, only readings belonging to parameter set VALUES (datapoints)
are stored.
@ -776,7 +775,6 @@ sub HMCCUCHN_Get ($@)
showDeviceReadings: Show readings of device and channel 0.<br/>
showLinkReadings: Show link readings.<br/>
showMasterReadings: Show configuration readings.<br/>
showServiceReadings: Show service readings (HmIP only)<br/>
trace: Write log file information for operations related to this device.
</li><br/>
<a name="ccuget"></a>
@ -855,7 +853,6 @@ sub HMCCUCHN_Get ($@)
MASTER (configuration parameters): 'R-'<br/>
LINK (links parameters): 'L-'<br/>
PEER (peering parameters): 'P-'<br/>
SERVICE (service parameters): S-<br/>
To hide prefix do not specify <i>prefix</i>.
</li><br/>
<a name="ccuscaleval"></a>

@ -6,7 +6,7 @@
#
# Version 5.0
#
# (c) 2022 zap (zap01 <at> t-online <dot> de)
# (c) 2024 zap (zap01 <at> t-online <dot> de)
#
######################################################################
# Client device for Homematic devices.
@ -31,7 +31,7 @@ sub HMCCUDEV_Set ($@);
sub HMCCUDEV_Get ($@);
sub HMCCUDEV_Attr ($@);
my $HMCCUDEV_VERSION = '5.0 240121821';
my $HMCCUDEV_VERSION = '5.0 2024-02';
######################################################################
# Initialize module
@ -52,7 +52,7 @@ sub HMCCUDEV_Initialize ($)
$hash->{parseParams} = 1;
$hash->{AttrList} = 'IODev ccuaggregate:textField-long ccucalculate:textField-long '.
'ccuflags:multiple-strict,ackState,hideStdReadings,replaceStdReadings,noAutoSubstitute,noBoundsChecking,logCommand,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings,showServiceReadings '.
'ccuflags:multiple-strict,ackState,hideStdReadings,replaceStdReadings,noAutoSubstitute,noBoundsChecking,logCommand,noReadings,trace,simulate,showMasterReadings,showLinkReadings,showDeviceReadings '.
'ccureadingfilter:textField-long '.
'ccureadingformat:name,namelc,address,addresslc,datapoint,datapointlc '.
'ccureadingname:textField-long ccuSetOnChange ccuReadingPrefix devStateFlags '.
@ -259,7 +259,7 @@ sub HMCCUDEV_InitDevice ($$)
}
# Update readings
HMCCU_GetUpdate ($devHash, $da);
HMCCU_ExecuteGetExtValuesCommand ($devHash, $da);
}
# Parse group options
@ -437,9 +437,6 @@ sub HMCCUDEV_Set ($@)
elsif ($lcopt eq 'datapoint') {
return HMCCU_ExecuteSetDatapointCommand ($hash, $a, $h);
}
# elsif ($lcopt eq 'toggle') {
# return HMCCU_ExecuteToggleCommand ($hash);
# }
elsif (exists($hash->{hmccu}{roleCmds}{set}{$opt})) {
return HMCCU_ExecuteRoleCommand ($ioHash, $hash, 'set', $opt, $a, $h);
}
@ -541,7 +538,7 @@ sub HMCCUDEV_Get ($@)
}
elsif ($lcopt eq 'extvalues') {
my $filter = shift @$a;
my $rc = HMCCU_GetUpdate ($hash, $ccuaddr, $filter);
my $rc = HMCCU_ExecuteGetExtValuesCommand ($hash, $ccuaddr, $filter);
return $rc < 0 ? HMCCU_SetError ($hash, $rc) : 'OK';
}
elsif ($lcopt eq 'paramsetdesc') {

@ -8,7 +8,7 @@
#
# Subprocess based RPC Server module for HMCCU.
#
# (c) 2023 by zap (zap01 <at> t-online <dot> de)
# (c) 2024 by zap (zap01 <at> t-online <dot> de)
#
##############################################################################
#
@ -31,15 +31,12 @@ use RPC::XML::Client;
use RPC::XML::Server;
use SetExtensions;
# require "$attr{global}{modpath}/FHEM/88_HMCCU.pm";
######################################################################
# Constants
######################################################################
# HMCCURPC version
my $HMCCURPCPROC_VERSION = '5.0 240121821';
my $HMCCURPCPROC_VERSION = '5.0 2024-02';
# Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100;
@ -89,6 +86,9 @@ my $HMCCURPCPROC_INIT_INTERVAL2 = 30;
# Delay for RPC server functionality check after start in seconds
my $HMCCURPCPROC_INIT_INTERVAL3 = 25;
# Interval for checking status of parent (FHEM) process in seconds
my $HMCCURPCPROC_PARENT_CHECK_INTERVAL = 5;
my %HMCCURPCPROC_RPC_FLAGS = (
'BidCos-Wired' => '_', 'BidCos-RF' => 'multicalls', 'HmIP-RF' => '_',
'VirtualDevices' => '_', 'Homegear' => '_', 'CUxD' => '_',
@ -133,7 +133,8 @@ my %RPC_METHODS = (
'getValue' => [ 'STRING', 'STRING' ]
);
# RPC event types
# RPC event types:
#
# EV = Event
# ND = New device
# DD = Delete device
@ -142,7 +143,7 @@ my %RPC_METHODS = (
# UD = Update device
# IN = Init RPC connection
# EX = Exit RPC process
# SL = Server loop
# SL = Server loop (server is accepting connections)
# ST = Statistics (not in list of event types)
# TO = Timeout
my @RPC_EVENT_TYPES = ('EV', 'ND', 'DD', 'RD', 'RA', 'UD', 'IN', 'EX', 'SL', 'TO');
@ -211,7 +212,7 @@ sub HMCCURPCPROC_HandleConnection ($$$$);
sub HMCCURPCPROC_SendQueue ($$$$);
sub HMCCURPCPROC_SendData ($$);
sub HMCCURPCPROC_ReceiveData ($$);
sub HMCCURPCPROC_ReadFromSocket ($$$);
sub HMCCURPCPROC_ReadFromSocket ($$);
sub HMCCURPCPROC_DataAvailableOnSocket ($$);
sub HMCCURPCPROC_WriteToSocket ($$$);
sub HMCCURPCPROC_Write ($$$$);
@ -569,7 +570,7 @@ sub HMCCURPCPROC_Shutdown ($)
}
######################################################################
# Set attribute
# Set/delete attribute
######################################################################
sub HMCCURPCPROC_Attr ($@)
@ -577,12 +578,15 @@ sub HMCCURPCPROC_Attr ($@)
my ($cmd, $name, $attrname, $attrval) = @_;
my $hash = $defs{$name};
my $ioHash = $hash->{IODev};
my $restartRPC = 0;
if ($cmd eq 'set') {
if ($attrname =~ /^(rpcAcceptTimeout|rpcReadTimeout|rpcWriteTimeout)$/ && $attrval == 0) {
$restartRPC = 1;
return "HMCCURPCPROC: [$name] Value for attribute $attrname must be greater than 0";
}
elsif ($attrname eq 'rpcServerAddr') {
$restartRPC = 1;
$hash->{hmccu}{localaddr} = $attrval;
}
elsif ($attrname eq 'rpcPingCCU') {
@ -594,12 +598,13 @@ sub HMCCURPCPROC_Attr ($@)
}
elsif ($cmd eq 'del') {
if ($attrname eq 'rpcServerAddr') {
$restartRPC = 1;
$hash->{hmccu}{localaddr} = $hash->{hmccu}{defaultaddr};
}
}
HMCCU_LogDisplay ($hash, 2, 'Please restart RPC server to apply attribute changes')
if ($init_done && (!defined($ioHash) || $ioHash->{hmccu}{postInit} == 0) &&
if ($restartRPC && $init_done && (!defined($ioHash) || $ioHash->{hmccu}{postInit} == 0) &&
HMCCURPCPROC_CheckProcessState ($hash, 'running'));
return undef;
@ -764,7 +769,6 @@ sub HMCCURPCPROC_Get ($@)
$result .= "$eh->{$i}{k} / $dn : $eh->{$i}{v}\n";
}
}
$result .= ('=' x 40)."\nRPC requests: ".$hash->{hmccu}{rpc}{requests};
return $result eq '' ? 'No event statistics found' : $result;
}
elsif ($opt eq 'rpcstate') {
@ -1406,6 +1410,9 @@ sub HMCCURPCPROC_RegisterCallback ($$)
######################################################################
# Deregister RPC callbacks at CCU
# force:
# >0 - Ignore state of RPC server. Deregister in any case.
# >1 - Do not update RPC server state.
######################################################################
sub HMCCURPCPROC_DeRegisterCallback ($$)
@ -1417,18 +1424,14 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
my $port = $hash->{rpcport};
my $clkey = HMCCURPCPROC_GetKey ($hash);
my $localaddr = $hash->{hmccu}{localaddr};
my $cburl = '';
my $clurl = '';
my $auth = '';
my $rpchash = \%{$hash->{hmccu}{rpc}};
return (0, "RPC server $clkey not in state registered or running")
if ($rpchash->{state} ne 'registered' && $rpchash->{state} ne 'running' && $force == 0);
$cburl = $rpchash->{cburl} if (exists($rpchash->{cburl}));
$clurl = $rpchash->{clurl} if (exists($rpchash->{clurl}));
$auth = $rpchash->{auth} if (exists($rpchash->{auth}));
$cburl = HMCCU_GetRPCCallbackURL ($ioHash, $localaddr, $rpchash->{cbport}, $clkey, $port) if ($cburl eq '');
my $cburl = $rpchash->{cburl} // HMCCU_GetRPCCallbackURL ($ioHash, $localaddr, $rpchash->{cbport}, $clkey, $port);
my $clurl = $rpchash->{clurl} // '';
my $auth = $rpchash->{auth} // '';
($clurl, $auth) = HMCCU_BuildURL ($ioHash, $port) if ($clurl eq '');
return (0, "Can't get RPC parameters for ID $clkey") if ($cburl eq '' || $clurl eq '');
@ -1439,7 +1442,7 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
my $err;
for (my $i=0; $i<2; $i++) {
($resp, $err) = HMCCURPCPROC_SendRequest ($hash, "init", "$cburl:STRING", '');
if (defined ($resp)) {
if (defined ($resp) && $force < 2) {
HMCCURPCPROC_SetRPCState ($hash, $force == 0 ? 'deregistered' : $rpchash->{state},
"Callback for RPC server $clkey deregistered", 1);
@ -1576,23 +1579,31 @@ sub HMCCURPCPROC_StartRPCServer ($)
my $rpcport = $hash->{rpcport};
my ($serveraddr, $interface) = HMCCU_GetRPCServerInfo ($ioHash, $rpcport, 'host,name');
my $clkey = 'CB'.$rpcport.$hash->{rpcid};
my $callbackport = $rpcserverport+$rpcport+($ccunum*10);
$hash->{hmccu}{localaddr} = $localaddr;
my ($clurl, $auth) = HMCCU_BuildURL ($ioHash, $hash->{rpcport});
my ($flags, $type) = HMCCU_GetRPCServerInfo ($ioHash, $rpcport, 'flags,type');
# Store parameters for child process
my %procpar;
$procpar{socktimeout} = AttrVal ($name, 'rpcWriteTimeout', $HMCCURPCPROC_TIMEOUT_WRITE);
$procpar{conntimeout} = AttrVal ($name, 'rpcConnTimeout', $HMCCURPCPROC_TIMEOUT_CONNECTION);
$procpar{acctimeout} = AttrVal ($name, 'rpcAcceptTimeout', $HMCCURPCPROC_TIMEOUT_ACCEPT);
$procpar{queuesize} = AttrVal ($name, 'rpcQueueSize', $HMCCURPCPROC_MAX_QUEUESIZE);
$procpar{queuesend} = AttrVal ($name, 'rpcQueueSend', $HMCCURPCPROC_MAX_QUEUESEND);
$procpar{statistics} = AttrVal ($name, 'rpcStatistics', $HMCCURPCPROC_STATISTICS);
$procpar{maxioerrors} = AttrVal ($name, 'rpcMaxIOErrors', $HMCCURPCPROC_MAX_IOERRORS);
$procpar{ccuflags} = AttrVal ($name, 'ccuflags', 'null');
$procpar{evttimeout} = $evttimeout;
$procpar{interface} = $interface;
($procpar{flags}, $procpar{type}) = HMCCU_GetRPCServerInfo ($ioHash, $rpcport, 'flags,type');
$procpar{name} = $name;
$procpar{clkey} = $clkey;
my %procpar = (
socktimeout => AttrVal ($name, 'rpcWriteTimeout', $HMCCURPCPROC_TIMEOUT_WRITE),
conntimeout => AttrVal ($name, 'rpcConnTimeout', $HMCCURPCPROC_TIMEOUT_CONNECTION),
acctimeout => AttrVal ($name, 'rpcAcceptTimeout', $HMCCURPCPROC_TIMEOUT_ACCEPT),
queuesize => AttrVal ($name, 'rpcQueueSize', $HMCCURPCPROC_MAX_QUEUESIZE),
queuesend => AttrVal ($name, 'rpcQueueSend', $HMCCURPCPROC_MAX_QUEUESEND),
statistics => AttrVal ($name, 'rpcStatistics', $HMCCURPCPROC_STATISTICS),
maxioerrors => AttrVal ($name, 'rpcMaxIOErrors', $HMCCURPCPROC_MAX_IOERRORS),
ccuflags => AttrVal ($name, 'ccuflags', 'null'),
name => $name,
evttimeout => $evttimeout,
serveraddr => $serveraddr,
interface => $interface,
clkey => $clkey,
flags => $flags,
type => $type,
parentPID => $$
);
# Reset state of server processes
$hash->{hmccu}{rpc}{state} = 'inactive';
@ -1603,18 +1614,16 @@ sub HMCCURPCPROC_StartRPCServer ($)
if (!socketpair ($sockchild, $sockparent, AF_UNIX, SOCK_STREAM, PF_UNSPEC));
$sockchild->autoflush (1);
$sockparent->autoflush (1);
$hash->{hmccu}{sockparent} = $sockparent;
$hash->{hmccu}{sockchild} = $sockchild;
$hash->{hmccu}{sockparent} = $sockparent;
$hash->{hmccu}{sockchild} = $sockchild;
# Enable FHEM I/O, calculate RPC server port
my $pid = $$;
$hash->{FD} = fileno $sockchild;
$selectlist{"RPC.$name.$pid"} = $hash;
my $callbackport = $rpcserverport+$rpcport+($ccunum*10);
# Initialize RPC server
# my $err = '';
# my %srvprocpar;
$hash->{hmccu}{rpc}{clkey} = $clkey;
$hash->{hmccu}{rpc}{cbport} = $callbackport;
# Start RPC server process
my $rpcpid = fhemFork ();
@ -1623,7 +1632,7 @@ sub HMCCURPCPROC_StartRPCServer ($)
close ($sockchild);
return (0, "Can't create RPC server process for interface $interface");
}
if (!$rpcpid) {
# Child process, only needs parent socket
HMCCURPCPROC_HandleConnection ($rpcport, $callbackport, $sockparent, \%procpar);
@ -1631,15 +1640,13 @@ sub HMCCURPCPROC_StartRPCServer ($)
# Connection loop ended. Close sockets and exit child process
close ($sockparent);
close ($sockchild);
exit (0);
exit(0);
}
# Parent process
HMCCU_Log ($hash, 2, "RPC server process started for interface $interface with PID=$rpcpid");
# Store process parameters
$hash->{hmccu}{rpc}{clkey} = $clkey;
$hash->{hmccu}{rpc}{cbport} = $callbackport;
$hash->{hmccu}{rpc}{pid} = $rpcpid;
$hash->{hmccu}{rpc}{state} = 'initialized';
@ -1687,7 +1694,7 @@ sub HMCCURPCPROC_RPCServerStarted ($)
# Update client devices if interface is managed by HMCCURPCPROC device.
# Normally interfaces are managed by HMCCU device.
if ($ioHash->{hmccu}{interfaces}{$ifname}{manager} eq 'HMCCURPCPROC') {
HMCCU_UpdateClients ($ioHash, '.*', 'Attr', 0, $ifname, 1);
HMCCU_UpdateClients ($ioHash, '.*', 'Attr', $ifname, 1);
}
RemoveInternalTimer ($hash, "HMCCURPCPROC_IsRPCServerRunning");
@ -2081,6 +2088,12 @@ sub HMCCURPCPROC_ProcessMulticallResponse ($$$$$)
######################################################################
# Send RPC request to CCU.
# Supports XML and BINRPC requests.
# Parameters:
# hash - FHEM hash reference or parameter hash reference
# Parameter hash used by sub processes:
# NAME - HMCCURPCPROC device name
# rpcport - CCU RPC port
# methods - list of RPC methods
# Return value:
# (response, undef) - Request successful
# (undef, error) - Request failed with error
@ -2089,22 +2102,29 @@ sub HMCCURPCPROC_ProcessMulticallResponse ($$$$$)
sub HMCCURPCPROC_SendRequest ($@)
{
my ($hash, $request, @param) = @_;
my $port = $hash->{rpcport};
my $ph = exists($hash->{TYPE}) ? 0 : 1;
my $ioHash = $hash->{IODev};
if (!defined($ioHash)) {
if (!$ph && !defined($ioHash)) {
HMCCU_Log ($hash, 2, 'I/O device not found');
return (undef, 'I/O device not found');
}
my $port = $hash->{rpcport};
my $multicalls = 0;
if (!$ph) {
$multicalls = 1 if (
!HMCCU_IsFlag ($hash, 'noMulticalls') && defined($hash->{hmccu}{rpc}{multicall}) &&
HMCCU_IsRPCType ($ioHash, $port, 'A')
);
}
my $retry = AttrVal ($hash->{NAME}, 'rpcRetryRequest', 1);
$retry = 2 if ($retry > 2);
$hash->{hmccu}{rpc}{requests} //= 0; # Count RPC requests
# Multicall request
if ($request eq 'system.multicall' && (
HMCCU_IsFlag ($hash, 'noMulticalls') || !defined($hash->{hmccu}{rpc}{multicall}) || HMCCU_IsRPCType ($ioHash, $port, 'B')
)) {
if ($request eq 'system.multicall' && !$multicalls) {
# If multicalls are not supported or disabled, execute multiple requests
my @respList = ();
my $reqList = shift @param; # Reference to request array
@ -2143,13 +2163,11 @@ sub HMCCURPCPROC_SendRequest ($@)
for (my $reqNo=0; $reqNo<=$retry; $reqNo++) {
if (HMCCU_IsRPCType ($ioHash, $port, 'A')) {
# XML RPC request
$hash->{hmccu}{rpc}{requests}++;
($resp, $err) = HMCCURPCPROC_SendXMLRequest ($hash, $ioHash, $request, @param);
last if (defined($resp));
}
elsif (HMCCU_IsRPCType ($ioHash, $port, 'B')) {
# Binary RPC request
$hash->{hmccu}{rpc}{requests}++;
($resp, $err) = HMCCURPCPROC_SendBINRequest ($hash, $ioHash, $request, @param);
last if (defined($resp));
}
@ -2258,7 +2276,7 @@ sub HMCCURPCPROC_SendBINRequest ($@)
my ($bytesWritten, $errmsg) = HMCCURPCPROC_WriteToSocket ($hash->{hmccu}{rpc}{connection}, $encreq, $timeoutWrite);
if ($bytesWritten > 0) {
my ($bytesRead, $encresp) = HMCCURPCPROC_ReadFromSocket ($hash, $hash->{hmccu}{rpc}{connection}, $timeoutRead);
my ($bytesRead, $encresp) = HMCCURPCPROC_ReadFromSocket ($hash->{hmccu}{rpc}{connection}, $timeoutRead);
# $socket->close ();
if ($bytesRead > 0) {
@ -2374,6 +2392,7 @@ sub HMCCURPCPROC_HandleConnection ($$$$)
my $maxsnd = $procpar->{queuesend};
my $maxioerrors = $procpar->{maxioerrors};
my $clkey = $procpar->{clkey};
my $parentPID = $procpar->{parentPID};
my $ioerrors = 0;
my $sioerrors = 0;
@ -2408,20 +2427,34 @@ sub HMCCURPCPROC_HandleConnection ($$$$)
$rpcsrv->{hmccu}{snd}{$et} = 0;
}
# Recover device hash
my $rpcDeviceHash = $defs{$name};
# Signal handler
$SIG{INT} = sub { $run = 0; HMCCU_Log ($name, 2, "$clkey received signal INT"); };
my $checkTime = time(); # At this point in time we checked the state of the parent process
HMCCURPCPROC_Write ($rpcsrv, 'SL', $clkey, $pid);
HMCCU_Log ($name, 2, "$clkey accepting connections. PID=$pid");
$rpcsrv->{__daemon}->timeout ($acctimeout) if ($acctimeout > 0.0);
while ($run) {
while ($run > 0) {
my $currentTime = time();
# Check for event timeout
if ($evttimeout > 0) {
my $difftime = time()-$rpcsrv->{hmccu}{evttime};
my $difftime = $currentTime-$rpcsrv->{hmccu}{evttime};
HMCCURPCPROC_Write ($rpcsrv, 'TO', $clkey, $difftime) if ($difftime >= $evttimeout);
}
# Check if parent process is still running
if ($currentTime-$checkTime > $HMCCURPCPROC_PARENT_CHECK_INTERVAL) {
$run = kill(0, $parentPID) ? 1 : -1;
$checkTime = $currentTime;
}
# Send queue entries to parent process
if (scalar (@queue) > 0) {
HMCCU_Log ($name, 4, "RPC server $clkey sending data to FHEM");
@ -2440,7 +2473,7 @@ sub HMCCURPCPROC_HandleConnection ($$$$)
HMCCU_Log ($name, 4, "RPC server $clkey accepting connections");
my $connection = $rpcsrv->{__daemon}->accept ();
next if (! $connection);
last if (! $run);
last if ($run < 1);
$connection->timeout ($conntimeout) if ($conntimeout > 0.0);
HMCCU_Log ($name, 4, "RPC server $clkey processing request");
@ -2456,10 +2489,18 @@ sub HMCCURPCPROC_HandleConnection ($$$$)
undef $connection;
}
HMCCU_Log ($name, 1, "RPC server $clkey stopped handling connections. PID=$pid");
HMCCU_Log ($name, 1, "RPC server $clkey stopped handling connections. PID=$pid run=$run");
close ($rpcsrv->{__daemon}) if ($prot eq 'B');
if ($run < 0) {
# Parent process not running: try to deregister callback URL and terminate RPC server process
HMCCU_Log ($name, 1, "Parent process (FHEM,PID=$parentPID) not running. Shutting down RPC server process $clkey.");
HMCCURPCPROC_DeRegisterCallback ($rpcDeviceHash, 1);
HMCCU_Log ($name, 1, "FHEM will be restarted automatically if restart is enabled in system.d configuration.");
return;
}
# Send statistic info
HMCCURPCPROC_WriteStats ($rpcsrv, $clkey);
@ -2593,9 +2634,9 @@ sub HMCCURPCPROC_ReceiveData ($$)
# Return (BytesRead, Data) on success.
######################################################################
sub HMCCURPCPROC_ReadFromSocket ($$$)
sub HMCCURPCPROC_ReadFromSocket ($$)
{
my ($hash, $socket, $timeout) = @_;
my ($socket, $timeout) = @_;
my $data = '';
my $totalBytes = 0;

@ -46,7 +46,8 @@ $HMCCU_CONFIG_VERSION = '5.0';
######################################################################
# Channel roles with state and control datapoints
# F: 1=Channel/HMCCUCHN, 2=Device/HMCCUDEV, 3=Both
# S: State datapoint, C: Control datapoint, V: Control values
# S: State datapoint, C: Control datapoint,
# V: Control values, #=Enum or const:value[,...]
# P: Priority (used by HMCCUDEV if more than 1 channel role fits)
# 1=lowest priority
######################################################################
@ -327,7 +328,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
# Set/Get commands related to channel role
# Role => { Command-Definition, ... }
# Command-Defintion:
# [Mode ]Command[:InterfaceExpr] => [No:]Datapoint-Def[:Function] [...]'
# '[Mode ]Command[:InterfaceExpr]' => '[CombDatapoint ][No:]Datapoint-Def[:Function] [...]'
# Mode:
# Either 'set' or 'get'. Default is 'set'.
# Command:
@ -335,6 +336,9 @@ $HMCCU_CONFIG_VERSION = '5.0';
# InterfaceExpr:
# Command is only available, if interface of device is matching the regular
# expression.
# CombDatapoint:
# Either 'COMBINED_PARAMETER' or 'SUBMIT'
# Datapoint names are combined datapoint shortcuts.
# No:
# Execution order of subcommands. By default subcommands are executed from left to
# right.
@ -375,7 +379,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
%HMCCU_ROLECMDS = (
'ACOUSTIC_SIGNAL_TRANSMITTER' => {
'level' => 'V:LEVEL:?level',
'on' => 'V:LEVEL:1',
'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0'
},
'ALARM_SWITCH_VIRTUAL_RECEIVER' => {
@ -388,7 +392,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
},
'BLIND' => {
'pct' => 'V:LEVEL:?level',
'open' => 'V:LEVEL:1',
'open' => 'V:LEVEL:100',
'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+20',
'down' => 'V:LEVEL:?delta=-20',
@ -397,7 +401,7 @@ $HMCCU_CONFIG_VERSION = '5.0';
},
'BLIND_VIRTUAL_RECEIVER' => {
'pct' => 'V:LEVEL:?level',
'open' => 'V:LEVEL:1',
'open' => 'V:LEVEL:100',
'close' => 'V:LEVEL:0',
'oldLevel' => 'V:LEVEL:1.005',
'up' => 'V:LEVEL:?delta=+20',
@ -425,27 +429,27 @@ $HMCCU_CONFIG_VERSION = '5.0';
'DIMMER' => {
'pct' => '3:V:LEVEL:?level 1:V:ON_TIME:?time=0.0 2:V:RAMP_TIME:?ramp=0.5',
'level' => 'V:LEVEL:?level',
'on' => 'V:LEVEL:1',
'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0',
'on-for-timer' => 'V:ON_TIME:?duration V:LEVEL:1',
'on-till' => 'V:ON_TIME:?time V:LEVEL:1',
'on-for-timer' => 'V:ON_TIME:?duration V:LEVEL:100',
'on-till' => 'V:ON_TIME:?time V:LEVEL:100',
'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10',
'stop' => 'V:RAMP_STOP:1',
'toggle' => 'V:LEVEL:0,1'
'toggle' => 'V:LEVEL:0,100'
},
'DIMMER_VIRTUAL_RECEIVER' => {
'pct' => '5:V:LEVEL:?level 1:V:DURATION_UNIT:0 2:V:ON_TIME,DURATION_VALUE:?time=0.0 3:V:RAMP_TIME_UNIT:0 4:V:RAMP_TIME,RAMP_TIME_VALUE:?ramp=0.5',
'level' => 'V:LEVEL:?level',
'on' => 'V:LEVEL:1',
'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0',
'oldLevel' => 'V:LEVEL:1.005',
'on-for-timer' => '1:V:DURATION_UNIT:0 2:V:ON_TIME,DURATION_VALUE:?duration 3:V:LEVEL:1',
'on-till' => '1:V:DURATION_UNIT:0 2:V:ON_TIME,DURATION_VALUE:?time 3:V:LEVEL:1',
'on-for-timer' => '1:V:DURATION_UNIT:0 2:V:ON_TIME,DURATION_VALUE:?duration 3:V:LEVEL:100',
'on-till' => '1:V:DURATION_UNIT:0 2:V:ON_TIME,DURATION_VALUE:?time 3:V:LEVEL:100',
'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10',
'color' => 'V:COLOR:#color',
'toggle' => 'V:LEVEL:0,1'
'toggle' => 'V:LEVEL:0,100'
},
'DIMMER_WEEK_PROFILE' => {
'progMode' => 'V:WEEK_PROGRAM_TARGET_CHANNEL_LOCK:#progMode'
@ -472,13 +476,13 @@ $HMCCU_CONFIG_VERSION = '5.0';
},
'JALOUSIE' => {
'pct' => 'V:LEVEL:?level',
'open' => 'V:LEVEL:1',
'open' => 'V:LEVEL:100',
'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+20',
'down' => 'V:LEVEL:?delta=-20',
'stop' => 'V:STOP:1',
'pctSlats' => 'V:LEVEL_SLATS:?level',
'openSlats' => 'V:LEVEL_SLATS:1',
'openSlats' => 'V:LEVEL_SLATS:100',
'closeSlats' => 'V:LEVEL_SLATS:0',
},
'KEY' => {
@ -513,9 +517,12 @@ $HMCCU_CONFIG_VERSION = '5.0';
'color' => 'V:COLOR:?color V:ACT_HSV_COLOR_VALUE:?hsvColor',
'brightness' => 'V:ACT_BRIGHTNESS:?brightness'
},
'SHUTTER_TRANSMITTER' => {
'calibrate' => 'V:SELF_CALIBRATION:#Mode'
},
'SHUTTER_VIRTUAL_RECEIVER' => {
'pct' => 'V:LEVEL:?level',
'open' => 'V:LEVEL:1',
'open' => 'V:LEVEL:100',
'oldLevel' => 'V:LEVEL:1.005',
'close' => 'V:LEVEL:0',
'up' => 'V:LEVEL:?delta=+20',
@ -543,9 +550,13 @@ $HMCCU_CONFIG_VERSION = '5.0';
'sensor-on-till' => 'V:ON_TIME:?time V:STATE:1'
},
'SWITCH_VIRTUAL_RECEIVER' => {
'COMBINED_PARAMETER' => {
'OT' => 'ON_TIME',
'S' => 'STATE'
},
'on' => 'V:STATE:1',
'off' => 'V:STATE:0',
'on-for-timer' => 'V:ON_TIME:?duration V:STATE:1',
'on-for-timer' => 'COMBINED_PARAMETER V:OT:?duration V:S:1',
'on-till' => 'V:ON_TIME:?time V:STATE:1',
'toggle' => 'V:STATE:0,1'
},
@ -560,15 +571,22 @@ $HMCCU_CONFIG_VERSION = '5.0';
'get week-program' => 'D:WEEK_PROGRAM_POINTER:#program:HMCCU_DisplayWeekProgram'
},
'UNIVERSAL_LIGHT_RECEIVER' => {
'COMBINED_PARAMETER' => {
'L' => 'LEVEL',
'OT' => 'ON_TIME',
'H' => 'HUE',
'SAT' => 'SATURATION'
},
'pct' => '5:V:LEVEL:?level 1:V:DURATION_UNIT:0 2:V:DURATION_VALUE:?time=0.0 3:V:RAMP_TIME_UNIT:0 4:V:RAMP_TIME_VALUE:?ramp=0.5',
'level' => 'V:LEVEL:?level',
'on' => 'V:LEVEL:1',
'on' => 'V:LEVEL:100',
'off' => 'V:LEVEL:0',
'on-for-timer' => '1:V:DURATION_UNIT:0 2:V:DURATION_VALUE:?duration 3:V:LEVEL:1',
'on-till' => '1:V:DURATION_UNIT:0 2:V:DURATION_VALUE:?time 3:V:LEVEL:1',
'on-for-timer' => '1:V:DURATION_UNIT:0 2:V:DURATION_VALUE:?duration 3:V:LEVEL:100',
'on-till' => '1:V:DURATION_UNIT:0 2:V:DURATION_VALUE:?time 3:V:LEVEL:100',
'up' => 'V:LEVEL:?delta=+10',
'down' => 'V:LEVEL:?delta=-10',
'toggle' => 'V:LEVEL:0,1'
'toggle' => 'V:LEVEL:0,100',
'color' => 'COMBINED_PARAMETER V:L:?level V:H:?hue V:SAT:?saturation'
},
'VIRTUAL_KEY' => {
'on' => 'V:PRESS_SHORT:1',