98_PID20 : Bugfix: processing of D-Portion and handling of disable
git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@7025 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -43,7 +43,8 @@
|
||||
# V 1.01
|
||||
# 19.10.2014 fix in sub PID20_Set : wrong parameter $hash instead of $name, when calling PID20_Calc
|
||||
# V 1.0.0.2 30.10.14 - fix in PID20_Calc when setting $retStr (thanks to Thorsten Pferdekaemper)
|
||||
#
|
||||
# V 1.0.0.3
|
||||
# 20.11.2014 Bug: processing of D-Portion and handling of disable
|
||||
####################################################################################################
|
||||
package main;
|
||||
use strict;
|
||||
@@ -53,25 +54,19 @@ use vars qw(%defs);
|
||||
use vars qw($readingFnAttributes);
|
||||
use vars qw(%attr);
|
||||
use vars qw(%modules);
|
||||
|
||||
my $PID20_Version="1.0.0.2";
|
||||
|
||||
my $PID20_Version = "1.0.0.3";
|
||||
sub PID20_Calc($);
|
||||
|
||||
########################################
|
||||
sub PID20_Log($$$)
|
||||
{
|
||||
my ( $hash, $loglevel, $text ) = @_;
|
||||
my $xline = ( caller(0) )[2];
|
||||
|
||||
my $xsubroutine = ( caller(1) )[3];
|
||||
my $sub = ( split( ':', $xsubroutine ) )[2];
|
||||
$sub = substr( $sub, 6 ); # without PID20
|
||||
|
||||
my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : "PID20";
|
||||
Log3 $hash, $loglevel, "PID20 $instName: $sub.$xline " . $text;
|
||||
}
|
||||
|
||||
########################################
|
||||
sub PID20_Initialize($)
|
||||
{
|
||||
@@ -100,6 +95,7 @@ sub PID20_Initialize($)
|
||||
. "pidSensorTimeout "
|
||||
. "pidReverseAction "
|
||||
. "pidUpdateInterval "
|
||||
|
||||
# . "pidDebugEnable:0,1 ";
|
||||
. "pidDebugSensor:0,1 "
|
||||
. "pidDebugActuation:0,1 "
|
||||
@@ -107,25 +103,21 @@ sub PID20_Initialize($)
|
||||
. "pidDebugDelta:0,1 "
|
||||
. "pidDebugUpdate:0,1 "
|
||||
. "pidDebugNotify:0,1 "
|
||||
|
||||
. "disable:0,1 "
|
||||
. $readingFnAttributes;
|
||||
|
||||
}
|
||||
|
||||
|
||||
########################################
|
||||
sub PID20_TimeDiff($) {
|
||||
sub PID20_TimeDiff($)
|
||||
{
|
||||
my ($strTS) = @_;
|
||||
|
||||
#my ( $package, $filename, $line ) = caller(0);
|
||||
#print "PID $strTS line $line \n";
|
||||
|
||||
my $serTS = ( defined($strTS) && $strTS ne "" ) ? time_str2num($strTS) : gettimeofday();
|
||||
my $timeDiff = gettimeofday() - $serTS;
|
||||
$timeDiff = 0 if ( $timeDiff < 0 );
|
||||
return $timeDiff;
|
||||
}
|
||||
|
||||
########################################
|
||||
sub PID20_Define($$$)
|
||||
{
|
||||
@@ -133,7 +125,6 @@ sub PID20_Define($$$)
|
||||
my @a = split( "[ \t][ \t]*", $def );
|
||||
my $name = $a[0];
|
||||
my $reFloat = '^([\\+,\\-]?\\d+\\.?\d*$)'; # gleitpunkt
|
||||
|
||||
if ( @a != 4 )
|
||||
{
|
||||
return "wrong syntax: define <name> PID20 " . "<sensor>:reading:[regexp] <actor>[:cmd] ";
|
||||
@@ -157,7 +148,6 @@ sub PID20_Define($$$)
|
||||
PID20_Log $hash, 1, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
$hash->{helper}{sensor} = $sensor;
|
||||
|
||||
# defaults for regexp
|
||||
@@ -165,29 +155,23 @@ sub PID20_Define($$$)
|
||||
{
|
||||
$regexp = $reFloat;
|
||||
}
|
||||
|
||||
$hash->{helper}{reading} = $reading;
|
||||
$hash->{helper}{regexp} = $regexp;
|
||||
|
||||
# Actor
|
||||
my ( $actor, $cmd ) = split( ":", $a[3], 2 );
|
||||
|
||||
if ( !$defs{$actor} )
|
||||
{
|
||||
my $msg = "$name: Unknown actor device $actor specified";
|
||||
PID20_Log $hash, 1, $msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
$hash->{helper}{actor} = $actor;
|
||||
$hash->{helper}{actorCommand} = ( defined($cmd) ) ? $cmd : "";
|
||||
$hash->{helper}{stopped} = 0;
|
||||
$hash->{helper}{adjust} = "";
|
||||
|
||||
$modules{PID20}{defptr}{$name} = $hash;
|
||||
|
||||
readingsSingleUpdate( $hash, 'state', 'initializing', 1 );
|
||||
|
||||
RemoveInternalTimer($name);
|
||||
InternalTimer( gettimeofday() + 10, "PID20_Calc", $name, 0 );
|
||||
return undef;
|
||||
@@ -208,28 +192,24 @@ PID20_Notify($$)
|
||||
my ( $hash, $dev ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $sensorName = $hash->{helper}{sensor};
|
||||
|
||||
my $DEBUG = AttrVal( $name, 'pidDebugNotify', '0' ) eq '1';
|
||||
|
||||
my $disable = AttrVal( $name, 'disable', '0' );
|
||||
|
||||
# no action if disabled
|
||||
if (defined($attr{$name}) && defined($attr{$name}{disable}) )
|
||||
if ( $disable eq '1' )
|
||||
{
|
||||
$hash->{helper}{sensorTsOld}=undef;
|
||||
return "";
|
||||
}
|
||||
|
||||
return if ( $dev->{NAME} ne $sensorName );
|
||||
|
||||
my $sensorReadingName = $hash->{helper}{reading};
|
||||
my $regexp = $hash->{helper}{regexp};
|
||||
my $desiredName = AttrVal( $name, 'pidDesiredName', 'desired' );
|
||||
my $desired = ReadingsVal( $name, $desiredName, undef );
|
||||
|
||||
my $max = int( @{ $dev->{CHANGED} } );
|
||||
PID20_Log $hash, 4, "check $max readings for " . $sensorReadingName;
|
||||
|
||||
for (my $i = 0; $i < $max; $i++) {
|
||||
for ( my $i = 0 ; $i < $max ; $i++ )
|
||||
{
|
||||
my $s = $dev->{CHANGED}[$i];
|
||||
|
||||
# continue, if no match with reading-name
|
||||
@@ -239,7 +219,6 @@ PID20_Notify($$)
|
||||
|
||||
# ---- build difference current - old value
|
||||
# get sensor value
|
||||
|
||||
my $sensorStr = ReadingsVal( $sensorName, $sensorReadingName, undef );
|
||||
$sensorStr =~ m/$regexp/;
|
||||
my $sensorValue = $1;
|
||||
@@ -247,11 +226,14 @@ PID20_Notify($$)
|
||||
# calc difference of delta/deltaOld
|
||||
my $delta = $desired - $sensorValue if ( defined($desired) );
|
||||
my $deltaOld = ( $hash->{helper}{deltaOld} + 0 ) if ( defined( $hash->{helper}{deltaOld} ) );
|
||||
|
||||
my $deltaDiff = ( $delta - $deltaOld ) if ( defined($delta) && defined($deltaOld) );
|
||||
PID20_Log $hash, 5, "Diff: delta[".sprintf( "%.2f",$delta)."]"
|
||||
." - deltaOld[".sprintf( "%.2f",$deltaOld)."]"
|
||||
."= Diff[".sprintf( "%.2f",$deltaDiff)."]"
|
||||
PID20_Log $hash, 5,
|
||||
"Diff: delta["
|
||||
. sprintf( "%.2f", $delta ) . "]"
|
||||
. " - deltaOld["
|
||||
. sprintf( "%.2f", $deltaOld ) . "]"
|
||||
. "= Diff["
|
||||
. sprintf( "%.2f", $deltaDiff ) . "]"
|
||||
if ($DEBUG);
|
||||
|
||||
# ----- build difference of timestamps (ok)
|
||||
@@ -263,21 +245,22 @@ PID20_Notify($$)
|
||||
PID20_Log $hash, 5, "tsDiff: tsDiff = $tsDiff " if ($DEBUG);
|
||||
|
||||
# ----- calculate gradient of delta
|
||||
my $deltaGradient =$deltaDiff/$tsDiff if(defined($deltaDiff) && defined($tsDiff) && ($tsDiff>0));
|
||||
my $deltaGradient = $deltaDiff / $tsDiff
|
||||
if ( defined($deltaDiff) && defined($tsDiff) && ( $tsDiff > 0 ) );
|
||||
$deltaGradient = 0 if ( !defined($deltaGradient) );
|
||||
|
||||
my $sdeltaDiff = ($deltaDiff) ? sprintf( "%.2f", $deltaDiff ) : "";
|
||||
my $sTSDiff = ($tsDiff) ? sprintf( "%.2f", $tsDiff ) : "";
|
||||
my $sDeltaGradient = ($deltaGradient) ? sprintf( "%.6f", $deltaGradient ) : "";
|
||||
PID20_Log $hash, 5, "deltaGradient: (Diff[$sdeltaDiff]"
|
||||
PID20_Log $hash, 5,
|
||||
"deltaGradient: (Diff[$sdeltaDiff]"
|
||||
. "/tsDiff[$sTSDiff]"
|
||||
."=deltaGradient per sec [$sDeltaGradient]" if ($DEBUG);
|
||||
. "=deltaGradient per sec [$sDeltaGradient]"
|
||||
if ($DEBUG);
|
||||
|
||||
# ----- store results
|
||||
$hash->{helper}{deltaGradient} = $deltaGradient;
|
||||
$hash->{helper}{deltaOld} = $delta;
|
||||
$hash->{helper}{deltaOldTS} = TimeNow();
|
||||
|
||||
last;
|
||||
}
|
||||
return "";
|
||||
@@ -307,7 +290,7 @@ sub PID20_Get($@)
|
||||
$ret .= 'Actor upper limit: ' . $hash->{helper}{actorLimitUpper} . "\n";
|
||||
return $ret;
|
||||
}
|
||||
default { return $usage; };
|
||||
default { return $usage; }
|
||||
}
|
||||
}
|
||||
########################################
|
||||
@@ -316,45 +299,40 @@ sub PID20_Set($@)
|
||||
my ( $hash, @a ) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $reFloat = '^([\\+,\\-]?\\d+\\.?\d*$)';
|
||||
|
||||
my $usage =
|
||||
"Unknown argument $a[1], choose one of stop:noArg start:noArg restart "
|
||||
. AttrVal( $name, 'pidDesiredName', 'desired' );
|
||||
return $usage if ( @a < 2 );
|
||||
|
||||
my $cmd = lc( $a[1] );
|
||||
my $desiredName = lc( AttrVal( $name, 'pidDesiredName', 'desired' ) );
|
||||
#PID20_Log $hash, 3, "name:$name cmd:$cmd $desired:$desired";
|
||||
|
||||
#PID20_Log $hash, 3, "name:$name cmd:$cmd $desired:$desired";
|
||||
given ($cmd)
|
||||
{
|
||||
when ("?")
|
||||
{
|
||||
return $usage;
|
||||
}
|
||||
|
||||
when ($desiredName)
|
||||
{
|
||||
return "Set " . AttrVal( $name, 'pidDesiredName', 'desired' ) . " needs a <value> parameter"
|
||||
return
|
||||
"Set "
|
||||
. AttrVal( $name, 'pidDesiredName', 'desired' )
|
||||
. " needs a <value> parameter"
|
||||
if ( @a != 3 );
|
||||
|
||||
my $value = $a[2];
|
||||
$value = ( $value =~ m/$reFloat/ ) ? $1 : undef;
|
||||
return "value " . $a[2] . " is not a number"
|
||||
if ( !defined($value) );
|
||||
|
||||
readingsSingleUpdate( $hash, $cmd, $value, 1 );
|
||||
PID20_Log $hash, 3, "set $name $cmd $a[2]";
|
||||
}
|
||||
|
||||
when ("start")
|
||||
{
|
||||
return "Set start needs a <value> parameter"
|
||||
if ( @a != 2 );
|
||||
$hash->{helper}{stopped} = 0;
|
||||
|
||||
}
|
||||
|
||||
when ("stop")
|
||||
{
|
||||
return "Set stop needs a <value> parameter"
|
||||
@@ -362,29 +340,24 @@ sub PID20_Set($@)
|
||||
$hash->{helper}{stopped} = 1;
|
||||
PID20_Calc($name);
|
||||
}
|
||||
|
||||
when ("restart")
|
||||
{
|
||||
return "Set restart needs a <value> parameter"
|
||||
if ( @a != 3 );
|
||||
|
||||
my $value = $a[2];
|
||||
$value = ( $value =~ m/$reFloat/ ) ? $1 : undef;
|
||||
#PID20_Log $hash, 1, "value:$value";
|
||||
|
||||
#PID20_Log $hash, 1, "value:$value";
|
||||
return "value " . $a[2] . " is not a number"
|
||||
if ( !defined($value) );
|
||||
|
||||
$hash->{helper}{stopped} = 0;
|
||||
$hash->{helper}{adjust} = $value;
|
||||
PID20_Log $hash, 3, "set $name $cmd $value";
|
||||
}
|
||||
|
||||
when ("calc") # inofficial function, only for debugging purposes
|
||||
{
|
||||
PID20_Calc($name);
|
||||
}
|
||||
|
||||
default
|
||||
{
|
||||
return $usage;
|
||||
@@ -392,7 +365,6 @@ sub PID20_Set($@)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
########################################
|
||||
# disabled = 0
|
||||
# idle = 1
|
||||
@@ -406,79 +378,77 @@ sub PID20_Calc($)
|
||||
my $reINT = '^([\\+,\\-]?\\d+$)'; # int
|
||||
my $reFloatpos = '^([\\+]?\\d+\\.?\d*$)'; # gleitpunkt positiv
|
||||
my $reFloat = '^([\\+,\\-]?\\d+\\.?\d*$)'; # gleitpunkt
|
||||
|
||||
my ($name) = @_;
|
||||
my $hash = $defs{$name};
|
||||
|
||||
my $sensor = $hash->{helper}{sensor};
|
||||
my $reading = $hash->{helper}{reading};
|
||||
my $regexp = $hash->{helper}{regexp};
|
||||
|
||||
my $DEBUG_Sensor = AttrVal( $name, 'pidDebugSensor', '0' ) eq '1';
|
||||
my $DEBUG_Actuation = AttrVal( $name, 'pidDebugActuation', '0' ) eq '1';
|
||||
my $DEBUG_Delta = AttrVal( $name, 'pidDebugDelta', '0' ) eq '1';
|
||||
my $DEBUG_Calc = AttrVal( $name, 'pidDebugCalc', '0' ) eq '1';
|
||||
my $DEBUG_Update = AttrVal( $name, 'pidDebugUpdate', '0' ) eq '1';
|
||||
|
||||
my $DEBUG = $DEBUG_Sensor || $DEBUG_Actuation || $DEBUG_Calc || $DEBUG_Delta || $DEBUG_Update;
|
||||
|
||||
my $actuation = "";
|
||||
my $actuationDone = ReadingsVal( $name, 'actuation', "" );
|
||||
my $actuationCalc = ReadingsVal( $name, 'actuationCalc', "" );
|
||||
my $actuationCalcOld = $actuationCalc;
|
||||
my $actorTimestamp = ($hash->{helper}{actorTimestamp})
|
||||
?$hash->{helper}{actorTimestamp}:FmtDateTime(gettimeofday()-3600*24);
|
||||
|
||||
my $actorTimestamp =
|
||||
( $hash->{helper}{actorTimestamp} )
|
||||
? $hash->{helper}{actorTimestamp}
|
||||
: FmtDateTime( gettimeofday() - 3600 * 24 );
|
||||
my $sensorStr = ReadingsVal( $sensor, $reading, "" );
|
||||
my $sensorValue = "";
|
||||
my $sensorTS = ReadingsTimestamp( $sensor, $reading, undef );
|
||||
my $sensorIsAlive = 0;
|
||||
|
||||
my $iPortion = ReadingsVal( $name, 'p_i', 0 );
|
||||
my $pPortion = "";
|
||||
my $dPortion = "";
|
||||
|
||||
my $stateStr = "";
|
||||
|
||||
my $deltaOld = ReadingsVal( $name, 'delta', 0 );
|
||||
my $delta = "";
|
||||
my $deltaGradient = ( $hash->{helper}{deltaGradient} ) ? $hash->{helper}{deltaGradient} : 0;
|
||||
|
||||
my $calcReq = 0;
|
||||
|
||||
# ---------------- check different conditions
|
||||
while (1)
|
||||
{
|
||||
# --------------- retrive values from attributes
|
||||
|
||||
$hash->{helper}{actorInterval} = (AttrVal($name, 'pidActorInterval', 180 ) =~ m/$reUINT/) ? $1:180;
|
||||
$hash->{helper}{actorThreshold} = (AttrVal($name, 'pidActorTreshold', 1 ) =~ m/$reUINT/) ? $1:1;
|
||||
$hash->{helper}{actorKeepAlive} = (AttrVal($name, 'pidActorKeepAlive', 1800 ) =~ m/$reUINT/) ? $1:1800;
|
||||
$hash->{helper}{actorValueDecPlaces} = (AttrVal($name, 'pidActorValueDecPlaces', 0 ) =~ m/$reUINT/) ? $1:0;
|
||||
|
||||
$hash->{helper}{actorErrorAction} = (AttrVal($name, 'pidActorErrorAction', 'freeze') eq 'errorPos') ?'errorPos':'freeze';
|
||||
$hash->{helper}{actorErrorPos} = (AttrVal($name, 'pidActorErrorPos', 0 ) =~ m/$reINT/) ? $1:0;
|
||||
|
||||
|
||||
$hash->{helper}{calcInterval} = (AttrVal($name, 'pidCalcInterval', 60 ) =~ m/$reUINT/) ? $1:60;
|
||||
$hash->{helper}{deltaTreshold} = (AttrVal($name, 'pidDeltaTreshold', 0 ) =~ m/$reFloatpos/) ? $1:0;
|
||||
$hash->{helper}{disable} = (AttrVal($name, 'Disable', 0 ) =~ m/$re01/) ? $1:'';
|
||||
|
||||
$hash->{helper}{sensorTimeout} = (AttrVal($name, 'pidSensorTimeout', 3600 ) =~ m/$reUINT/) ? $1:3600;
|
||||
$hash->{helper}{reverseAction} = (AttrVal($name, 'pidReverseAction', 0 ) =~ m/$re01/) ? $1:0;
|
||||
$hash->{helper}{updateInterval} = (AttrVal($name, 'pidUpdateInterval', 600 ) =~ m/$reUINT/) ? $1:600;
|
||||
|
||||
$hash->{helper}{actorInterval} =
|
||||
( AttrVal( $name, 'pidActorInterval', 180 ) =~ m/$reUINT/ ) ? $1 : 180;
|
||||
$hash->{helper}{actorThreshold} =
|
||||
( AttrVal( $name, 'pidActorTreshold', 1 ) =~ m/$reUINT/ ) ? $1 : 1;
|
||||
$hash->{helper}{actorKeepAlive} =
|
||||
( AttrVal( $name, 'pidActorKeepAlive', 1800 ) =~ m/$reUINT/ ) ? $1 : 1800;
|
||||
$hash->{helper}{actorValueDecPlaces} =
|
||||
( AttrVal( $name, 'pidActorValueDecPlaces', 0 ) =~ m/$reUINT/ ) ? $1 : 0;
|
||||
$hash->{helper}{actorErrorAction} =
|
||||
( AttrVal( $name, 'pidActorErrorAction', 'freeze' ) eq 'errorPos' ) ? 'errorPos' : 'freeze';
|
||||
$hash->{helper}{actorErrorPos} =
|
||||
( AttrVal( $name, 'pidActorErrorPos', 0 ) =~ m/$reINT/ ) ? $1 : 0;
|
||||
$hash->{helper}{calcInterval} =
|
||||
( AttrVal( $name, 'pidCalcInterval', 60 ) =~ m/$reUINT/ ) ? $1 : 60;
|
||||
$hash->{helper}{deltaTreshold} =
|
||||
( AttrVal( $name, 'pidDeltaTreshold', 0 ) =~ m/$reFloatpos/ ) ? $1 : 0;
|
||||
$hash->{helper}{disable} = ( AttrVal( $name, 'disable', 0 ) =~ m/$re01/ ) ? $1 : '';
|
||||
$hash->{helper}{sensorTimeout} =
|
||||
( AttrVal( $name, 'pidSensorTimeout', 3600 ) =~ m/$reUINT/ ) ? $1 : 3600;
|
||||
$hash->{helper}{reverseAction} =
|
||||
( AttrVal( $name, 'pidReverseAction', 0 ) =~ m/$re01/ ) ? $1 : 0;
|
||||
$hash->{helper}{updateInterval} =
|
||||
( AttrVal( $name, 'pidUpdateInterval', 600 ) =~ m/$reUINT/ ) ? $1 : 600;
|
||||
$hash->{helper}{measuredName} = AttrVal( $name, 'pidMeasuredName', 'measured' );
|
||||
$hash->{helper}{desiredName} = AttrVal( $name, 'pidDesiredName', 'desired' );
|
||||
|
||||
$hash->{helper}{actorLimitLower} = (AttrVal($name, 'pidActorLimitLower', 0) =~ m/$reFloat/) ? $1:0;
|
||||
$hash->{helper}{actorLimitLower} =
|
||||
( AttrVal( $name, 'pidActorLimitLower', 0 ) =~ m/$reFloat/ ) ? $1 : 0;
|
||||
my $actorLimitLower = $hash->{helper}{actorLimitLower};
|
||||
|
||||
$hash->{helper}{actorLimitUpper} = (AttrVal($name, 'pidActorLimitUpper', 100) =~ m/$reFloat/) ? $1:100;
|
||||
$hash->{helper}{actorLimitUpper} =
|
||||
( AttrVal( $name, 'pidActorLimitUpper', 100 ) =~ m/$reFloat/ ) ? $1 : 100;
|
||||
my $actorLimitUpper = $hash->{helper}{actorLimitUpper};
|
||||
|
||||
$hash->{helper}{factor_P} = (AttrVal($name, 'pidFactor_P', 25) =~ m/$reFloatpos/) ? $1:25;
|
||||
$hash->{helper}{factor_I} = (AttrVal($name, 'pidFactor_I', 0.25) =~ m/$reFloatpos/) ? $1:0.25;
|
||||
$hash->{helper}{factor_P} =
|
||||
( AttrVal( $name, 'pidFactor_P', 25 ) =~ m/$reFloatpos/ ) ? $1 : 25;
|
||||
$hash->{helper}{factor_I} =
|
||||
( AttrVal( $name, 'pidFactor_I', 0.25 ) =~ m/$reFloatpos/ ) ? $1 : 0.25;
|
||||
$hash->{helper}{factor_D} = ( AttrVal( $name, 'pidFactor_D', 0 ) =~ m/$reFloatpos/ ) ? $1 : 0;
|
||||
|
||||
if ( $hash->{helper}{disable} )
|
||||
@@ -486,13 +456,11 @@ sub PID20_Calc($)
|
||||
$stateStr = "disabled";
|
||||
last;
|
||||
}
|
||||
|
||||
if ( $hash->{helper}{stopped} )
|
||||
{
|
||||
$stateStr = "stopped";
|
||||
last;
|
||||
}
|
||||
|
||||
my $desired = ReadingsVal( $name, $hash->{helper}{desiredName}, "" );
|
||||
|
||||
# sensor found
|
||||
@@ -508,9 +476,13 @@ sub PID20_Calc($)
|
||||
$sensorStr =~ m/$regexp/;
|
||||
$sensorValue = $1;
|
||||
$sensorValue = "" if ( !defined($sensorValue) );
|
||||
PID20_Log $hash, 2, "S2 timeOfDay:".gettimeofday()
|
||||
." timeDiff:$timeDiff sensorTimeout:".$hash->{helper}{sensorTimeout}
|
||||
." --> sensorIsAlive:$sensorIsAlive" if ($DEBUG_Sensor);
|
||||
PID20_Log $hash, 2,
|
||||
"S2 timeOfDay:"
|
||||
. gettimeofday()
|
||||
. " timeDiff:$timeDiff sensorTimeout:"
|
||||
. $hash->{helper}{sensorTimeout}
|
||||
. " --> sensorIsAlive:$sensorIsAlive"
|
||||
if ($DEBUG_Sensor);
|
||||
}
|
||||
|
||||
# sensor dead
|
||||
@@ -521,17 +493,18 @@ sub PID20_Calc($)
|
||||
|
||||
# check delta threshold
|
||||
$delta = ( $desired ne "" && $sensorValue ne "" ) ? $desired - $sensorValue : "";
|
||||
|
||||
$calcReq = 1 if (!$stateStr && $delta ne "" && (abs($delta) >= abs( $hash->{helper}{deltaTreshold})) );
|
||||
|
||||
PID20_Log $hash, 2, "D1 desired[". ($desired ne "") ? sprintf( "%.1f", $desired) : ""
|
||||
."] - sensorValue: [". ($sensorValue ne "") ? sprintf( "%.1f", $sensorValue) : ""
|
||||
."] = delta[". ($delta ne "") ? sprintf( "%.2f", $delta):""
|
||||
."] calcReq:$calcReq"
|
||||
$calcReq = 1
|
||||
if ( !$stateStr
|
||||
&& $delta ne ""
|
||||
&& ( abs($delta) >= abs( $hash->{helper}{deltaTreshold} ) ) );
|
||||
PID20_Log $hash, 2,
|
||||
"D1 desired[" . ( $desired ne "" ) ? sprintf( "%.1f", $desired )
|
||||
: "" . "] - sensorValue: [" . ( $sensorValue ne "" ) ? sprintf( "%.1f", $sensorValue )
|
||||
: "" . "] = delta[" . ( $delta ne "" ) ? sprintf( "%.2f", $delta )
|
||||
: "" . "] calcReq:$calcReq"
|
||||
if ($DEBUG_Delta);
|
||||
|
||||
#request for calculation
|
||||
|
||||
# ---------------- calculation request
|
||||
if ($calcReq)
|
||||
{
|
||||
@@ -545,44 +518,43 @@ sub PID20_Calc($)
|
||||
# calc d-Portion
|
||||
$dPortion = ($deltaGradient) * $hash->{helper}{calcInterval} * $hash->{helper}{factor_D};
|
||||
|
||||
|
||||
# calc i-portion respecting windUp
|
||||
# freeze i-portion if windUp is active
|
||||
my $isWindup =
|
||||
$actuationCalcOld &&
|
||||
(
|
||||
( $workDelta > 0 && $actuationCalcOld > $actorLimitUpper )
|
||||
|| ( $workDelta < 0 && $actuationCalcOld < $actorLimitLower )
|
||||
);
|
||||
|
||||
my $isWindup = $actuationCalcOld
|
||||
&& (( $workDelta > 0 && $actuationCalcOld > $actorLimitUpper )
|
||||
|| ( $workDelta < 0 && $actuationCalcOld < $actorLimitLower ) );
|
||||
if ( $hash->{helper}{adjust} ne "" )
|
||||
{
|
||||
$iPortion = $hash->{helper}{adjust} - ( $pPortion + $dPortion );
|
||||
$iPortion = $actorLimitUpper if ( $iPortion > $actorLimitUpper );
|
||||
$iPortion = $actorLimitLower if ( $iPortion < $actorLimitLower );
|
||||
PID20_Log $hash, 5, "adjust request with:".$hash->{helper}{adjust}." ==> p_i:$iPortion";
|
||||
|
||||
PID20_Log $hash, 5,
|
||||
"adjust request with:" . $hash->{helper}{adjust} . " ==> p_i:$iPortion";
|
||||
$hash->{helper}{adjust} = "";
|
||||
}
|
||||
elsif ( !$isWindup ) # integrate only if no windUp
|
||||
} elsif ( !$isWindup ) # integrate only if no windUp
|
||||
{
|
||||
# normalize the intervall to minute=60 seconds
|
||||
$iPortion = $iPortion + $workDelta * $hash->{helper}{factor_I}*$hash->{helper}{calcInterval}/60;
|
||||
$iPortion =
|
||||
$iPortion +
|
||||
$workDelta * $hash->{helper}{factor_I} * $hash->{helper}{calcInterval} / 60;
|
||||
$hash->{helper}{isWindUP} = 0;
|
||||
}
|
||||
$hash->{helper}{isWindUP} = $isWindup;
|
||||
|
||||
# calc actuation
|
||||
$actuationCalc = $pPortion + $iPortion + $dPortion;
|
||||
PID20_Log $hash, 2, "P1 delta:".sprintf( "%.2f",$delta)
|
||||
." isWindup:$isWindup"
|
||||
PID20_Log $hash, 2, "P1 delta:" . sprintf( "%.2f", $delta ) . " isWindup:$isWindup"
|
||||
if ($DEBUG_Calc);
|
||||
PID20_Log $hash, 2,
|
||||
"P2 pPortion:"
|
||||
. sprintf( "%.2f", $pPortion )
|
||||
. " iPortion:"
|
||||
. sprintf( "%.2f", $iPortion )
|
||||
. " dPortion:"
|
||||
. sprintf( "%.2f", $dPortion )
|
||||
. " actuationCalc:"
|
||||
. sprintf( "%.2f", $actuationCalc )
|
||||
if ($DEBUG_Calc);
|
||||
|
||||
PID20_Log $hash, 2, "P2 pPortion:".sprintf( "%.2f",$pPortion)
|
||||
." iPortion:".sprintf( "%.2f",$iPortion)
|
||||
." dPortion:".sprintf( "%.2f",$dPortion)
|
||||
." actuationCalc:".sprintf( "%.2f", $actuationCalc) if ($DEBUG_Calc);
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate( $hash, 'p_p', $pPortion );
|
||||
readingsBulkUpdate( $hash, 'p_i', $iPortion );
|
||||
@@ -590,6 +562,7 @@ sub PID20_Calc($)
|
||||
readingsBulkUpdate( $hash, 'actuationCalc', $actuationCalc );
|
||||
readingsBulkUpdate( $hash, 'delta', $delta );
|
||||
readingsEndUpdate( $hash, 0 );
|
||||
|
||||
#PID20_Log $hash, 3, "calculation done";
|
||||
}
|
||||
|
||||
@@ -614,70 +587,75 @@ sub PID20_Calc($)
|
||||
# check if round request
|
||||
my $fmt = "%." . $hash->{helper}{actorValueDecPlaces} . "f";
|
||||
$actuation = sprintf( $fmt, $actuation ) if ( $actuation ne "" );
|
||||
|
||||
my $actuationDiff = abs( $actuation - $actuationDone) if ($actuation ne "" && $actuationDone ne "");
|
||||
PID20_Log $hash, 2, "A1 act:$actuation actDone:$actuationDone "
|
||||
." actThreshold:".$hash->{helper}{actorThreshold}
|
||||
my $actuationDiff = abs( $actuation - $actuationDone )
|
||||
if ( $actuation ne "" && $actuationDone ne "" );
|
||||
PID20_Log $hash, 2,
|
||||
"A1 act:$actuation actDone:$actuationDone "
|
||||
. " actThreshold:"
|
||||
. $hash->{helper}{actorThreshold}
|
||||
. " actDiff:$actuationDiff"
|
||||
if ($DEBUG_Actuation);
|
||||
|
||||
# check threshold-condition for actuation
|
||||
my $rsTS = $actuationDone ne "" # limit exceeded
|
||||
&& $actuationDiff >= $hash->{helper}{actorThreshold};
|
||||
|
||||
my $rsUp = $actuationDone ne "" # upper range
|
||||
&& $actuation > $actorLimitUpper - $hash->{helper}{actorThreshold}
|
||||
&& $actuationDiff != 0
|
||||
&& $actuation >= $actorLimitUpper;
|
||||
|
||||
my $rsDown = $actuationDone ne "" # low range
|
||||
&& $actuation < $actorLimitLower + $hash->{helper}{actorThreshold}
|
||||
&& $actuationDiff != 0
|
||||
&& $actuation <= $actorLimitLower;
|
||||
|
||||
my $rsLimit = $actuationDone ne ""
|
||||
&& ( $actuationDone < $actorLimitLower || $actuationDone > $actorLimitUpper );
|
||||
|
||||
my $actuationByThreshold = ( ( $rsTS || $rsUp || $rsDown ) && $noTrouble );
|
||||
|
||||
PID20_Log $hash, 2, "A2 rsTS:$rsTS rsUp:$rsUp rsDown:$rsDown noTrouble:$noTrouble" if ($DEBUG_Actuation);
|
||||
PID20_Log $hash, 2, "A2 rsTS:$rsTS rsUp:$rsUp rsDown:$rsDown noTrouble:$noTrouble"
|
||||
if ($DEBUG_Actuation);
|
||||
|
||||
# check time condition for actuation
|
||||
my $actTimeDiff = PID20_TimeDiff($actorTimestamp); # $actorTimestamp is valid in each case
|
||||
my $actuationByTime = ($noTrouble) && ( $actTimeDiff > $hash->{helper}{actorInterval} );
|
||||
|
||||
PID20_Log $hash, 2, "A3 actTS:$actorTimestamp"
|
||||
." actTimeDiff:".sprintf( "%.2f",$actTimeDiff)
|
||||
." actInterval:".$hash->{helper}{actorInterval}
|
||||
."-->actByTime:$actuationByTime " if ($DEBUG_Actuation);
|
||||
PID20_Log $hash, 2,
|
||||
"A3 actTS:$actorTimestamp"
|
||||
. " actTimeDiff:"
|
||||
. sprintf( "%.2f", $actTimeDiff )
|
||||
. " actInterval:"
|
||||
. $hash->{helper}{actorInterval}
|
||||
. "-->actByTime:$actuationByTime "
|
||||
if ($DEBUG_Actuation);
|
||||
|
||||
# check keep alive condition for actuation
|
||||
my $actuationKeepAliveReq = ( $actTimeDiff >= $hash->{helper}{actorKeepAlive} )
|
||||
if ( defined($actTimeDiff) && $actuation ne "" );
|
||||
|
||||
# summary actuation reques
|
||||
|
||||
my $actuationReq = (
|
||||
( $actuationByThreshold && $actuationByTime )
|
||||
|| $actuationKeepAliveReq
|
||||
|| $rsLimit
|
||||
|| $actuationDone eq "" # startup condition
|
||||
)
|
||||
&& $actuation ne "";
|
||||
|
||||
PID20_Log $hash, 2, "A4 (actByTh:$actuationByThreshold && actByTime:$actuationByTime)"
|
||||
) && $actuation ne "";
|
||||
PID20_Log $hash, 2,
|
||||
"A4 (actByTh:$actuationByThreshold && actByTime:$actuationByTime)"
|
||||
. "||actKeepAlive:$actuationKeepAliveReq"
|
||||
."||rsLimit:$rsLimit=actnReq:$actuationReq" if ($DEBUG_Actuation);
|
||||
. "||rsLimit:$rsLimit=actnReq:$actuationReq"
|
||||
if ($DEBUG_Actuation);
|
||||
|
||||
# perform output to actor
|
||||
if ($actuationReq)
|
||||
{
|
||||
#build command for fhem
|
||||
PID20_Log $hash, 5, "actor:".$hash->{helper}{actor}
|
||||
." actorCommand:".$hash->{helper}{actorCommand}
|
||||
." actuation:".$actuation;
|
||||
|
||||
my $cmd= sprintf("set %s %s %g", $hash->{helper}{actor}, $hash->{helper}{actorCommand},$actuation);
|
||||
PID20_Log $hash, 5,
|
||||
"actor:"
|
||||
. $hash->{helper}{actor}
|
||||
. " actorCommand:"
|
||||
. $hash->{helper}{actorCommand}
|
||||
. " actuation:"
|
||||
. $actuation;
|
||||
my $cmd = sprintf( "set %s %s %g",
|
||||
$hash->{helper}{actor},
|
||||
$hash->{helper}{actorCommand}, $actuation );
|
||||
|
||||
# execute command
|
||||
my $ret;
|
||||
@@ -690,13 +668,12 @@ sub PID20_Calc($)
|
||||
$retStr = " with return-value:" . $ret if ( defined($ret) && ( $ret ne '' ) );
|
||||
PID20_Log $hash, 3, "<$cmd> " . $retStr;
|
||||
}
|
||||
|
||||
my $updateAlive = ( $actuation ne "" )
|
||||
&& PID20_TimeDiff(ReadingsTimestamp( $name, 'actuation', gettimeofday()))>=$hash->{helper}{updateInterval};
|
||||
|
||||
&& PID20_TimeDiff( ReadingsTimestamp( $name, 'actuation', gettimeofday() ) ) >=
|
||||
$hash->{helper}{updateInterval};
|
||||
my $updateReq = ( ( $actuationReq || $updateAlive ) && $actuation ne "" );
|
||||
|
||||
PID20_Log $hash, 2, "U1 actReq:$actuationReq updateAlive:$updateAlive --> updateReq:$updateReq"
|
||||
PID20_Log $hash, 2,
|
||||
"U1 actReq:$actuationReq updateAlive:$updateAlive --> updateReq:$updateReq"
|
||||
if ($DEBUG_Update);
|
||||
|
||||
# ---------------- update request
|
||||
@@ -704,7 +681,8 @@ sub PID20_Calc($)
|
||||
{
|
||||
readingsBeginUpdate($hash);
|
||||
readingsBulkUpdate( $hash, $hash->{helper}{desiredName}, $desired ) if ( $desired ne "" );
|
||||
readingsBulkUpdate( $hash, $hash->{helper}{measuredName}, $sensorValue ) if ($sensorValue ne "");
|
||||
readingsBulkUpdate( $hash, $hash->{helper}{measuredName}, $sensorValue )
|
||||
if ( $sensorValue ne "" );
|
||||
readingsBulkUpdate( $hash, 'p_p', $pPortion ) if ( $pPortion ne "" );
|
||||
readingsBulkUpdate( $hash, 'p_d', $dPortion ) if ( $dPortion ne "" );
|
||||
readingsBulkUpdate( $hash, 'p_i', $iPortion ) if ( $iPortion ne "" );
|
||||
@@ -721,7 +699,6 @@ sub PID20_Calc($)
|
||||
$stateStr = "idle" if ( !$stateStr && !$calcReq );
|
||||
$stateStr = "processing" if ( !$stateStr && $calcReq );
|
||||
readingsSingleUpdate( $hash, 'state', $stateStr, 0 );
|
||||
|
||||
PID20_Log $hash, 2, "C1 stateStr:$stateStr calcReq:$calcReq" if ($DEBUG_Calc);
|
||||
|
||||
# timer setup
|
||||
@@ -730,11 +707,8 @@ sub PID20_Calc($)
|
||||
InternalTimer( $next, "PID20_Calc", $name, 1 );
|
||||
|
||||
#PID20_Log $hash, 2, "InternalTimer next:".FmtDateTime($next)." PID20_Calc name:$name DEBUG_Calc:$DEBUG_Calc";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
|
||||
Reference in New Issue
Block a user