Skip to content

Instantly share code, notes, and snippets.

@erpalma
Last active April 27, 2020 18:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erpalma/4f4d73cb0f6ee54fe758b67446b9d044 to your computer and use it in GitHub Desktop.
Save erpalma/4f4d73cb0f6ee54fe758b67446b9d044 to your computer and use it in GitHub Desktop.
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