Files
seweb/secop.py
2024-10-23 16:34:12 +02:00

163 lines
6.0 KiB
Python

import logging
import uuid
from base import Instrument, get_abs_time
from frappy.client import SecopClient as SecNodeClient
from frappy.lib.enum import EnumMember
from frappy.datatypes import get_datatype
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'
return result
class SecopClient:
prio_par = ["value", "status", "target"]
hide_par = ["baseclass", "class", "pollinterval"]
skip_par = ["status2"]
def __init__(self, instrument):
self.instrument = instrument
self.id = uuid.uuid4().hex[0:15]
self.module_updates = set()
self.param_updates = set()
self.updates = {}
def w_getblock(self, path):
path = path.split(',')[-1] # TODO: why this?
if path == "main":
components = [dict(type='rdlink', name=name+':value', title=name)
for node in self.instrument.nodes for name in node.modules]
self.param_updates = {'value'}
return dict(type='draw', path='main', title='modules', components=components)
self.module_updates.add(path) # TODO: remove others?
node = self.instrument.node_map[path]
module = node.modules[path]
# logging.info('MP %r', path)
parameters = dict(module["parameters"])
components = []
for name in SecopClient.skip_par:
if name in parameters:
parameters.pop(name)
for name in SecopClient.prio_par:
if name in parameters:
components.append(convert_par(path, name, parameters.pop(name)))
components1 = []
for name in SecopClient.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]))
components.extend(components1)
return dict(type='draw', path=path, title=path, components=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)}
else:
item = {'name': name, 'value': str(entry), 'formatted': entry.formatted()}
# print(item)
self.updates[key] = item
def w_updateblock(self, path):
if path == 'main':
path = ''
for node in self.instrument.nodes:
for modname in node.modules:
key = modname, 'value'
if key in node.cache:
self.updateItem(*key, node.cache[key])
else:
node = self.instrument.node_map[path]
for param in node.modules[path]['parameters']:
key = path, param
if key in node.cache:
self.updateItem(*key, node.cache[key])
return dict(type='accept-block')
def w_console(self):
return dict(type='accept-console')
def w_sendcommand(self, command):
logging.info('SENDCOMMAND %r', command)
if not command.strip():
return dict(type='accept-command')
if command.startswith('change '):
command = command[7:]
modpar, _, strvalue = command.partition(' ')
module, _, parameter = modpar.partition(':')
if not parameter:
parameter = 'target'
node = self.instrument.node_map[module]
try:
node.setParameterFromString(module, parameter, strvalue)
except Exception as e:
print(f"{e!r} converting {strvalue} to {node.modules[module]['parameters'][parameter]['datatype']}")
return dict(type='accept-command')
def w_gettime(self, time):
"""parse time (using server time)
time: comma separated time range (beg,end) values < 1 year are treated as relative to the current time
"""
time = [float(t) for t in time.split(',')]
return dict(type='time', time=get_abs_time(time))
def poll(self):
updates, self.updates = self.updates, {}
if not updates:
return []
messages = [dict(type='update', updates=list(updates.values()))]
return messages
def info(self):
return ["na"]
class SecopInstrument(Instrument):
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 = 'UNDEFINED'
self.nodes = []
self.node_map = {}
for host_port in host_ports.split(','):
node = SecNodeClient(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))