2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

HMCCU: Fixed CUxD floating point numbers bug

git-svn-id: https://svn.fhem.de/fhem/trunk@16165 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2018-02-13 10:55:01 +00:00
parent 44102c8bc4
commit af2d53573e
6 changed files with 137 additions and 79 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.
- bugfix: 88_HMCCU: fixed CUxD bug and minor bugs
- feature: 93_DbRep: V7.10.0, new "changeValue" command, minor fixes - feature: 93_DbRep: V7.10.0, new "changeValue" command, minor fixes
- bugfix: 88_xs1Bridge: fix Filelog check - bugfix: 88_xs1Bridge: fix Filelog check
- new: 39_Talk2Fhem: new module for language control - new: 39_Talk2Fhem: new module for language control

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 4.2.001 # Version 4.2.002
# #
# Module for communication between FHEM and Homematic CCU2. # Module for communication between FHEM and Homematic CCU2.
# #
@ -104,7 +104,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS; my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version # HMCCU version
my $HMCCU_VERSION = '4.2.001'; my $HMCCU_VERSION = '4.2.002';
# Default RPC port (BidCos-RF) # Default RPC port (BidCos-RF)
my $HMCCU_RPC_PORT_DEFAULT = 2001; my $HMCCU_RPC_PORT_DEFAULT = 2001;
@ -1271,6 +1271,7 @@ sub HMCCU_Set ($@)
} }
elsif ($opt eq 'rpcserver') { elsif ($opt eq 'rpcserver') {
my $action = shift @$a; my $action = shift @$a;
$action = shift @$a if ($action eq $opt);
$usage = "Usage: set $name $opt {'on'|'off'|'restart'}"; $usage = "Usage: set $name $opt {'on'|'off'|'restart'}";
return HMCCU_SetError ($hash, $usage) return HMCCU_SetError ($hash, $usage)
@ -2201,8 +2202,10 @@ sub HMCCU_SetState ($@)
} }
###################################################################### ######################################################################
# Set state of RPC server. # Set state of RPC server. Update all client devices if overall state
# Parameters iface and msg are optional. # is 'running'.
# Parameters iface and msg are optional. If iface is set function
# was called by HMCCURPCPROC device.
###################################################################### ######################################################################
sub HMCCU_SetRPCState ($@) sub HMCCU_SetRPCState ($@)
@ -2212,11 +2215,21 @@ sub HMCCU_SetRPCState ($@)
my $ccuflags = AttrVal ($name, 'ccuflags', 'null'); my $ccuflags = AttrVal ($name, 'ccuflags', 'null');
my $filter; my $filter;
my $f = 0; # Overall process states: 0=starting/stopping, 1=running/error, 2=stopped/error my $rpcstate = $state;
if ($ccuflags =~ /(intrpc|extrpc)/) { if ($ccuflags =~ /(intrpc|extrpc)/ || $ccuflags !~ /(intrpc|extrpc|procrpc)/) {
$f = 1 if ($state eq 'running'); if ($state ne $hash->{RPCState}) {
$f = 2 if ($state eq 'inactive'); $hash->{RPCState} = $state;
readingsSingleUpdate ($hash, "rpcstate", $state, 1);
HMCCU_Log ($hash, 4, "Set rpcstate to $state", undef);
HMCCU_Log ($hash, 1, $msg, undef) if (defined ($msg));
HMCCU_Log ($hash, 1, "All RPC servers $state", undef);
DoTrigger ($name, "RPC server $state");
if ($state eq 'running') {
my ($c_ok, $c_err) = HMCCU_UpdateClients ($hash, '.*', 'Attr', 0, $filter);
HMCCU_Log ($hash, 2, "Updated devices. Success=$c_ok Failed=$c_err", undef);
}
}
} }
elsif (defined ($iface) && $ccuflags =~ /procrpc/) { elsif (defined ($iface) && $ccuflags =~ /procrpc/) {
# Set interface state # Set interface state
@ -2224,47 +2237,50 @@ sub HMCCU_SetRPCState ($@)
$hash->{hmccu}{interfaces}{$ifname}{state} = $state if (defined ($ifname)); $hash->{hmccu}{interfaces}{$ifname}{state} = $state if (defined ($ifname));
# Count number of processes in state running, error or inactive # Count number of processes in state running, error or inactive
my %statecount = ("running" => 0, "error" => 0, "inactive" => 0); # Prepare filter for updating client devices
my %stc = ("running" => 0, "error" => 0, "inactive" => 0);
my @iflist = HMCCU_GetRPCInterfaceList ($hash); my @iflist = HMCCU_GetRPCInterfaceList ($hash);
foreach my $i (@iflist) { foreach my $i (@iflist) {
my $st = $hash->{hmccu}{interfaces}{$i}{state}; my $st = $hash->{hmccu}{interfaces}{$i}{state};
$statecount{$st}++ if (exists ($statecount{$st})); $stc{$st}++ if (exists ($stc{$st}));
if ($hash->{hmccu}{interfaces}{$i}{manager} eq 'HMCCU') { if ($hash->{hmccu}{interfaces}{$i}{manager} eq 'HMCCU') {
$filter = defined ($filter) ? "$filter|$i" : $i; $filter = defined ($filter) ? "$filter|$i" : $i;
} }
} }
# Determine overall process state # Determine overall process state
$f = 1 if ($statecount{"running"}+$statecount{"error"} == scalar (@iflist)); my $rpcstate = 'null';
$f = 2 if ($statecount{"inactive"}+$statecount{"error"} == scalar (@iflist)); $rpcstate = "running" if ($stc{"running"} == scalar (@iflist));
} $rpcstate = "inactive" if ($stc{"inactive"} == scalar (@iflist));
$rpcstate = "error" if ($stc{"error"} == scalar (@iflist));
if ($state ne $hash->{RPCState}) { if ($rpcstate =~ /^(running|inactive|error)$/) {
# Update RPC state if ($rpcstate ne $hash->{RPCState}) {
$hash->{RPCState} = $state; $hash->{RPCState} = $rpcstate;
readingsSingleUpdate ($hash, "rpcstate", $state, 1); readingsSingleUpdate ($hash, "rpcstate", $rpcstate, 1);
HMCCU_Log ($hash, 4, "Set rpcstate to $rpcstate", undef);
if ($f > 0) { HMCCU_Log ($hash, 1, $msg, undef) if (defined ($msg));
# Running or inactive HMCCU_Log ($hash, 1, "All RPC servers $rpcstate", undef);
HMCCU_SetState ($hash, 'OK'); DoTrigger ($name, "RPC server $rpcstate");
HMCCU_Log ($hash, 1, "All RPC servers $state", undef); if ($rpcstate eq 'running') {
DoTrigger ($name, "RPC server $state"); my ($c_ok, $c_err) = HMCCU_UpdateClients ($hash, '.*', 'Attr', 0, $filter);
HMCCU_Log ($hash, 2, "Updated devices. Success=$c_ok Failed=$c_err", undef);
if ($f == 1) { }
# If RPC process(es) running update all devices where interface is managed by HMCCU
my ($c_ok, $c_err) = HMCCU_UpdateClients ($hash, '.*', 'Attr', 0, $filter);
Log3 $name, 2, "HMCCU: Updated devices. Success=$c_ok Failed=$c_err";
} }
} }
else {
# Starting or stopping
HMCCU_SetState ($hash, 'busy');
}
HMCCU_Log ($hash, 4, "Set rpcstate to $state", undef);
HMCCU_Log ($hash, 1, $msg, undef) if (defined ($msg));
} }
# Set I/O device state
if ($rpcstate eq 'running' || $rpcstate eq 'inactive') {
HMCCU_SetState ($hash, "OK");
}
elsif ($rpcstate eq 'error') {
HMCCU_SetState ($hash, "error");
}
else {
HMCCU_SetState ($hash, "busy");
}
return undef; return undef;
} }
@ -3422,13 +3438,13 @@ sub HMCCU_IsRPCServerRunning ($$$)
$c = $r; $c = $r;
} }
} }
elsif ($ccuflags =~ /procprc/) { elsif ($ccuflags =~ /procrpc/) {
@$pids = () if (defined ($pids)); @$pids = () if (defined ($pids));
my @iflist = HMCCU_GetRPCInterfaceList ($hash); my @iflist = HMCCU_GetRPCInterfaceList ($hash);
foreach my $ifname (@iflist) { foreach my $ifname (@iflist) {
my ($rpcdev, $save) = HMCCU_GetRPCDevice ($hash, 0, $ifname); my ($rpcdev, $save) = HMCCU_GetRPCDevice ($hash, 0, $ifname);
next if ($rpcdev eq ''); next if ($rpcdev eq '');
my ($rc, $msg) = HMCCURPCPROC_CheckProcessState ($defs{$rpcdev}, 'running'); my $rc = HMCCURPCPROC_CheckProcessState ($defs{$rpcdev}, 'running');
if ($rc < 0 || $rc > 1) { if ($rc < 0 || $rc > 1) {
push (@$pids, $rc); push (@$pids, $rc);
$c++; $c++;
@ -5038,7 +5054,7 @@ sub HMCCU_ReadRPCQueue ($)
# Output statistic counters # Output statistic counters
foreach my $cnt (sort keys %{$hash->{hmccu}{ev}}) { foreach my $cnt (sort keys %{$hash->{hmccu}{ev}}) {
Log3 $name, 2, "HMCCU: Eventcount $cnt = ".$hash->{hmccu}{ev}{$cnt}; Log3 $name, 3, "HMCCU: Eventcount $cnt = ".$hash->{hmccu}{ev}{$cnt};
} }
} }
@ -6988,7 +7004,7 @@ sub HMCCU_CCURPC_ListDevicesCB ($$)
practice for creating a custom default attribute file is by exporting predefined default practice for creating a custom default attribute file is by exporting predefined default
attributes from HMCCU with command 'get exportdefaults'. attributes from HMCCU with command 'get exportdefaults'.
</li><br/> </li><br/>
<li><b>ccuflags {extrpc, procprc, <u>intrpc</u>}</b><br/> <li><b>ccuflags {extrpc, procrpc, <u>intrpc</u>}</b><br/>
Control behaviour of several HMCCU functions:<br/> Control behaviour of several HMCCU functions:<br/>
ackState - Acknowledge command execution by setting STATE to error or success.<br/> ackState - Acknowledge command execution by setting STATE to error or success.<br/>
dptnocheck - Do not check within set or get commands if datapoint is valid<br/> dptnocheck - Do not check within set or get commands if datapoint is valid<br/>

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 4.2 # Version 4.2.001
# #
# (c) 2018 zap (zap01 <at> t-online <dot> de) # (c) 2018 zap (zap01 <at> t-online <dot> de)
# #
@ -760,11 +760,10 @@ sub HMCCUCHN_Get ($@)
dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/> dewpoint = calculate dewpoint, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
abshumidity = calculate absolute humidity, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/> abshumidity = calculate absolute humidity, <i>dp-list</i> = &lt;temperature&gt;,&lt;humidity&gt;<br/>
inc = increment datapoint value considering reset of datapoint, <i>dp-list</i> = &lt;counter-datapoint&gt;<br/> inc = increment datapoint value considering reset of datapoint, <i>dp-list</i> = &lt;counter-datapoint&gt;<br/>
inc = increment datapoint value considering reset of datapoint, <i>dp-list</i> = &lt;counter-datapoint&gt;<br/>
min = calculate minimum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/> min = calculate minimum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
max = calculate maximum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/> max = calculate maximum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
sum = calculate sum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/> sum = calculate sum continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
avg = calculate average continuously, <i>dp-list</i> = &lt;datapoint&gt; avg = calculate average continuously, <i>dp-list</i> = &lt;datapoint&gt;<br/>
Example:<br/> Example:<br/>
<code>dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY</code> <code>dewpoint:taupunkt:1.TEMPERATURE,1.HUMIDITY</code>
</li><br/> </li><br/>

View File

@ -1556,13 +1556,13 @@ sub HMCCURPC_RPCServerStarted ($$)
# $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");
if (defined ($hmccu_hash)) { # if (defined ($hmccu_hash)) {
HMCCU_SetState ($hmccu_hash, "OK"); # HMCCU_SetState ($hmccu_hash, "OK");
($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0, undef); # ($c_ok, $c_err) = HMCCU_UpdateClients ($hmccu_hash, '.*', 'Attr', 0, undef);
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);
DoTrigger ($name, "RPC server running"); # DoTrigger ($name, "RPC server running");
} }
return ($run, $c_ok, $c_err); return ($run, $c_ok, $c_err);
@ -2441,15 +2441,23 @@ sub HMCCURPC_EncDouble ($)
{ {
my ($v) = @_; my ($v) = @_;
my $s = $v < 0 ? -1.0 : 1.0; # my $s = $v < 0 ? -1.0 : 1.0;
my $l = log (abs($v))/log (2); # my $l = log (abs($v))/log (2);
my $f = $l; # my $f = $l;
#
if ($l-int ($l) > 0) { # if ($l-int ($l) > 0) {
$f = ($l < 0) ? -int (abs ($l)+1.0) : int ($l); # $f = ($l < 0) ? -int (abs ($l)+1.0) : int ($l);
# }
# my $e = $f+1;
# my $m = int ($s*$v*2**-$e*0x40000000);
my $m = 0;
my $e = 0;
if ($v != 0.0) {
$e = int(log(abs($v))/log(2.0))+1;
$m = int($v/(2**$e)*0x40000000);
} }
my $e = $f+1;
my $m = int ($s*$v*2**-$e*0x40000000);
return pack ('NNN', $BINRPC_DOUBLE, $m, $e); return pack ('NNN', $BINRPC_DOUBLE, $m, $e);
} }
@ -2664,10 +2672,17 @@ sub HMCCURPC_DecDouble ($$)
return (undef, undef) if ($i+8 > length ($d)); return (undef, undef) if ($i+8 > length ($d));
my $m = unpack ('N', substr ($d, $i, 4)); # my $m = unpack ('N', substr ($d, $i, 4));
my $e = unpack ('N', substr ($d, $i+4, 4)); # my $e = unpack ('N', substr ($d, $i+4, 4));
#
# return (sprintf ("%.6f",$m/0x40000000*(2**$e)), 8);
return (sprintf ("%.6f",$m/0x40000000*(2**$e)), 8); my $m = unpack ('l', reverse (substr ($d, $i, 4)));
my $e = unpack ('l', reverse (substr ($d, $i+4, 4)));
$m = $m/(1<<30);
my $v = $m*(2**$e);
return (sprintf ("%.6f",$v), 8);
} }
###################################################################### ######################################################################

