The BELEKTRONIG benchtop temperature controllers of the BTC series are used to control heating or Peltier elements. For my thesis project i had to write a driver for the device and now i’m sharing it for whoever is using the same device and wants a ready driver to communicate with the device
Code import pyvisa, time, logging class PIDDriverV2(): def __init__(self, base): self.logger = logging.getLogger('logger') try: rm = pyvisa.ResourceManager() self.ser = rm.open_resource(str(base.pid_port)) self.ser.write_termination = "\r" except Exception as e: self.logger.critical("Failed to establish connection to Thermostat " + str(e)) self.max_voltage = self.getRatedVoltage() self.output_min, self.output_max = self.getOutputLimits() self.primary_sensor = self.getPrimarySensor() def getRatedVoltage(self): """Reading of the rated voltage of power supply used for temperature control.""" self.ser.write('U1') res = self.ser.read_bytes(2) value = int.from_bytes(res, "big", signed = True) value = round(value/10.0,0) # to V/°C return value def getOutputLimits(self): self.ser.write('G8') res = self.ser.read_bytes(8) value = int.from_bytes(res[0:4], "big", signed = True) min = value / (2**16-1) * 100 value = int.from_bytes(res[4:8], "big", signed = True) max = value / (2**16-1) * 100 return min, max def getPrimarySensor(self): """Get the Primary active sensor""" self.ser.write('R7') res = self.ser.read_bytes(1) value = int.from_bytes(res, "big") return value def getVoltageLimits(self): self.ser.write('G8') res = self.ser.read_bytes(8) value = int.from_bytes(res[0:4], "big", signed = True) min = value / (2**16-1) * self.max_voltage value = int.from_bytes(res[4:8], "big", signed = True) max = value / (2**16-1) * self.max_voltage return min, max def getDeviceConfiguration(self): """ get the device configuration of the instrument """ self.ser.write('N1') answer = self.ser.read_bytes(16) return answer def getSerialNumber(self): """ get the serial number of the instrument """ self.ser.write('N2') answer = self.ser.read_bytes(4) value = int.from_bytes(answer, "big") return value def getFirmwareVersion(self): """ get the firmware version of the instrument """ self.ser.write('N3') answer = self.ser.read_bytes(4) value = int.from_bytes(answer, "big") return value def getDeviceFeatures(self): """ get the device features of the instrument """ self.ser.write('N5') answer = self.ser.read_bytes(4) value = int.from_bytes(answer, "big") bit_string = "{0:32b}".format(value) bit_list = [x == "1" for x in bit_string][::-1] return bit_list def getOutputVoltage(self): """reading of the output power of the control output.""" self.ser.write("A1") res = self.ser.read_bytes(4) value = int.from_bytes(res, "big", signed = True) return value / (2**16-1) * self.max_voltage def getOutputPower(self): """reading of the output power of the control output. -100% to 100%""" self.ser.write("A1") res = self.ser.read_bytes(4) value = int.from_bytes(res, "big", signed = True) value = value / (2**16-1) * self.max_voltage return value def getControllerMode(self): """reading of the mode of operation of the control output.""" self.ser.write("B1") res = self.ser.read_bytes(1) value = int.from_bytes(res, "big", signed = True) return value def getSetpointTemp(self): """reading of the setpoint temperature in °C""" self.ser.write("S1") time.sleep(1) res = self.ser.read_bytes(4) #print(res) return int.from_bytes(res, "big", signed = True) / 1000 def getSetpointTempNoOverwrite(self): """reading of the setpoint temperature WITHOUT overwriting the internal memory. Reading of the actual value of the setpoint temperature of the active temperature ramp.""" self.ser.write("S2") res = '' while not res: time.sleep(0.3) res = self.ser.read_bytes(4) return int.from_bytes(res, "big", signed = True) / 1000 def getSensorTemp(self, sensor = 0): """Reading of the temperature of sensor input 1...5 in °C""" if sensor == 0: sensor = self.primary_sensor self.ser.write("T"+str(sensor)) time.sleep(0.3) answer = self.ser.read_bytes(4) temperature = int.from_bytes(answer, "big", signed = True) / 1000 return temperature def setControllerMode(self, mode): """ set the cooling/heating mode for a given integer 0 = read only 1 = heat only 2 = cool only 3 = heat and cool """ mode = int(mode) modeByte = mode.to_bytes(1, "big") self.ser.write('b1' + modeByte.decode('latin-1')) def setSetpointTemp(self, value): """setting of the setpoint temperature in °C, don't use if setting point will change frequently so there won't be damage to the internal memory""" cmdprefixBytes = str.encode("s1") value = int(float(value) * 1000) valueBytes = value.to_bytes(4, byteorder='big', signed = True) cmdBytes = cmdprefixBytes + valueBytes + str.encode("\x0D") self.ser.write_raw(cmdBytes) return self.ser.read_bytes(1) def setSetpointTempNoOverwrite(self, value): """setting of the setpoint temperature WITHOUT overwriting the internal memory. Reading of the actual value of the setpoint temperature of the active temperature ramp.""" cmdprefixBytes = str.encode("s2") value = int(float(value) * 1000) valueBytes = value.to_bytes(4, byteorder='big', signed = True) cmdBytes = cmdprefixBytes + valueBytes + str.encode("\x0D") self.ser.write_raw(cmdBytes) return self.ser.read_bytes(1) ...