From b59a77be01cc5476ba18e88bdca4fc8714a4bcaa Mon Sep 17 00:00:00 2001 From: Matthias Schuessler Date: Tue, 14 Jan 2025 15:20:16 +0100 Subject: [PATCH 1/4] ENH: Add script and example .yaml for Julabo Magio MS-1000F chiller --- basil/HL/julabo1000F.py | 142 ++++++++++++++++++ .../lab_devices/julabo1000F_pyserial.yaml | 14 ++ 2 files changed, 156 insertions(+) create mode 100644 basil/HL/julabo1000F.py create mode 100644 examples/lab_devices/julabo1000F_pyserial.yaml diff --git a/basil/HL/julabo1000F.py b/basil/HL/julabo1000F.py new file mode 100644 index 00000000..90ad805e --- /dev/null +++ b/basil/HL/julabo1000F.py @@ -0,0 +1,142 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# + +""" +This script is used to communicate with the chiller julabo fp50 +""" + +import logging +import time + +from basil.HL.HardwareLayer import HardwareLayer + + +logger = logging.getLogger(__name__) + + +class julabo1000F(HardwareLayer): + ''' Driver for the Julabo Magio MS-1000F chiller. + A simple protocol via crossed null modem serial port is used with baud rate of 9600. + All commands were taken from Julabo Magio MS-1000F manual. + ''' + + CMDS = {'get_temp': 'in_sp_00', + 'set_temp': 'out_sp_00', + 'get_curr_temp': 'in_pv_00', + 'get_fluid_level': 'in_pv_16', + 'get_version': 'version', + 'get_status': 'status', + 'start': 'out_mode_05 1', + 'stop': 'out_mode_05 0', + 'set_power': 'out_sp_10', + 'get_power': 'in_sp_10', + 'get_curr_power': 'in_pv_01', + 'get_actuator_source': 'in_mode_11', + 'set_actuator_source': 'out_mode_11' + } + + def __init__(self, intf, conf): + super(julabo1000F, self).__init__(intf, conf) + self.pre_time = time.time() + + def init(self): + super(julabo1000F, self).init() + + def read(self): + ret = self._intf.read() + if len(ret) < 2 or ret[-2:] != "\r\n": + logger.warning("read() termination error") + return ret[:-2] + + def write(self, cmd): + if time.time() - self.pre_time < 1.0: + time.sleep(1.0) + self._intf.write(str(cmd)) + self.pre_time = time.time() + + def get_version(self): + ''' Read identifier + ''' + self.write(self.CMDS['get_version']) + ret = self.read() + return ret + + def start_chiller(self): + ''' Start chiller + ''' + self.write(self.CMDS['start']) + + def stop_chiller(self): + ''' Stop chiller + ''' + self.write(self.CMDS['stop']) + + def get_status(self): + ''' Get status + ''' + self.write(self.CMDS['get_status']) + ret = self.read() + logger.debug("status:{:s}".format(ret)) + try: + tmp = ret.split(" ", 1) + status = int(tmp[0]) + status_str = tmp[1:] + except (ValueError, AttributeError): + logger.warning("get_status() wrong format: {}".format(repr(ret))) + status = -99 + status_str = ret + return status, status_str + + def get_set_temp(self): + '''get the set temperature + ''' + self.write(self.CMDS['get_temp']) + ret = self.read() + return float(ret) + + def set_temp(self, temp): + '''set the temperature + ''' + self.write(f"{self.CMDS['set_temp']} {temp}") + + def get_temp(self): + '''get the current temperature in chiller + ''' + self.write(self.CMDS['get_curr_temp']) + ret = self.read() + return float(ret) + + def set_power(self, variable): + '''Set the power for heater/cooler via serial interface (positive value for heating, negative value for cooling) + ''' + self.write(f"{self.CMDS['set_power']} {variable}") + + def get_power(self): + '''get the current power for heater/cooler + ''' + self.write(self.CMDS['get_curr_power']) + ret = self.read() + return float(ret) + + def get_power(self): + '''get the power for heater/cooler set via serial interface + ''' + self.write(self.CMDS['get_power']) + ret = self.read() + return float(ret) + + def get_mode(self): + '''get the source for the actuating variable. 0=Thermostat, 1=Serial, 2=Analog (EPROG) + ''' + self.write(self.CMDS['get_actuator_source']) + ret = self.read() + return int(ret) + + def set_mode(self, variable): + '''Set the source for the actuating variable. 0=Thermostat, 1=Serial, 2=Analog (EPROG) + ''' + self.write(f"{self.CMDS['set_actuator_source']} {variable}") \ No newline at end of file diff --git a/examples/lab_devices/julabo1000F_pyserial.yaml b/examples/lab_devices/julabo1000F_pyserial.yaml new file mode 100644 index 00000000..32486d30 --- /dev/null +++ b/examples/lab_devices/julabo1000F_pyserial.yaml @@ -0,0 +1,14 @@ +transfer_layer: + - name : Serial + type : Serial + init : + port : /dev/ttyACM0 + read_termination : "\r\n" + write_termination : "\r" + +hw_drivers: + - name : chiller + type : julabo1000F + interface : Serial + init: + device: julabo 1000F From 1d78d261db886fedcc8d1a3d342caa23133db0d6 Mon Sep 17 00:00:00 2001 From: Matthias Schuessler Date: Tue, 14 Jan 2025 15:28:18 +0100 Subject: [PATCH 2/4] MAINT: Codestyle --- basil/HL/julabo1000F.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basil/HL/julabo1000F.py b/basil/HL/julabo1000F.py index 90ad805e..951533d8 100644 --- a/basil/HL/julabo1000F.py +++ b/basil/HL/julabo1000F.py @@ -114,21 +114,21 @@ def set_power(self, variable): '''Set the power for heater/cooler via serial interface (positive value for heating, negative value for cooling) ''' self.write(f"{self.CMDS['set_power']} {variable}") - + def get_power(self): '''get the current power for heater/cooler ''' self.write(self.CMDS['get_curr_power']) ret = self.read() return float(ret) - + def get_power(self): '''get the power for heater/cooler set via serial interface ''' self.write(self.CMDS['get_power']) ret = self.read() return float(ret) - + def get_mode(self): '''get the source for the actuating variable. 0=Thermostat, 1=Serial, 2=Analog (EPROG) ''' @@ -139,4 +139,4 @@ def get_mode(self): def set_mode(self, variable): '''Set the source for the actuating variable. 0=Thermostat, 1=Serial, 2=Analog (EPROG) ''' - self.write(f"{self.CMDS['set_actuator_source']} {variable}") \ No newline at end of file + self.write(f"{self.CMDS['set_actuator_source']} {variable}") From 8482086ec56c741d6dc94c8bd91a22570aa9df09 Mon Sep 17 00:00:00 2001 From: Matthias Schuessler Date: Tue, 14 Jan 2025 15:31:42 +0100 Subject: [PATCH 3/4] MAINT: Fix a naming error --- basil/HL/julabo1000F.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basil/HL/julabo1000F.py b/basil/HL/julabo1000F.py index 951533d8..c1530eb5 100644 --- a/basil/HL/julabo1000F.py +++ b/basil/HL/julabo1000F.py @@ -122,7 +122,7 @@ def get_power(self): ret = self.read() return float(ret) - def get_power(self): + def get_set_power(self): '''get the power for heater/cooler set via serial interface ''' self.write(self.CMDS['get_power']) From 117c5318cc220e6c2863304bb4bde3a1d0ce85f6 Mon Sep 17 00:00:00 2001 From: Matthias Schuessler Date: Wed, 15 Jan 2025 15:03:35 +0100 Subject: [PATCH 4/4] MAINT: Fix description --- basil/HL/julabo1000F.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basil/HL/julabo1000F.py b/basil/HL/julabo1000F.py index c1530eb5..c43889b0 100644 --- a/basil/HL/julabo1000F.py +++ b/basil/HL/julabo1000F.py @@ -6,7 +6,7 @@ # """ -This script is used to communicate with the chiller julabo fp50 +This script is used to communicate with the chiller julabo 1000F """ import logging