View File

@ -4,7 +4,7 @@
# #
# $Id$ # $Id$
# #
# Version 1.0.001 # Version 1.0.002
# #
# 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.0.001'; my $HMCCURPCPROC_VERSION = '1.0.002';
# 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;
@ -590,7 +590,9 @@ sub HMCCURPCPROC_SetRPCState ($$$$)
my ($hash, $state, $msg, $level) = @_; my ($hash, $state, $msg, $level) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $hmccu_hash = $hash->{IODev}; my $hmccu_hash = $hash->{IODev};
return undef if (exists ($hash->{RPCState}) && $hash->{RPCState} eq $state);
$hash->{hmccu}{rpc}{state} = $state; $hash->{hmccu}{rpc}{state} = $state;
$hash->{RPCState} = $state; $hash->{RPCState} = $state;
@ -822,7 +824,7 @@ sub HMCCURPCPROC_ProcessEvent ($$)
# Input: TO|clkey|Time # Input: TO|clkey|Time
# Output: TO, clkey, Port, Time # Output: TO, clkey, Port, Time
# #
if ($evttimeout > 0) { if ($evttimeout > 0 && $evttimeout >= $t[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' && $ccuflags =~ /reconnect/) { if ($hash->{RPCState} eq 'running' && $ccuflags =~ /reconnect/) {
@ -1257,12 +1259,12 @@ sub HMCCURPCPROC_CleanupIO ($)
delete $hash->{FD} if (defined ($hash->{FD})); delete $hash->{FD} if (defined ($hash->{FD}));
} }
if (defined ($hash->{hmccu}{sockchild})) { if (defined ($hash->{hmccu}{sockchild})) {
Log3 $name, 2, "HMCCURPCPROC: [$name] Close child socket"; Log3 $name, 3, "HMCCURPCPROC: [$name] Close child socket";
$hash->{hmccu}{sockchild}->close (); $hash->{hmccu}{sockchild}->close ();
delete $hash->{hmccu}{sockchild}; delete $hash->{hmccu}{sockchild};
} }
if (defined ($hash->{hmccu}{sockparent})) { if (defined ($hash->{hmccu}{sockparent})) {
Log3 $name, 2, "HMCCURPCPROC: [$name] Close parent socket"; Log3 $name, 3, "HMCCURPCPROC: [$name] Close parent socket";
$hash->{hmccu}{sockparent}->close (); $hash->{hmccu}{sockparent}->close ();
delete $hash->{hmccu}{sockparent}; delete $hash->{hmccu}{sockparent};
} }
@ -2080,16 +2082,24 @@ sub HMCCURPCPROC_EncDouble ($)
{ {
my ($v) = @_; my ($v) = @_;
my $s = $v < 0 ? -1.0 : 1.0; # my $s = $v < 0 ? -1.0 : 1.0;
my $l = log (abs($v))/log (2); # my $l = $v != 0.0 ? log (abs($v))/log (2) : 0.0;
my $f = $l; # my $f = $l;
#
if ($l-int ($l) > 0) { # if ($l-int ($l) > 0) {
$f = ($l < 0) ? -int (abs ($l)+1.0) : int ($l); # $f = ($l < 0) ? -int (abs ($l)+1.0) : int ($l);
# }
# my $e = $f+1;
# my $m = int ($v*2**-$e*0x40000000);
my $m = 0;
my $e = 0;
if ($v != 0.0) {
$e = int(log(abs($v))/log(2.0))+1;
$m = int($v/(2**$e)*0x40000000);
} }
my $e = $f+1;
my $m = int ($s*$v*2**-$e*0x40000000);
return pack ('NNN', $BINRPC_DOUBLE, $m, $e); return pack ('NNN', $BINRPC_DOUBLE, $m, $e);
} }
@ -2303,10 +2313,12 @@ sub HMCCURPCPROC_DecDouble ($$)
return (undef, undef) if ($i+8 > length ($d)); return (undef, undef) if ($i+8 > length ($d));
my $m = unpack ('N', substr ($d, $i, 4)); my $m = unpack ('l', reverse (substr ($d, $i, 4)));
my $e = unpack ('N', substr ($d, $i+4, 4)); my $e = unpack ('l', reverse (substr ($d, $i+4, 4)));
$m = $m/(1<<30);
return (sprintf ("%.6f",$m/0x40000000*(2**$e)), 8); my $v = $m*(2**$e);
return (sprintf ("%.6f",$v), 8);
} }
###################################################################### ######################################################################

