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)