import logging from frappy.client import SecopClient def convert_par(module, name, par): result = dict(type='input', name=module+":"+name, title=name) if par.get('readonly', True): result['type'] = 'rdonly' else: result['command'] = 'change %s:%s' % (module, name) if par['datainfo']['type'] == 'enum': result['enum_names'] = [dict(title=k, value=v) for k, v in par['datainfo']['members'].items()] result['type'] = 'enum' elif par['datainfo']['type'] == 'bool': result['type'] = 'checkbox' if par['description']: result['info'] = par['description'] return result def convert_cmd(module, name, cmd): result = dict(type='pushbutton', name=module+":"+name, title=name) result['command'] = 'do %s:%s' % (module, name) argument = cmd['datainfo'].get('argument') if cmd['datainfo'].get('result'): result['result'] = True else: if not argument: # simple command like stop return result result['button'] = not argument # result['type'] = pushbutton will be replaced below if argument: if argument['type'] == 'enum': result['enum_names'] = [dict(title=k, value=v) for k, v in argument['members'].items()] result['type'] = 'enum' elif argument['type'] == 'bool': result['type'] = 'checkbox' else: result['type'] = 'input' else: result['type'] = 'rdonly' if cmd['description']: result['info'] = cmd['description'] return result 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.change_callback = change_callback try: self.connect() self.update_node_map(node_map) self.register_callback(None, descriptiveDataChange=self.descChanged) except Exception as e: print(repr(e)) def update_node_map(self, node_map): node_map.update({k: self for k in self.modules}) def descChanged(self, module, desc): if module is None and self.change_callback: self.change_callback() def add_main_components(self, components): for name, desc in self.modules.items(): parameters = desc['parameters'] component = {'type': 'rdonly' if 'value' in parameters else 'none'} if 'status' in parameters: component['statusname'] = f'{name}:status' targetpar = parameters.get('target') if targetpar: component.update(convert_par(name, 'target', targetpar)) component['targetname'] = f'{name}:target' info = desc['properties'].get('description') if info: component['info'] = info component['name'] = f'{name}:value' component['title'] = name components.append(component) def get_components(self, path): module = self.modules[path] parameters = dict(module["parameters"]) components = [] for name in SecopInteractor.skip_par: if name in parameters: parameters.pop(name) for name in SecopInteractor.prio_par: if name in parameters: components.append(convert_par(path, name, parameters.pop(name))) components1 = [] for name in SecopInteractor.hide_par: if name in parameters: components1.append(convert_par(path, name, parameters.pop(name))) for name, par in parameters.items(): components.append(convert_par(path, name, par)) components.extend(components1) for name, cmd in module.get("commands", {}).items(): components.append(convert_cmd(path, name, cmd)) return components 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""" if not command.strip(): return dict(type='accept-command') is_param = True if command.startswith('change '): command = command[7:] elif command.startswith('do '): is_param = False command = command[3:] modpar, _, strvalue = command.partition(' ') module, _, parameter = modpar.partition(':') if not parameter: parameter = 'target' if module not in self.modules: return None logging.info('SENDCOMMAND %r', command) if is_param: try: entry = self.setParameterFromString(module, parameter, strvalue) item = {'name': f'{module}:{parameter}', 'value': str(entry), 'formatted': entry.formatted()} except Exception as e: print(f"{e!r} converting {strvalue} to {self.modules[module]['parameters'][parameter]['datatype']}") self.updates[module, parameter] = item return True # called a command 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, 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"]