Merge branch 'wip' of gitlab.psi.ch-samenv:samenv/frappy into wip

This commit is contained in:
zolliker 2023-05-31 08:43:19 +02:00
commit 726665ebd8
8 changed files with 397 additions and 70 deletions

20
cfg/main/haakeuro_cfg.py Normal file
View File

@ -0,0 +1,20 @@
Node(
description = '''Haake thermostat + Eurotherm controller''',
id = haakeuro.config.sea.psi.ch,
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for haakeuro.config',
config = 'haakeuro.config',
service = 'main',
)
Mod('th',
'frappy_psi.sea.SeaDrivable', '',
io = 'sea_main',
sea_object = 'th',
)
Mod('te',
'frappy_psi.sea.SeaDrivable', '',
io = 'sea_main',
sea_object = 'te',
)

View File

@ -0,0 +1,160 @@
{"th": {"base": "/th", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run th", "kids": 26},
{"path": "unit", "type": "text", "readonly": false, "cmd": "th unit", "visibility": 3},
{"path": "t2", "type": "float", "visibility": 3},
{"path": "set", "type": "float"},
{"path": "running", "type": "int", "readonly": false, "cmd": "th running", "visibility": 3},
{"path": "extcontrol", "type": "int", "readonly": false, "cmd": "th extcontrol", "visibility": 3},
{"path": "relais", "type": "int", "visibility": 3},
{"path": "overtemp", "type": "int", "visibility": 3},
{"path": "lowlevel", "type": "int", "visibility": 3},
{"path": "pumpalarm", "type": "int", "visibility": 3},
{"path": "externalarm", "type": "int", "visibility": 3},
{"path": "coolalarm", "type": "int", "visibility": 3},
{"path": "sensor1alarm", "type": "int", "visibility": 3},
{"path": "sensor2alarm", "type": "int", "visibility": 3},
{"path": "reset", "type": "int", "readonly": false, "cmd": "th reset", "visibility": 3},
{"path": "with2sensors", "type": "int", "readonly": false, "cmd": "th with2sensors", "visibility": 3},
{"path": "upperLimit", "type": "float", "readonly": false, "cmd": "th upperLimit"},
{"path": "lowerLimit", "type": "float", "readonly": false, "cmd": "th lowerLimit"},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "th tolerance"},
{"path": "maxwait", "type": "int", "readonly": false, "cmd": "th maxwait"},
{"path": "settle", "type": "int", "readonly": false, "cmd": "th settle"},
{"path": "targetValue", "type": "float"},
{"path": "is_running", "type": "int", "visibility": 3},
{"path": "verbose", "type": "int", "readonly": false, "cmd": "th verbose", "visibility": 3},
{"path": "driver", "type": "text", "visibility": 3},
{"path": "creationCmd", "type": "text", "visibility": 3},
{"path": "status", "type": "text", "readonly": false, "cmd": "th status"}]},
"te": {"base": "/te", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run te", "kids": 30},
{"path": "unit", "type": "text", "readonly": false, "cmd": "te unit", "visibility": 3},
{"path": "mode", "type": "int", "readonly": false, "cmd": "te mode"},
{"path": "model", "type": "text", "visibility": 3},
{"path": "pbPow", "type": "float", "visibility": 3},
{"path": "pbMin", "type": "float", "visibility": 3},
{"path": "pbScl", "type": "float", "visibility": 3},
{"path": "output", "type": "float"},
{"path": "position", "type": "float", "readonly": false, "cmd": "te position"},
{"path": "asymmetry", "type": "float", "readonly": false, "cmd": "te asymmetry", "visibility": 3},
{"path": "range", "type": "float", "readonly": false, "cmd": "te range", "visibility": 3},
{"path": "set", "type": "float", "readonly": false, "cmd": "te set"},
{"path": "rdonly", "type": "int", "readonly": false, "cmd": "te rdonly", "visibility": 3},
{"path": "task", "type": "text", "readonly": false, "cmd": "te task"},
{"path": "upperLimit", "type": "float", "readonly": false, "cmd": "te upperLimit"},
{"path": "lowerLimit", "type": "float", "readonly": false, "cmd": "te lowerLimit", "visibility": 3},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "te tolerance"},
{"path": "maxwait", "type": "int", "readonly": false, "cmd": "te maxwait"},
{"path": "settle", "type": "int", "readonly": false, "cmd": "te settle"},
{"path": "targetValue", "type": "float"},
{"path": "is_running", "type": "int", "visibility": 3},
{"path": "verbose", "type": "int", "readonly": false, "cmd": "te verbose", "visibility": 3},
{"path": "driver", "type": "text", "visibility": 3},
{"path": "creationCmd", "type": "text", "visibility": 3},
{"path": "status", "type": "text", "readonly": false, "cmd": "te status"},
{"path": "pb", "type": "float", "readonly": false, "cmd": "te pb"},
{"path": "ti", "type": "float", "readonly": false, "cmd": "te ti"},
{"path": "td", "type": "float", "readonly": false, "cmd": "te td"},
{"path": "manual", "type": "float", "readonly": false, "cmd": "te manual"},
{"path": "rate", "type": "float", "readonly": false, "cmd": "te rate"},
{"path": "workset", "type": "float", "readonly": false, "cmd": "te workset"}]},
"cc": {"base": "/cc", "params": [
{"path": "", "type": "bool", "kids": 96},
{"path": "send", "type": "text", "readonly": false, "cmd": "cc send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "autodevice", "type": "bool", "readonly": false, "cmd": "cc autodevice"},
{"path": "fav", "type": "bool", "readonly": false, "cmd": "cc fav"},
{"path": "f", "type": "float", "visibility": 3},
{"path": "fs", "type": "enum", "enum": {"ok": 0, "no_sens": 1}, "readonly": false, "cmd": "cc fs", "visibility": 3},
{"path": "mav", "type": "bool", "readonly": false, "cmd": "cc mav"},
{"path": "fm", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}, "visibility": 3},
{"path": "fa", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "offline": 3}, "readonly": false, "cmd": "cc fa", "visibility": 3},
{"path": "mp", "type": "float", "readonly": false, "cmd": "cc mp", "visibility": 3},
{"path": "msp", "type": "float", "visibility": 3},
{"path": "mmp", "type": "float", "visibility": 3},
{"path": "mc", "type": "float", "readonly": false, "cmd": "cc mc", "visibility": 3},
{"path": "mfc", "type": "float", "readonly": false, "cmd": "cc mfc", "visibility": 3},
{"path": "moc", "type": "float", "readonly": false, "cmd": "cc moc", "visibility": 3},
{"path": "mtc", "type": "float", "readonly": false, "cmd": "cc mtc", "visibility": 3},
{"path": "mtl", "type": "float", "visibility": 3},
{"path": "mft", "type": "float", "readonly": false, "cmd": "cc mft", "visibility": 3},
{"path": "mt", "type": "float", "visibility": 3},
{"path": "mo", "type": "float", "visibility": 3},
{"path": "mcr", "type": "float", "visibility": 3},
{"path": "mot", "type": "float", "visibility": 3},
{"path": "mw", "type": "float", "readonly": false, "cmd": "cc mw", "description": "correction pulse after automatic open", "visibility": 3},
{"path": "hav", "type": "bool", "readonly": false, "cmd": "cc hav"},
{"path": "h", "type": "float", "visibility": 3},
{"path": "hr", "type": "float", "visibility": 3},
{"path": "hc", "type": "float", "visibility": 3},
{"path": "hu", "type": "float", "visibility": 3},
{"path": "hh", "type": "float", "readonly": false, "cmd": "cc hh", "visibility": 3},
{"path": "hl", "type": "float", "readonly": false, "cmd": "cc hl", "visibility": 3},
{"path": "htf", "type": "float", "readonly": false, "cmd": "cc htf", "description": "meas. period in fast mode", "visibility": 3},
{"path": "hts", "type": "float", "readonly": false, "cmd": "cc hts", "description": "meas. period in slow mode", "visibility": 3},
{"path": "hd", "type": "float", "readonly": false, "cmd": "cc hd", "visibility": 3},
{"path": "hwr", "type": "float", "readonly": false, "cmd": "cc hwr", "visibility": 3},
{"path": "hem", "type": "float", "readonly": false, "cmd": "cc hem", "description": "sensor length in mm from top to empty pos.", "visibility": 3},
{"path": "hfu", "type": "float", "readonly": false, "cmd": "cc hfu", "description": "sensor length in mm from top to full pos.", "visibility": 3},
{"path": "hcd", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3, "manual": 7}, "readonly": false, "cmd": "cc hcd", "visibility": 3},
{"path": "hv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4}, "visibility": 3},
{"path": "hsf", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "ha", "type": "bool", "readonly": false, "cmd": "cc ha", "visibility": 3},
{"path": "hm", "type": "bool", "visibility": 3},
{"path": "hf", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf", "visibility": 3},
{"path": "hbe", "type": "bool", "readonly": false, "cmd": "cc hbe", "visibility": 3},
{"path": "hmf", "type": "float", "visibility": 3},
{"path": "hms", "type": "float", "visibility": 3},
{"path": "hit", "type": "float", "readonly": false, "cmd": "cc hit", "visibility": 3},
{"path": "hft", "type": "int", "readonly": false, "cmd": "cc hft", "visibility": 3},
{"path": "hea", "type": "enum", "enum": {"0": 0, "1": 1, "6": 6}, "readonly": false, "cmd": "cc hea"},
{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch", "visibility": 3},
{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0", "visibility": 3},
{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos.", "visibility": 3},
{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos.", "visibility": 3},
{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)", "visibility": 3},
{"path": "h0", "type": "float", "visibility": 3},
{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "h1", "type": "float", "visibility": 3},
{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "h2", "type": "float", "visibility": 3},
{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "h3", "type": "float", "visibility": 3},
{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "h4", "type": "float", "visibility": 3},
{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "h5", "type": "float", "visibility": 3},
{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
{"path": "hfb", "type": "float", "visibility": 3},
{"path": "nav", "type": "bool", "readonly": false, "cmd": "cc nav"},
{"path": "nu", "type": "float", "visibility": 3},
{"path": "nl", "type": "float", "visibility": 3},
{"path": "nth", "type": "float", "readonly": false, "cmd": "cc nth", "visibility": 3},
{"path": "ntc", "type": "float", "readonly": false, "cmd": "cc ntc", "visibility": 3},
{"path": "ntm", "type": "float", "readonly": false, "cmd": "cc ntm", "visibility": 3},
{"path": "ns", "type": "enum", "enum": {"sens_ok": 0, "no_sens": 1, "short_circuit": 2, "upside_down": 3, "sens_warm": 4, "empty": 5}, "visibility": 3},
{"path": "na", "type": "bool", "readonly": false, "cmd": "cc na", "visibility": 3},
{"path": "nv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4, "boost": 5}, "visibility": 3},
{"path": "nc", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3}, "readonly": false, "cmd": "cc nc", "visibility": 3},
{"path": "nfb", "type": "float", "visibility": 3},
{"path": "cda", "type": "float"},
{"path": "cdb", "type": "float"},
{"path": "cba", "type": "float"},
{"path": "cbb", "type": "float"},
{"path": "cvs", "type": "int"},
{"path": "csp", "type": "int"},
{"path": "cdv", "type": "text", "readonly": false, "cmd": "cc cdv"},
{"path": "cic", "type": "text", "readonly": false, "cmd": "cc cic"},
{"path": "cin", "type": "text"},
{"path": "cds", "type": "enum", "enum": {"local": 0, "remote": 1, "loading": 2, "by_code": 3, "by_touch": 4}, "readonly": false, "cmd": "cc cds"},
{"path": "timing", "type": "bool", "readonly": false, "cmd": "cc timing"},
{"path": "tc", "type": "float", "visibility": 3},
{"path": "tn", "type": "float", "visibility": 3},
{"path": "th", "type": "float", "visibility": 3},
{"path": "tf", "type": "float", "visibility": 3},
{"path": "tm", "type": "float", "visibility": 3},
{"path": "tv", "type": "float", "visibility": 3},
{"path": "tq", "type": "float", "visibility": 3},
{"path": "bdl", "type": "float", "readonly": false, "cmd": "cc bdl"}]}}

View File

@ -245,8 +245,10 @@ class ProxyClient:
except UnregisterCallback: except UnregisterCallback:
cblist.remove(cbfunc) cblist.remove(cbfunc)
except Exception as e: except Exception as e:
# the programmer should catch all errors in callbacks
# if not, the log will be flooded with errors
if self.log: if self.log:
self.log.error('error %r calling %s%r', e, cbfunc.__name__, args) self.log.exception('error %r calling %s%r', e, cbfunc.__name__, args)
return bool(cblist) return bool(cblist)
def updateValue(self, module, param, value, timestamp, readerror): def updateValue(self, module, param, value, timestamp, readerror):
@ -398,6 +400,7 @@ class SecopClient(ProxyClient):
value = data[0] value = data[0]
readerror = None readerror = None
module, param = module_param module, param = module_param
timestamp = min(time.time(), timestamp) # no timestamps in the future!
try: try:
self.updateValue(module, param, value, timestamp, readerror) self.updateValue(module, param, value, timestamp, readerror)
except KeyError: except KeyError:

View File

@ -405,4 +405,8 @@ def merge_status(*args):
texts matching maximal code are joined with ', ' texts matching maximal code are joined with ', '
""" """
maxcode = max(a[0] for a in args) maxcode = max(a[0] for a in args)
return maxcode, ', '.join([a[1] for a in args if a[0] == maxcode and a[1]]) # take status value matching highest status code
merged = [a[1] for a in args if a[0] == maxcode and a[1]]
# merge the split texts. use dict instead of set for keeping order
merged = {m: 0 for mm in merged for m in mm.split(', ')}
return maxcode, ', '.join(merged)

View File

@ -25,7 +25,7 @@ from frappy.core import Readable, Parameter, IntRange, EnumType, FloatRange, \
Attached, StructOf, WARN, Done, BoolType, Enum Attached, StructOf, WARN, Done, BoolType, Enum
from frappy_psi.convergence import HasConvergence from frappy_psi.convergence import HasConvergence
from frappy_psi.mixins import HasOutputModule, HasControlledBy from frappy.mixins import HasOutputModule, HasControlledBy
class Ls340IO(StringIO): class Ls340IO(StringIO):

View File

@ -20,78 +20,120 @@
# #
# ***************************************************************************** # *****************************************************************************
from frappy.datatypes import BoolType, EnumType, Enum import time
from frappy.core import Parameter, Writable, Attached from math import copysign
from frappy.datatypes import BoolType, FloatRange
from frappy.core import Parameter, BUSY
from frappy.lib import merge_status, clamp
from frappy.errors import RangeError
class HasControlledBy(Writable): class HasRamp:
"""mixin for modules with controlled_by """software ramp"""
# make sure it is a drivable
status = Parameter()
target = Parameter()
ramp = Parameter('ramp rate', FloatRange(0, unit='$/min'), default=0, readonly=False)
ramp_used = Parameter('False: infinite ramp', BoolType(), default=False, readonly=False)
setpoint = Parameter('ramping setpoint', FloatRange(unit='$'), readonly=False)
maxdif = Parameter('''max. difference between setpoint and value
in the :meth:`write_target` the hardware action to switch to own control should be done stop ramp then value lags behind setpoint by more than maxdif
and in addition self.self_controlled() should be called maxdif=0: use 'ramp' value (value lags 1 minute behind setpoint)
""" ''',
controlled_by = Parameter('source of target value', EnumType(members={'self': 0}), default=0) FloatRange(0, unit='$'), default=0, readonly=False)
inputCallbacks = () rampinterval = Parameter('interval for changing the setpoint', FloatRange(0, unit='s'),
default=1, readonly=False)
workingramp = Parameter('effective ramp', FloatRange(unit='$/min'))
def register_input(self, name, control_off): _ramp_status = None
"""register input _last_time = None
_buffer = 0
:param name: the name of the module (for controlled_by enum) def doPoll(self):
:param control_off: a method on the input module to switch off control super().doPoll() # suppose that this is reading value and status
""" self.ramp_step(self.target)
if not self.inputCallbacks:
self.inputCallbacks = {}
self.inputCallbacks[name] = control_off
prev_enum = self.parameters['controlled_by'].datatype.export_datatype()['members']
# add enum member, using autoincrement feature of Enum
self.parameters['controlled_by'].datatype = EnumType(Enum(prev_enum, **{name: None}))
def self_controlled(self): def ramp_step(self, target):
"""method to change controlled_by to self now = time.time()
setpoint = self.setpoint
if self._ramp_status is not None:
if setpoint == target:
self._ramp_status = None # at target
self.workingramp = 0
else:
sign = copysign(1, target - setpoint)
prev_t, prev_v = self._last_point
if self.value == prev_v:
return # no reads happened
delay = (now - prev_t) / 60.0 # minutes !
slope = (self.value - prev_v) / max(1e-5, delay)
dif = (setpoint - self.value) * sign
maxdif = self.maxdif or self.ramp
if dif < maxdif:
# reduce ramp when slope is bigger than ramp
ramp = max(2 * self.ramp - sign * slope, 0) + self._buffer
if ramp > self.ramp:
self._buffer = min(ramp - self.ramp, self.ramp)
ramp = self.ramp
else:
self._buffer = 0
setpoint += sign * delay * ramp
if sign * (setpoint - target) >= 0:
self.write_setpoint(setpoint)
self.workingramp = 0
self._ramp_status = None # at target
else:
if ramp != self.workingramp:
self.workingramp = sign * ramp
self.write_setpoint(setpoint)
self._ramp_status = 'ramping'
else:
self._ramp_status = 'holding'
self._last_point = now, self.value
self.read_status()
must be called from the write_target method def read_status(self):
""" status = super().read_status()
if self.controlled_by: if self._ramp_status is None:
self.controlled_by = 0 if self.pollInfo.fast_flag:
for name, control_off in self.inputCallbacks.items(): self.setFastPoll(False)
control_off(self.name) return status
if self.pollInfo.interval != self.rampinterval:
self.setFastPoll(True, self.rampinterval)
return merge_status((BUSY, self._ramp_status), status)
def write_ramp(self, ramp):
if ramp:
self.write_ramp_used(True)
else:
raise RangeError('ramp must not 0, use ramp_used = False to disable ramping')
return ramp
class HasOutputModule(Writable): def write_ramp_used(self, used):
"""mixin for modules having an output module if used != self.ramp_used:
self.ramp_used = used
if self._ramp_status:
self.write_target(self.target)
in the :meth:`write_target` the hardware action to switch to own control should be done def write_setpoint(self, setpoint):
and in addition self.activate_output() should be called super().write_target(setpoint)
""" return setpoint
# allow unassigned output module, it should be possible to configure a
# module with fixed control
output_module = Attached(HasControlledBy, mandatory=False)
control_active = Parameter('control mode', BoolType())
def initModule(self): def read_target(self):
super().initModule() if not self._ramp_status:
if self.output_module: return super().read_target()
self.output_module.register_input(self.name, self.control_off) return self.target
def activate_output(self): def write_target(self, target):
"""method to switch control_active on if self.ramp_used:
if self.parameters['setpoint'].readerror:
self.activate_output() must be called from the write_target method self.write_setpoint(self.read_value())
""" self._ramp_status = 'changed target'
out = self.output_module self._last_time = time.time()
if out: self.setFastPoll(True, self.rampinterval)
for name, control_off in out.inputCallbacks.items(): self.ramp_step(target)
if name != self.name: return target
control_off(self.name) self._ramp_status = None
out.controlled_by = self.name self.write_setpoint(target)
self.control_active = True return target
def control_off(self, switched_by):
"""control_off is called, when an other module takes over control
if possible avoid hardware access in an overriding method in an overriding method
as this might lead to a deadlock with the modules accessLock
"""
if self.control_active:
self.control_active = False
self.log.warning(f'switched to manual mode by {switched_by}')

99
frappy_psi/parmod.py Normal file
View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""modules to access parameters"""
from frappy.core import Drivable, IDLE, Attached, StringType, Property, \
Parameter, FloatRange
from frappy.errors import ConfigError
from frappy_psi.convergence import HasConvergence
from frappy_psi.mixins import HasRamp
class Driv(Drivable):
value = Parameter(datatype=FloatRange(unit='$'))
target = Parameter(datatype=FloatRange(unit='$'))
read = Attached(description='<module>.<parameter> for read')
write = Attached(description='<module>.<parameter> for read')
unit = Property('main unit', StringType())
def setProperty(self, key, value):
if key in ('read', 'write'):
value, param = value.split('.')
setattr(self, f'{key}_param', param)
super().setProperty(key, value)
def checkProperties(self):
self.applyMainUnit(self.unit)
if self.read == self.name or self.write == self.name:
raise ConfigError('illegal recursive read/write module')
super().checkProperties()
#def registerUpdates(self):
# self.read.valueCallbacks[self.read_param].append(self.update_value)
# self.write.valueCallbacks[self.write_param].append(self.update_target)
#
#def startModule(self, start_events):
# start_events.queue(self.registerUpdates)
# super().startModule(start_events)
def read_value(self):
return getattr(self.read, f'{self.read_param}')
def read_target(self):
return getattr(self.write, f'{self.write_param}')
def read_status(self):
return IDLE, ''
def write_target(self, target):
return getattr(self.write, f'write_{self.write_param}')(target)
class Converging(HasConvergence, Driv):
"""drivable with convergence"""
pollinterval = 1
def checkProperties(self):
self.parameters['tolerance'].setProperty('unit', self.unit)
super().checkProperties()
#def update_value(self, value):
# print('UV', value)
# self.value = value
#def error_update_value(self, err):
# raise err
#def update_target(self, value):
# self.target = value
#def error_update_target(self, err):
# raise err
def write_target(self, target):
self.convergence_start()
return super().write_target(target)
class RampDriv(HasRamp, Driv):
pass

View File

@ -48,9 +48,8 @@ from frappy.modules import Attached, Command, Done, Drivable, \
from frappy.protocol.dispatcher import make_update from frappy.protocol.dispatcher import make_update
CFG_HEADER = """Node( CFG_HEADER = """Node('%(config)s.sea.psi.ch',
description = '''%(nodedescr)s''', '''%(nodedescr)s''',
id = %(config)s.sea.psi.ch,
) )
Mod(%(seaconn)r, Mod(%(seaconn)r,
'frappy_psi.sea.SeaClient', 'frappy_psi.sea.SeaClient',