update secop_psi/sea.py

fixes after serveral changes in frappy
This commit is contained in:
zolliker 2022-04-29 16:30:19 +02:00
parent 1ded96abba
commit f9db90d89b
2 changed files with 54 additions and 29 deletions

View File

@ -71,6 +71,9 @@ class GeneralConfig:
if configfile is None: if configfile is None:
configfile = environ.get('FRAPPY_CONFIG_FILE', configfile = environ.get('FRAPPY_CONFIG_FILE',
path.join(cfg['confdir'], 'generalConfig.cfg')) path.join(cfg['confdir'], 'generalConfig.cfg'))
configfile = path.expanduser(configfile)
if not path.exists(configfile):
raise FileNotFoundError(configfile)
if configfile and path.exists(configfile): if configfile and path.exists(configfile):
parser = ConfigParser() parser = ConfigParser()
parser.optionxform = str parser.optionxform = str

View File

@ -40,8 +40,9 @@ from os.path import expanduser, join, exists
from secop.client import ProxyClient from secop.client import ProxyClient
from secop.datatypes import ArrayOf, BoolType, \ from secop.datatypes import ArrayOf, BoolType, \
EnumType, FloatRange, IntRange, StringType EnumType, FloatRange, IntRange, StringType
from secop.errors import ConfigError, HardwareError, secop_error, NoSuchModuleError from secop.errors import ConfigError, HardwareError, secop_error, NoSuchModuleError, \
from secop.lib import getGeneralConfig, mkthread, formatExtendedStack CommunicationFailedError
from secop.lib import generalConfig, mkthread, formatExtendedStack
from secop.lib.asynconn import AsynConn, ConnectionClosed from secop.lib.asynconn import AsynConn, ConnectionClosed
from secop.modules import Attached, Command, Done, Drivable, \ from secop.modules import Attached, Command, Done, Drivable, \
Module, Parameter, Property, Readable, Writable Module, Parameter, Property, Readable, Writable
@ -73,7 +74,7 @@ SERVICE_NAMES = {
} }
SEA_DIR = expanduser('~/sea') SEA_DIR = expanduser('~/sea')
for confdir in getGeneralConfig()['confdir'].split(os.pathsep): for confdir in generalConfig.confdir.split(os.pathsep):
seaconfdir = join(confdir, 'sea') seaconfdir = join(confdir, 'sea')
if exists(seaconfdir): if exists(seaconfdir):
break break
@ -108,6 +109,7 @@ class SeaClient(ProxyClient, Module):
service = Property("main/stick/addons", StringType(), default='') service = Property("main/stick/addons", StringType(), default='')
visibility = 'expert' visibility = 'expert'
default_json_file = {} default_json_file = {}
_connect_thread = None
def __init__(self, name, log, opts, srv): def __init__(self, name, log, opts, srv):
instance = srv.node_cfg['name'].rsplit('_', 1)[0] instance = srv.node_cfg['name'].rsplit('_', 1)[0]
@ -123,8 +125,8 @@ class SeaClient(ProxyClient, Module):
config = opts.get('config') config = opts.get('config')
if config: if config:
self.default_json_file[name] = config.split()[0] + '.json' self.default_json_file[name] = config.split()[0] + '.json'
self.io = None self.syncio = None
self.asyncio = None self.asynio = None
ProxyClient.__init__(self) ProxyClient.__init__(self)
Module.__init__(self, name, log, opts, srv) Module.__init__(self, name, log, opts, srv)
@ -133,42 +135,58 @@ class SeaClient(ProxyClient, Module):
self.path2param.update(module.path2param) self.path2param.update(module.path2param)
self.register_callback(module.name, module.updateEvent) self.register_callback(module.name, module.updateEvent)
def startModule(self, started_callback): def startModule(self, start_events):
mkthread(self._connect, started_callback) super().startModule(start_events)
self._connect_thread = mkthread(self._connect, start_events.get_trigger())
def _connect(self, started_callback): def _connect(self, started_callback):
if '//' not in self.uri: if '//' not in self.uri:
self.uri = 'tcp://' + self.uri self.uri = 'tcp://' + self.uri
self.asyncio = AsynConn(self.uri) self.asynio = AsynConn(self.uri)
assert self.asyncio.readline() == b'OK' # print('CONNECT', self.uri, self.asynio)
self.asyncio.writeline(b'Spy 007') # print(formatExtendedStack())
assert self.asyncio.readline() == b'Login OK' reply = self.asynio.readline()
if reply != b'OK':
raise CommunicationFailedError('reply %r should be "OK"' % reply)
for _ in range(2):
self.asynio.writeline(b'Spy 007')
reply = self.asynio.readline()
if reply == b'Login OK':
break
else:
raise CommunicationFailedError('reply %r should be "Login OK"' % reply)
self.request('frappy_config %s %s' % (self.service, self.config)) self.request('frappy_config %s %s' % (self.service, self.config))
# frappy_async_client switches to the json protocol (better for updates) # frappy_async_client switches to the json protocol (better for updates)
self.asyncio.writeline(b'frappy_async_client') self.asynio.writeline(b'frappy_async_client')
self.asyncio.writeline(('get_all_param ' + ' '.join(self.objects)).encode()) self.asynio.writeline(('get_all_param ' + ' '.join(self.objects)).encode())
self._connect_thread = None
mkthread(self._rxthread, started_callback) mkthread(self._rxthread, started_callback)
def request(self, command): def request(self, command):
"""send a request and wait for reply""" """send a request and wait for reply"""
with self._write_lock: with self._write_lock:
if not self.io or not self.io.connection: if not self.syncio or not self.syncio.connection:
if not self.asyncio or not self.asyncio.connection: if not self.asynio or not self.asynio.connection:
try:
self._connect_thread.join()
except AttributeError:
pass
self._connect(None) self._connect(None)
self.io = AsynConn(self.uri) self.syncio = AsynConn(self.uri)
assert self.io.readline() == b'OK' # print('SYNCIO', self.uri)
self.io.writeline(b'seauser seaser') assert self.syncio.readline() == b'OK'
assert self.io.readline() == b'Login OK' self.syncio.writeline(b'seauser seaser')
assert self.syncio.readline() == b'Login OK'
print('connected to %s' % self.uri) print('connected to %s' % self.uri)
self.io.flush_recv() self.syncio.flush_recv()
# print('> %s' % command) # print('> %s' % command)
self.io.writeline(('fulltransact %s' % command).encode()) self.syncio.writeline(('fulltransact %s' % command).encode())
result = None result = None
deadline = time.time() + 10 deadline = time.time() + 10
while time.time() < deadline: while time.time() < deadline:
try: try:
reply = self.io.readline() reply = self.syncio.readline()
if reply is None: if reply is None:
continue continue
except ConnectionClosed: except ConnectionClosed:
@ -197,7 +215,7 @@ class SeaClient(ProxyClient, Module):
def _rxthread(self, started_callback): def _rxthread(self, started_callback):
while not self.shutdown: while not self.shutdown:
try: try:
reply = self.asyncio.readline() reply = self.asynio.readline()
if reply is None: if reply is None:
continue continue
except ConnectionClosed: except ConnectionClosed:
@ -252,7 +270,7 @@ class SeaClient(ProxyClient, Module):
if path == '/device/changetime': if path == '/device/changetime':
result = self.request('check_config %s %s' % (self.service, self.config)) result = self.request('check_config %s %s' % (self.service, self.config))
if result == '1': if result == '1':
self.asyncio.writeline(('get_all_param ' + ' '.join(self.objects)).encode()) self.asynio.writeline(('get_all_param ' + ' '.join(self.objects)).encode())
else: else:
self.DISPATCHER.shutdown() self.DISPATCHER.shutdown()
elif path.startswith('/device/frappy_%s' % self.service) and value == '': elif path.startswith('/device/frappy_%s' % self.service) and value == '':
@ -293,7 +311,7 @@ class SeaClient(ProxyClient, Module):
class SeaConfigCreator(SeaClient): class SeaConfigCreator(SeaClient):
def startModule(self, started_callback): def startModule(self, started_callback):
"""save objects (and sub-objects) description and exit""" """save objects (and sub-objects) description and exit"""
self._connect(lambda: None) self._connect(None)
reply = self.request('describe_all') reply = self.request('describe_all')
reply = ''.join('' if line.startswith('WARNING') else line for line in reply.split('\n')) reply = ''.join('' if line.startswith('WARNING') else line for line in reply.split('\n'))
description, reply = json.loads(reply) description, reply = json.loads(reply)
@ -369,7 +387,6 @@ def get_datatype(paramdesc):
class SeaModule(Module): class SeaModule(Module):
io = Attached() io = Attached()
# pollerClass=None
path2param = None path2param = None
sea_object = None sea_object = None
hdbpath = None # hdbpath for main writable hdbpath = None # hdbpath for main writable
@ -457,6 +474,7 @@ class SeaModule(Module):
if issubclass(cls, SeaWritable): if issubclass(cls, SeaWritable):
paramdesc = params[0] paramdesc = params[0]
assert paramdesc['key'] == 'value' assert paramdesc['key'] == 'value'
params.append(paramdesc.copy()) # copy value?
if paramdesc.get('readonly', True): if paramdesc.get('readonly', True):
raise ConfigError('%s/%s is not writable' % (sea_object, paramdesc['path'])) raise ConfigError('%s/%s is not writable' % (sea_object, paramdesc['path']))
paramdesc['key'] = 'target' paramdesc['key'] = 'target'
@ -476,10 +494,12 @@ class SeaModule(Module):
path = paramdesc['path'] path = paramdesc['path']
readonly = paramdesc.get('readonly', True) readonly = paramdesc.get('readonly', True)
dt = get_datatype(paramdesc) dt = get_datatype(paramdesc)
#print('----', sea_object)
#print(dt, paramdesc)
kwds = dict(description=paramdesc.get('description', path), kwds = dict(description=paramdesc.get('description', path),
datatype=dt, datatype=dt,
visibility=paramdesc.get('visibility', 1), visibility=paramdesc.get('visibility', 1),
needscfg=False, poll=False, readonly=readonly) needscfg=False, readonly=readonly)
if kwds['datatype'] is None: if kwds['datatype'] is None:
kwds.update(visibility=3, default='', datatype=StringType()) kwds.update(visibility=3, default='', datatype=StringType())
pathlist = path.split('/') if path else [] pathlist = path.split('/') if path else []
@ -531,6 +551,7 @@ class SeaModule(Module):
# an updateEvent will be handled before above returns # an updateEvent will be handled before above returns
return reply return reply
rfunc.poll = False
attributes['read_' + key] = rfunc attributes['read_' + key] = rfunc
if not readonly: if not readonly:
@ -555,13 +576,11 @@ class SeaModule(Module):
attributes[pname] = pobj attributes[pname] = pobj
pobj.__set_name__(cls, pname) pobj.__set_name__(cls, pname)
elif pname not in attributes and isinstance(pobj, Parameter): elif pname not in attributes and isinstance(pobj, Parameter):
pobj.poll = False
pobj.needscfg = False pobj.needscfg = False
attributes[pname] = pobj attributes[pname] = pobj
pobj.__set_name__(cls, pname) pobj.__set_name__(cls, pname)
classname = '%s_%s' % (cls.__name__, sea_object) classname = '%s_%s' % (cls.__name__, sea_object)
attributes['pollerClass'] = None
newcls = type(classname, (cls,), attributes) newcls = type(classname, (cls,), attributes)
return Module.__new__(newcls) return Module.__new__(newcls)
@ -592,6 +611,9 @@ class SeaModule(Module):
self.io.register_obj(self, self.sea_object) self.io.register_obj(self, self.sea_object)
super().initModule() super().initModule()
def doPoll(self):
pass
class SeaReadable(SeaModule, Readable): class SeaReadable(SeaModule, Readable):