Skip to content

Instantly share code, notes, and snippets.

@erpalma

erpalma/thermaltake_dps.py

Last active Apr 27, 2020
Embed
What would you like to do?
Python script to read fan, temperature, voltage and current from Thermaltake DPS PSUs via USB. (pip install pyusb first)
import usb.core
import usb.util
PSU_VALUES_DICT = {
'AC_IN': (0x31, 0x33),
'V_12V': (0x31, 0x34),
'V_5V': (0x31, 0x35),
'V_3V3': (0x31, 0x36),
'I_12V': (0x31, 0x37),
'I_5V': (0x31, 0x38),
'I_3V3': (0x31, 0x39),
'TEMP': (0x31, 0x3A),
'RPM': (0x31, 0x3B),
}
def usb_init():
dev = usb.core.find(idVendor=0x264A, idProduct=0x2329)
if dev is None:
raise ValueError('Device not found')
dev.reset()
for config in dev:
for i in range(config.bNumInterfaces):
if dev.is_kernel_driver_active(i):
dev.detach_kernel_driver(i)
dev.set_configuration()
cfg = dev.get_active_configuration()
intf = cfg[(0, 0)]
epo = usb.util.find_descriptor(
intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT,
)
epi = usb.util.find_descriptor(
intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN,
)
assert epo is not None
assert epi is not None
return epo, epi
def _pad(data, length=64):
return list(data) + [0] * (length - len(data))
def usb_write(epo, data, length=64):
try:
epo.write(_pad(data, length))
except OverflowError:
pass
def usb_read(epi, length=64):
data = epi.read(length)
return data
def controller_init():
try:
epo, epi = usb_init()
usb_write(epo, [0xFE, 0x31])
res = usb_read(epi)
assert res[0] == 0xFE
res = ''.join(map(chr, filter(lambda x: x, res[1:])))
print('Initialized device: {:s}'.format(res))
return epo, epi
except usb.core.USBError as e:
print(e.strerror)
exit(1)
def convert_result(low, high):
result = high << 8 | low
exponent = (result & 0x7800) >> 11
sign = (result & 0x8000) >> 15
fraction = result & 0x7FF
if sign == 1:
exponent -= 16
return (2 ** exponent) * fraction
def read_value(epo, epi, value):
usb_write(epo, PSU_VALUES_DICT[value])
res = usb_read(epi)
assert tuple(res[:2]) == PSU_VALUES_DICT[value]
return convert_result(*res[2:4])
def main():
epo, epi = controller_init()
cur_values = {}
for value in PSU_VALUES_DICT:
cur_values[value] = read_value(epo, epi, value)
total_pwr = sum(cur_values['V_' + line] * cur_values['I_' + line] for line in ('12V', '5V', '3V3'))
print('\nAC Input: {:.1f} V - {:.1f} W'.format(cur_values['AC_IN'], total_pwr))
print('\n12V line: {:.2f} V - {:.2f} A'.format(cur_values['V_12V'], cur_values['I_12V']))
print('5V line: {:.2f} V - {:.2f} A'.format(cur_values['V_5V'], cur_values['I_5V']))
print('3.3V line: {:.2f} V - {:.2f} A'.format(cur_values['V_3V3'], cur_values['I_3V3']))
print('\nTemp: {:.1f} C - Fan: {:.0f} RPM'.format(cur_values['TEMP'], cur_values['RPM']))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.