From 08244e17e0fae1c4c8891b5eee3ed8ac46dc9167 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Mon, 25 Aug 2025 09:27:31 +0200 Subject: [PATCH] frappy_psi.thermofisher: add limits also switch off control when T is outside limits by more than security_margin Change-Id: I3df513c7bc36ca23bf249c61fdfadb39870db3a5 --- frappy_psi/thermofisher.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/frappy_psi/thermofisher.py b/frappy_psi/thermofisher.py index 4a4a9f7a..1d098b38 100644 --- a/frappy_psi/thermofisher.py +++ b/frappy_psi/thermofisher.py @@ -20,7 +20,7 @@ """bath thermostat Thermo Scientificâ„¢ ARCTIC A10 Refrigerated Circulators""" from frappy.core import Command, StringIO, Parameter, HasIO, \ - Drivable, FloatRange, IDLE, BUSY, ERROR, WARN, BoolType + Drivable, FloatRange, IDLE, BUSY, ERROR, WARN, BoolType, Limit from frappy.extparams import StructParam from frappy_psi.convergence import HasConvergence @@ -34,7 +34,7 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): ioClass = ThermFishIO value = Parameter('temperature', unit='degC') target = Parameter('setpoint/target', datatype=FloatRange, unit='degC', default=0) - control_active = Parameter('circilation and control is on', BoolType(), default=False) + control_active = Parameter('circulation and control is on', BoolType(), default=False) ctrlpars = StructParam('control parameters struct', dict( p_heat = Parameter('proportional heat parameter', FloatRange()), i_heat = Parameter('integral heat parameter', FloatRange()), @@ -43,6 +43,11 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): i_cool = Parameter('integral cool parameter', FloatRange()), d_cool = Parameter('derivative cool parameter', FloatRange()), ), readonly=False) + target_min = Limit(default=-99) + target_max = Limit(default=199) + security_margin = Parameter('security margin for automatic switch off', + FloatRange(), default=1) + _off_reason = None status_messages = [ (ERROR, 'high tempr. cutout fault', 2, 0), @@ -89,7 +94,12 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): """ Reading internal temperature sensor value. """ - return self.get_par('T') + value = self.get_par('T') + if value > self.target_max + self.security_margin: + self.switch_control_off('T above limit') + elif value < self.target_min - self.security_margin: + self.switch_control_off('T below limit') + return value def read_status(self): """ convert from RUFS Command: Description of Bits @@ -132,15 +142,24 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): # else our own status return BUSY, conv_status[1] if 'tolerance' in conv_status[1] else status_msg return status_type, status_msg - return WARN, 'circulation off' + return WARN, (self._off_reason or 'circulation and control off') def read_control_active(self): return int(self.get_par('O')) + def initialReads(self): + super().initialReads() + self.target_max = min(self.target_max, self.get_par('RHTF')) + self.target_min = max(self.target_min, self.get_par('RLTF')) + + def switch_control_off(self, reason=None): + self._off_reason = reason + self.control_active = self.set_par('O', 0) + @Command def control_off(self): """switch control and circulation off""" - self.control_active = self.set_par('O', 0) + self.switch_control_off() def read_target(self): return self.get_par('S')