So a side affect of this mornings issue with the UPS is I have a new power supply, and it has usb-accessible sensors. If we build OpenCorsairLink, we can access them:
# OpenCorsairLink.elf --device 0 Dev=0, CorsairLink Device Found: HX750i! Vendor: CORSAIR Product: HX750i Firmware: NA Temperature 0: 40.50 C Temperature 1: 33.50 C Powered: 13161 (0d. 3h) Uptime: 13161 (0d. 3h) Supply Voltage: 115.00 Total Watts: 116.00 Output 12v: Voltage 12.16 Amps 7.50 Watts 88.00 Output 5v: Voltage 5.00 Amps 5.00 Watts 25.00 Output 3.3v: Voltage 3.31 Amps 0.62 Watts 2.00
Seems like the kind of thing you’d want to graph right? And netdata is the tool of choice for system graphing.
So first, we want to make the device readable by netdata (rather than having it run as root!). So lets put a rule in udev:
# cat /lib/udev/rules.d/50-corsair.rules SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="1c05", GROUP="netdata", MODE="0664"
done. Restart the systemd-udevd, and trygger:
systemctl restart systemd-udevd.service udevadm trigger
OK, now check the permissions worked:
# ls -al /dev/bus/usb/001/003 crw-rw-r-- 1 root netdata 189, 2 Nov 26 16:50 /dev/bus/usb/001/003
done.
OK, now we need to parse that output. Its not overly complex, not designed for simple scraping, but should be trivial with some Python.
OK, lets put this script in /usr/libexec/netdata/python.d, and we are golden!
# -*- coding: utf-8 -*- # Description: OpenCorsairLink netdata python module # Author: Don Bowman (db@donbowman.ca) #from bases.FrameworkServices.ExecutableService import ExecutableService from base import ExecutableService # default module values (can be overridden per job in `config`) update_every = 5 priority = 60000 retries = 5 # charts order (can be overridden if you want less charts, or different order) ORDER = ['temp', 'input_voltage', 'output_wattage', 'out_v', 'out_a', 'out_w', ] CHARTS = { # id: { # 'options': [name, title, units, family, context, charttype], # 'lines': [ # [unique_dimension_name, name, algorithm, multiplier, divisor] # ]} 'temp': { 'options': [None, "PSU Temp0", "C", 'psu', 'psu.temp0', 'line'], 'lines': [ ['temp0', 'temp0', 'absolute', 1, 100], ['temp1', 'temp1', 'absolute', 1, 100] ]}, 'input_voltage': { 'options': [None, "PSU Input Voltage", "V", 'psu', 'psu.input_voltage', 'line'], 'lines': [ ['input_voltage', 'input_voltage', 'absolute', 1, 100] ]}, 'output_wattage': { 'options': [None, "PSU Output Wattage", "V", 'psu', 'psu.output_wattage', 'line'], 'lines': [ ['output_wattage', 'output_wattage', 'absolute', 1, 100] ]}, 'out_v': { 'options': [None, "PSU Voltage", "V", 'psu', 'psu.out_v', 'line'], 'lines': [ ['out_12v_v', 'out_12v_v', 'absolute', 1, 100], ['out_5v_v', 'out_5v_v', 'absolute', 1, 100], ['out_3v_v', 'out_3v_v', 'absolute', 1, 100] ]}, 'out_a': { 'options': [None, "PSU Amperage", "A", 'psu', 'psu.out_a', 'line'], 'lines': [ ['out_12v_a', 'out_12v_a', 'absolute', 1, 100], ['out_5v_a', 'out_5v_a', 'absolute', 1, 100], ['out_3v_a', 'out_3v_a', 'absolute', 1, 100] ]}, 'out_w': { 'options': [None, "PSU Wattage", "W", 'psu', 'psu.out_w', 'line'], 'lines': [ ['out_12v_w', 'out_12v_w', 'absolute', 1, 100], ['out_5v_w', 'out_5v_w', 'absolute', 1, 100], ['out_3v_w', 'out_3v_w', 'absolute', 1, 100] ]}, } class Service(ExecutableService): def __init__(self, configuration=None, name=None): ExecutableService.__init__(self, configuration=configuration, name=name) self.command = "OpenCorsairLink.elf --device 0" self.order = ORDER self.definitions = CHARTS def _get_data(self): """ Format data received from shell command :return: dict """ raw_data = self._get_raw_data() self.debug('raw_data: <<%s>>' % raw_data) if not raw_data: return None ckeys = {} ckeys['Temperature 0'] = 'temp0' ckeys['Temperature 1'] = 'temp1' ckeys['Supply Voltage'] = 'input_voltage' ckeys['Total Watts'] = 'output_wattage' ckeys['Output 12v'] = '12v' ckeys['Output 5v'] = '5v' ckeys['Output 3.3v'] = '3v' data = {} lm = '' raw_data = ''.join(raw_data) self.debug('==================================') for l in raw_data.split('\n'): l = ''.join(l.strip()) self.debug('l: <<%s>>' % l) fields = l.split(':') if len(fields) > 1: keyn = ''.join(fields[0]).strip() keyv = ''.join(fields[1]).strip() if keyn in ckeys: x = ckeys.get(keyn,"None") if len(keyv): keyv = keyv.split(' ')[0] data[x] = int ( float(keyv) * 100) lm = x elif len(lm) > 0: fields = l.split(' ') if (fields[0] == 'Voltage'): data['out_%s_v' % lm] = int( float(fields[-1]) * 100) elif (fields[0] == 'Amps'): data['out_%s_a' % lm] = int( float(fields[-1]) * 100) elif (fields[0] == 'Watts'): data['out_%s_w' % lm] = int( float(fields[-1]) * 100) self.debug('data: <<%s>>' % data) return data
Leave a Reply