From 6f0b090d9dbb46c67be26f0b56c037c09b0946e0 Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Sun, 12 Jul 2026 20:09:07 +0200 Subject: [PATCH] added lakeshore to temperature logging facility --- pyproject.toml | 1 + src/damaris/tools/lakeshore.py | 103 +++++++++++++++++++++++++++---- src/damaris/tools/temperature.py | 8 +++ 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2568eb3..d357af0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ dependencies = [ "matplotlib >= 1.4.1, <= 3.6", "pyxdg", "PyGObject >= 3.14.0, <= 3.51.0", + "pyserial>=3.5", ] authors = [ {name = "Achim Gädke"}, diff --git a/src/damaris/tools/lakeshore.py b/src/damaris/tools/lakeshore.py index 0b0c8b0..09a68b2 100644 --- a/src/damaris/tools/lakeshore.py +++ b/src/damaris/tools/lakeshore.py @@ -2,6 +2,9 @@ import serial import re import operator import numpy as np +from functools import reduce + +from .temperature import TemperatureController, register_controller DEBUG = False @@ -15,20 +18,25 @@ reply_pattern = re.compile(r"\x02..(.*)\x03.", re.DOTALL) # [ACK] = \x06 # BCC = checksum -standard_device = '/dev/ttyUSB0' -#EOT = '\x04' -#STX = '\x02' -#ENQ = '\x05' -#ETX = '\x03' -#ACK = '\x06' -#NAK = '\x15' +standard_device = '0011' +EOT = '\x04' +STX = '\x02' +ENQ = '\x05' +ETX = '\x03' +ACK = '\x06' +NAK = '\x15' + + +def checksum(message): + bcc = (reduce(operator.xor, list(map(ord,message)))) + return chr(bcc) """ Parameter read example: Master: [EOT]0011PV[ENQ] -Instrument: [STX]PV16.4[ETX]{BCC} +Instrument: [STX]PV16.4[ETX]{BCC} Writing data: @@ -38,7 +46,7 @@ Master: [EOT] {GID}{GID}{UID}{UID}[STX]{CHAN}(c1)(c2)[ETX](BCC) -class Lakeshore(object): +class Lakeshore(TemperatureController): def __init__(self, serial_device, baudrate=57600): self.device = standard_device # timeout: 110 ms to get all answers. @@ -51,7 +59,9 @@ class Lakeshore(object): self._expect_len = 50 def __del__(self): - self.s.close() + if hasattr(self, 's') and self.s is not None: + if self.s.is_open: + self.s.close() #def get_current_temperature(self): # Temp A # self.s.write("KRDG? a\n") @@ -104,5 +114,76 @@ class Lakeshore(object): except ValueError: return np.nan + def send_read_param(self, param): + self.s.write(EOT + self.device + param + ENQ) + + def read_param(self, param): + self.s.flushInput() + self.send_read_param(param) + answer = self.s.read(self._expect_len) + m = reply_pattern.search(answer) + if m is None: + # Reading _expect_len bytes was not enough... + answer += self.s.read(200) + m = reply_pattern.search(answer) + if m is not None: + self._expect_len = len(answer) + return m.group(1) + else: + print("received:", repr(answer)) + return None + + def write_param(self, mnemonic, data): + if len(mnemonic) > 2: + raise ValueError + bcc = checksum(mnemonic + data + ETX) + mes = EOT+self.device+STX+mnemonic+data+ETX+bcc + if DEBUG: + for i in mes: + print(i,hex(ord(i))) + self.s.flushInput() + self.s.write(mes) + answer = self.s.read(1) + # print "received:", repr(answer) + if answer == "": + # raise IOError("No answer from device") + return None + return answer[-1] == ACK + + # TemperatureController interface implementation + + def get_temperature(self) -> float: + """Read current temperature in Celsius.""" + temp = self.get_temperature_A() + if temp is None: + return 0.0 + try: + return float(temp) + except (ValueError, TypeError): + return 0.0 + + def get_setpoint(self) -> float: + """Read target setpoint temperature in Celsius.""" + temp = self.get_set_temperature() + if temp is None: + return 0.0 + try: + return float(temp) + except (ValueError, TypeError): + return 0.0 + + def set_setpoint(self, temperature: float) -> bool: + """Set target temperature in Celsius.""" + self.set_temperature(temperature) + return True + def close(self): - self.s.close() \ No newline at end of file + """Close the serial connection.""" + if hasattr(self, 's') and self.s is not None: + if self.s.is_open: + self.s.close() + self.s = None + + +# Register Lakeshore with the factory +register_controller('lakeshore', Lakeshore) \ No newline at end of file diff --git a/src/damaris/tools/temperature.py b/src/damaris/tools/temperature.py index 5ab04b8..a50c01d 100644 --- a/src/damaris/tools/temperature.py +++ b/src/damaris/tools/temperature.py @@ -44,6 +44,7 @@ def create_controller(name: str, *args, **kwargs): module_map = { 'simulated': 'damaris.tools.temperature_simulator', 'eurotherm': 'damaris.tools.eurotherm', + 'lakeshore': 'damaris.tools.lakeshore', } if name in module_map: try: @@ -79,6 +80,13 @@ except ImportError as e: # That's OK, it will be imported on-demand if needed pass +try: + from . import lakeshore +except ImportError as e: + # Lakeshore may require serial module which might not be installed + # That's OK, it will be imported on-demand if needed + pass + try: from . import temperature_simulator except ImportError as e: