2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-22 02:10:32 +00:00

98_Modbus.pm: small bugfix regarding update timer

git-svn-id: https://svn.fhem.de/fhem/trunk@17880 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
StefanStrobel 2018-12-02 09:21:09 +00:00
parent 1ed4a9cea9
commit 5834221233

View File

@ -124,6 +124,7 @@
# 2018-10-12 smaller bugfixes, new attributes enableQueueLengthReading and retriesAfterTimeout # 2018-10-12 smaller bugfixes, new attributes enableQueueLengthReading and retriesAfterTimeout
# 2018-11-05 use DevIO_IsOpen, check if fc6 can be used or fc16 needs to be used, rework open calls # 2018-11-05 use DevIO_IsOpen, check if fc6 can be used or fc16 needs to be used, rework open calls
# 2018-11-10 fixed setExpr -> setexpr # 2018-11-10 fixed setExpr -> setexpr
# 2018-12-01 fixed bug in startUpdateTimer when interval > timeout of a slave
# #
# #
# #
@ -305,9 +306,9 @@ sub ModbusLD_Set($@);
sub ModbusLD_GetUpdate($); sub ModbusLD_GetUpdate($);
sub ModbusLD_GetIOHash($); sub ModbusLD_GetIOHash($);
sub ModbusLD_DoRequest($$$;$$$); sub ModbusLD_DoRequest($$$;$$$);
sub ModbusLD_StartUpdateTimer($;$); sub ModbusLD_StartUpdateTimer($);
my $Modbus_Version = '4.0.17 - 10.11.2018'; my $Modbus_Version = '4.0.18 - 1.12.2018';
my $Modbus_PhysAttrs = my $Modbus_PhysAttrs =
"queueDelay " . "queueDelay " .
"queueMax " . "queueMax " .
@ -585,8 +586,6 @@ sub ModbusLD_Define($$)
$hash->{MODBUSID} = $id; $hash->{MODBUSID} = $id;
$hash->{MODE} = $mode; $hash->{MODE} = $mode;
$hash->{PROTOCOL} = $proto; $hash->{PROTOCOL} = $proto;
$hash->{INTERVAL} = $interval if ($interval);
$hash->{RELAY} = $relay if ($relay);
$hash->{'.getList'} = ""; $hash->{'.getList'} = "";
$hash->{'.setList'} = ""; $hash->{'.setList'} = "";
$hash->{".updateSetGet"} = 1; $hash->{".updateSetGet"} = 1;
@ -594,6 +593,17 @@ sub ModbusLD_Define($$)
$hash->{NOTIFYDEV} = "global"; # NotifyFn nur aufrufen wenn global events (INITIALIZED etc.) $hash->{NOTIFYDEV} = "global"; # NotifyFn nur aufrufen wenn global events (INITIALIZED etc.)
$hash->{MODULEVERSION} = "Modbus $Modbus_Version"; $hash->{MODULEVERSION} = "Modbus $Modbus_Version";
if ($interval) {
$hash->{INTERVAL} = $interval;
} else {
delete $hash->{INTERVAL};
}
if ($relay) {
$hash->{RELAY} = $relay;
} else {
delete $hash->{RELAY};
}
if ($dest) { # Modbus über TCP mit IP Adresse (TCP oder auch RTU/ASCII über TCP) if ($dest) { # Modbus über TCP mit IP Adresse (TCP oder auch RTU/ASCII über TCP)
$dest .= ":502" if ($dest !~ /.*:[0-9]/); # add default port if no port specified $dest .= ":502" if ($dest !~ /.*:[0-9]/); # add default port if no port specified
$hash->{DeviceName} = $dest; # needed by DevIo to get Device, Port, Speed etc. $hash->{DeviceName} = $dest; # needed by DevIo to get Device, Port, Speed etc.
@ -835,7 +845,7 @@ sub ModbusLD_Attr(@)
Log3 $name, 3, "$name: no IODev for communication"; Log3 $name, 3, "$name: no IODev for communication";
} }
} }
ModbusLD_StartUpdateTimer($hash, 1); # first Update in 1 second or aligned if interval is defined ModbusLD_StartUpdateTimer($hash); # first Update in 1 second or aligned if interval is defined
} }
} }
return; return;
@ -1479,7 +1489,7 @@ sub Modbus_Notify($$)
} }
# logical device going through an IO Device # logical device going through an IO Device
if ($hash->{TYPE} ne "Modbus" && $hash->{MODE} eq 'master') { if ($hash->{TYPE} ne "Modbus" && $hash->{MODE} eq 'master') {
ModbusLD_StartUpdateTimer($hash, 1); # logical device -> first Update in 1 second or aligned if interval is defined ModbusLD_StartUpdateTimer($hash); # logical device -> first Update in 1 second or aligned if interval is defined
# relay device to communicate through # relay device to communicate through
} elsif ($hash->{MODE} && $hash->{MODE} eq 'relay') { # Mode relay -> find / check relay device } elsif ($hash->{MODE} && $hash->{MODE} eq 'relay') { # Mode relay -> find / check relay device
@ -3551,31 +3561,61 @@ sub Modbus_Send($$$;$)
# set internal Timer to call GetUpdate if necessary # set internal Timer to call GetUpdate if necessary
# either at next interval # either at next interval
# or if start is passed in start seconds (e.g. 2 seconds after Fhem init) # or if start is passed in start seconds (e.g. 2 seconds after Fhem init)
sub ModbusLD_StartUpdateTimer($;$) # called from attr (disable, alignTime), set (interval, start), openCB,
# notify (INITIALIZED|REREADCFG|MODIFIED|DEFINED) and getUpdate
# problem: when disconected while waiting for next update cycle,
# StartUpdateTimer gets called after immediate reopen.
# Timer should be set as short as possible (>= lastUpdate + Interval)
# or if timeAlign, then
# how to set timer after a new open?
# if timer is still running, just keep it
# but maybe alignTime was set in the meantime -> timer needs new alignment now or after next update
# if alignTime didn't change, timer can be kept.
#
# if timer is not running and last update was longer ago than interval, schedule update to happen immediately
#
sub ModbusLD_StartUpdateTimer($)
{ {
my ($hash, $start) = @_; my ($hash) = @_;
my $nextTrigger; my $name = $hash->{NAME};
my $name = $hash->{NAME}; my $now = gettimeofday();
my $now = gettimeofday(); my $action = "updated timer";
$start = 0 if (!$start); my $intvl = ($hash->{INTERVAL} ? $hash->{INTERVAL} : 0);
my $delay;
my $nextUpdate;
#Log3 $name, 5, "$name: StartUpdateTimer called from " . Modbus_Caller(); Log3 $name, 5, "$name: StartUpdateTimer called from " . Modbus_Caller();
if ($intvl > 0) { # there is an interval -> set timer
if ($hash->{INTERVAL} && $hash->{INTERVAL} > 0) {
if ($hash->{TimeAlign}) { if ($hash->{TimeAlign}) {
my $count = int(($now - $hash->{TimeAlign} + $start) / $hash->{INTERVAL}); # it doesn't matter when last update was, or if timer is still set. we can always calculate next update
my $curCycle = $hash->{TimeAlign} + $count * $hash->{INTERVAL}; my $start = ($hash->{lastUpdate} ? 0 : 2); # first update at least 2 secs from now
$nextTrigger = $curCycle + $hash->{INTERVAL}; my $count = int(($now - $hash->{TimeAlign} + $start) / $intvl);
$nextUpdate = $hash->{TimeAlign} + $count * $intvl + $intvl;
} elsif ($hash->{TRIGGERTIME} && $hash->{TRIGGERTIME} <= ($now + $intvl)) {
# timer is still set and shorter than new calculation -> keep and log
$action = "kept existing timer";
$nextUpdate = $hash->{TRIGGERTIME};
} elsif (!$hash->{lastUpdate}) {
# first time timer is set
$action = "initialisation";
$nextUpdate = $now + 2;
} else { } else {
$nextTrigger = $now + ($start ? $start : $hash->{INTERVAL}); $nextUpdate = $hash->{lastUpdate} + $intvl;
$nextUpdate = $now if ($nextUpdate < $now );
} }
$hash->{TRIGGERTIME} = $nextTrigger; $hash->{TRIGGERTIME} = $nextUpdate;
$hash->{TRIGGERTIME_FMT} = FmtDateTime($nextTrigger); $hash->{TRIGGERTIME_FMT} = FmtDateTime($nextUpdate);
$delay = sprintf ("%.1f", $nextUpdate - $now);
Log3 $name, 5, "$name: SetartUpdateTimer $action, will call GetUpdate in $delay sec at $hash->{TRIGGERTIME_FMT}, interval $intvl";
RemoveInternalTimer("update:$name"); RemoveInternalTimer("update:$name");
InternalTimer($nextTrigger, "ModbusLD_GetUpdate", "update:$name", 0); InternalTimer($nextUpdate, "ModbusLD_GetUpdate", "update:$name", 0);
Log3 $name, 4, "$name: SetUpdateTimer updated timer - will call GetUpdate in " .
sprintf ("%.1f", $nextTrigger - $now) . " seconds at $hash->{TRIGGERTIME_FMT} - Interval $hash->{INTERVAL}"; } else { # no interval -> no timer
} else {
ModbusLD_StopUpdateTimer($hash); ModbusLD_StopUpdateTimer($hash);
} }
return; return;
@ -3593,6 +3633,7 @@ sub ModbusLD_StopUpdateTimer($)
Log3 $name, 4, "$name: internal update interval timer stopped"; Log3 $name, 4, "$name: internal update interval timer stopped";
delete $hash->{TRIGGERTIME}; delete $hash->{TRIGGERTIME};
delete $hash->{TRIGGERTIME_FMT}; delete $hash->{TRIGGERTIME_FMT};
$hash->{TRIGGERTIME_SAVED} = $hash->{TRIGGERTIME};
} }
return; return;
} }
@ -3617,7 +3658,10 @@ sub ModbusLD_GetUpdate($) {
my $now = gettimeofday(); my $now = gettimeofday();
Log3 $name, 5, "$name: GetUpdate called from " . Modbus_Caller(); Log3 $name, 5, "$name: GetUpdate called from " . Modbus_Caller();
$hash->{lastUpdate} = $now;
if ($calltype eq "update") { if ($calltype eq "update") {
delete $hash->{TRIGGERTIME};
delete $hash->{TRIGGERTIME_FMT};
ModbusLD_StartUpdateTimer($hash); ModbusLD_StartUpdateTimer($hash);
} }