2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-21 14:04:15 +00:00

HMCCU: New commands and bug fixes

git-svn-id: https://svn.fhem.de/fhem/trunk@18552 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2019-02-10 11:52:28 +00:00
parent 32fa778897
commit 62e257e40c
6 changed files with 493 additions and 138 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- feature: 88_HMCCU: New commands and bug fixes
- changed: 93_DbLog: CommandRef revised - changed: 93_DbLog: CommandRef revised
- feature: 98_HTTPMOD: starting with featurelevel >5.9 enableCookies, - feature: 98_HTTPMOD: starting with featurelevel >5.9 enableCookies,
enableControlSet, handleRedirects and enableControlSet, handleRedirects and

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 4.3.010 # Version 4.3.011
# #
# Module for communication between FHEM and Homematic CCU2/3. # Module for communication between FHEM and Homematic CCU2/3.
# #
@ -51,7 +51,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version # HMCCU version
my $HMCCU_VERSION = '4.3.010'; my $HMCCU_VERSION = '4.3.011';
# Default RPC interface and port (BidCos-RF) # Default RPC interface and port (BidCos-RF)
my $HMCCU_RPC_PORT_DEFAULT = 2001; my $HMCCU_RPC_PORT_DEFAULT = 2001;
@ -73,6 +73,11 @@ my $HMCCU_TIMEOUT_EVENT = 600;
my $HMCCU_STATISTICS = 500; my $HMCCU_STATISTICS = 500;
my $HMCCU_TIMEOUT_REQUEST = 4; my $HMCCU_TIMEOUT_REQUEST = 4;
# ReGa Ports
my %HMCCU_REGA_PORT = (
'http' => 8181, 'https' => '48181'
);
# RPC port name by port number # RPC port name by port number
my %HMCCU_RPC_NUMPORT = ( my %HMCCU_RPC_NUMPORT = (
2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices', 2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices',
@ -87,10 +92,15 @@ my %HMCCU_RPC_PORT = (
# RPC flags # RPC flags
my %HMCCU_RPC_FLAG = ( my %HMCCU_RPC_FLAG = (
2000 => 'forceASCII', 2001 => 'forceASCII', 2003 => '_', 2010 => '_', 2000 => 'forceASCII', 2001 => 'forceASCII', 2003 => '_', 2010 => 'forceASCII',
7000 => 'forceInit', 8701 => 'forceInit', 9292 => '_' 7000 => 'forceInit', 8701 => 'forceInit', 9292 => '_'
); );
my %HMCCU_RPC_SSL = (
2000 => 1, 2001 => 1, 2010 => 1, 9292 => 1,
'BidCos-Wired' => 1, 'BidCos-RF' => 1, 'HmIP-RF' => 1, 'VirtualDevices' => 1
);
# Initial intervals for registration of RPC callbacks and reading RPC queue # Initial intervals for registration of RPC callbacks and reading RPC queue
# #
# X = Start RPC server # X = Start RPC server
@ -323,14 +333,19 @@ sub HMCCU_QueueEnq ($$);
sub HMCCU_QueueDeq ($); sub HMCCU_QueueDeq ($);
# Helper functions # Helper functions
sub HMCCU_BuildURL ($$);
sub HMCCU_CalculateReading ($$); sub HMCCU_CalculateReading ($$);
sub HMCCU_CorrectName ($);
sub HMCCU_Encrypt ($);
sub HMCCU_Decrypt ($);
sub HMCCU_DeleteReadings ($$);
sub HMCCU_EncodeEPDisplay ($); sub HMCCU_EncodeEPDisplay ($);
sub HMCCU_ExprMatch ($$$); sub HMCCU_ExprMatch ($$$);
sub HMCCU_ExprNotMatch ($$$); sub HMCCU_ExprNotMatch ($$$);
sub HMCCU_GetDutyCycle ($); sub HMCCU_GetDutyCycle ($);
sub HMCCU_GetHMState ($$$); sub HMCCU_GetHMState ($$$);
sub HMCCU_GetIdFromIP ($$);
sub HMCCU_GetTimeSpec ($); sub HMCCU_GetTimeSpec ($);
sub HMCCU_CorrectName ($);
sub HMCCU_RefToString ($); sub HMCCU_RefToString ($);
sub HMCCU_ResolveName ($$); sub HMCCU_ResolveName ($$);
sub HMCCU_TCPConnect ($$); sub HMCCU_TCPConnect ($$);
@ -393,7 +408,16 @@ sub HMCCU_Define ($$)
return "Specify CCU hostname or IP address as a parameter" if (scalar (@$a) < 3); return "Specify CCU hostname or IP address as a parameter" if (scalar (@$a) < 3);
$hash->{host} = $$a[2]; # Setup http or ssl connection
if ($$a[2] =~ /^(https?):\/\/(.+)/) {
$hash->{prot} = $1;
$hash->{host} = $2;
}
else {
$hash->{prot} = 'http';
$hash->{host} = $$a[2];
}
$hash->{Clients} = ':HMCCUDEV:HMCCUCHN:HMCCURPC:HMCCURPCPROC:'; $hash->{Clients} = ':HMCCUDEV:HMCCUCHN:HMCCURPC:HMCCURPCPROC:';
$hash->{hmccu}{ccu}{delay} = exists ($h->{ccudelay}) ? $h->{ccudelay} : $HMCCU_CCU_BOOT_DELAY; $hash->{hmccu}{ccu}{delay} = exists ($h->{ccudelay}) ? $h->{ccudelay} : $HMCCU_CCU_BOOT_DELAY;
$hash->{hmccu}{ccu}{timeout} = exists ($h->{waitforccu}) ? $h->{waitforccu} : $HMCCU_CCU_PING_TIMEOUT; $hash->{hmccu}{ccu}{timeout} = exists ($h->{waitforccu}) ? $h->{waitforccu} : $HMCCU_CCU_PING_TIMEOUT;
@ -408,12 +432,12 @@ sub HMCCU_Define ($$)
HMCCU_Log ($hash, 1, "Forced delayed initialization", 0); HMCCU_Log ($hash, 1, "Forced delayed initialization", 0);
} }
else { else {
if (HMCCU_TCPPing ($hash->{host}, 8181, $hash->{hmccu}{ccu}{timeout})) { if (HMCCU_TCPPing ($hash->{host}, $HMCCU_REGA_PORT{$hash->{prot}}, $hash->{hmccu}{ccu}{timeout})) {
$hash->{ccustate} = 'active'; $hash->{ccustate} = 'active';
} }
else { else {
$hash->{ccustate} = 'unreachable'; $hash->{ccustate} = 'unreachable';
HMCCU_Log ($hash, 1, "CCU port 8181 is not reachable", 0); HMCCU_Log ($hash, 1, "CCU port ".$HMCCU_REGA_PORT{$hash->{prot}}." is not reachable", 0);
} }
} }
@ -481,7 +505,7 @@ sub HMCCU_Define ($$)
# Initialization of FHEM device. # Initialization of FHEM device.
# Called during Define() or by HMCCU after CCU ready. # Called during Define() or by HMCCU after CCU ready.
# Return 0 on successful initialization or >0 on error: # Return 0 on successful initialization or >0 on error:
# 1 = CCU port 8181 is not reachable. # 1 = CCU port 8181 or 48181 is not reachable.
# 2 = Error while reading device list from CCU. # 2 = Error while reading device list from CCU.
###################################################################### ######################################################################
@ -492,9 +516,9 @@ sub HMCCU_InitDevice ($)
if ($hash->{hmccu}{ccu}{delayed} == 1) { if ($hash->{hmccu}{ccu}{delayed} == 1) {
HMCCU_Log ($hash, 1, "HMCCU: Initializing devices", 0); HMCCU_Log ($hash, 1, "HMCCU: Initializing devices", 0);
if (!HMCCU_TCPPing ($hash->{host}, 8181, $hash->{hmccu}{ccu}{timeout})) { if (!HMCCU_TCPPing ($hash->{host}, $HMCCU_REGA_PORT{$hash->{prot}}, $hash->{hmccu}{ccu}{timeout})) {
$hash->{ccustate} = 'unreachable'; $hash->{ccustate} = 'unreachable';
HMCCU_Log ($hash, 1, "HMCCU: CCU port 8181 is not reachable", 0); HMCCU_Log ($hash, 1, "HMCCU: CCU port ".$HMCCU_REGA_PORT{$hash->{prot}}." is not reachable", 0);
return 1; return 1;
} }
} }
@ -1169,12 +1193,12 @@ sub HMCCU_Detail ($$$$)
<table class="block wide"> <table class="block wide">
<tr class="odd"> <tr class="odd">
<td><div class="col1"> <td><div class="col1">
&gt; <a target="_blank" href="http://$hash->{host}">CCU WebUI</a> &gt; <a target="_blank" href="$hash->{prot}://$hash->{host}">CCU WebUI</a>
</div></td> </div></td>
</tr> </tr>
<tr class="odd"> <tr class="odd">
<td><div class="col1"> <td><div class="col1">
&gt; <a target="_blank" href="http://$hash->{host}/addons/cuxd/index.ccc">CUxD Config</a> &gt; <a target="_blank" href="$hash->{prot}://$hash->{host}/addons/cuxd/index.ccc">CUxD Config</a>
</div></td> </div></td>
</tr> </tr>
</table> </table>
@ -1379,8 +1403,8 @@ sub HMCCU_Set ($@)
my ($hash, $a, $h) = @_; my ($hash, $a, $h) = @_;
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a;
my $options = "var delete execute hmscript cleardefaults:noArg defaults:noArg ". my $options = "var clear delete execute hmscript cleardefaults:noArg defaults:noArg ".
"importdefaults rpcregister:all rpcserver:on,off,restart ackmessages:noArg"; "importdefaults rpcregister:all rpcserver:on,off,restart ackmessages:noArg authentication";
my @ifList = HMCCU_GetRPCInterfaceList ($hash); my @ifList = HMCCU_GetRPCInterfaceList ($hash);
if (scalar (@ifList) > 0) { if (scalar (@ifList) > 0) {
my $ifStr = join (',', @ifList); my $ifStr = join (',', @ifList);
@ -1389,7 +1413,9 @@ sub HMCCU_Set ($@)
my $usage = "HMCCU: Unknown argument $opt, choose one of $options"; my $usage = "HMCCU: Unknown argument $opt, choose one of $options";
my $host = $hash->{host}; my $host = $hash->{host};
return "HMCCU: I/O device not initialized. Try again later." if ($hash->{hmccu}{ccu}{delayed}); return undef if ($hash->{hmccu}{ccu}{delayed});
return "HMCCU: CCU is unreachable, choose one of initialize:noArg" if ($hash->{ccustate} eq 'unreachable');
return undef if ($hash->{ccustate} ne 'active');
return "HMCCU: CCU busy, choose one of rpcserver:off" return "HMCCU: CCU busy, choose one of rpcserver:off"
if ($opt ne 'rpcserver' && HMCCU_IsRPCStateBlocking ($hash)); if ($opt ne 'rpcserver' && HMCCU_IsRPCStateBlocking ($hash));
@ -1419,7 +1445,7 @@ sub HMCCU_Set ($@)
$vartype = shift @$a if (scalar (@$a) == 3); $vartype = shift @$a if (scalar (@$a) == 3);
my $objname = shift @$a; my $objname = shift @$a;
my $objvalue = shift @$a; my $objvalue = shift @$a;
$usage = "set $name $opt [{'bool'|'list'|'number'|'test'}] variable value [param=value [...]]"; $usage = "set $name $opt [{'bool'|'list'|'number'|'text'}] variable value [param=value [...]]";
return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue)); return HMCCU_SetError ($hash, $usage) if (!defined ($objvalue));
@ -1432,6 +1458,48 @@ sub HMCCU_Set ($@)
return HMCCU_SetError ($hash, $result) if ($result < 0); return HMCCU_SetError ($hash, $result) if ($result < 0);
return HMCCU_SetState ($hash, "OK"); return HMCCU_SetState ($hash, "OK");
} }
# elsif ($opt eq 'test') {
# my $backend = shift @$a;
# my $url = defined ($backend) ? HMCCU_BuildURL ($hash, $backend) : '';
# return "URL=$url";
# }
elsif ($opt eq 'initialize') {
return HMCCU_SetError ($hash, "State of CCU must be unreachable")
if ($hash->{ccustate} ne 'unreachable');
my $err = HMCCU_InitDevice ($hash);
return HMCCU_SetError ($hash, "CCU not reachable") if ($err == 1);
return HMCCU_SetError ($hash, "Can't read device list from CCU") if ($err == 2);
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'authentication') {
my $username = shift @$a;
my $password = shift @$a;
$usage = "set $name $opt username password";
if (!defined ($username)) {
setKeyValue ($name."_username", undef);
setKeyValue ($name."_password", undef);
return "Credentials for CCU authentication deleted";
}
return HMCCU_SetError ($hash, $usage) if (!defined ($password));
my $encuser = HMCCU_Encrypt ($username);
my $encpass = HMCCU_Encrypt ($password);
return HMCCU_SetError ($hash, "Encryption of credentials failed") if ($encuser eq '' || $encpass eq '');
my $err = setKeyValue ($name."_username", $encuser);
return HMCCU_SetError ($hash, "Can't store credentials. $err") if (defined ($err));
$err = setKeyValue ($name."_password", $encpass);
return HMCCU_SetError ($hash, "Can't store credentials. $err") if (defined ($err));
return "Credentials for CCU authentication stored";
}
elsif ($opt eq 'clear') {
my $rnexp = shift @$a;
HMCCU_DeleteReadings ($hash, $rnexp);
return HMCCU_SetState ($hash, "OK");
}
elsif ($opt eq 'datapoint') { elsif ($opt eq 'datapoint') {
return HMCCU_SetError ($hash, "Command set datapoint is no longer supported by I/O device"); return HMCCU_SetError ($hash, "Command set datapoint is no longer supported by I/O device");
} }
@ -1626,11 +1694,12 @@ sub HMCCU_Get ($@)
my $opt = shift @$a; my $opt = shift @$a;
my $options = "defaults:noArg exportdefaults devicelist dump dutycycle:noArg vars update". my $options = "defaults:noArg exportdefaults devicelist dump dutycycle:noArg vars update".
" updateccu parfile configdesc firmware rpcevents:noArg rpcstate:noArg deviceinfo"; " updateccu parfile configdesc firmware rpcevents:noArg rpcstate:noArg deviceinfo".
" ccumsg:alarm,service";
my $usage = "HMCCU: Unknown argument $opt, choose one of $options"; my $usage = "HMCCU: Unknown argument $opt, choose one of $options";
my $host = $hash->{host}; my $host = $hash->{host};
return "HMCCU: I/O device not initialized. Try again later." if ($hash->{hmccu}{ccu}{delayed}); return undef if ($hash->{hmccu}{ccu}{delayed} || $hash->{ccustate} ne 'active');
return "HMCCU: CCU busy, choose one of rpcstate:noArg" return "HMCCU: CCU busy, choose one of rpcstate:noArg"
if ($opt ne 'rpcstate' && HMCCU_IsRPCStateBlocking ($hash)); if ($opt ne 'rpcstate' && HMCCU_IsRPCStateBlocking ($hash));
@ -1876,7 +1945,7 @@ sub HMCCU_Get ($@)
# Define new client device # Define new client device
my $ret = CommandDefine (undef, $devname." $defmod ".$add); my $ret = CommandDefine (undef, $devname." $defmod ".$add);
if ($ret) { if ($ret) {
Log3 $name, 2, "HMCCU: Define command failed $devname $defmod $ccuname"; Log3 $name, 2, "HMCCU: [$name] Define command failed $devname $defmod $ccuname";
Log3 $name, 2, "$defmod: $ret"; Log3 $name, 2, "$defmod: $ret";
$result .= "\nCan't create device $devname. $ret"; $result .= "\nCan't create device $devname. $ret";
next; next;
@ -1996,6 +2065,24 @@ sub HMCCU_Get ($@)
return HMCCU_SetError ($hash, $rc) if ($rc < 0); return HMCCU_SetError ($hash, $rc) if ($rc < 0);
return HMCCU_SetState ($hash, "OK", $res); return HMCCU_SetState ($hash, "OK", $res);
} }
elsif ($opt eq 'ccumsg') {
my $msgtype = shift @$a;
$usage = "Usage: get $name $opt {service|alarm}";
return HMCCU_SetError ($hash, $usage) if (!defined ($msgtype));
my $script = ($msgtype eq 'service') ? "!GetServiceMessages" : "!GetAlarms";
my $res = HMCCU_HMScriptExt ($hash, $script, undef);
return HMCCU_SetError ($hash, "Error") if ($res eq '' || $res =~ /^ERROR:.*/);
# Generate event for each message
foreach my $msg (split /\n/, $res) {
next if ($msg =~ /^[0-9]+$/);
DoTrigger ($name, $msg);
}
return HMCCU_SetState ($hash, "OK", $res);
}
else { else {
if (exists ($hash->{hmccu}{agg})) { if (exists ($hash->{hmccu}{agg})) {
my @rules = keys %{$hash->{hmccu}{agg}}; my @rules = keys %{$hash->{hmccu}{agg}};
@ -2186,9 +2273,7 @@ sub HMCCU_FilterReading ($$$)
return 1 if (!defined ($hmccu_hash)); return 1 if (!defined ($hmccu_hash));
my $grf = AttrVal ($hmccu_hash->{NAME}, 'ccudef-readingfilter', '.*'); my $grf = AttrVal ($hmccu_hash->{NAME}, 'ccudef-readingfilter', '.*');
# $grf = '.*' if ($grf eq '');
my $rf = AttrVal ($name, 'ccureadingfilter', $grf); my $rf = AttrVal ($name, 'ccureadingfilter', $grf);
# $rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*' && $grf ne '');
$rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*'); $rf = $grf.";".$rf if ($rf ne $grf && $grf ne '.*');
my $chnnam = ''; my $chnnam = '';
@ -3526,8 +3611,11 @@ sub HMCCU_GetRPCCallbackURL ($$$$$)
my $ifname = $iface =~ /^[0-9]+$/ ? $hmccu_hash->{hmccu}{ifports}{$iface} : $iface; my $ifname = $iface =~ /^[0-9]+$/ ? $hmccu_hash->{hmccu}{ifports}{$iface} : $iface;
return undef if (!exists ($hmccu_hash->{hmccu}{interfaces}{$ifname})); return undef if (!exists ($hmccu_hash->{hmccu}{interfaces}{$ifname}));
return $hmccu_hash->{hmccu}{interfaces}{$ifname}{prot}."://$localaddr:$cbport/fh". my $url = $hmccu_hash->{hmccu}{interfaces}{$ifname}{prot}."://$localaddr:$cbport/fh".
$hmccu_hash->{hmccu}{interfaces}{$ifname}{port}; $hmccu_hash->{hmccu}{interfaces}{$ifname}{port};
$url =~ s/^https/http/;
return $url;
} }
###################################################################### ######################################################################
@ -3535,6 +3623,7 @@ sub HMCCU_GetRPCCallbackURL ($$$$$)
# Parameter iface can be a port number or an interface name. # Parameter iface can be a port number or an interface name.
# Valid values for info are: # Valid values for info are:
# url, port, prot, host, type, name, flags, device. # url, port, prot, host, type, name, flags, device.
# Return undef for invalid interface or info token.
###################################################################### ######################################################################
sub HMCCU_GetRPCServerInfo ($$$) sub HMCCU_GetRPCServerInfo ($$$)
@ -3760,7 +3849,7 @@ sub HMCCU_StopExtRPCServer ($)
next; next;
} }
$hash->{hmccu}{interfaces}{$ifname}{manager} = 'HMCCU'; $hash->{hmccu}{interfaces}{$ifname}{manager} = 'HMCCU';
$rc &= HMCCURPCPROC_StopRPCServer ($defs{$rpcdev}); $rc &= HMCCURPCPROC_StopRPCServer ($defs{$rpcdev}, undef);
} }
return $rc; return $rc;
@ -3867,7 +3956,7 @@ sub HMCCU_StartIntRPCServer ($)
# Initialize statistic counters # Initialize statistic counters
HMCCU_ResetCounters ($hash); HMCCU_ResetCounters ($hash);
Log3 $name, 0, "RPC server(s) starting"; Log3 $name, 0, "HMCCU: [$name] RPC server(s) starting";
DoTrigger ($name, "RPC server starting"); DoTrigger ($name, "RPC server starting");
InternalTimer (gettimeofday()+$rpcinterval, 'HMCCU_ReadRPCQueue', $hash, 0); InternalTimer (gettimeofday()+$rpcinterval, 'HMCCU_ReadRPCQueue', $hash, 0);
@ -4252,6 +4341,7 @@ sub HMCCU_GetDeviceList ($)
# Delete old entries # Delete old entries
%{$hash->{hmccu}{dev}} = (); %{$hash->{hmccu}{dev}} = ();
%{$hash->{hmccu}{adr}} = (); %{$hash->{hmccu}{adr}} = ();
%{$hash->{hmccu}{interfaces}} = ();
%{$hash->{hmccu}{grp}} = (); %{$hash->{hmccu}{grp}} = ();
%{$hash->{hmccu}{prg}} = (); %{$hash->{hmccu}{prg}} = ();
$hash->{hmccu}{updatetime} = time (); $hash->{hmccu}{updatetime} = time ();
@ -4319,6 +4409,10 @@ sub HMCCU_GetDeviceList ($)
$port -= 30000; $port -= 30000;
$ifurl =~ s/:3$port/:$port/; $ifurl =~ s/:3$port/:$port/;
} }
# if ($hash->{prot} eq 'https') {
# # For secure connections add 40000 to port
# $ifurl =~ s/:$port/:4$port/;
# }
if ($hash->{ccuip} ne 'N/A') { if ($hash->{ccuip} ne 'N/A') {
$ifurl =~ s/127\.0\.0\.1/$hash->{ccuip}/; $ifurl =~ s/127\.0\.0\.1/$hash->{ccuip}/;
$ipaddr =~ s/127\.0\.0\.1/$hash->{ccuip}/; $ipaddr =~ s/127\.0\.0\.1/$hash->{ccuip}/;
@ -5121,6 +5215,7 @@ sub HMCCU_GetRPCDevice ($$$)
my $rpcdevname; my $rpcdevname;
my $rpcdevtype = 'HMCCURPCPROC'; my $rpcdevtype = 'HMCCURPCPROC';
my $rpchost = $hash->{host}; my $rpchost = $hash->{host};
my $rpcprot = $hash->{prot};
my $ccuflags = HMCCU_GetFlags ($name); my $ccuflags = HMCCU_GetFlags ($name);
@ -5156,8 +5251,12 @@ sub HMCCU_GetRPCDevice ($$$)
my $devhash = $defs{$dev}; my $devhash = $defs{$dev};
next if ($devhash->{TYPE} ne $rpcdevtype); next if ($devhash->{TYPE} ne $rpcdevtype);
my $ip = 'null'; my $ip = 'null';
my $addrnum = inet_aton ($devhash->{host}); if (!exists ($devhash->{rpcip})) {
$ip = inet_ntoa ($addrnum) if (defined ($addrnum)); $ip = HMCCU_Resolve ($devhash->{host}, 'null');
}
else {
$ip = $devhash->{rpcip};
}
next if ($devhash->{host} ne $rpchost && $ip ne $rpchost); next if ($devhash->{host} ne $rpchost && $ip ne $rpchost);
# next if ($rpcdevtype eq 'HMCCURPCPROC' && $devhash->{rpcinterface} ne $ifname); # next if ($rpcdevtype eq 'HMCCURPCPROC' && $devhash->{rpcinterface} ne $ifname);
next if ($devhash->{rpcinterface} ne $ifname); next if ($devhash->{rpcinterface} ne $ifname);
@ -5181,15 +5280,20 @@ sub HMCCU_GetRPCDevice ($$$)
# Create RPC device # Create RPC device
if ($create) { if ($create) {
my $alias = "CCU RPC"; my $alias = "CCU RPC $ifname";
my $rpccreate = "d_rpc $rpcdevtype ".$hash->{host}; my $rpccreate = '';
$rpcdevname = "d_rpc"; $rpcdevname = "d_rpc";
if (defined ($ifname)) {
$rpcdevname = makeDeviceName ("d_rpc".$ifname);
$alias .= " $ifname";
$rpccreate = "$rpcdevname $rpcdevtype $rpchost $ifname";
}
# Ensure unique device name by appending last 2 digits of CCU IP address
$rpcdevname .= HMCCU_GetIdFromIP ($hash->{ccuip}, '') if (exists ($hash->{ccuip}));
# Build device name and define command
$rpcdevname = makeDeviceName ($rpcdevname.$ifname);
$rpccreate = "$rpcdevname $rpcdevtype $rpcprot://$rpchost $ifname";
return (HMCCU_Log ($hash, 2, "Device $rpcdevname already exists. Please delete or rename it.", ''), 0)
if (exists ($defs{"$rpcdevname"}));
# Create RPC device
HMCCU_Log ($hash, 1, "Creating new RPC device $rpcdevname", undef); HMCCU_Log ($hash, 1, "Creating new RPC device $rpcdevname", undef);
my $ret = CommandDefine (undef, $rpccreate); my $ret = CommandDefine (undef, $rpccreate);
if (!defined ($ret)) { if (!defined ($ret)) {
@ -5237,7 +5341,7 @@ sub HMCCU_AssignIODevice ($$$)
return 0; return 0;
} }
if ($type eq 'HMCCURPCPROC' && defined ($ifname)) { if ($type eq 'HMCCURPCPROC' && defined ($ifname) && exists ($hmccu_hash->{hmccu}{interfaces}{$ifname})) {
# Register RPC device # Register RPC device
$hmccu_hash->{hmccu}{interfaces}{$ifname}{device} = $name; $hmccu_hash->{hmccu}{interfaces}{$ifname}{device} = $name;
} }
@ -5794,7 +5898,7 @@ sub HMCCU_ReadRPCQueue ($)
if ($hash->{hmccu}{evtime} > 0 && time()-$hash->{hmccu}{evtime} > $rpcevtimeout && if ($hash->{hmccu}{evtime} > 0 && time()-$hash->{hmccu}{evtime} > $rpcevtimeout &&
$hash->{hmccu}{evtimeout} == 0) { $hash->{hmccu}{evtimeout} == 0) {
$hash->{hmccu}{evtimeout} = 1; $hash->{hmccu}{evtimeout} = 1;
$hash->{ccustate} = HMCCU_TCPConnect ($hash->{host}, 8181) ne '' ? 'timeout' : 'unreachable'; $hash->{ccustate} = HMCCU_TCPConnect ($hash->{host}, $HMCCU_REGA_PORT{$hash->{prot}}) ne '' ? 'timeout' : 'unreachable';
Log3 $name, 2, "HMCCU: Received no events from CCU since $rpcevtimeout seconds"; Log3 $name, 2, "HMCCU: Received no events from CCU since $rpcevtimeout seconds";
DoTrigger ($name, "No events from CCU since $rpcevtimeout seconds"); DoTrigger ($name, "No events from CCU since $rpcevtimeout seconds");
} }
@ -5858,6 +5962,7 @@ sub HMCCU_ReadRPCQueue ($)
###################################################################### ######################################################################
# Execute Homematic command on CCU. # Execute Homematic command on CCU.
# If parameter mode is 1 an empty string is a valid result. # If parameter mode is 1 an empty string is a valid result.
# Return undef on error.
###################################################################### ######################################################################
sub HMCCU_HMCommand ($$$) sub HMCCU_HMCommand ($$$)
@ -5868,20 +5973,26 @@ sub HMCCU_HMCommand ($$$)
my $io_hash = HMCCU_GetHash ($cl_hash); my $io_hash = HMCCU_GetHash ($cl_hash);
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST); my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$io_hash->{host}.":8181/tclrega.exe"; my $url = HMCCU_BuildURL ($io_hash, 'rega');
my $value; my $value;
HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url, cmd=$cmd"); HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url, cmd=$cmd");
my $response = GetFileFromURL ($url, $ccureqtimeout, $cmd); my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST" };
if (defined ($response)) { $param->{sslargs} = { SSL_verify_mode => 0 };
my ($err, $response) = HttpUtils_BlockingGet ($param);
# my $response = GetFileFromURL ($url, $ccureqtimeout, $cmd);
if ($err eq '') {
$value = $response; $value = $response;
$value =~ s/<xml>(.*)<\/xml>//; $value =~ s/<xml>(.*)<\/xml>//;
$value =~ s/\r//g; $value =~ s/\r//g;
HMCCU_Trace ($cl_hash, 2, $fnc, "Response=$response, Value=".(defined ($value) ? $value : "undef")); HMCCU_Trace ($cl_hash, 2, $fnc, "Response=$response, Value=".(defined ($value) ? $value : "undef"));
} }
else { else {
HMCCU_Trace ($cl_hash, 2, $fnc, "Response=undef"); HMCCU_Log ($io_hash, 2, "Error during HTTP request: $err", undef);
HMCCU_Trace ($cl_hash, 2, $fnc, "Response=$response");
return undef;
} }
if ($mode == 1) { if ($mode == 1) {
@ -5904,18 +6015,20 @@ sub HMCCU_HMCommandNB ($$$)
my $io_hash = HMCCU_GetHash ($cl_hash); my $io_hash = HMCCU_GetHash ($cl_hash);
my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST); my $ccureqtimeout = AttrVal ($io_hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
my $url = "http://".$io_hash->{host}.":8181/tclrega.exe"; my $url = HMCCU_BuildURL ($io_hash, 'rega');
HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url"); HMCCU_Trace ($cl_hash, 2, $fnc, "URL=$url");
if (defined ($cbfunc)) { if (defined ($cbfunc)) {
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST", my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST",
callback => $cbfunc, devhash => $cl_hash }; callback => $cbfunc, devhash => $cl_hash };
$param->{sslargs} = { SSL_verify_mode => 0 };
HttpUtils_NonblockingGet ($param); HttpUtils_NonblockingGet ($param);
} }
else { else {
my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST", my $param = { url => $url, timeout => $ccureqtimeout, data => $cmd, method => "POST",
callback => \&HMCCU_HMCommandCB, devhash => $cl_hash }; callback => \&HMCCU_HMCommandCB, devhash => $cl_hash };
$param->{sslargs} = { SSL_verify_mode => 0 };
HttpUtils_NonblockingGet ($param); HttpUtils_NonblockingGet ($param);
} }
} }
@ -5957,6 +6070,8 @@ sub HMCCU_HMScriptExt ($$$)
return HMCCU_LogError ($hash, 2, "CCU host name not defined") if (!exists ($hash->{host})); return HMCCU_LogError ($hash, 2, "CCU host name not defined") if (!exists ($hash->{host}));
my $host = $hash->{host}; my $host = $hash->{host};
my $ccureqtimeout = AttrVal ($hash->{NAME}, "ccuReqTimeout", $HMCCU_TIMEOUT_REQUEST);
if ($hmscript =~ /^!(.*)$/) { if ($hmscript =~ /^!(.*)$/) {
# Internal script # Internal script
$scrname = $1; $scrname = $1;
@ -6004,19 +6119,25 @@ sub HMCCU_HMScriptExt ($$$)
} }
# Execute script on CCU # Execute script on CCU
my $url = "http://".$host.":8181/tclrega.exe"; my $url = HMCCU_BuildURL ($hash, 'rega');
my $ua = new LWP::UserAgent (); my $param = { url => $url, timeout => $ccureqtimeout, data => $code, method => "POST" };
my $response = $ua->post($url, Content => $code); $param->{sslargs} = { SSL_verify_mode => 0 };
if ($response->is_success ()) { my ($err, $response) = HttpUtils_BlockingGet ($param);
my $output = $response->content;
# my $ua = new LWP::UserAgent ();
# my $response = $ua->post($url, Content => $code);
# if ($response->is_success ()) {
# my $output = $response->content;
if ($err eq '') {
my $output = $response;
$output =~ s/<xml>.*<\/xml>//; $output =~ s/<xml>.*<\/xml>//;
$output =~ s/\r//g; $output =~ s/\r//g;
return $output; return $output;
} }
else { else {
my $msg = $response->status_line(); # my $msg = $response->status_line();
Log3 $name, 2, "HMCCU: HMScript failed. $msg"; HMCCU_Log ($hash, 2, "HMScript failed. $err", undef);
return "ERROR: HMScript failed. $msg"; return "ERROR: HMScript failed. $err";
} }
} }
@ -6027,8 +6148,27 @@ sub HMCCU_HMScriptExt ($$$)
sub HMCCU_BulkUpdate ($$$$) sub HMCCU_BulkUpdate ($$$$)
{ {
my ($hash, $reading, $orgval, $subval) = @_; my ($hash, $reading, $orgval, $subval) = @_;
my $name = $hash->{NAME};
my $excl = AttrVal ($hash->{NAME}, 'substexcl', ''); my $excl = AttrVal ($name, 'substexcl', '');
#
# For later use: Suppress reading update
#
# my $suppress = AttrVal ($name, 'ccusuppress', '');
#
# if ($suppress ne '') {
# my $ct = time();
# my @srules = split (";", $suppress);
#
# foreach my $sr (@srules) {
# my ($rnexp, $to) = split (":", $sr);
# next if (!defined ($to));
# if ($reading =~ /$rnexp/) {
# my $rt = ReadingsTimestamp ($name, $reading, '');
# return if ($rt ne '' && $ct-time_str2num($rt) < $to);
# }
# }
# }
readingsBulkUpdate ($hash, $reading, ($excl ne '' && $reading =~ /$excl/ ? $orgval : $subval)); readingsBulkUpdate ($hash, $reading, ($excl ne '' && $reading =~ /$excl/ ? $orgval : $subval));
} }
@ -6664,7 +6804,8 @@ sub HMCCU_RPCGetConfig ($$$$)
} }
} }
else { else {
my $url = HMCCU_GetRPCServerInfo ($hmccu_hash, $int, 'url'); # my $url = HMCCU_GetRPCServerInfo ($hmccu_hash, $int, 'url');
my $url = HMCCU_BuildURL ($hmccu_hash, $int);
return (-9, '') if (!defined ($url)); return (-9, '') if (!defined ($url));
HMCCU_Trace ($hash, 2, $fnc, "Method=$method Addr=$addr Port=$port"); HMCCU_Trace ($hash, 2, $fnc, "Method=$method Addr=$addr Port=$port");
my $client = RPC::XML::Client->new ($url); my $client = RPC::XML::Client->new ($url);
@ -6793,7 +6934,8 @@ sub HMCCU_RPCSetConfig ($$$)
} }
} }
else { else {
my $url = HMCCU_GetRPCServerInfo ($hmccu_hash, $int, 'url'); # my $url = HMCCU_GetRPCServerInfo ($hmccu_hash, $int, 'url');
my $url = HMCCU_BuildURL ($hmccu_hash, $int);
return -9 if (!defined ($url)); return -9 if (!defined ($url));
my $client = RPC::XML::Client->new ($url); my $client = RPC::XML::Client->new ($url);
$res = $client->simple_request ("putParamset", $addr, "MASTER", $parref); $res = $client->simple_request ("putParamset", $addr, "MASTER", $parref);
@ -7023,6 +7165,51 @@ sub HMCCU_GetTimeSpec ($)
return ($s-$cs); return ($s-$cs);
} }
######################################################################
# Build ReGa or RPC client URL
# Parameter backend specifies type of URL, 'rega' or name or port of
# RPC interface.
# Return empty string on error.
######################################################################
sub HMCCU_BuildURL ($$)
{
my ($hash, $backend) = @_;
my $name = $hash->{NAME};
my $url = '';
my $username = '';
my $password = '';
my ($erruser, $encuser) = getKeyValue ($name."_username");
my ($errpass, $encpass) = getKeyValue ($name."_password");
if (!defined ($erruser) && !defined ($errpass) && defined ($encuser) && defined ($encpass)) {
$username = HMCCU_Decrypt ($encuser);
$password = HMCCU_Decrypt ($encpass);
}
my $auth = ($username ne '' && $password ne '') ? "$username:$password".'@' : '';
if ($backend eq 'rega') {
$url = $hash->{prot}."://$auth".$hash->{host}.":".
$HMCCU_REGA_PORT{$hash->{prot}}."/tclrega.exe";
}
else {
$url = HMCCU_GetRPCServerInfo ($hash, $backend, 'url');
if (defined ($url)) {
if (exists ($HMCCU_RPC_SSL{$backend})) {
my $p = $hash->{prot} eq 'https' ? '4' : '';
$url =~ s/^http:\/\//$hash->{prot}:\/\/$auth/;
$url =~ s/:([0-9]+)/:$p$1/;
}
}
else {
$url = '';
}
}
HMCCU_Log ($hash, 4, "Build URL = $url", undef);
return $url;
}
###################################################################### ######################################################################
# Calculate special readings. Requires hash of client device, channel # Calculate special readings. Requires hash of client device, channel
# number and datapoint. Supported functions: # number and datapoint. Supported functions:
@ -7184,6 +7371,73 @@ sub HMCCU_CalculateReading ($$)
return @result; return @result;
} }
######################################################################
# Encrypt string with FHEM unique ID
######################################################################
sub HMCCU_Encrypt ($)
{
my ($istr) = @_;
my $ostr = '';
my $id = getUniqueId();
return '' if (!defined ($id) || $id eq '');
my $key = $id;
foreach my $c (split //, $istr) {
my $k = chop($key);
if ($k eq '') {
$key = $id;
$k = chop($key);
}
$ostr .= sprintf ("%.2x",ord($c)^ord($k));
}
return $ostr;
}
######################################################################
# Decrypt string with FHEM unique ID
######################################################################
sub HMCCU_Decrypt ($)
{
my ($istr) = @_;
my $ostr = '';
my $id = getUniqueId();
return '' if (!defined ($id) || $id eq '');
my $key = $id;
for my $c (map { pack('C', hex($_)) } ($istr =~ /(..)/g)) {
my $k = chop($key);
if ($k eq '') {
$key = $id;
$k = chop($key);
}
$ostr .= chr(ord($c)^ord($k));
}
return $ostr;
}
######################################################################
# Delete readings matching regular expression.
# Default for rnexp is .*
# Readings 'state' and 'control' are ignored.
######################################################################
sub HMCCU_DeleteReadings ($$)
{
my ($hash, $rnexp) = @_;
$rnexp = '.*' if (!defined ($rnexp));
my @readlist = keys %{$hash->{READINGS}};
foreach my $rd (@readlist) {
delete ($hash->{READINGS}{$rd}) if ($rd ne 'state' && $rd ne 'control' && $rd =~ /$rnexp/);
}
}
###################################################################### ######################################################################
# Encode command string for e-paper display # Encode command string for e-paper display
# #
@ -7380,7 +7634,8 @@ sub HMCCU_GetDutyCycle ($)
foreach my $port (@rpcports) { foreach my $port (@rpcports) {
next if ($port != 2001 && $port != 2010); next if ($port != 2001 && $port != 2010);
my $url = HMCCU_GetRPCServerInfo ($hash, $port, 'url'); # my $url = HMCCU_GetRPCServerInfo ($hash, $port, 'url');
my $url = HMCCU_BuildURL ($hash, $port);
next if (!defined ($url)); next if (!defined ($url));
my $rpcclient = RPC::XML::Client->new ($url); my $rpcclient = RPC::XML::Client->new ($url);
my $response = $rpcclient->simple_request ("listBidcosInterfaces"); my $response = $rpcclient->simple_request ("listBidcosInterfaces");
@ -7445,6 +7700,23 @@ sub HMCCU_TCPConnect ($$)
return ''; return '';
} }
######################################################################
# Generate a 6 digit Id from last 2 segments of IP address
######################################################################
sub HMCCU_GetIdFromIP ($$)
{
my ($ip, $default) = @_;
my @ipseg = split (/\./, $ip);
if (scalar (@ipseg) == 4) {
return sprintf ("%03d%03d", $ipseg[2], $ipseg[3]);
}
else {
return $default;
}
}
###################################################################### ######################################################################
# Resolve hostname. # Resolve hostname.
# Return value defip if hostname can't be resolved. # Return value defip if hostname can't be resolved.
@ -7806,15 +8078,16 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<a name="HMCCUdefine"></a> <a name="HMCCUdefine"></a>
<b>Define</b><br/><br/> <b>Define</b><br/><br/>
<ul> <ul>
<code>define &lt;name&gt; HMCCU &lt;HostOrIP&gt; [&lt;ccu-number&gt;] [waitforccu=&lt;timeout&gt;] <code>define &lt;name&gt; HMCCU [&lt;Protocol&gt;://]&lt;HostOrIP&gt; [&lt;ccu-number&gt;] [waitforccu=&lt;timeout&gt;]
[ccudelay=&lt;delay&gt;] [delayedinit=&lt;delay&gt;]</code> [ccudelay=&lt;delay&gt;] [delayedinit=&lt;delay&gt;]</code>
<br/><br/> <br/><br/>
Example:<br/> Example:<br/>
<code>define myccu HMCCU 192.168.1.10 ccudelay=180</code> <code>define myccu HMCCU https://192.168.1.10 ccudelay=180</code>
<br/><br/> <br/><br/>
The parameter <i>HostOrIP</i> is the hostname or IP address of a Homematic CCU2 or CCU3. If you have The parameter <i>HostOrIP</i> is the hostname or IP address of a Homematic CCU2 or CCU3. Optionally
more than one CCU you can specifiy a unique CCU number with parameter <i>ccu-number</i>. With the <i>protocol</i> 'http' or 'https' can be specified. Default protocol is 'http'.<br/>
option <i>waitforccu</i> HMCCU will wait for the specified time if CCU is not reachable. If you have more than one CCU you can specifiy a unique CCU number with parameter <i>ccu-number</i>.
With option <i>waitforccu</i> HMCCU will wait for the specified time if CCU is not reachable.
Parameter <i>timeout</i> should be a multiple of 20 in seconds. Warning: This option will Parameter <i>timeout</i> should be a multiple of 20 in seconds. Warning: This option will
block the start of FHEM for <i>timeout</i> seconds.<br/> block the start of FHEM for <i>timeout</i> seconds.<br/>
The option <i>ccudelay</i> specifies the time for delayed initialization of CCU environment if The option <i>ccudelay</i> specifies the time for delayed initialization of CCU environment if
@ -7846,6 +8119,15 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<ul> <ul>
<li><b>set &lt;name&gt; ackmessages</b><br/> <li><b>set &lt;name&gt; ackmessages</b><br/>
Acknowledge device was unreachable messages in CCU. Acknowledge device was unreachable messages in CCU.
</li><br/>
<li><b>set &lt;name&gt; authentication [&lt;username&gt; &lt;password&gt;]</b><br/>
Set credentials for CCU authentication. Authentication must be activated by setting
attribute ccuflags to 'authenticate'.<br/>
When executing this command without arguments credentials are deleted.
</li><br/>
<li><b>set &lt;name&gt; clear [&lt;reading-exp&gt;]</b><br/>
Delete readings matching specified reading name expression. Default expression is '.*'.
Readings 'state' and 'control' are not deleted.
</li><br/> </li><br/>
<li><b>set &lt;name&gt; cleardefaults</b><br/> <li><b>set &lt;name&gt; cleardefaults</b><br/>
Clear default attributes imported from file. Clear default attributes imported from file.
@ -7877,6 +8159,9 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<li><b>set &lt;name&gt; importdefaults &lt;filename&gt;</b><br/> <li><b>set &lt;name&gt; importdefaults &lt;filename&gt;</b><br/>
Import default attributes from file. Import default attributes from file.
</li><br/> </li><br/>
<li><b>set &lt;name&gt; initialize</b><br/>
Initialize I/O device if state of CCU is unreachable.
</li><br/>
<li><b>set &lt;name&gt; rpcregister [{all | &lt;interface&gt;}]</b><br/> <li><b>set &lt;name&gt; rpcregister [{all | &lt;interface&gt;}]</b><br/>
Register RPC servers at CCU. Register RPC servers at CCU.
</li><br/> </li><br/>
@ -7899,6 +8184,9 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
<li><b>get &lt;name&gt; aggregation {&lt;rule&gt;|all}</b><br/> <li><b>get &lt;name&gt; aggregation {&lt;rule&gt;|all}</b><br/>
Process aggregation rule defined with attribute ccuaggregate. Process aggregation rule defined with attribute ccuaggregate.
</li><br/> </li><br/>
<li><b>get &lt;name&gt; ccumsg {service|alarm}</b><br/>
Query active service or alarm messages from CCU. Generate FHEM event for each message.
</li><br/>
<li><b>get &lt;name&gt; configdesc {&lt;device&gt;|&lt;channel&gt;}</b><br/> <li><b>get &lt;name&gt; configdesc {&lt;device&gt;|&lt;channel&gt;}</b><br/>
Get configuration parameter description of CCU device or channel (similar Get configuration parameter description of CCU device or channel (similar
to device settings in CCU). Not every CCU device or channel provides a configuration to device settings in CCU). Not every CCU device or channel provides a configuration

View File

@ -4,9 +4,9 @@
# #
# $Id$ # $Id$
# #
# Version 4.3.005 # Version 4.3.006
# #
# (c) 2018 zap (zap01 <at> t-online <dot> de) # (c) 2019 zap (zap01 <at> t-online <dot> de)
# #
###################################################################### ######################################################################
# Client device for Homematic channels. # Client device for Homematic channels.
@ -208,8 +208,8 @@ sub HMCCUCHN_Set ($@)
my $rocmds = "clear config defaults:noArg"; my $rocmds = "clear config defaults:noArg";
# Get I/O device, check device state # Get I/O device, check device state
return HMCCU_SetError ($hash, -19) if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending'); return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev})); !defined ($hash->{IODev}));
return undef if ($hash->{statevals} eq 'readonly' && $opt ne '?' && return undef if ($hash->{statevals} eq 'readonly' && $opt ne '?' &&
$opt !~ /^(clear|config|defaults)$/); $opt !~ /^(clear|config|defaults)$/);
@ -403,11 +403,8 @@ sub HMCCUCHN_Set ($@)
} }
elsif ($opt eq 'clear') { elsif ($opt eq 'clear') {
my $rnexp = shift @$a; my $rnexp = shift @$a;
$rnexp = '.*' if (!defined ($rnexp)); HMCCU_DeleteReadings ($hash, $rnexp);
my @readlist = keys %{$hash->{READINGS}}; return HMCCU_SetState ($hash, "OK");
foreach my $rd (@readlist) {
delete ($hash->{READINGS}{$rd}) if ($rd ne 'state' && $rd ne 'control' && $rd =~ /$rnexp/);
}
} }
elsif ($opt eq 'config') { elsif ($opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name config [device] {parameter}={value} [...]") return HMCCU_SetError ($hash, "Usage: set $name config [device] {parameter}={value} [...]")
@ -460,7 +457,8 @@ sub HMCCUCHN_Get ($@)
my $name = shift @$a; my $name = shift @$a;
my $opt = shift @$a; my $opt = shift @$a;
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev})); return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
my $disable = AttrVal ($name, "disable", 0); my $disable = AttrVal ($name, "disable", 0);
return undef if ($disable == 1); return undef if ($disable == 1);
@ -794,16 +792,33 @@ sub HMCCUCHN_Get ($@)
If set to 1 values read from CCU will be stored as readings. Default is 1. If set to 1 values read from CCU will be stored as readings. Default is 1.
</li><br/> </li><br/>
<li><b>ccureadingfilter &lt;filter-rule[;...]&gt;</b><br/> <li><b>ccureadingfilter &lt;filter-rule[;...]&gt;</b><br/>
Only datapoints matching specified expression are stored as readings.<br/> Only datapoints matching specified expression <i>RegExp</i> are stored as readings.<br/>
Syntax for <i>filter-rule</i> is either:<br/> Syntax for <i>filter-rule</i> is either:<br/>
[N:]{&lt;channel-name&gt;|&lt;channel-number&gt;}!&lt;RegExp&gt; or:<br/> [N:]{&lt;channel-name&gt;}!RegExp&gt; or:<br/>
[N:][&lt;channel-number&gt;.]&lt;RegExp&gt;<br/> [N:][&lt;channel-number&gt;.]&lt;RegExp&gt;<br/>
If <i>channel-name</i> or <i>channel-number</i> is specified the following rule If <i>channel-name</i> or <i>channel-number</i> is specified the following rule
applies only to this channel. applies only to this channel.<br/>
By default all datapoints will be stored as readings. Attribute ccudef-readingfilter
of I/O device will be checked before this attribute.<br/>
If a rule starts with 'N:' the filter is negated which means that a reading is If a rule starts with 'N:' the filter is negated which means that a reading is
stored if rule doesn't match. stored if rule doesn't match.<br/>
The following table describes the dependencies between this attribute and attribute
ccudef-readingfilter in I/O device. The filtering of readings depends on which attribute
is set.<br/>
<table>
<tr><th>ccureadingfilter<br/>Device</th><th>ccudef-readingfilter<br/>I/O Device</th><th>Update Readings/Datapoints</th></tr>
<tr><td>not set</td><td>not set</td><td>all readings</td></tr>
<tr><td>not set</td><td>set</td><td>only readings from ccudef-readingfilter</td></tr>
<tr><td>set</td><td>not set</td><td>only readings from ccureadingfilter</td></tr>
<tr><td>set</td><td>set</td><td>both readings from ccureadingfilter and ccudef-readingfilter</td></tr>
</table>
So if ccudef-readingfilter is set in I/O device one must also set ccureadingfilter to
get updates for additional, device specific readings. Please keep in mind, that readings updates
are also affected by attributes event-on-change-reading and event-on-update-reading.<br/><br/>
Examples:<br/>
<code>
attr mydev ccureadingfilter .*<br/>
attr mydev ccureadingfilter 1.(^ACTUAL|CONTROL|^SET_TEMP);(^WINDOW_OPEN|^VALVE)<br/>
attr mydev ccureadingfilter MyBlindChannel!^LEVEL$<br/>
</code>
</li><br/> </li><br/>
<li><b>ccureadingformat {address[lc] | name[lc] | datapoint[lc]}</b><br/> <li><b>ccureadingformat {address[lc] | name[lc] | datapoint[lc]}</b><br/>
Set format of reading names. Default for virtual device groups is 'name'. The default for all Set format of reading names. Default for virtual device groups is 'name'. The default for all

