diff --git a/base.py b/base.py index 1fd0f81..6f4438d 100644 --- a/base.py +++ b/base.py @@ -88,10 +88,14 @@ class Client(HandlerBase): return dict(type='accept-console') def w_sendcommand(self, command): + result = None for node in self.nodes.values(): - if node.handle_command(command): + result = node.handle_command(command) + if result is not None: break - return dict(type='accept-command') + if isinstance(result, str): + return dict(type='accept-command', result=result) + return dict(type='accept-command') # TODO: how to handle result is None? def info(self): return ["na"] diff --git a/client/jsFiles/SEAWebClientCommunication.js b/client/jsFiles/SEAWebClientCommunication.js index b85cfa8..5e38b52 100644 --- a/client/jsFiles/SEAWebClientCommunication.js +++ b/client/jsFiles/SEAWebClientCommunication.js @@ -277,7 +277,7 @@ function updateStatus(component) { case 3: status_icon.classList.add('status-icon-busy'); break; - case 3: + case 4: status_icon.classList.add('status-icon-error'); break; } diff --git a/secop.py b/secop.py index fc4867c..1d2489d 100644 --- a/secop.py +++ b/secop.py @@ -1,8 +1,5 @@ import logging -from base import HandlerBase from frappy.client import SecopClient -# from frappy.lib.enum import EnumMember -# from frappy.datatypes import get_datatype def convert_par(module, name, par): @@ -21,6 +18,25 @@ def convert_par(module, name, par): return result +def convert_cmd(module, name, cmd): + result = dict(type='input', button=True, 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 + 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'] = 'rdonly' + if cmd['description']: + result['info'] = cmd['description'] + return result + + class SecopInteractor(SecopClient): prio_par = ["value", "status", "target"] hide_par = ["baseclass", "class", "pollinterval"] @@ -40,6 +56,8 @@ class SecopInteractor(SecopClient): component = dict(type='rdlink', name=f'{name}:value', title=name) if 'status' in desc['parameters']: component['statusname'] = f'{name}:status' + if 'target' in desc['parameters']: + component['targetname'] = f'{name}:target' info = desc['properties'].get('description') if info: component['info'] = info @@ -63,9 +81,11 @@ class SecopInteractor(SecopClient): for name in SecopInteractor.hide_par: if name in parameters: components1.append(convert_par(path, name, parameters.pop(name))) - for name, p in parameters.items(): - components.append(convert_par(path, name, parameters[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 updateItem(self, module, parameter, entry): @@ -89,9 +109,10 @@ class SecopInteractor(SecopClient): def update_main(self): cache = self.cache for modname in self.modules: - key = modname, 'value' - if key in cache: - self.updateItem(*key, cache[key]) + 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 @@ -104,20 +125,28 @@ class SecopInteractor(SecopClient): """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[7:] modpar, _, strvalue = command.partition(' ') module, _, parameter = modpar.partition(':') if not parameter: parameter = 'target' if module not in self.modules: - return False + return None logging.info('SENDCOMMAND %r', command) try: - self.setParameterFromString(module, parameter, strvalue) + if is_param: + self.setParameterFromString(module, parameter, strvalue) + result = True + else: + result = self.execCommandFromString(module, parameter, strvalue)[0] except Exception as e: print(f"{e!r} converting {strvalue} to {self.modules[module]['parameters'][parameter]['datatype']}") - return True + return result def get_updates(self): updates, self.updates = self.updates, {} @@ -125,39 +154,3 @@ class SecopInteractor(SecopClient): def info(self): return ["na"] - - -# class SecopInstrument(HandlerBase): -# -# def __init__(self, inst_name, instrument_config): -# super().__init__() -# self.instrument_config = instrument_config -# host_ports = instrument_config['hostport'] -# self.logger_dir = instrument_config.get('logger_dir', '') -# # test_day = instrument_config.get('test_day', None) -# # self.test_day = [int(x) for x in test_day.split('-')] if test_day else None -# self.title = inst_name -# self.device = '' -# self.nodes = [] -# self.node_map = {} -# for host_port in host_ports.split(','): -# node = SecopClient(host_port) -# node.connect() -# self.nodes.append(node) -# for name, mod in node.modules.items(): -# self.node_map[name] = node -# -# def register(self, client): -# print('OPEN') -# for node in self.nodes: -# node.register_callback(None, client.updateItem) -# return super().register(client) -# -# def remove(self, client): -# print('REMOVE') -# for node in self.nodes: -# node.unregister_callback(None, client.updateItem) -# super().remove(client) -# -# def new_client(self): -# return self.register(SecopClient(self))