import serial import serial.tools.list_ports from enum import Enum class libreCAL: def __init__(self, serialnum = ''): self.ser = None for p in serial.tools.list_ports.comports(): if p.vid == 0x0483 and p.pid == 0x4122: self.ser = serial.Serial(p.device, timeout = 1) idn = self.SCPICommand("*IDN?").split("_") if idn[0] != "LibreCAL": continue self.serial = idn[1] if len(serialnum) > 0: # serial number specified, compare if self.serial != serialnum: self.ser = None continue break if self.ser == None: if len(serialnum) > 0: raise Exception("LibreCAL with serial number '"+serialnum+"' not detected") else: raise Exception("No LibreCAL device detected") def getSerial(self) -> str: return self.serial class Standard(Enum): NONE = 0, OPEN = 1, SHORT = 2, LOAD = 3, THROUGH = 4 def reset(self): self.SCPICommand(":PORT 1 NONE") self.SCPICommand(":PORT 2 NONE") self.SCPICommand(":PORT 3 NONE") self.SCPICommand(":PORT 4 NONE") def setPort(self, s : Standard, port, port2 = -1): if s == self.Standard.THROUGH and port2 == -1: raise Exception("When setting a port to THROUGH, the destination port must also be specified") cmd = ":PORT "+str(port)+" "+s.name if s == self.Standard.THROUGH: cmd += " "+str(port2) if len(self.SCPICommand(cmd)) == 0: return True else: return False def getPort(self, port): resp = self.SCPICommand(":PORT? "+str(port)).split(" ")[0] try: s = self.Standard[resp] return s except: raise Exception("LibreCAL reported unknown standard '"+resp+"'") def getTemperature(self): return float(self.SCPICommand(":TEMP?")) def isStable(self) -> bool: if self.SCPICommand(":TEMP:STABLE?") == "TRUE": return True else: return False def getHeaterPower(self): return float(self.SCPICommand(":HEAT:POW?")) def SCPICommand(self, cmd: str) -> str: self.ser.write((cmd+"\r\n").encode()) resp = self.ser.readline().decode("ascii") if len(resp) == 0: raise Exception("Timeout occurred in communication with LibreCAL") if resp.strip() == "ERROR": raise Exception("LibreCAL returned 'ERROR' for command '"+cmd+"'") return resp.strip()