diff --git a/base.py b/base.py index e5586e9..af93f43 100644 --- a/base.py +++ b/base.py @@ -48,6 +48,8 @@ class Client(HandlerBase): self.id = uuid.uuid4().hex[0:15] self.nodes = {} self.node_map = {} + self.update_filter = set() # modules to be updated + self.cache = {} # a dict to store the current state of all values if streams: for uri in streams: urisplit = uri.rsplit('://') @@ -69,12 +71,11 @@ class Client(HandlerBase): self.server = server self.instrument_name = instrument_name self.device_name = device_name # do not know if this is needed - self.updates = {} def poll(self): - updates = sum((n.get_updates() for n in self.nodes.values()), start=[]) + updates = sum((n.get_updates(self.cache, self.update_filter) for n in self.nodes.values()), start=[]) result = [dict(type='update', updates=updates)] if updates else [] - graph_updates = self.handlers.get('graphpoll', object)() + graph_updates = self.handlers.get('graphpoll', type(None))() if graph_updates: result.append(graph_updates) return result @@ -91,11 +92,9 @@ class Client(HandlerBase): def w_updateblock(self, path): if path == 'main': # TODO: change to "-main-"? - for node in self.nodes.values(): - node.update_main() + self.update_filter.add('') # ready to accept updates for main block else: - node = self.node_map[path] - node.update_params(path) + self.update_filter.add(path) return dict(type='accept-block') def w_console(self): # TODO: check if still used diff --git a/secop.py b/secop.py index 6b697d0..539ab17 100644 --- a/secop.py +++ b/secop.py @@ -48,17 +48,15 @@ class SecopInteractor(SecopClient): prio_par = ["value", "status", "target"] hide_par = ["baseclass", "class", "pollinterval"] skip_par = ["status2"] + main_params = {'value', 'status', 'param'} def __init__(self, uri, node_map, change_callback=None): super().__init__(uri) - self.module_updates = set() - self.param_updates = set() - self.updates = {} self.change_callback = change_callback try: self.connect() self.update_node_map(node_map) - self.register_callback(None, updateItem=self.updateItem, descriptiveDataChange=self.descChanged) + self.register_callback(None, descriptiveDataChange=self.descChanged) except Exception as e: print(repr(e)) @@ -85,13 +83,9 @@ class SecopInteractor(SecopClient): component['name'] = f'{name}:value' component['title'] = name components.append(component) - self.param_updates.add('value') - self.param_updates.add('status') - self.param_updates.add('target') def get_components(self, path): module = self.modules[path] - self.module_updates.add(path) # TODO: remove others? parameters = dict(module["parameters"]) components = [] for name in SecopInteractor.skip_par: @@ -111,38 +105,19 @@ class SecopInteractor(SecopClient): components.append(convert_cmd(path, name, cmd)) return components - def updateItem(self, module, parameter, entry): - key = module, parameter - # print(key, entry) - if module in self.module_updates or parameter in self.param_updates: - name = f'{module}:{parameter}' - if entry.readerror: - item = {'name': name, 'error': str(entry.readerror)} - elif parameter == 'status': - # statuscode: 0: DISABLED, 1: IDLE, 2: WARN, 3: BUSY, 4: ERROR - statuscode, statustext = entry[0] - formatted = statuscode.name + (f', {statustext}' if statustext else '') - item = {'name': name, 'value': str(entry), 'statuscode': entry[0][0] // 100, - 'formatted': formatted} - else: - item = {'name': name, 'value': str(entry), 'formatted': entry.formatted()} - # print(item) - self.updates[key] = item - - def update_main(self): - cache = self.cache - for modname in self.modules: - for param in 'value', 'status', 'target': - key = modname, param - if key in cache: - self.updateItem(*key, cache[key]) - - def update_params(self, path): - cache = self.cache - for param in self.modules[path]['parameters']: - key = path, param - if key in cache: - self.updateItem(*key, cache[key]) + def buildUpdateEvent(self, module, parameter, entry): + name = f'{module}:{parameter}' + if entry.readerror: + item = {'name': name, 'error': str(entry.readerror)} + elif parameter == 'status': + # statuscode: 0: DISABLED, 1: IDLE, 2: WARN, 3: BUSY, 4: ERROR + statuscode, statustext = entry[0] + formatted = statuscode.name + (f', {statustext}' if statustext else '') + item = {'name': name, 'value': str(entry), 'statuscode': entry[0][0] // 100, + 'formatted': formatted} + else: + item = {'name': name, 'value': str(entry), 'formatted': entry.formatted()} + return item def handle_command(self, command): """handle command if we can, else return False""" @@ -170,12 +145,20 @@ class SecopInteractor(SecopClient): self.updates[module, parameter] = item return True # called a command - formatted = self.execCommandFromString(module, parameter, strvalue)[0] # ignore qualifiers - return {'name': f'{module}:{parameter}', 'value': str(result), 'formatted': formatted} + item = self.execCommandFromString(module, parameter, strvalue)[0] # ignore qualifiers + return {'name': f'{module}:{parameter}', 'value': str(item.value), 'formatted': item.formatted()} - def get_updates(self): - updates, self.updates = self.updates, {} - return list(updates.values()) + def get_updates(self, client_state, update_filter): + updates = [] + main_params = self.main_params if '' in update_filter else () + for (module, param), item in self.cache.items(): + if param in main_params or module in update_filter: + key = module, param + prev = client_state.get(key) + if prev is None or item.value != prev.value or item.readerror != prev.readerror: + updates.append(self.buildUpdateEvent(module, param, item)) + client_state[key] = item + return updates def info(self): return ["na"]