From e27b4f72b548701c381dee8ccce4a33bd6f61875 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Mon, 16 Oct 2023 17:28:44 +0200 Subject: [PATCH] newset version of oksanas drivers Change-Id: Ia6d8b727e48e96a14b75feeef5d3e6c002cb82a0 --- frappy_psi/thermofisher.py | 192 ++++++++++++++++++++++--------------- 1 file changed, 116 insertions(+), 76 deletions(-) diff --git a/frappy_psi/thermofisher.py b/frappy_psi/thermofisher.py index f160e06..589dfe0 100644 --- a/frappy_psi/thermofisher.py +++ b/frappy_psi/thermofisher.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python +# -*- 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 @@ -15,13 +17,64 @@ # # Module authors: # Oksana Shliakhtun -# Markus Zolliker # ***************************************************************************** -"""bath thermostat Thermo Scientificâ„¢ ARCTIC A10 Refrigerated Circulators""" +""" RUFS Command: Description of Bits -from frappy.core import Command, StringIO, Parameter, HasIO, \ + ====== ======================================================== ============================================== + Value Description + ====== ======================================================== ============================================== + V1 + B6: warning, rtd1 (internal temp. sensor) is shorted + B0 --> 1 + B7: warning, rtd1 is open + B1 --> 2 + V2 + B0: error, HTC (high temperature cutout) fault B2 --> 4 + + B1: error, high RA (refrigeration) temperature fault B3 --> 8 + + V3 B4 --> 16 + B0: warning, low level in the bath + B5 --> 32 + B1: warning, low temperature + B6 --> 64 + B2: warning, high temperature + B7 --> 128 + B3: error, low level in the bath + + B4: error, low temperature fault + + B5: error, high temperature fault + + B6: error, low temperature fixed* fault + + B7: error, high temperature fixed** fault + + V4 + B3: idle, circulator** is running + + B5: error, circulator** fault + + V5 + B0: error, pump speed fault + + B1: error, motor overloaded + + B2: error, high pressure cutout + + B3: idle, maximum cooling + + B4: idle, cooling + + B5: idle, maximum heating + + B6: idle, heating + ====== ======================================================== ============================================== + +""" + +from frappy.core import StringIO, Parameter, HasIO, \ Drivable, FloatRange, IDLE, BUSY, ERROR, WARN, BoolType -from frappy.structparam import StructParam from frappy_psi.convergence import HasConvergence @@ -32,17 +85,17 @@ class ThermFishIO(StringIO): class TemperatureLoopA10(HasConvergence, HasIO, Drivable): ioClass = ThermFishIO + value = Parameter('internal temperature', unit='degC') 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) - ctrlpars = StructParam('control parameters struct', dict( - p_heat = Parameter('proportional heat parameter', FloatRange()), - i_heat = Parameter('integral heat parameter', FloatRange()), - d_heat = Parameter('derivative heat parameter', FloatRange()), - p_cool = Parameter('proportional cool parameter', FloatRange()), - i_cool = Parameter('integral cool parameter', FloatRange()), - d_cool = Parameter('derivative cool parameter', FloatRange()), - ), readonly=False) + circ_on = Parameter('is circulation running', BoolType(), readonly=False, default=False) + # pids + p_heat = Parameter('proportional heat parameter', FloatRange(), readonly=False) + i_heat = Parameter('integral heat parameter', FloatRange(), readonly=False) + d_heat = Parameter('derivative heat parameter', FloatRange(), readonly=False) + p_cool = Parameter('proportional cool parameter', FloatRange(), readonly=False) + i_cool = Parameter('integral cool parameter', FloatRange(), readonly=False) + d_cool = Parameter('derivative cool parameter', FloatRange(), readonly=False) status_messages = [ (ERROR, 'high tempr. cutout fault', 2, 0), @@ -69,22 +122,20 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): ] def get_par(self, cmd): - """get parameter and convert to float + """ + All the reading commands starts with 'R', in the source code all the commands are written without 'R' (except + 'RUFS').The result of a reading command is a value in the format '20C', without spaces. - :param cmd: hardware command without the leading 'R' + :param cmd: any hardware command - :return: result converted to float + :return: 'R'+cmd """ new_cmd = 'R' + cmd - reply = self.communicate(new_cmd).strip() - while reply[-1].isalpha(): - reply = reply[:-1] + reply = self.communicate(new_cmd) + if any(unit.isalpha() for unit in reply): + reply = ''.join(unit for unit in reply if not unit.isalpha()) return float(reply) - def set_par(self, cmd, value): - self.communicate(f'S{cmd} {value}') - return self.get_par(cmd) - def read_value(self): """ Reading internal temperature sensor value. @@ -92,34 +143,6 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): return self.get_par('T') def read_status(self): - """ convert from RUFS Command: Description of Bits - - ====== ======================================================== =============== - Value Description - ====== ======================================================== =============== - V1 B6: warning, rtd1 (internal temp. sensor) is shorted B0 --> 1 - B7: warning, rtd1 is open B1 --> 2 - V2 B0: error, HTC (high temperature cutout) fault B2 --> 4 - B1: error, high RA (refrigeration) temperature fault B3 --> 8 - V3 B0: warning, low level in the bath B5 --> 32 - B1: warning, low temperature B6 --> 64 - B2: warning, high temperature B7 --> 128 - B3: error, low level in the bath - B4: error, low temperature fault - B5: error, high temperature fault - B6: error, low temperature fixed* fault - B7: error, high temperature fixed** fault - V4 B3: idle, circulator** is running - B5: error, circulator** fault - V5 B0: error, pump speed fault - B1: error, motor overloaded - B2: error, high pressure cutout - B3: idle, maximum cooling - B4: idle, cooling - B5: idle, maximum heating - B6: idle, heating - ====== ======================================================== =============== - """ result_str = self.communicate('RUFS') # read unit fault status values_str = result_str.strip().split() values_int = [int(val) for val in values_str] @@ -134,55 +157,72 @@ class TemperatureLoopA10(HasConvergence, HasIO, Drivable): return status_type, status_msg return WARN, 'circulation off' - def read_control_active(self): - return int(self.get_par('O')) + def read_circ_on(self): + return self.communicate('RO') - @Command - def control_off(self): - """switch control and circulation off""" - self.control_active = self.set_par('O', 0) + def write_circ_on(self, circ_on): + circ_on_str = '1' if circ_on else '0' + self.communicate(f'SO {circ_on_str}') + return self.read_circ_on() def read_target(self): return self.get_par('S') def write_target(self, target): - self.control_active = self.set_par('O', 1) + """ + :param target: here, it serves as an equivalent to a setpoint. + """ + self.write_circ_on('1') self.communicate(f'SS {target}') self.convergence_start() return target + ## heat PID def read_p_heat(self): - return self.get_par('PH') + p_heat = self.get_par('PH') + return float(p_heat) - def write_p_heat(self, value): - return self.set_par('PH', value) + def write_p_heat(self, p_heat): + self.communicate(f'SPH {p_heat}') + return p_heat def read_i_heat(self): - return self.get_par('IH') + i_heat = self.get_par('IH') + return float(i_heat) - def write_i_heat(self, value): - return self.set_par('IH', value) + def write_i_heat(self, i_heat): + self.communicate(f'SIH {i_heat}') + return i_heat def read_d_heat(self): - return self.get_par('DH') + d_heat = self.get_par('DH') + return float(d_heat) - def write_d_heat(self, value): - return self.set_par('DH', value) + def write_d_heat(self, d_heat): + self.communicate(f'SDH {d_heat}') + return d_heat + ## cool PID def read_p_cool(self): - return self.get_par('PC') + p_cool = self.get_par('PC') + return float(p_cool) - def write_p_cool(self, value): - return self.set_par('PC', value) + def write_p_cool(self, p_cool): + self.communicate(f'SPC {p_cool}') + return p_cool def read_i_cool(self): - return self.get_par('IC') + i_cool = self.get_par('IC') + return float(i_cool) - def write_i_cool(self, value): - return self.set_par('IC', value) + def write_i_cool(self, i_cool): + self.communicate(f'SIC {i_cool}') + return i_cool def read_d_cool(self): - return self.get_par('DC') + d_cool = self.get_par('DC') + return float(d_cool) - def write_d_cool(self, value): - return self.set_par('DC', value) + def write_d_cool(self, d_cool): + self.communicate(f'SDC {d_cool}') + return d_cool