View File

@ -4,9 +4,9 @@
# #
# $Id$ # $Id$
# #
# Version 4.3.006 # Version 4.3.008
# #
# (c) 2018 zap (zap01 <at> t-online <dot> de) # (c) 2019 zap (zap01 <at> t-online <dot> de)
# #
###################################################################### ######################################################################
# Client device for Homematic devices. # Client device for Homematic devices.
@ -239,7 +239,6 @@ sub HMCCUDEV_InitDevice ($$)
# Group specified by CCU virtual group name # Group specified by CCU virtual group name
@devlist = HMCCU_GetGroupMembers ($hmccu_hash, $gdname); @devlist = HMCCU_GetGroupMembers ($hmccu_hash, $gdname);
$gdcount = scalar (@devlist); $gdcount = scalar (@devlist);
return 5 if ($gdcount == 0);
} }
return 3 if ($gdcount == 0); return 3 if ($gdcount == 0);
@ -345,8 +344,8 @@ sub HMCCUDEV_Set ($@)
my $rocmds = "clear config defaults:noArg"; my $rocmds = "clear config defaults:noArg";
# Get I/O device, check device state # Get I/O device, check device state
return HMCCU_SetError ($hash, -19) if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending'); return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev})); !defined ($hash->{IODev}));
my $hmccu_hash = $hash->{IODev}; my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME}; my $hmccu_name = $hmccu_hash->{NAME};
@ -580,11 +579,8 @@ sub HMCCUDEV_Set ($@)
} }
elsif ($opt eq 'clear') { elsif ($opt eq 'clear') {
my $rnexp = shift @$a; my $rnexp = shift @$a;
$rnexp = '.*' if (!defined ($rnexp)); HMCCU_DeleteReadings ($hash, $rnexp);
my @readlist = keys %{$hash->{READINGS}}; return HMCCU_SetState ($hash, "OK");
foreach my $rd (@readlist) {
delete ($hash->{READINGS}{$rd}) if ($rd ne 'state' && $rd ne 'control' && $rd =~ /$rnexp/);
}
} }
elsif ($opt eq 'config') { elsif ($opt eq 'config') {
return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]") return HMCCU_SetError ($hash, "Usage: set $name config [{channel-number}] {parameter}={value} [...]")
@ -645,7 +641,8 @@ sub HMCCUDEV_Get ($@)
my $opt = shift @$a; my $opt = shift @$a;
# Get I/O device # Get I/O device
return HMCCU_SetError ($hash, -3) if (!defined ($hash->{IODev})); return undef if (!defined ($hash->{ccudevstate}) || $hash->{ccudevstate} eq 'pending' ||
!defined ($hash->{IODev}));
my $hmccu_hash = $hash->{IODev}; my $hmccu_hash = $hash->{IODev};
my $hmccu_name = $hmccu_hash->{NAME}; my $hmccu_name = $hmccu_hash->{NAME};

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 1.5 # Version 1.6
# #
# Subprocess based RPC Server module for HMCCU. # Subprocess based RPC Server module for HMCCU.
# #
@ -35,7 +35,7 @@ use SetExtensions;
###################################################################### ######################################################################
# HMCCURPC version # HMCCURPC version
my $HMCCURPCPROC_VERSION = '1.5'; my $HMCCURPCPROC_VERSION = '1.6';
# Maximum number of events processed per call of Read() # Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100; my $HMCCURPCPROC_MAX_EVENTS = 100;
@ -107,6 +107,7 @@ sub HMCCURPCPROC_Initialize ($);
sub HMCCURPCPROC_Define ($$); sub HMCCURPCPROC_Define ($$);
sub HMCCURPCPROC_InitDevice ($$); sub HMCCURPCPROC_InitDevice ($$);
sub HMCCURPCPROC_Undef ($$); sub HMCCURPCPROC_Undef ($$);
sub HMCCURPCPROC_DelayedShutdown ($);
sub HMCCURPCPROC_Shutdown ($); sub HMCCURPCPROC_Shutdown ($);
sub HMCCURPCPROC_Attr ($@); sub HMCCURPCPROC_Attr ($@);
sub HMCCURPCPROC_Set ($@); sub HMCCURPCPROC_Set ($@);
@ -134,7 +135,7 @@ sub HMCCURPCPROC_RPCServerStopped ($);
sub HMCCURPCPROC_SendRequest ($@); sub HMCCURPCPROC_SendRequest ($@);
sub HMCCURPCPROC_SetRPCState ($$$$); sub HMCCURPCPROC_SetRPCState ($$$$);
sub HMCCURPCPROC_StartRPCServer ($); sub HMCCURPCPROC_StartRPCServer ($);
sub HMCCURPCPROC_StopRPCServer ($); sub HMCCURPCPROC_StopRPCServer ($$);
sub HMCCURPCPROC_TerminateProcess ($); sub HMCCURPCPROC_TerminateProcess ($);
# Helper functions # Helper functions
@ -197,6 +198,7 @@ sub HMCCURPCPROC_Initialize ($)
$hash->{ReadFn} = "HMCCURPCPROC_Read"; $hash->{ReadFn} = "HMCCURPCPROC_Read";
$hash->{AttrFn} = "HMCCURPCPROC_Attr"; $hash->{AttrFn} = "HMCCURPCPROC_Attr";
$hash->{ShutdownFn} = "HMCCURPCPROC_Shutdown"; $hash->{ShutdownFn} = "HMCCURPCPROC_Shutdown";
$hash->{DelayedShutdownFn} = "HMCCURPCPROC_DelayedShutdown";
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
@ -231,17 +233,32 @@ sub HMCCURPCPROC_Define ($$)
$hmccu_hash = $defs{$ioname}; $hmccu_hash = $defs{$ioname};
if (scalar (@$a) < 4) { if (scalar (@$a) < 4) {
$hash->{host} = $hmccu_hash->{host}; $hash->{host} = $hmccu_hash->{host};
$hash->{prot} = $hmccu_hash->{prot};
$iface = $$a[2]; $iface = $$a[2];
} }
else { else {
$hash->{host} = $$a[2]; if ($$a[2] =~ /^(https?):\/\/(.+)/) {
$hash->{prot} = $1;
$hash->{host} = $2;
}
else {
$hash->{prot} = 'http';
$hash->{host} = $$a[2];
}
$iface = $$a[3]; $iface = $$a[3];
} }
$rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A'); $rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A');
} }
else { else {
return $usage if (scalar (@$a) < 4); return $usage if (scalar (@$a) < 4);
$hash->{host} = $$a[2]; if ($$a[2] =~ /^(https?):\/\/(.+)/) {
$hash->{prot} = $1;
$hash->{host} = $2;
}
else {
$hash->{prot} = 'http';
$hash->{host} = $$a[2];
}
$iface = $$a[3]; $iface = $$a[3];
$rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A'); $rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A');
@ -250,11 +267,7 @@ sub HMCCURPCPROC_Define ($$)
my $dh = $defs{$d}; my $dh = $defs{$d};
next if (!exists ($dh->{TYPE}) || !exists ($dh->{NAME})); next if (!exists ($dh->{TYPE}) || !exists ($dh->{NAME}));
next if ($dh->{TYPE} ne 'HMCCU'); next if ($dh->{TYPE} ne 'HMCCU');
if ($dh->{ccuip} eq $rpcip) {
# The following call will fail during FHEM start if CCU is not ready
my $ifhost = HMCCU_GetRPCServerInfo ($dh, $iface, 'host');
next if (!defined ($ifhost));
if ($dh->{host} eq $hash->{host} || $ifhost eq $hash->{host} || $ifhost eq $rpcip) {
$hmccu_hash = $dh; $hmccu_hash = $dh;
last; last;
} }
@ -338,9 +351,10 @@ sub HMCCURPCPROC_InitDevice ($$) {
# Get unique ID for RPC server: last 2 segments of local IP address # Get unique ID for RPC server: last 2 segments of local IP address
# Do not append random digits because of https://forum.fhem.de/index.php/topic,83544.msg797146.html#msg797146 # Do not append random digits because of https://forum.fhem.de/index.php/topic,83544.msg797146.html#msg797146
my @ipseg = split (/\./, $dev_hash->{hmccu}{localaddr}); my $id1 = HMCCU_GetIdFromIP ($dev_hash->{hmccu}{localaddr}, '');
return 3 if (scalar (@ipseg) != 4); my $id2 = HMCCU_GetIdFromIP ($hmccu_hash->{ccuip}, '');
$dev_hash->{rpcid} = sprintf ("%03d%03d", $ipseg[2], $ipseg[3]); return 3 if ($id1 eq '' || $id2 eq '');
$dev_hash->{rpcid} = $id1.$id2;
# Set I/O device and store reference for RPC device in I/O device # Set I/O device and store reference for RPC device in I/O device
my $ioname = $hmccu_hash->{NAME}; my $ioname = $hmccu_hash->{NAME};
@ -380,10 +394,11 @@ sub HMCCURPCPROC_Undef ($$)
my $ifname = $hash->{rpcinterface}; my $ifname = $hash->{rpcinterface};
# Shutdown RPC server # Shutdown RPC server
HMCCURPCPROC_Shutdown ($hash); HMCCURPCPROC_StopRPCServer ($hash, $HMCCURPCPROC_INIT_INTERVAL2);
# Delete RPC device name in I/O device # Delete RPC device name in I/O device
if (exists ($hmccu_hash->{hmccu}{interfaces}{$ifname}{device}) && if (exists ($hmccu_hash->{hmccu}{interfaces}{$ifname}) &&
exists ($hmccu_hash->{hmccu}{interfaces}{$ifname}{device}) &&
$hmccu_hash->{hmccu}{interfaces}{$ifname}{device} eq $name) { $hmccu_hash->{hmccu}{interfaces}{$ifname}{device} eq $name) {
delete $hmccu_hash->{hmccu}{interfaces}{$ifname}{device}; delete $hmccu_hash->{hmccu}{interfaces}{$ifname}{device};
} }
@ -391,6 +406,30 @@ sub HMCCURPCPROC_Undef ($$)
return undef; return undef;
} }
######################################################################
# Delayed shutdown FHEM
######################################################################
sub HMCCURPCPROC_DelayedShutdown ($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $delay = max (AttrVal ("global", "maxShutdownDelay", 10)-2, 0);
# Shutdown RPC server
if (!exists ($hash->{hmccu}{delayedShutdown})) {
$hash->{hmccu}{delayedShutdown} = 1;
Log3 $name, 1, "HMCCURPCPROC: [$name] Graceful shutdown";
HMCCURPCPROC_StopRPCServer ($hash, $delay);
}
else {
Log3 $name, 1, "HMCCURPCPROC: [$name] Shutdown already in progress";
}
return 1;
}
###################################################################### ######################################################################
# Shutdown FHEM # Shutdown FHEM
###################################################################### ######################################################################
@ -398,9 +437,15 @@ sub HMCCURPCPROC_Undef ($$)
sub HMCCURPCPROC_Shutdown ($) sub HMCCURPCPROC_Shutdown ($)
{ {
my ($hash) = @_; my ($hash) = @_;
my $name = $hash->{NAME};
# Shutdown RPC server # Shutdown RPC server
HMCCURPCPROC_StopRPCServer ($hash); if (!exists ($hash->{hmccu}{delayedShutdown})) {
Log3 $name, 1, "HMCCURPCPROC: [$name] Immediate shutdown";
HMCCURPCPROC_StopRPCServer ($hash, 0);
}
# Remove all internal timers
RemoveInternalTimer ($hash); RemoveInternalTimer ($hash);
return undef; return undef;
@ -511,7 +556,7 @@ sub HMCCURPCPROC_Set ($@)
} }
elsif ($action eq 'off') { elsif ($action eq 'off') {
$hmccu_hash->{hmccu}{interfaces}{$hash->{rpcinterface}}{manager} = 'HMCCURPCPROC'; $hmccu_hash->{hmccu}{interfaces}{$hash->{rpcinterface}}{manager} = 'HMCCURPCPROC';
HMCCURPCPROC_StopRPCServer ($hash); HMCCURPCPROC_StopRPCServer ($hash, $HMCCURPCPROC_INIT_INTERVAL2);
} }
return undef; return undef;
@ -565,7 +610,11 @@ sub HMCCURPCPROC_Get ($@)
$result .= "--------------------------\n"; $result .= "--------------------------\n";
my $sid = defined ($hash->{hmccu}{rpc}{pid}) ? sprintf ("%5d", $hash->{hmccu}{rpc}{pid}) : "N/A "; my $sid = defined ($hash->{hmccu}{rpc}{pid}) ? sprintf ("%5d", $hash->{hmccu}{rpc}{pid}) : "N/A ";
my $sname = sprintf ("%-10s", $clkey); my $sname = sprintf ("%-10s", $clkey);
$result .= $sid." ".$sname." ".$hash->{hmccu}{rpc}{state}."\n"; my $cbport = defined ($hash->{hmccu}{rpc}{cbport}) ? $hash->{hmccu}{rpc}{cbport} : "N/A";
my $addr = defined ($hash->{hmccu}{localaddr}) ? $hash->{hmccu}{localaddr} : "N/A";
$result .= $sid." ".$sname." ".$hash->{hmccu}{rpc}{state}."\n\n";
$result .= "Local address = $addr\n";
$result .= "Callback port = $cbport\n";
return $result; return $result;
} }
else { else {
@ -760,7 +809,8 @@ sub HMCCURPCPROC_IsRPCStateBlocking ($)
{ {
my ($hash) = @_; my ($hash) = @_;
return ($hash->{RPCState} eq "running" || $hash->{RPCState} eq "inactive") ? 0 : 1; return (exists ($hash->{RPCState}) &&
($hash->{RPCState} eq "running" || $hash->{RPCState} eq "inactive")) ? 0 : 1;
} }
###################################################################### ######################################################################
@ -950,7 +1000,7 @@ sub HMCCURPCPROC_ProcessEvent ($$)
# Input: TO|clkey|DiffTime # Input: TO|clkey|DiffTime
# Output: TO, clkey, Port, DiffTime # Output: TO, clkey, Port, DiffTime
# #
if ($evttimeout > 0 && $t[0] > $evttimeout) { if ($evttimeout > 0) {
Log3 $name, 2, "HMCCURPCPROC: [$name] Received no events from interface $clkey for ".$t[0]." seconds"; Log3 $name, 2, "HMCCURPCPROC: [$name] Received no events from interface $clkey for ".$t[0]." seconds";
$hash->{ccustate} = 'timeout'; $hash->{ccustate} = 'timeout';
if ($hash->{RPCState} eq 'running' && $hash->{rpcport} == $defPort) { if ($hash->{RPCState} eq 'running' && $hash->{rpcport} == $defPort) {
@ -1021,7 +1071,8 @@ sub HMCCURPCPROC_RegisterCallback ($$)
} }
my $cburl = HMCCU_GetRPCCallbackURL ($hmccu_hash, $localaddr, $hash->{hmccu}{rpc}{cbport}, $clkey, $port); my $cburl = HMCCU_GetRPCCallbackURL ($hmccu_hash, $localaddr, $hash->{hmccu}{rpc}{cbport}, $clkey, $port);
my $clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url'); # my $clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url');
my $clurl = HMCCU_BuildURL ($hmccu_hash, $port);
my $rpctype = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'type'); my $rpctype = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'type');
return (0, "Can't get RPC parameters for ID $clkey") if (!defined ($cburl) || !defined ($clurl) || !defined ($rpctype)); return (0, "Can't get RPC parameters for ID $clkey") if (!defined ($cburl) || !defined ($clurl) || !defined ($rpctype));
@ -1069,7 +1120,8 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
$cburl = $rpchash->{cburl} if (exists ($rpchash->{cburl})); $cburl = $rpchash->{cburl} if (exists ($rpchash->{cburl}));
$clurl = $rpchash->{clurl} if (exists ($rpchash->{clurl})); $clurl = $rpchash->{clurl} if (exists ($rpchash->{clurl}));
$cburl = HMCCU_GetRPCCallbackURL ($hmccu_hash, $localaddr, $rpchash->{cbport}, $clkey, $port) if ($cburl eq ''); $cburl = HMCCU_GetRPCCallbackURL ($hmccu_hash, $localaddr, $rpchash->{cbport}, $clkey, $port) if ($cburl eq '');
$clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url') if ($clurl eq ''); # $clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url') if ($clurl eq '');
$clurl = HMCCU_BuildURL ($hmccu_hash, $port) if ($clurl eq '');
return (0, "Can't get RPC parameters for ID $clkey") if ($cburl eq '' || $clurl eq ''); return (0, "Can't get RPC parameters for ID $clkey") if ($cburl eq '' || $clurl eq '');
Log3 $name, 1, "HMCCURPCPROC: [$name] Deregistering RPC server $cburl with ID $clkey at $clurl"; Log3 $name, 1, "HMCCURPCPROC: [$name] Deregistering RPC server $cburl with ID $clkey at $clurl";
@ -1378,6 +1430,9 @@ sub HMCCURPCPROC_RPCServerStopped ($)
RemoveInternalTimer ($hash); RemoveInternalTimer ($hash);
DoTrigger ($name, "RPC server $clkey stopped"); DoTrigger ($name, "RPC server $clkey stopped");
# Inform FHEM that instance can be shut down
CancelDelayedShutdown ($name) if (exists ($hash->{hmccu}{delayedShutdown}));
} }
###################################################################### ######################################################################
@ -1535,14 +1590,17 @@ sub HMCCURPCPROC_Housekeeping ($)
###################################################################### ######################################################################
# Stop RPC server processes. # Stop RPC server processes.
# If function is called by Shutdown, parameter wait must be 0
###################################################################### ######################################################################
sub HMCCURPCPROC_StopRPCServer ($) sub HMCCURPCPROC_StopRPCServer ($$)
{ {
my ($hash) = @_; my ($hash, $wait) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $clkey = 'CB'.$hash->{rpcport}.$hash->{rpcid}; my $clkey = 'CB'.$hash->{rpcport}.$hash->{rpcid};
$wait = $HMCCURPCPROC_INIT_INTERVAL2 if (!defined ($wait));
if (HMCCURPCPROC_CheckProcessState ($hash, 'running')) { if (HMCCURPCPROC_CheckProcessState ($hash, 'running')) {
Log3 $name, 1, "HMCCURPCPROC: [$name] Stopping RPC server $clkey"; Log3 $name, 1, "HMCCURPCPROC: [$name] Stopping RPC server $clkey";
HMCCURPCPROC_SetState ($hash, "busy"); HMCCURPCPROC_SetState ($hash, "busy");
@ -1556,8 +1614,14 @@ sub HMCCURPCPROC_StopRPCServer ($)
# Trigger timer function for checking successful RPC stop # Trigger timer function for checking successful RPC stop
# Timer will be removed wenn receiving EX event from RPC server process # Timer will be removed wenn receiving EX event from RPC server process
InternalTimer (gettimeofday()+$HMCCURPCPROC_INIT_INTERVAL2, "HMCCURPCPROC_Housekeeping", if ($wait > 0) {
$hash, 0); Log3 $name, 2, "HMCCURPCPROC: [$name] Scheduling cleanup in $wait seconds";
InternalTimer (gettimeofday()+$wait, "HMCCURPCPROC_Housekeeping", $hash, 0);
}
else {
Log3 $name, 2, "HMCCURPCPROC: [$name] Cleaning up immediately";
HMCCURPCPROC_Housekeeping ($hash);
}
# Give process the chance to terminate # Give process the chance to terminate
sleep (1); sleep (1);
@ -1587,12 +1651,14 @@ sub HMCCURPCPROC_SendRequest ($@)
if (HMCCU_IsRPCType ($hmccu_hash, $port, 'A')) { if (HMCCU_IsRPCType ($hmccu_hash, $port, 'A')) {
# Use XMLRPC # Use XMLRPC
my $clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url'); # my $clurl = HMCCU_GetRPCServerInfo ($hmccu_hash, $port, 'url');
my $clurl = HMCCU_BuildURL ($hmccu_hash, $port);
return HMCCU_Log ($hash, 2, "Can't get client URL for port $port", undef) return HMCCU_Log ($hash, 2, "Can't get client URL for port $port", undef)
if (!defined ($clurl)); if (!defined ($clurl));
Log3 $name, 4, "HMCCURPCPROC: [$name] Send ASCII RPC request $request to $clurl"; Log3 $name, 4, "HMCCURPCPROC: [$name] Send ASCII RPC request $request to $clurl";
my $rpcclient = RPC::XML::Client->new ($clurl); my $rpcclient = RPC::XML::Client->new ($clurl, useragent => [
ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 } ]);
$rc = $rpcclient->simple_request ($request, @param); $rc = $rpcclient->simple_request ($request, @param);
Log3 $name, 2, "HMCCURPCPROC: [$name] RPC request error ".$RPC::XML::ERROR if (!defined ($rc)); Log3 $name, 2, "HMCCURPCPROC: [$name] RPC request error ".$RPC::XML::ERROR if (!defined ($rc));
} }

View File

@ -4,19 +4,11 @@
# #
# $Id$ # $Id$
# #
# Version 4.5 # Version 4.6
# #
# Configuration parameters for HomeMatic devices. # Configuration parameters for HomeMatic devices.
# #
# (c) 2018 by zap (zap01 <at> t-online <dot> de) # (c) 2019 by zap (zap01 <at> t-online <dot> de)
#
# Datapoints LOWBAT, LOW_BAT, UNREACH, ERROR.*, SABOTAGE and FAULT.*
# must not be specified in attribute ccureadingfilter. They are always
# stored as readings.
# Datapoints LOWBAT, LOW_BAT and UNREACH must not be specified in
# attribute substitute because they are substituted by default.
# See also documentation of attributes ccudef-readingname and
# ccudef-substitute in module HMCCU.
# #
######################################################################### #########################################################################
@ -554,7 +546,7 @@ use vars qw(%HMCCU_SCRIPTS);
}, },
"HMIP-PSM" => { "HMIP-PSM" => {
_description => "Steckdose mit Energiemessung IP", _description => "Steckdose mit Energiemessung IP",
ccureadingfilter => "(STATE|CURRENT|^ENERGY_COUNTER\$|POWER)", ccureadingfilter => "3.STATE;6.(CURRENT|^ENERGY_COUNTER\$|POWER)",
controldatapoint => "3.STATE", controldatapoint => "3.STATE",
statedatapoint => "3.STATE", statedatapoint => "3.STATE",
statevals => "on:true,off:false", statevals => "on:true,off:false",
@ -1473,21 +1465,17 @@ if(oTmpArray) {
object oTmp = dom.GetObject(sTmp); object oTmp = dom.GetObject(sTmp);
if (oTmp) { if (oTmp) {
if(oTmp.IsTypeOf(OT_ALARMDP) && (oTmp.AlState() == asOncoming)) { if(oTmp.IsTypeOf(OT_ALARMDP) && (oTmp.AlState() == asOncoming)) {
boolean collect = true;
object trigDP = dom.GetObject(oTmp.AlTriggerDP()); object trigDP = dom.GetObject(oTmp.AlTriggerDP());
object och = dom.GetObject((trigDP.Channel())); object och = dom.GetObject((trigDP.Channel()));
object odev = dom.GetObject((och.Device())); object odev = dom.GetObject((och.Device()));
var ival = trigDP.Value(); var ival = trigDP.Value();
time sftime = oTmp.AlOccurrenceTime(); time sftime = oTmp.AlOccurrenceTime(); ! erste Meldezeit
time sltime = oTmp.LastTriggerTime(); time sltime = oTmp.LastTriggerTime();!letze Meldezeit
var sdesc = trigDP.HSSID(); var sdesc = trigDP.HssType();
var sserial = odev.Address(); var sserial = odev.Address();
string sAlarmMessage = web.webKeyFromStringTable(sdesc.Name()); var sname = odev.Name();
if(!sAlarmMessage.Length()) { WriteLine(sftime.Format("%d.%m.%y %H:%M") # ";" # sltime.Format("%d.%m.%y %H:%M") # ";" # sserial # ";" # sname # ";" # sdesc);
sAlarmMessage = sdesc;
}
c = c+1; c = c+1;
WriteLine(sftime # ";" # sltime # ";" # sAlarmMessage # ";" # sserial);
} }
} }
} }