From d76d79aebb6c2cb4bcd43f54747d8e48750e105c Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 10 Nov 2021 09:27:15 +0100 Subject: [PATCH] omit updates of unchanged values within short time Sometimes it happens, that the same value determined once is assigned several times to a parameter within a very short period. Sending multiple updates is not useful in this case. Change-Id: Icea66934c831fd9b2eac7d0394a124d002469914 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27091 Tested-by: Jenkins Automated Tests Reviewed-by: Markus Zolliker --- secop/modules.py | 25 ++++++++++++++----------- secop/protocol/dispatcher.py | 3 ++- test/test_iohandler.py | 6 ++++++ test/test_modules.py | 6 +++++- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/secop/modules.py b/secop/modules.py index 5504680..4f48517 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -29,7 +29,7 @@ from collections import OrderedDict from secop.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \ IntRange, StatusType, StringType, TextType, TupleOf -from secop.errors import BadValueError, ConfigError, InternalError, \ +from secop.errors import BadValueError, ConfigError, \ ProgrammingError, SECoPError, SilentError, secop_error from secop.lib import formatException, mkthread from secop.lib.enum import Enum @@ -243,12 +243,12 @@ class Module(HasAccessibles): # reference to the dispatcher (used for sending async updates) DISPATCHER = None - pollerClass = Poller #: default poller used def __init__(self, name, logger, cfgdict, srv): # remember the dispatcher object (for the async callbacks) self.DISPATCHER = srv.dispatcher + self.omit_unchanged_within = getattr(self.DISPATCHER, 'omit_unchanged_within', 0.1) self.log = logger self.name = name self.valueCallbacks = {} @@ -441,18 +441,21 @@ class Module(HasAccessibles): def announceUpdate(self, pname, value=None, err=None, timestamp=None): """announce a changed value or readerror""" pobj = self.parameters[pname] - if value is not None: - pobj.value = value # store the value even in case of error + timestamp = timestamp or time.time() + changed = pobj.value != value + try: + # store the value even in case of error + pobj.value = pobj.datatype(value) + except Exception as e: + if not err: # do not overwrite given error + err = e if err: - if not isinstance(err, SECoPError): - err = InternalError(err) + err = secop_error(err) if str(err) == str(pobj.readerror): return # do call updates for repeated errors - else: - try: - pobj.value = pobj.datatype(value) - except Exception as e: - err = secop_error(e) + elif not changed and timestamp < (pobj.timestamp or 0) + self.omit_unchanged_within: + # no change within short time -> omit + return pobj.timestamp = timestamp or time.time() pobj.readerror = err if pobj.export: diff --git a/secop/protocol/dispatcher.py b/secop/protocol/dispatcher.py index d9e27fc..7d9f7ff 100644 --- a/secop/protocol/dispatcher.py +++ b/secop/protocol/dispatcher.py @@ -60,10 +60,11 @@ def make_update(modulename, pobj): class Dispatcher: - def __init__(self, name, logger, options, srv): # to avoid errors, we want to eat all options here self.equipment_id = options.pop('id', name) + # time interval for omitting updates of unchanged values + self.omit_unchanged_within = options.pop('omit_unchanged_within', 0.1) self.nodeprops = {} for k in list(options): self.nodeprops[k] = options.pop(k) diff --git a/test/test_iohandler.py b/test/test_iohandler.py index 03dd95b..f860a10 100644 --- a/test/test_iohandler.py +++ b/test/test_iohandler.py @@ -71,6 +71,12 @@ class Data: class DispatcherStub: + # the first update from the poller comes a very short time after the + # initial value from the timestamp. However, in the test below + # the second update happens after the updates dict is cleared + # -> we have to inhibit the 'omit unchanged update' feature + omit_unchanged_within = 0 + def __init__(self, updates): self.updates = updates diff --git a/test/test_modules.py b/test/test_modules.py index 3bfe4e7..22bbeeb 100644 --- a/test/test_modules.py +++ b/test/test_modules.py @@ -34,7 +34,11 @@ from secop.poller import BasicPoller class DispatcherStub: - OMIT_UNCHANGED_WITHIN = 0 + # the first update from the poller comes a very short time after the + # initial value from the timestamp. However, in the test below + # the second update happens after the updates dict is cleared + # -> we have to inhibit the 'omit unchanged update' feature + omit_unchanged_within = 0 def __init__(self, updates): self.updates = updates