2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-04 05:16:45 +00:00

HMCCU: Fix for events with unknown RPC ID

git-svn-id: https://svn.fhem.de/fhem/trunk@16664 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2018-04-27 10:58:36 +00:00
parent 69f645b96e
commit 269f3efe9a
2 changed files with 94 additions and 56 deletions

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 4.2.005
# Version 4.2.006
#
# Module for communication between FHEM and Homematic CCU2.
#
@ -105,7 +105,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '4.2.005';
my $HMCCU_VERSION = '4.2.006';
# Default RPC port (BidCos-RF)
my $HMCCU_RPC_PORT_DEFAULT = 2001;
@ -326,6 +326,7 @@ sub HMCCU_ExprNotMatch ($$$);
sub HMCCU_GetDutyCycle ($);
sub HMCCU_TCPPing ($$$);
sub HMCCU_TCPConnect ($$);
sub HMCCU_ResolveName ($$);
sub HMCCU_CorrectName ($);
# Subprocess functions
@ -397,12 +398,7 @@ sub HMCCU_Define ($$)
}
# Get CCU IP address
$hash->{ccuip} = 'N/A';
my $ccuname = inet_aton ($hash->{host});
if (defined ($ccuname)) {
my $ccuip = inet_ntoa ($ccuname);
$hash->{ccuip} = $ccuip if (defined ($ccuip));
}
$hash->{ccuip} = HMCCU_ResolveName ($hash->{host}, 'N/A');
# Get CCU number (if more than one)
if (scalar (@$a) >= 4) {
@ -4483,6 +4479,7 @@ sub HMCCU_GetRPCDevice ($$$)
my $name = $hash->{NAME};
my $rpcdevname;
my $rpcdevtype = 'HMCCURPC';
my $rpchost = $hash->{host};
my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
@ -4490,7 +4487,8 @@ sub HMCCU_GetRPCDevice ($$$)
return (HMCCU_Log ($hash, 1, "Interface not defined for RPC server of type HMCCURPCPROC", ''), 0)
if (!defined ($ifname));
$rpcdevname = HMCCU_GetRPCServerInfo ($hash, $ifname, 'device');
return ($rpcdevname, 0) if (defined ($rpcdevname));
$rpchost = HMCCU_GetRPCServerInfo ($hash, $ifname, 'host');
return ($rpcdevname, 0) if (defined ($rpcdevname) || !defined ($rpchost));
$rpcdevtype = 'HMCCURPCPROC';
}
elsif ($ccuflags =~ /extrpc/) {
@ -4514,7 +4512,11 @@ sub HMCCU_GetRPCDevice ($$$)
my @devlist;
foreach my $dev (keys %defs) {
my $devhash = $defs{$dev};
next if ($devhash->{TYPE} ne $rpcdevtype || $devhash->{host} ne $hash->{host});
next if ($devhash->{TYPE} ne $rpcdevtype);
my $ip = 'null';
my $addrnum = inet_aton ($devhash->{host});
$ip = inet_ntoa ($addrnum) if (defined ($addrnum));
next if ($devhash->{host} ne $rpchost && $ip ne $rpchost);
next if ($rpcdevtype eq 'HMCCURPCPROC' && $devhash->{rpcinterface} ne $ifname);
push @devlist, $devhash->{NAME};
}
@ -4542,13 +4544,13 @@ sub HMCCU_GetRPCDevice ($$$)
if (defined ($ifname)) {
$rpcdevname = makeDeviceName ("d_rpc".$ifname);
$alias .= " $ifname";
$rpccreate = "$rpcdevname $rpcdevtype ".$hash->{host}. " $ifname";
$rpccreate = "$rpcdevname $rpcdevtype $rpchost $ifname";
}
HMCCU_Log ($hash, 1, "Creating new RPC device $rpcdevname", undef);
my $ret = CommandDefine (undef, $rpccreate);
if (!defined ($ret)) {
# HMCCURPC device created. Set/copy some attributes from HMCCU device
# RPC device created. Set/copy some attributes from HMCCU device
my %rpcdevattr = ('room' => 'copy', 'group' => 'copy', 'icon' => 'copy',
'stateFormat' => 'rpcstate/state', 'eventMap' => '/rpcserver on:on/rpcserver off:off/',
'verbose' => 2, 'alias' => $alias );
@ -6506,6 +6508,22 @@ sub HMCCU_TCPConnect ($$)
return 0;
}
######################################################################
# Resolve hostname.
# Return value defip if hostname can't be resolved.
######################################################################
sub HMCCU_ResolveName ($$)
{
my ($hname, $defip) = @_;
my $ip = $defip;
my $addrnum = inet_aton ($hname);
$ip = inet_ntoa ($addrnum) if (defined ($addrnum));
return $ip;
}
######################################################################
# Substitute invalid characters in reading name.
# Substitution rules: ':' => '.', any other illegal character => '_'

View File

@ -4,7 +4,7 @@
#
# $Id$
#
# Version 1.0.003
# Version 1.0.004
#
# Subprocess based RPC Server module for HMCCU.
#
@ -35,7 +35,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
my $HMCCURPCPROC_VERSION = '1.0.003';
my $HMCCURPCPROC_VERSION = '1.0.004';
# Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100;
@ -214,33 +214,47 @@ sub HMCCURPCPROC_Define ($$)
my ($hash, $a, $h) = @_;
my $name = $hash->{NAME};
my $hmccu_hash;
my $ioname = '';
my $rpcip = '';
my $iface;
my $usage = "Usage: define $name HMCCURPCPROC { CCUHost | iodev=Name } { RPCPort | RPCInterface }";
my $usage = "Usage: define $name HMCCURPCPROC { CCUHost } { RPCPort | RPCInterface } [iodev={device}]";
if (exists ($h->{iodev})) {
my $ioname = $h->{iodev};
$ioname = $h->{iodev};
return $usage if (scalar (@$a) < 3);
return "HMCCU I/O device $ioname not found" if (!exists ($defs{$ioname}));
return "Device $ioname is not a HMCCU device" if ($defs{$ioname}->{TYPE} ne 'HMCCU');
$hmccu_hash = $defs{$ioname};
if (scalar (@$a) < 4) {
$hash->{host} = $hmccu_hash->{host};
$iface = $$a[2];
}
else {
$hash->{host} = $$a[2];
$iface = $$a[3];
}
$rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A');
}
else {
return $usage if (scalar (@$a) < 4);
$hash->{host} = $$a[2];
$iface = $$a[3];
$rpcip = HMCCU_ResolveName ($hash->{host}, 'N/A');
# Find IO device
for my $d (keys %defs) {
my $dh = $defs{$d};
next if (!exists ($dh->{TYPE}) || !exists ($dh->{NAME}));
if ($dh->{TYPE} eq 'HMCCU' && $dh->{host} eq $hash->{host}) {
next if ($dh->{TYPE} ne 'HMCCU');
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;
last;
}
}
return "Can't find HMCCU I/O device" if (!defined ($hmccu_hash));
$ioname = $hmccu_hash->{NAME};
}
# Check if interface is valid
@ -258,11 +272,25 @@ sub HMCCURPCPROC_Define ($$)
}
}
# Detect local IP address and check if CCU is reachable
my $socket = IO::Socket::INET->new (PeerAddr => $hash->{host}, PeerPort => $ifport);
return (0, "Can't connect to CCU ".$hash->{host}." port $ifport") if (!$socket);
$hash->{hmccu}{localaddr} = $socket->sockhost ();
close ($socket);
# 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
my @ipseg = split (/\./, $hash->{hmccu}{localaddr});
return (0, "Invalid local IP address ".$hash->{hmccu}{localaddr}) if (scalar (@ipseg) != 4);
# my $base = (time() % 10)+1;
$hash->{rpcid} = sprintf ("%03d%03d", $ipseg[2], $ipseg[3]); # . join '', map int rand ($base), 1..2;
# Set I/O device and store reference for RPC device in I/O device
AssignIoPort ($hash, $hmccu_hash->{NAME});
$hmccu_hash->{hmccu}{interfaces}{$ifname}{device} = $name;
# Store internals
$hash->{rpcip} = $rpcip;
$hash->{rpcport} = $ifport;
$hash->{rpcinterface} = $ifname;
$hash->{ccuip} = $hmccu_hash->{ccuip};
@ -271,7 +299,7 @@ sub HMCCURPCPROC_Define ($$)
$hash->{ccustate} = $hmccu_hash->{ccustate};
$hash->{version} = $HMCCURPCPROC_VERSION;
Log3 $name, 1, "HMCCURPCPROC: [$name] Initialized version $HMCCURPCPROC_VERSION for interface $ifname";
Log3 $name, 1, "HMCCURPCPROC: [$name] Initialized version $HMCCURPCPROC_VERSION for interface $ifname with I/O device $ioname";
# Set some attributes
$attr{$name}{stateFormat} = "rpcstate/state";
@ -692,7 +720,7 @@ sub HMCCURPCPROC_ProcessEvent ($$)
# Check for valid server
if ($clkey ne $rpcname) {
Log3 $name, 0, "HMCCURPCPROC: [$name] Received SL event for unknown RPC server $clkey";
Log3 $name, 2, "HMCCURPCPROC: [$name] Received $et event for unknown RPC server $clkey";
return undef;
}
@ -951,6 +979,9 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
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";
# Deregister up to 2 times
for (my $i=0; $i<2; $i++) {
my $rc;
if (HMCCU_IsRPCType ($hmccu_hash, $port, 'A')) {
$rc = HMCCURPCPROC_SendRequest ($hash, "init", $cburl);
@ -969,9 +1000,9 @@ sub HMCCURPCPROC_DeRegisterCallback ($$)
return (1, 'working');
}
else {
return (0, "Failed to deregister RPC server $clkey");
}
return (0, "Failed to deregister RPC server $clkey");
}
######################################################################
@ -1084,33 +1115,22 @@ sub HMCCURPCPROC_StartRPCServer ($)
my $name = $hash->{NAME};
my $hmccu_hash = $hash->{IODev};
# Local IP address and callback ID should be set during device definition
return (0, "Local address and/or callback ID not defined")
if (!exists ($hash->{hmccu}{localaddr}) || !exists ($hash->{rpcid}));
# Check if RPC server is already running
return (0, "RPC server already running") if (HMCCURPCPROC_CheckProcessState ($hash, 'running'));
# Get parameters and attributes
my %procpar;
my $localaddr = HMCCURPCPROC_GetAttribute ($hash, 'rpcServerAddr', 'rpcserveraddr', '');
my $localaddr = HMCCURPCPROC_GetAttribute ($hash, 'rpcServerAddr', 'rpcserveraddr', $hash->{hmccu}{localaddr});
my $rpcserverport = HMCCURPCPROC_GetAttribute ($hash, 'rpcServerPort', 'rpcserverport', $HMCCURPCPROC_SERVER_PORT);
my $evttimeout = HMCCURPCPROC_GetAttribute ($hash, 'rpcEventTimeout', 'rpcevtimeout', $HMCCURPCPROC_TIMEOUT_EVENT);
my $ccunum = $hash->{CCUNum};
my $rpcport = $hash->{rpcport};
my $serveraddr = HMCCU_GetRPCServerInfo ($hmccu_hash, $rpcport, 'host');
my $interface = HMCCU_GetRPCServerInfo ($hmccu_hash, $rpcport, 'name');
# Detect local IP address
if ($localaddr eq '') {
my $socket = IO::Socket::INET->new (PeerAddr => $serveraddr, PeerPort => $rpcport);
return (0, "Can't connect to CCU port $rpcport") if (!$socket);
$localaddr = $socket->sockhost ();
close ($socket);
}
$hash->{hmccu}{localaddr} = $localaddr;
# Get unique ID for RPC server: last segment of local IP address followed by 2 random digits
my @ipseg = split (/\./, $localaddr);
return (0, "Invalid local IP address $localaddr") if (scalar (@ipseg) != 4);
my $base = (time() % 10)+1;
$hash->{rpcid} = sprintf ("%03d", $ipseg[3]) . join '', map int rand ($base), 1..2;
my $clkey = 'CB'.$rpcport.$hash->{rpcid};
# Store parameters for child process