From 2d310bc612b428cffcb9b78f247a36c48d499a86 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Tue, 12 Jan 2021 15:41:06 +0100 Subject: [PATCH] TupleOf and StructOf create multiple curves the components of TupleOf and StructOf are storead as separate curves in history Change-Id: I42ebf84653408de7148796763a4d4ea9dd309696 --- secop/histwriter.py | 103 ++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/secop/histwriter.py b/secop/histwriter.py index 251a878..4123671 100644 --- a/secop/histwriter.py +++ b/secop/histwriter.py @@ -21,15 +21,40 @@ import time from secop.datatypes import get_datatype, IntRange, FloatRange, ScaledInteger,\ EnumType, BoolType, StringType, TupleOf, StructOf -import history.histwriter +import histreader.histwriter as histwriter -class HistWriter(history.histwriter.HistWriter): +def make_cvt_list(dt, tail=''): + """create conversion list + + list of tuple (, , ) + tail is a postfix to be appended in case of tuples and structs + """ + if isinstance(dt, (EnumType, IntRange, BoolType)): + return[(int, tail, dict(type='NUM'))] + if isinstance(dt, (FloatRange, ScaledInteger)): + return [(dt.import_value, tail, dict(type='NUM', unit=dt.unit, period=5) if dt.unit else {})] + if isinstance(dt, StringType): + return [(lambda x: x, tail, dict(type='STR'))] + if isinstance(dt, TupleOf): + items = enumerate(dt.members) + elif isinstance(dt, StructOf): + items = dt.members.items() + else: + return [] # ArrayType, BlobType and TextType are ignored: too much data, probably not used + result = [] + for subkey, elmtype in items: + for fun, tail, opts in make_cvt_list(elmtype, '%s.%s' % (tail, subkey)): + result.append((lambda v, k=subkey, f=fun: f(v[k]), tail, opts)) + return result + + +class HistWriter(histwriter.HistWriter): """extend writer to be used as an internal frappy connection""" def __init__(self, directory, predefined_names, dispatcher): super().__init__(directory) self.predefined_names = predefined_names - self.parameters = {} # dict of (, ) + self.cvt_lists = {} # dict of self.activated = False self.dispatcher = dispatcher self._init_time = None @@ -38,7 +63,6 @@ class HistWriter(history.histwriter.HistWriter): def init(self, msg): action, _, description = msg assert action == 'describing' - vars = [] self._init_time = time.time() for modname, moddesc in description['modules'].items(): @@ -47,14 +71,19 @@ class HistWriter(history.histwriter.HistWriter): if pname.startswith('_') and pname[1:] not in self.predefined_names: key = modname + ':' + pname[1:] dt = get_datatype(pdesc['datainfo']) - - if pname == 'value': - continuous = isinstance(dt, (FloatRange, ScaledInteger)) - vars.append('%s|%s|%s||%d' % (key, dt.unit or '1', modname, continuous)) - elif pname == 'target': - vars.append('%s|%s|%s_target||0' % (key, dt.unit or '1', modname)) - self.parameters[ident] = dt, key - self.put(self._init_time, 'STR', 'vars', ' '.join(vars)) + cvt_list = make_cvt_list(dt, key) + for _, hkey, opts in cvt_list: + if pname == 'value': + opts['period'] = opts.get('period', 0) + opts['show'] = True + opts['label'] = modname + elif pname == 'target': + opts['period'] = 0 + opts['label'] = modname + '_target' + opts['show'] = True + self.put_def(hkey, opts) + self.cvt_lists[ident] = cvt_list + # self.put(self._init_time, 'STR', 'vars', ' '.join(vars)) self.dispatcher.handle_activate(self, None, None) self._init_time = None return @@ -64,45 +93,17 @@ class HistWriter(history.histwriter.HistWriter): if not action.endswith('update'): print('unknown async message %r' % msg) return - now = self._init_time or time.time() # on initialisation, make all timestamps equal - dt, key = self.parameters[ident] + now = self._init_time or time.time() # on initialisation, us the same timestamp for all if action == 'update': - - def convert(value, dt, key): - if isinstance(dt, (EnumType, IntRange, BoolType)): - return [('NUM', key, str(int(value)))] - if isinstance(dt, (FloatRange, ScaledInteger)): - return [('NUM', key, str(dt.import_value(value)))] - if isinstance(dt, StringType): - return [('STR', key, value)] - if isinstance(dt, TupleOf): - return sum((convert(value[i], d, '%s.%s' % (key, i)) for i, d in enumerate(dt.members)), []) - if isinstance(dt, StructOf): - return sum((convert(value[k], d, '%s.%s' % (key, k)) for d, k in dt.members.items()), []) - # ArrayType, BlobType and TextType are not considered: too much data, proabably not used - return [] - - # omit qualifiers. we do not use the timestamp here, as a potentially decreasing - # values might get the reader software into trouble - result = convert(value[0], dt, key) - for htype, key, strval in convert(value[0], dt, key): - self.put(now, htype, key, strval) + for fun, key, opts in self.cvt_lists[ident]: + # we only look at the value, qualifiers are ignored for now + # we do not use the timestamp here, as a potentially decreasing value might + # bring the reader software into trouble + self.put(now, key, str(fun(value[0]))) else: # error_update - old = self.cache.get(key) - if old is None: - return # ignore if this key is not yet used - - def get_keys(dt, key): - if isinstance(dt, (IntRange, FloatRange, ScaledInteger, BoolType, EnumType)): - return [('NUM', key)] - if isinstance(dt, StringType): - return [('STR', key)] - if isinstance(dt, TupleOf): - return sum((get_keys(d, '%s.%s' % (key, i)) for i, d in enumerate(dt.members)), []) - if isinstance(dt, StructOf): - return sum((get_keys(d, '%s.%s' % (key, k)) for d, k in dt.members.items()), []) - return [] - - for htype, key in get_keys(dt, key): - self.put(now, htype, key, '') + for _, key, _ in self.cvt_lists[ident]: + old = self.cache.get(key) + if old is None: + return # ignore if this key is not yet used + self.put(now, key, '')