Last active
April 27, 2020 18:58
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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