View File

@ -42,6 +42,14 @@ use vars qw(%HMCCU_SCRIPTS);
statedatapoint => "STATE", statedatapoint => "STATE",
substitute => "STATE!(0|false):closed,(1|true):open" substitute => "STATE!(0|false):closed,(1|true):open"
}, },
"HmIP-SWDO-I" => {
_description => "Tuer/Fensterkontakt verdeckt",
_channels => "1",
ccureadingfilter => "STATE",
hmstatevals => "SABOTAGE!1:sabotage",
statedatapoint => "STATE",
substitute => "STATE!(0|false):closed,(1|true):open"
},
"HM-Sec-RHS|HM-Sec-RHS-2" => { "HM-Sec-RHS|HM-Sec-RHS-2" => {
_description => "Fenster Drehgriffkontakt", _description => "Fenster Drehgriffkontakt",
_channels => "1", _channels => "1",
@ -391,6 +399,13 @@ use vars qw(%HMCCU_SCRIPTS);
statedatapoint => "1.STATE", statedatapoint => "1.STATE",
substitute => "STATE!(0|false):closed,(1|true):open" substitute => "STATE!(0|false):closed,(1|true):open"
}, },
"HmIP-SWDO-I" => {
_description => "Tuer/Fensterkontakt verdeckt",
ccureadingfilter => "STATE",
hmstatevals => "SABOTAGE!1:sabotage",
statedatapoint => "1.STATE",
substitute => "STATE!(0|false):closed,(1|true):open"
},
"HM-Sec-RHS|HM-Sec-RHS-2" => { "HM-Sec-RHS|HM-Sec-RHS-2" => {
_description => "Fenster Drehgriffkontakt", _description => "Fenster Drehgriffkontakt",
ccureadingfilter => "STATE", ccureadingfilter => "STATE",