mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-13 05:06:35 +00:00
HMCCU: Fixed update of virtual devices
git-svn-id: https://svn.fhem.de/fhem/trunk@13842 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
3e7a518628
commit
d7bc42ff58
@ -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.
|
||||||
|
- bugfix: 88_HMCCU: fixed bug in update of virtual devices
|
||||||
- feature: 70_BRAVIA: command remoteControl supports 'Netflix'
|
- feature: 70_BRAVIA: command remoteControl supports 'Netflix'
|
||||||
- feature: 50_TelegramBot: favorite handling / hidden favorites /
|
- feature: 50_TelegramBot: favorite handling / hidden favorites /
|
||||||
utf8Special for unicode issues /
|
utf8Special for unicode issues /
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Version 3.9.010
|
# Version 3.9.011
|
||||||
#
|
#
|
||||||
# Module for communication between FHEM and Homematic CCU2.
|
# Module for communication between FHEM and Homematic CCU2.
|
||||||
# Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels,
|
# Supports BidCos-RF, BidCos-Wired, HmIP-RF, virtual CCU channels,
|
||||||
@ -101,7 +101,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
|
|||||||
my %HMCCU_CUST_DEV_DEFAULTS;
|
my %HMCCU_CUST_DEV_DEFAULTS;
|
||||||
|
|
||||||
# HMCCU version
|
# HMCCU version
|
||||||
my $HMCCU_VERSION = '3.9.010';
|
my $HMCCU_VERSION = '3.9.011';
|
||||||
|
|
||||||
# RPC Ports and URL extensions
|
# RPC Ports and URL extensions
|
||||||
my %HMCCU_RPC_NUMPORT = (
|
my %HMCCU_RPC_NUMPORT = (
|
||||||
@ -2199,99 +2199,123 @@ sub HMCCU_UpdateSingleDevice ($$$)
|
|||||||
return 0 if ($clthash->{IODev} != $ccuhash);
|
return 0 if ($clthash->{IODev} != $ccuhash);
|
||||||
|
|
||||||
# Check for updated data
|
# Check for updated data
|
||||||
my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clthash->{ccuaddr});
|
my ($devaddr, $cnum) = HMCCU_SplitChnAddr ($clthash->{ccuaddr});
|
||||||
return 0 if (!exists ($objects->{$devaddr}));
|
# return 0 if (!exists ($objects->{$devaddr}));
|
||||||
return 0 if ($clttype eq 'HMCUCCHN' && !exists ($objects->{$devaddr}{$cnum}) &&
|
# return 0 if ($clttype eq 'HMCUCCHN' && !exists ($objects->{$devaddr}{$cnum}) &&
|
||||||
!exists ($objects->{$devaddr}{0}));
|
# !exists ($objects->{$devaddr}{0}));
|
||||||
|
|
||||||
# Get attributes of IO device
|
# Get attributes of IO device
|
||||||
my $ccuflags = AttrVal ($ccuname, 'ccuflags', 'null');
|
my $ccuflags = AttrVal ($ccuname, 'ccuflags', 'null');
|
||||||
|
|
||||||
# Get attributes of client device
|
# Get attributes of client device
|
||||||
my $cltflags = AttrVal ($cltname, 'ccuflags', 'null');
|
my $cltflags = AttrVal ($cltname, 'ccuflags', 'null');
|
||||||
my $disable = AttrVal ($cltname, 'disable', 0);
|
# my $disable = AttrVal ($cltname, 'disable', 0);
|
||||||
my $update = AttrVal ($cltname, 'ccureadings', 1);
|
# my $update = AttrVal ($cltname, 'ccureadings', 1);
|
||||||
return 0 if ($update == 0 || $disable == 1);
|
# return 0 if ($update == 0 || $disable == 1);
|
||||||
|
|
||||||
my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash);
|
# my $crf = HMCCU_GetAttrReadingFormat ($clthash, $ccuhash);
|
||||||
my $substitute = HMCCU_GetAttrSubstitute ($clthash, $ccuhash);
|
# my $substitute = HMCCU_GetAttrSubstitute ($clthash, $ccuhash);
|
||||||
my ($sc, $st, $cc, $cd) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
|
# my ($sc, $st, $cc, $cd) = HMCCU_GetSpecialDatapoints ($clthash, '', 'STATE', '', '');
|
||||||
|
|
||||||
# Build device list
|
# Build device list including virtual devices
|
||||||
my @devlist = ($devaddr);
|
my @grplist = ($cltname);
|
||||||
if ($clttype eq 'HMCCUDEV' && $clthash->{ccuif} eq "VirtualDevices" && exists ($clthash->{ccugroup})) {
|
my @virlist = HMCCU_FindClientDevices ($ccuhash, "HMCCUDEV", undef, "ccuif=VirtualDevices");
|
||||||
foreach my $gadd (split (",", $clthash->{ccugroup})) {
|
foreach my $vd (@virlist) {
|
||||||
my ($gd, $gc) = HMCCU_SplitChnAddr ($gadd);
|
my $vh = $defs{$vd};
|
||||||
push (@devlist, $gd);
|
next if (!defined ($vh->{ccugroup}));
|
||||||
|
foreach my $gadd (split (",", $vh->{ccugroup})) {
|
||||||
|
if ("$gadd" eq "$devaddr") {
|
||||||
|
push @grplist, $vd;
|
||||||
|
last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cltflags =~ /trace/) {
|
if ($cltflags =~ /trace/) {
|
||||||
Log3 $ccuname, 2, "HMCCU: $cltname Devlist = ".join(',', @devlist);
|
Log3 $ccuname, 2, "HMCCU: $cltname Devlist = ".join(',', @virlist);
|
||||||
Log3 $ccuname, 2, "HMCCU: $cltname Objects = ".join(',', keys %{$objects});
|
Log3 $ccuname, 2, "HMCCU: $cltname Objects = ".join(',', keys %{$objects});
|
||||||
}
|
}
|
||||||
|
|
||||||
# Store the resulting readings
|
# Store the resulting readings
|
||||||
my %results;
|
my %results;
|
||||||
|
|
||||||
# Update datapoint readings and control/state readings
|
|
||||||
readingsBeginUpdate ($clthash);
|
|
||||||
|
|
||||||
# Update device considering foreign device data assigned to group device
|
# Update device considering foreign device data assigned to group device
|
||||||
foreach my $dev (@devlist) {
|
foreach my $cn (@grplist) {
|
||||||
next if (!exists ($objects->{$dev}));
|
my $ch = $defs{$cn};
|
||||||
|
my $ct = $ch->{TYPE};
|
||||||
|
my $cf = AttrVal ($cn, 'ccuflags', 'null');
|
||||||
|
my $disable = AttrVal ($cn, 'disable', 0);
|
||||||
|
my $update = AttrVal ($cn, 'ccureadings', 1);
|
||||||
|
next if ($update == 0 || $disable == 1);
|
||||||
|
|
||||||
|
my $crf = HMCCU_GetAttrReadingFormat ($ch, $ccuhash);
|
||||||
|
my $substitute = HMCCU_GetAttrSubstitute ($ch, $ccuhash);
|
||||||
|
my ($sc, $st, $cc, $cd) = HMCCU_GetSpecialDatapoints ($ch, '', 'STATE', '', '');
|
||||||
|
|
||||||
|
my @devlist = ($ch->{ccuaddr});
|
||||||
|
push @devlist, split (",", $ch->{ccugroup})
|
||||||
|
if ($ch->{ccuif} eq 'VirtualDevices' && exists ($ch->{ccugroup}));
|
||||||
|
|
||||||
|
readingsBeginUpdate ($ch);
|
||||||
|
|
||||||
# Update channels of device
|
foreach my $dev (@devlist) {
|
||||||
foreach my $chnnum (keys (%{$objects->{$dev}})) {
|
my ($da, $cnum) = HMCCU_SplitChnAddr ($dev);
|
||||||
next if ($clttype eq 'HMCCUCHN' && "$chnnum" ne "$cnum" && "$chnnum" ne "0");
|
next if (!exists ($objects->{$da}));
|
||||||
next if ("$chnnum" eq "0" && $cltflags =~ /nochn0/);
|
next if ($clttype eq 'HMCUCCHN' && !exists ($objects->{$da}{$cnum}) &&
|
||||||
my $chnadd = "$dev:$chnnum";
|
!exists ($objects->{$da}{0}));
|
||||||
|
|
||||||
|
# Update channels of device
|
||||||
|
foreach my $chnnum (keys (%{$objects->{$da}})) {
|
||||||
|
next if ($ct eq 'HMCCUCHN' && "$chnnum" ne "$cnum" && "$chnnum" ne "0");
|
||||||
|
next if ("$chnnum" eq "0" && $cf =~ /nochn0/);
|
||||||
|
my $chnadd = "$dev:$chnnum";
|
||||||
|
|
||||||
# Update datapoints of channel
|
# Update datapoints of channel
|
||||||
foreach my $dpt (keys (%{$objects->{$dev}{$chnnum}})) {
|
foreach my $dpt (keys (%{$objects->{$da}{$chnnum}})) {
|
||||||
my $value = $objects->{$dev}{$chnnum}{$dpt};
|
my $value = $objects->{$da}{$chnnum}{$dpt};
|
||||||
next if (!defined ($value));
|
next if (!defined ($value));
|
||||||
$clthash->{hmccu}{dp}{"$chnnum.$dpt"}{VAL} = $value;
|
$clthash->{hmccu}{dp}{"$chnnum.$dpt"}{VAL} = $value;
|
||||||
|
|
||||||
Log3 $ccuname, 2, "HMCCU: $fnc device=$cltname, chnadd=$dev:$chnnum, dpt=$dpt, value=$value"
|
Log3 $ccuname, 2, "HMCCU: $fnc dev=$cn, chnadd=$dev:$chnnum, dpt=$dpt, value=$value"
|
||||||
if ($cltflags =~ /trace/);
|
if ($cf =~ /trace/);
|
||||||
|
|
||||||
if (HMCCU_FilterReading ($clthash, $chnadd, $dpt)) {
|
if (HMCCU_FilterReading ($ch, $chnadd, $dpt)) {
|
||||||
my @readings = HMCCU_GetReadingName ($clthash, '', $dev, $chnnum, $dpt, '', $crf);
|
my @readings = HMCCU_GetReadingName ($ch, '', $da, $chnnum, $dpt, '', $crf);
|
||||||
my $svalue = HMCCU_ScaleValue ($clthash, $dpt, $value, 0);
|
my $svalue = HMCCU_ScaleValue ($ch, $dpt, $value, 0);
|
||||||
my $fvalue = HMCCU_FormatReadingValue ($clthash, $svalue);
|
my $fvalue = HMCCU_FormatReadingValue ($ch, $svalue);
|
||||||
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chnnum, $dpt);
|
my $cvalue = HMCCU_Substitute ($fvalue, $substitute, 0, $chnnum, $dpt);
|
||||||
my %calcs = HMCCU_CalculateReading ($clthash, $chnnum, $dpt);
|
my %calcs = HMCCU_CalculateReading ($ch, $chnnum, $dpt);
|
||||||
|
|
||||||
# Store the resulting value after scaling, formatting and substitution
|
# Store the resulting value after scaling, formatting and substitution
|
||||||
$results{$dev}{$dpt} = $cvalue;
|
$results{$dev}{$dpt} = $cvalue;
|
||||||
|
|
||||||
Log3 $ccuname, 2, "HMCCU: $fnc device=$cltname, readings=".join(',', @readings).
|
Log3 $ccuname, 2, "HMCCU: $fnc device=$cltname, readings=".join(',', @readings).
|
||||||
", orgvalue=$value value=$cvalue" if ($cltflags =~ /trace/);
|
", orgvalue=$value value=$cvalue" if ($cf =~ /trace/);
|
||||||
|
|
||||||
foreach my $rn (@readings) {
|
foreach my $rn (@readings) {
|
||||||
HMCCU_BulkUpdate ($clthash, $rn, $fvalue, $cvalue) if ($rn ne '');
|
HMCCU_BulkUpdate ($ch, $rn, $fvalue, $cvalue) if ($rn ne '');
|
||||||
}
|
}
|
||||||
foreach my $clcr (keys %calcs) {
|
foreach my $clcr (keys %calcs) {
|
||||||
HMCCU_BulkUpdate ($clthash, $clcr, $calcs{$clcr}, $calcs{$clcr});
|
HMCCU_BulkUpdate ($ch, $clcr, $calcs{$clcr}, $calcs{$clcr});
|
||||||
}
|
}
|
||||||
HMCCU_BulkUpdate ($clthash, 'control', $fvalue, $cvalue)
|
HMCCU_BulkUpdate ($ch, 'control', $fvalue, $cvalue)
|
||||||
if ($cd ne '' && $dpt eq $cd && $chnnum eq $cc);
|
if ($cd ne '' && $dpt eq $cd && $chnnum eq $cc);
|
||||||
HMCCU_BulkUpdate ($clthash, 'state', $fvalue, $cvalue)
|
HMCCU_BulkUpdate ($ch, 'state', $fvalue, $cvalue)
|
||||||
if ($dpt eq $st && ($sc eq '' || $sc eq $chnnum));
|
if ($dpt eq $st && ($sc eq '' || $sc eq $chnnum));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
# Calculate and update HomeMatic state
|
# Calculate and update HomeMatic state
|
||||||
if ($ccuflags !~ /nohmstate/) {
|
if ($ccuflags !~ /nohmstate/) {
|
||||||
my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cltname, $ccuname, undef);
|
my ($hms_read, $hms_chn, $hms_dpt, $hms_val) = HMCCU_GetHMState ($cn, $ccuname, undef);
|
||||||
HMCCU_BulkUpdate ($clthash, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
|
HMCCU_BulkUpdate ($ch, $hms_read, $hms_val, $hms_val) if (defined ($hms_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsEndUpdate ($ch, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
readingsEndUpdate ($clthash, 1);
|
|
||||||
|
|
||||||
return \%results;
|
return \%results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# Version 0.9 beta
|
# Version 0.92 beta
|
||||||
#
|
#
|
||||||
# Thread based RPC Server module for HMCCU.
|
# Thread based RPC Server module for HMCCU.
|
||||||
#
|
#
|
||||||
@ -40,7 +40,7 @@ use SetExtensions;
|
|||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
# HMCCURPC version
|
# HMCCURPC version
|
||||||
my $HMCCURPC_VERSION = '0.9 beta';
|
my $HMCCURPC_VERSION = '0.92 beta';
|
||||||
|
|
||||||
# Maximum number of events processed per call of Read()
|
# Maximum number of events processed per call of Read()
|
||||||
my $HMCCURPC_MAX_EVENTS = 50;
|
my $HMCCURPC_MAX_EVENTS = 50;
|
||||||
@ -66,19 +66,31 @@ my $HMCCURPC_TIMEOUT_WRITE = 0.001;
|
|||||||
# Timeout for accepting incoming connections
|
# Timeout for accepting incoming connections
|
||||||
my $HMCCURPC_TIMEOUT_ACCEPT = 1;
|
my $HMCCURPC_TIMEOUT_ACCEPT = 1;
|
||||||
|
|
||||||
# RPC Ports and URL extensions
|
# Send statistic information after specified amount of events
|
||||||
|
my $HMCCURPC_STATISTICS = 500;
|
||||||
|
|
||||||
|
# RPC protocol name by port number
|
||||||
my %HMCCURPC_RPC_NUMPORT = (
|
my %HMCCURPC_RPC_NUMPORT = (
|
||||||
2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices',
|
2000 => 'BidCos-Wired', 2001 => 'BidCos-RF', 2010 => 'HmIP-RF', 9292 => 'VirtualDevices',
|
||||||
2003 => 'Homegear'
|
2003 => 'Homegear'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# RPC ports by protocol name
|
||||||
my %HMCCURPC_RPC_PORT = (
|
my %HMCCURPC_RPC_PORT = (
|
||||||
'BidCos-Wired', 2000, 'BidCos-RF', 2001, 'HmIP-RF', 2010, 'VirtualDevices', 9292,
|
'BidCos-Wired', 2000, 'BidCos-RF', 2001, 'HmIP-RF', 2010, 'VirtualDevices', 9292,
|
||||||
'Homegear', 2003
|
'Homegear', 2003
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# URL extensions
|
||||||
my %HMCCURPC_RPC_URL = (
|
my %HMCCURPC_RPC_URL = (
|
||||||
9292, 'groups'
|
9292, 'groups'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# Type of RPC interface. A=ASCII B=BINARY
|
||||||
|
my %HMCCURPC_RPC_PROT = (
|
||||||
|
2000 => 'A', 2001 => 'A', 2010 => 'A', 9292 => 'A', 2003 => 'A', 8701 => 'B'
|
||||||
|
);
|
||||||
|
|
||||||
# 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
|
||||||
@ -95,6 +107,21 @@ my $HMCCURPC_THREAD_DATA = 1;
|
|||||||
my $HMCCURPC_THREAD_SERVER = 2;
|
my $HMCCURPC_THREAD_SERVER = 2;
|
||||||
my $HMCCURPC_THREAD_ALL = 3;
|
my $HMCCURPC_THREAD_ALL = 3;
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
my $BINRPC_INTEGER = 1;
|
||||||
|
my $BINRPC_BOOL = 2;
|
||||||
|
my $BINRPC_STRING = 3;
|
||||||
|
my $BINRPC_DOUBLE = 4;
|
||||||
|
my $BINRPC_BASE64 = 17;
|
||||||
|
my $BINRPC_ARRAY = 256;
|
||||||
|
my $BINRPC_STRUCT = 257;
|
||||||
|
|
||||||
|
# Message types
|
||||||
|
my $BINRPC_REQUEST = 0x42696E00;
|
||||||
|
my $BINRPC_RESPONSE = 0x42696E01;
|
||||||
|
my $BINRPC_REQUEST_HEADER = 0x42696E40;
|
||||||
|
my $BINRPC_ERROR = 0x42696EFF;
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Functions
|
# Functions
|
||||||
@ -140,6 +167,7 @@ sub HMCCURPC_HandleConnection ($$$$);
|
|||||||
sub HMCCURPC_TriggerIO ($$$);
|
sub HMCCURPC_TriggerIO ($$$);
|
||||||
sub HMCCURPC_ProcessData ($$$$);
|
sub HMCCURPC_ProcessData ($$$$);
|
||||||
sub HMCCURPC_Write ($$$$);
|
sub HMCCURPC_Write ($$$$);
|
||||||
|
sub HMCCURPC_WriteStats ($$);
|
||||||
sub HMCCURPC_NewDevicesCB ($$$);
|
sub HMCCURPC_NewDevicesCB ($$$);
|
||||||
sub HMCCURPC_DeleteDevicesCB ($$$);
|
sub HMCCURPC_DeleteDevicesCB ($$$);
|
||||||
sub HMCCURPC_UpdateDeviceCB ($$$$);
|
sub HMCCURPC_UpdateDeviceCB ($$$$);
|
||||||
@ -148,6 +176,31 @@ sub HMCCURPC_ReaddDevicesCB ($$$);
|
|||||||
sub HMCCURPC_EventCB ($$$$$);
|
sub HMCCURPC_EventCB ($$$$$);
|
||||||
sub HMCCURPC_ListDevicesCB ($$);
|
sub HMCCURPC_ListDevicesCB ($$);
|
||||||
|
|
||||||
|
# Binary RPC encoding functions
|
||||||
|
sub HMCCURPC_EncInteger ($);
|
||||||
|
sub HMCCURPC_EncBool ($);
|
||||||
|
sub HMCCURPC_EncString ($);
|
||||||
|
sub HMCCURPC_EncName ($);
|
||||||
|
sub HMCCURPC_EncDouble ($);
|
||||||
|
sub HMCCURPC_EncBase64 ($);
|
||||||
|
sub HMCCURPC_EncArray ($);
|
||||||
|
sub HMCCURPC_EncStruct ($);
|
||||||
|
sub HMCCURPC_EncType ($$);
|
||||||
|
sub HMCCURPC_EncodeRequest ($$);
|
||||||
|
sub HMCCURPC_EncodeResponse ($$);
|
||||||
|
|
||||||
|
# Binary RPC decoding functions
|
||||||
|
sub HMCCURPC_DecInteger ($$$);
|
||||||
|
sub HMCCURPC_DecBool ($$);
|
||||||
|
sub HMCCURPC_DecString ($$);
|
||||||
|
sub HMCCURPC_DecDouble ($$);
|
||||||
|
sub HMCCURPC_DecBase64 ($$);
|
||||||
|
sub HMCCURPC_DecArray ($$);
|
||||||
|
sub HMCCURPC_DecStruct ($$);
|
||||||
|
sub HMCCURPC_DecType ($$);
|
||||||
|
sub HMCCURPC_DecodeRequest ($);
|
||||||
|
sub HMCCURPC_DecodeResponse ($);
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Initialize module
|
# Initialize module
|
||||||
@ -170,7 +223,7 @@ sub HMCCURPC_Initialize ($)
|
|||||||
$hash->{AttrList} = "rpcInterfaces:multiple-strict,".join(',',sort keys %HMCCURPC_RPC_PORT).
|
$hash->{AttrList} = "rpcInterfaces:multiple-strict,".join(',',sort keys %HMCCURPC_RPC_PORT).
|
||||||
" ccuflags:multiple-strict,expert rpcMaxEvents rpcQueueSize rpcTriggerTime".
|
" ccuflags:multiple-strict,expert rpcMaxEvents rpcQueueSize rpcTriggerTime".
|
||||||
" rpcServer:on,off rpcServerAddr rpcServerPort rpcWriteTimeout rpcAcceptTimeout".
|
" rpcServer:on,off rpcServerAddr rpcServerPort rpcWriteTimeout rpcAcceptTimeout".
|
||||||
" rpcConnTimeout rpcWaitTime ".
|
" rpcConnTimeout rpcWaitTime rpcStatistics ".
|
||||||
$readingFnAttributes;
|
$readingFnAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +409,7 @@ sub HMCCURPC_Get ($@)
|
|||||||
foreach my $clkey (keys %{$hash->{hmccu}{rpc}}) {
|
foreach my $clkey (keys %{$hash->{hmccu}{rpc}}) {
|
||||||
next if ($clkey eq 'DATA');
|
next if ($clkey eq 'DATA');
|
||||||
$result .= "Event statistics for server $clkey\n";
|
$result .= "Event statistics for server $clkey\n";
|
||||||
|
$result .= "Average event delay = ".$hash->{hmccu}{rpc}{$clkey}{avgdelay}."\n";
|
||||||
$result .= "========================================\n";
|
$result .= "========================================\n";
|
||||||
$result .= "ET Sent by RPC server Received by FHEM\n";
|
$result .= "ET Sent by RPC server Received by FHEM\n";
|
||||||
$result .= "----------------------------------------\n";
|
$result .= "----------------------------------------\n";
|
||||||
@ -648,9 +702,9 @@ sub HMCCURPC_ProcessEvent ($$)
|
|||||||
my $rh = \%{$hash->{hmccu}{rpc}}; # Just for code simplification
|
my $rh = \%{$hash->{hmccu}{rpc}}; # Just for code simplification
|
||||||
my $hmccu_hash = $hash->{IODev};
|
my $hmccu_hash = $hash->{IODev};
|
||||||
|
|
||||||
# Number of arguments in RPC events
|
# Number of arguments in RPC events (without event type and clkey)
|
||||||
my %rpceventargs = (
|
my %rpceventargs = (
|
||||||
"EV", 3,
|
"EV", 4,
|
||||||
"ND", 6,
|
"ND", 6,
|
||||||
"DD", 1,
|
"DD", 1,
|
||||||
"RD", 2,
|
"RD", 2,
|
||||||
@ -659,7 +713,7 @@ sub HMCCURPC_ProcessEvent ($$)
|
|||||||
"IN", 2,
|
"IN", 2,
|
||||||
"EX", 2,
|
"EX", 2,
|
||||||
"SL", 1,
|
"SL", 1,
|
||||||
"ST", 9
|
"ST", 10
|
||||||
);
|
);
|
||||||
|
|
||||||
# Parse event
|
# Parse event
|
||||||
@ -702,11 +756,14 @@ sub HMCCURPC_ProcessEvent ($$)
|
|||||||
if ($et eq 'EV') {
|
if ($et eq 'EV') {
|
||||||
#
|
#
|
||||||
# Update of datapoint
|
# Update of datapoint
|
||||||
# Input: EV|clkey|Address|Datapoint|Value
|
# Input: EV|clkey|Time|Address|Datapoint|Value
|
||||||
# Output: EV, clkey, DevAdd, ChnNo, Datapoint, Value
|
# Output: EV, clkey, DevAdd, ChnNo, Datapoint, Value
|
||||||
#
|
#
|
||||||
my ($add, $chn) = split (/:/, $t[0]);
|
my $delay = $rh->{$clkey}{evtime}-$t[0];
|
||||||
return ($et, $clkey, $add, $chn, $t[1], $t[2]);
|
$rh->{$clkey}{sumdelay} += $delay;
|
||||||
|
$rh->{$clkey}{avgdelay} = $rh->{$clkey}{sumdelay}/$rh->{$clkey}{rec}{$et};
|
||||||
|
my ($add, $chn) = split (/:/, $t[1]);
|
||||||
|
return ($et, $clkey, $add, $chn, $t[2], $t[3]);
|
||||||
}
|
}
|
||||||
elsif ($et eq 'SL') {
|
elsif ($et eq 'SL') {
|
||||||
#
|
#
|
||||||
@ -747,6 +804,7 @@ sub HMCCURPC_ProcessEvent ($$)
|
|||||||
$hash->{hmccu}{rpcstarttime} = 0;
|
$hash->{hmccu}{rpcstarttime} = 0;
|
||||||
HMCCURPC_SetRPCState ($hash, "running", "All RPC servers running");
|
HMCCURPC_SetRPCState ($hash, "running", "All RPC servers running");
|
||||||
HMCCURPC_SetState ($hash, "OK");
|
HMCCURPC_SetState ($hash, "OK");
|
||||||
|
HMCCU_SetState ($hmccu_hash, "OK");
|
||||||
($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0);
|
($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0);
|
||||||
Log3 $name, 2, "HMCCURPC: Updated devices. Success=$c_ok Failed=$c_err";
|
Log3 $name, 2, "HMCCURPC: Updated devices. Success=$c_ok Failed=$c_err";
|
||||||
RemoveInternalTimer ($hash);
|
RemoveInternalTimer ($hash);
|
||||||
@ -827,14 +885,15 @@ sub HMCCURPC_ProcessEvent ($$)
|
|||||||
}
|
}
|
||||||
elsif ($et eq 'ST') {
|
elsif ($et eq 'ST') {
|
||||||
#
|
#
|
||||||
# Statistic data. Store snapshots of sent and received events.
|
# Statistic data. Store snapshots of sent events.
|
||||||
# Input: ST|clkey|nTotal|nEV|nND|nDD|nRD|nRA|nUD|nIN|nSL|nEX
|
# Input: ST|clkey|nTotal|nEV|nND|nDD|nRD|nRA|nUD|nIN|nEX|nSL
|
||||||
# Output: ST, clkey, ...
|
# Output: ST, clkey, ...
|
||||||
#
|
#
|
||||||
my @res = ($et, $clkey);
|
my @res = ($et, $clkey);
|
||||||
push (@res, @t);
|
push (@res, @t);
|
||||||
|
my $total = shift @t;
|
||||||
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
|
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
|
||||||
for (my $i=0; $i<$rpceventargs{$et}; $i++) {
|
for (my $i=0; $i<9; $i++) {
|
||||||
$hash->{hmccu}{rpc}{$clkey}{snd}{$eventtypes[$i]} += $t[$i];
|
$hash->{hmccu}{rpc}{$clkey}{snd}{$eventtypes[$i]} += $t[$i];
|
||||||
}
|
}
|
||||||
return @res;
|
return @res;
|
||||||
@ -1108,6 +1167,7 @@ sub HMCCURPC_StartRPCServer ($)
|
|||||||
$thrpar{waittime} = AttrVal ($name, 'rpcWaitTime', $HMCCURPC_TIME_WAIT);
|
$thrpar{waittime} = AttrVal ($name, 'rpcWaitTime', $HMCCURPC_TIME_WAIT);
|
||||||
$thrpar{queuesize} = AttrVal ($name, 'rpcQueueSize', $HMCCURPC_MAX_QUEUESIZE);
|
$thrpar{queuesize} = AttrVal ($name, 'rpcQueueSize', $HMCCURPC_MAX_QUEUESIZE);
|
||||||
$thrpar{triggertime} = AttrVal ($name, 'rpcTriggerTime', $HMCCURPC_TIME_TRIGGER);
|
$thrpar{triggertime} = AttrVal ($name, 'rpcTriggerTime', $HMCCURPC_TIME_TRIGGER);
|
||||||
|
$thrpar{statistics} = AttrVal ($name, 'rpcStatistics', $HMCCURPC_STATISTICS);
|
||||||
$thrpar{name} = $name;
|
$thrpar{name} = $name;
|
||||||
|
|
||||||
my $ccunum = $hash->{CCUNum};
|
my $ccunum = $hash->{CCUNum};
|
||||||
@ -1197,6 +1257,7 @@ sub HMCCURPC_StartRPCServer ($)
|
|||||||
$hash->{hmccu}{rpc}{$clkey}{rec}{$et} = 0;
|
$hash->{hmccu}{rpc}{$clkey}{rec}{$et} = 0;
|
||||||
$hash->{hmccu}{rpc}{$clkey}{snd}{$et} = 0;
|
$hash->{hmccu}{rpc}{$clkey}{snd}{$et} = 0;
|
||||||
}
|
}
|
||||||
|
$hash->{hmccu}{rpc}{$clkey}{sumdelay} = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep (1);
|
sleep (1);
|
||||||
@ -1470,6 +1531,7 @@ sub HMCCURPC_HandleConnection ($$$$)
|
|||||||
|
|
||||||
# Initialize RPC server
|
# Initialize RPC server
|
||||||
my $iface = $HMCCURPC_RPC_NUMPORT{$port};
|
my $iface = $HMCCURPC_RPC_NUMPORT{$port};
|
||||||
|
my $prot = $HMCCURPC_RPC_PROT{$port};
|
||||||
Log3 $name, 2, "CCURPC: Initializing RPC server $clkey for interface $iface";
|
Log3 $name, 2, "CCURPC: Initializing RPC server $clkey for interface $iface";
|
||||||
my $rpcsrv = HMCCURPC_InitRPCServer ($name, $port, $callbackport);
|
my $rpcsrv = HMCCURPC_InitRPCServer ($name, $port, $callbackport);
|
||||||
if (!defined ($rpcsrv)) {
|
if (!defined ($rpcsrv)) {
|
||||||
@ -1486,8 +1548,10 @@ sub HMCCURPC_HandleConnection ($$$$)
|
|||||||
$rpcsrv->{hmccu}{clkey} = $clkey;
|
$rpcsrv->{hmccu}{clkey} = $clkey;
|
||||||
$rpcsrv->{hmccu}{eventqueue} = $queue;
|
$rpcsrv->{hmccu}{eventqueue} = $queue;
|
||||||
$rpcsrv->{hmccu}{queuesize} = $thrpar->{queuesize};
|
$rpcsrv->{hmccu}{queuesize} = $thrpar->{queuesize};
|
||||||
|
$rpcsrv->{hmccu}{statistics} = $thrpar->{statistics};
|
||||||
|
|
||||||
# Initialize statistic counters
|
# Initialize statistic counters
|
||||||
|
$rpcsrv->{hmccu}{snd}{total} = 0;
|
||||||
foreach my $et (@eventtypes) {
|
foreach my $et (@eventtypes) {
|
||||||
$rpcsrv->{hmccu}{snd}{$et} = 0;
|
$rpcsrv->{hmccu}{snd}{$et} = 0;
|
||||||
}
|
}
|
||||||
@ -1506,19 +1570,20 @@ sub HMCCURPC_HandleConnection ($$$$)
|
|||||||
last if (! $run);
|
last if (! $run);
|
||||||
$connection->timeout ($thrpar->{conntimeout});
|
$connection->timeout ($thrpar->{conntimeout});
|
||||||
Log3 $name, 4, "CCURPC: $clkey processing CCU request";
|
Log3 $name, 4, "CCURPC: $clkey processing CCU request";
|
||||||
$rpcsrv->process_request ($connection);
|
if ($prot eq 'A') {
|
||||||
|
$rpcsrv->process_request ($connection);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# HMCCURPC_ProcessRequest ($connection);
|
||||||
|
}
|
||||||
shutdown ($connection, 2);
|
shutdown ($connection, 2);
|
||||||
undef $connection;
|
undef $connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send statistic info
|
# Send statistic info
|
||||||
my $et = shift @eventtypes;
|
HMCCURPC_WriteStats ($rpcsrv, $clkey);
|
||||||
my $st = $rpcsrv->{hmccu}{snd}{$et};
|
|
||||||
foreach $et (@eventtypes) {
|
# Send exit information
|
||||||
$st .= '|'.$rpcsrv->{hmccu}{snd}{$et};
|
|
||||||
}
|
|
||||||
HMCCURPC_Write ($rpcsrv, "ST", $clkey, $st);
|
|
||||||
|
|
||||||
HMCCURPC_Write ($rpcsrv, "EX", $clkey, "SHUTDOWN|$tid");
|
HMCCURPC_Write ($rpcsrv, "EX", $clkey, "SHUTDOWN|$tid");
|
||||||
Log3 $name, 2, "CCURPC: RPC server $clkey stopped handling connections. TID=$tid";
|
Log3 $name, 2, "CCURPC: RPC server $clkey stopped handling connections. TID=$tid";
|
||||||
|
|
||||||
@ -1586,6 +1651,7 @@ sub HMCCURPC_ProcessData ($$$$)
|
|||||||
my $warn = 0;
|
my $warn = 0;
|
||||||
my $ec = 0;
|
my $ec = 0;
|
||||||
my $tid = threads->tid ();
|
my $tid = threads->tid ();
|
||||||
|
my $triggertime = $thrpar->{triggertime};
|
||||||
|
|
||||||
$SIG{INT} = sub { $run = 0; };
|
$SIG{INT} = sub { $run = 0; };
|
||||||
|
|
||||||
@ -1612,14 +1678,16 @@ sub HMCCURPC_ProcessData ($$$$)
|
|||||||
# Inform reader about new items in queue
|
# Inform reader about new items in queue
|
||||||
Log3 $name, 4, "CCURPC: Trigger I/O for $num_items items";
|
Log3 $name, 4, "CCURPC: Trigger I/O for $num_items items";
|
||||||
my ($ttime, $err) = HMCCURPC_TriggerIO ($socket, $num_items, $thrpar);
|
my ($ttime, $err) = HMCCURPC_TriggerIO ($socket, $num_items, $thrpar);
|
||||||
if ($ttime == 0) {
|
if ($triggertime > 0) {
|
||||||
$ec++;
|
if ($ttime == 0) {
|
||||||
Log3 $name, 2, "CCURPC: I/O error during data processing ($err)" if ($ec == 1);
|
$ec++;
|
||||||
$ec = 0 if ($ec == $HMCCURPC_MAX_IOERRORS);
|
Log3 $name, 2, "CCURPC: I/O error during data processing ($err)" if ($ec == 1);
|
||||||
sleep ($thrpar->{triggertime});
|
$ec = 0 if ($ec == $HMCCURPC_MAX_IOERRORS);
|
||||||
}
|
sleep ($triggertime);
|
||||||
else {
|
}
|
||||||
$ec = 0;
|
else {
|
||||||
|
$ec = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1641,9 +1709,9 @@ sub HMCCURPC_ProcessData ($$$$)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
##################################################
|
######################################################################
|
||||||
# Write event into queue
|
# Write event into queue
|
||||||
##################################################
|
######################################################################
|
||||||
|
|
||||||
sub HMCCURPC_Write ($$$$)
|
sub HMCCURPC_Write ($$$$)
|
||||||
{
|
{
|
||||||
@ -1662,9 +1730,34 @@ sub HMCCURPC_Write ($$$$)
|
|||||||
Log3 $name, 4, "CCURPC: $cb enqueue event $et. parameter = $msg";
|
Log3 $name, 4, "CCURPC: $cb enqueue event $et. parameter = $msg";
|
||||||
$queue->enqueue ($et."|".$cb."|".$msg);
|
$queue->enqueue ($et."|".$cb."|".$msg);
|
||||||
$server->{hmccu}{snd}{$et}++;
|
$server->{hmccu}{snd}{$et}++;
|
||||||
|
$server->{hmccu}{snd}{total}++;
|
||||||
|
HMCCURPC_WriteStats ($server, $cb)
|
||||||
|
if ($server->{hmccu}{snd}{total} % $server->{hmccu}{statistics} == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Write statistics
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_WriteStats ($$)
|
||||||
|
{
|
||||||
|
my ($server, $clkey) = @_;
|
||||||
|
my $name = $server->{hmccu}{name};
|
||||||
|
|
||||||
|
my @eventtypes = ("EV", "ND", "DD", "RD", "RA", "UD", "IN", "EX", "SL");
|
||||||
|
|
||||||
|
# Send statistic info
|
||||||
|
my $st = $server->{hmccu}{snd}{total};
|
||||||
|
foreach my $et (@eventtypes) {
|
||||||
|
$st .= '|'.$server->{hmccu}{snd}{$et};
|
||||||
|
}
|
||||||
|
|
||||||
|
Log3 $name, 4, "CCURPC: Event statistics = $st";
|
||||||
|
my $queue = $server->{hmccu}{eventqueue};
|
||||||
|
$queue->enqueue ("ST|$clkey|$st");
|
||||||
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Callback functions
|
# Callback functions
|
||||||
######################################################################
|
######################################################################
|
||||||
@ -1769,8 +1862,9 @@ sub HMCCURPC_EventCB ($$$$$)
|
|||||||
{
|
{
|
||||||
my ($server, $cb, $devid, $attr, $val) = @_;
|
my ($server, $cb, $devid, $attr, $val) = @_;
|
||||||
my $name = $server->{hmccu}{name};
|
my $name = $server->{hmccu}{name};
|
||||||
|
my $etime = time ();
|
||||||
|
|
||||||
HMCCURPC_Write ($server, "EV", $cb, $devid."|".$attr."|".$val);
|
HMCCURPC_Write ($server, "EV", $cb, $etime."|".$devid."|".$attr."|".$val);
|
||||||
|
|
||||||
# Never remove this statement!
|
# Never remove this statement!
|
||||||
return;
|
return;
|
||||||
@ -1792,6 +1886,463 @@ sub HMCCURPC_ListDevicesCB ($$)
|
|||||||
return RPC::XML::array->new ();
|
return RPC::XML::array->new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Binary RPC encoding functions
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode integer (type = 1)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncInteger ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
return pack ('Nl', $BINRPC_INTEGER, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode bool (type = 2)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncBool ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
return pack ('NC', $BINRPC_BOOL, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode string (type = 3)
|
||||||
|
# Input is string. Empty string = void
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncString ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
return pack ('NN', $BINRPC_STRING, length ($v)).$v;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode name
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncName ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
return pack ('N', length ($v)).$v;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode double (type = 4)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncDouble ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
my $s = $v < 0 ? -1.0 : 1.0;
|
||||||
|
my $l = log (abs($v))/log (2);
|
||||||
|
my $f = $l;
|
||||||
|
|
||||||
|
if ($l-int ($l) > 0) {
|
||||||
|
$f = ($l < 0) ? -int (abs ($l)+1.0) : int ($l);
|
||||||
|
}
|
||||||
|
my $e = $f+1;
|
||||||
|
my $m = int ($s*$v*2**-$e*0x40000000);
|
||||||
|
|
||||||
|
return pack ('NNN', $BINRPC_DOUBLE, $m, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode base64 (type = 17)
|
||||||
|
# Input is base64 encoded string
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncBase64 ($)
|
||||||
|
{
|
||||||
|
my ($v) = @_;
|
||||||
|
|
||||||
|
return pack ('NN', $BINRPC_DOUBLE, length ($v)).$v;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode array (type = 256)
|
||||||
|
# Input is array reference. Array must contain (type, value) pairs
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncArray ($)
|
||||||
|
{
|
||||||
|
my ($a) = @_;
|
||||||
|
|
||||||
|
my $r = '';
|
||||||
|
my $s = 0;
|
||||||
|
|
||||||
|
while (my $t = shift @$a) {
|
||||||
|
my $e = shift @$a;
|
||||||
|
if ($e) {
|
||||||
|
$r .= HMCCURPC_EncType ($t, $e);
|
||||||
|
$s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pack ('NN', $BINRPC_ARRAY, $s).$r;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode struct (type = 257)
|
||||||
|
# Input is hash reference. Hash elements:
|
||||||
|
# hash->{$element}{T} = Type
|
||||||
|
# hash->{$element}{V} = Value
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncStruct ($)
|
||||||
|
{
|
||||||
|
my ($h) = @_;
|
||||||
|
|
||||||
|
my $r = '';
|
||||||
|
my $s = 0;
|
||||||
|
|
||||||
|
foreach my $k (keys %{$h}) {
|
||||||
|
$r .= HMCCURPC_EncName ($k);
|
||||||
|
$r .= HMCCURPC_EncType ($h->{$k}{T}, $h->{$k}{V});
|
||||||
|
$s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pack ('NN', $BINRPC_STRUCT, $s).$r;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode any type
|
||||||
|
# Input is type and value
|
||||||
|
# Return encoded data or empty string on error
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncType ($$)
|
||||||
|
{
|
||||||
|
my ($t, $v) = @_;
|
||||||
|
|
||||||
|
if ($t == $BINRPC_INTEGER) {
|
||||||
|
return HMCCURPC_EncInteger ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_BOOL) {
|
||||||
|
return HMCCURPC_EncBool ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_STRING) {
|
||||||
|
return HMCCURPC_EncString ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_DOUBLE) {
|
||||||
|
return HMCCURPC_EncDouble ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_BASE64) {
|
||||||
|
return HMCCURPC_EncBase64 ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_ARRAY) {
|
||||||
|
return HMCCURPC_EncArray ($v);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_STRUCT) {
|
||||||
|
return HMCCURPC_EncStruct ($v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode RPC request with method and optional parameters.
|
||||||
|
# Headers are not supported.
|
||||||
|
# Input is method name reference to parameter array.
|
||||||
|
# Array must contain (type, value) pairs
|
||||||
|
# Return encoded data or empty string on error
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncodeRequest ($$)
|
||||||
|
{
|
||||||
|
my ($method, $args) = @_;
|
||||||
|
|
||||||
|
# Encode method
|
||||||
|
my $m = HMCCURPC_EncName ($method);
|
||||||
|
|
||||||
|
# Encode parameters
|
||||||
|
my $r = '';
|
||||||
|
my $s = 0;
|
||||||
|
|
||||||
|
if (defined ($args)) {
|
||||||
|
while (my $t = shift @$args) {
|
||||||
|
my $e = shift @$args;
|
||||||
|
last if (!defined ($e));
|
||||||
|
$r .= HMCCURPC_EncType ($t, $e);
|
||||||
|
$s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Method, ParameterCount, Parameters
|
||||||
|
$r = $m.pack ('N', $s).$r;
|
||||||
|
|
||||||
|
# Identifier, ContentLength, Content
|
||||||
|
# Ggf. +8
|
||||||
|
$r = pack ('NN', $BINRPC_REQUEST, length ($r)+8).$r;
|
||||||
|
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Encode RPC response
|
||||||
|
# Input is type and value
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_EncodeResponse ($$)
|
||||||
|
{
|
||||||
|
my ($t, $v) = @_;
|
||||||
|
|
||||||
|
if (defined ($t) && defined ($v)) {
|
||||||
|
my $r = HMCCURPC_EncType ($t, $v);
|
||||||
|
# Ggf. +8
|
||||||
|
return pack ('NN', $BINRPC_RESPONSE, length ($r)).$r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return pack ('NN', $BINRPC_RESPONSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decoding functions
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode integer (type = 1)
|
||||||
|
# Return (value, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecInteger ($$$)
|
||||||
|
{
|
||||||
|
my ($d, $i, $u) = @_;
|
||||||
|
|
||||||
|
return ($i+4 <= length ($d)) ? (unpack ($u, substr ($d, $i, 4)), 4) : (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode bool (type = 2)
|
||||||
|
# Return (value, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecBool ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
|
||||||
|
return ($i+1 <= length ($d)) ? (unpack ('C', substr ($d, $i, 1)), 1) : (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode string or void (type = 3)
|
||||||
|
# Return (string, packet size) or (undef, undef)
|
||||||
|
# Return ('', 4) for special type 'void'
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecString ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
|
||||||
|
my ($s, $o) = HMCCURPC_DecInteger ($d, $i, 'N');
|
||||||
|
if (defined ($s) && $i+$s+4 <= length ($d)) {
|
||||||
|
return $s > 0 ? (substr ($d, $i+4, $s), $s+4) : ('', 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode double (type = 4)
|
||||||
|
# Return (value, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecDouble ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
|
||||||
|
return (undef, undef) if ($i+8 > length ($d));
|
||||||
|
|
||||||
|
my $m = unpack ('N', substr ($d, $i, 4));
|
||||||
|
my $e = unpack ('N', substr ($d, $i+4, 4));
|
||||||
|
|
||||||
|
return (sprintf ("%.6f",$m/0x40000000*(2**$e)), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode base64 encoded string (type = 17)
|
||||||
|
# Return (string, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecBase64 ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
|
||||||
|
return HMCCURPC_DecString ($d, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode array (type = 256)
|
||||||
|
# Return (arrayref, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecArray ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
my @r = ();
|
||||||
|
|
||||||
|
my ($s, $x) = HMCCURPC_DecInteger ($d, $i, 'N');
|
||||||
|
if (defined ($s)) {
|
||||||
|
my $j = $x;
|
||||||
|
for (my $n=0; $n<$s; $n++) {
|
||||||
|
my ($v, $o) = HMCCURPC_DecType ($d, $i+$j);
|
||||||
|
return (undef, undef) if (!defined ($o));
|
||||||
|
push (@r, $v);
|
||||||
|
$j += $o;
|
||||||
|
}
|
||||||
|
return (\@r, $j);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode struct (type = 257)
|
||||||
|
# Return (hashref, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecStruct ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
my %r;
|
||||||
|
|
||||||
|
my ($s, $x) = HMCCURPC_DecInteger ($d, $i, 'N');
|
||||||
|
if (defined ($s)) {
|
||||||
|
my $j = $x;
|
||||||
|
for (my $n=0; $n<$s; $n++) {
|
||||||
|
my ($k, $o1) = HMCCURPC_DecString ($d, $i+$j);
|
||||||
|
return (undef, undef) if (!defined ($o1));
|
||||||
|
my ($v, $o2) = HMCCURPC_DecType ($d, $i+$j+$o1);
|
||||||
|
return (undef, undef) if (!defined ($o2));
|
||||||
|
$r{$k} = $v;
|
||||||
|
$j += $o1+$o2;
|
||||||
|
}
|
||||||
|
return (\%r, $j);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode any type
|
||||||
|
# Return (element, packetsize) or (undef, undef)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecType ($$)
|
||||||
|
{
|
||||||
|
my ($d, $i) = @_;
|
||||||
|
|
||||||
|
return (undef, undef) if ($i+4 > length ($d));
|
||||||
|
|
||||||
|
my @r = ();
|
||||||
|
|
||||||
|
my $t = unpack ('N', substr ($d, $i, 4));
|
||||||
|
$i += 4;
|
||||||
|
|
||||||
|
if ($t == $BINRPC_INTEGER) {
|
||||||
|
# Integer
|
||||||
|
@r = HMCCURPC_DecInteger ($d, $i, 'l');
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_BOOL) {
|
||||||
|
# Bool
|
||||||
|
@r = HMCCURPC_DecBool ($d, $i);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_STRING || $t == $BINRPC_BASE64) {
|
||||||
|
# String / Base64
|
||||||
|
@r = HMCCURPC_DecString ($d, $i);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_DOUBLE) {
|
||||||
|
# Double
|
||||||
|
@r = HMCCURPC_DecDouble ($d, $i);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_ARRAY) {
|
||||||
|
# Array
|
||||||
|
@r = HMCCURPC_DecArray ($d, $i);
|
||||||
|
}
|
||||||
|
elsif ($t == $BINRPC_STRUCT) {
|
||||||
|
# Struct
|
||||||
|
@r = HMCCURPC_DecStruct ($d, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$r[1] += 4;
|
||||||
|
|
||||||
|
return @r;
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode request.
|
||||||
|
# Return method, arguments. Arguments are returned as array.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecodeRequest ($)
|
||||||
|
{
|
||||||
|
my ($data) = @_;
|
||||||
|
|
||||||
|
my @r = ();
|
||||||
|
my $i = 8;
|
||||||
|
|
||||||
|
return (undef, undef) if (length ($data) < 8);
|
||||||
|
|
||||||
|
# Decode method
|
||||||
|
my ($method, $o) = HMCCURPC_DecString ($data, $i);
|
||||||
|
return (undef, undef) if (!defined ($method));
|
||||||
|
|
||||||
|
$i += $o;
|
||||||
|
|
||||||
|
my $c = unpack ('N', substr ($data, $i, 4));
|
||||||
|
for (my $n=0; $n<$c; $n++) {
|
||||||
|
my ($d, $s) = HMCCURPC_DecType ($data, $i);
|
||||||
|
return (undef, undef) if (!defined ($d) || !defined ($s));
|
||||||
|
push (@r, $d);
|
||||||
|
$i += $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($method, \@r);
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Decode response.
|
||||||
|
# Return (ref, type) or (undef, undef)
|
||||||
|
# type: 1=ok, 0=error
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
sub HMCCURPC_DecodeResponse ($)
|
||||||
|
{
|
||||||
|
my ($data) = @_;
|
||||||
|
|
||||||
|
return (undef, undef) if (length ($data) < 8);
|
||||||
|
|
||||||
|
my $id = unpack ('N', substr ($data, 0, 4));
|
||||||
|
if ($id == $BINRPC_RESPONSE) {
|
||||||
|
# Data
|
||||||
|
my ($result, $offset) = HMCCURPC_DecType ($data, 8);
|
||||||
|
return ($result, 1);
|
||||||
|
}
|
||||||
|
elsif ($id == $BINRPC_ERROR) {
|
||||||
|
# Error
|
||||||
|
my ($result, $offset) = HMCCURPC_DecType ($data, 8);
|
||||||
|
return ($result, 0);
|
||||||
|
}
|
||||||
|
# Response with header not supported
|
||||||
|
# elsif ($id == 0x42696E41) {
|
||||||
|
# }
|
||||||
|
|
||||||
|
return (undef, undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
@ -1879,9 +2430,10 @@ sub HMCCURPC_ListDevicesCB ($$)
|
|||||||
is used. Default value is 5400.
|
is used. Default value is 5400.
|
||||||
</li><br/>
|
</li><br/>
|
||||||
<li><b>rpcTriggerTime <seconds></b><br/>
|
<li><b>rpcTriggerTime <seconds></b><br/>
|
||||||
Set time to wait before trigger I/O again after I/O error. Default value is 10 seconds.
|
Set time to wait before triggering I/O again after an I/O error "no reader" occurred.
|
||||||
On fast systems this value can be set to 5 seconds. Reduces number of log messages
|
Default value is 10 seconds, 0 will deactivate error handling for this kind of error.
|
||||||
written if FHEM is busy and not able to read data from CCU.
|
On fast systems this value can be set to 5 seconds. Higher values Reduce number of
|
||||||
|
log messages written if FHEM is busy and not able to read data from CCU.
|
||||||
</li><br/>
|
</li><br/>
|
||||||
<li><b>rpcWaitTime <microseconds></b><br/>
|
<li><b>rpcWaitTime <microseconds></b><br/>
|
||||||
Specify time to wait for data processing thread after each loop. Default value is
|
Specify time to wait for data processing thread after each loop. Default value is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user