def test_reads_status_from_hwmon(mock_smart2, tmp_path): mock_smart2._hwmon = HwmonDevice("mock_module", tmp_path) (tmp_path / "pwm1_enable").write_text("1\n") (tmp_path / "pwm2_enable").write_text("0\n") (tmp_path / "pwm3_enable").write_text("0\n") (tmp_path / "pwm1_mode").write_text("1\n") (tmp_path / "pwm2_mode").write_text("0\n") (tmp_path / "pwm3_mode").write_text("0\n") (tmp_path / "pwm1_input").write_text("127\n") (tmp_path / "pwm2_input").write_text("102\n") (tmp_path / "pwm3_input").write_text("102\n") (tmp_path / "fan1_input").write_text("1020\n") (tmp_path / "fan2_input").write_text("0\n") (tmp_path / "fan3_input").write_text("0\n") expected = [ ("Fan 1 speed", 1020, "rpm"), ("Fan 1 duty", pytest.approx(50, rel=1.0 / 255), "%"), ("Fan 1 control mode", "PWM", ""), ("Fan 2 speed", 0, "rpm"), ("Fan 2 duty", pytest.approx(40, rel=1.0 / 255), "%"), ("Fan 2 control mode", "DC", ""), ("Fan 3 speed", 0, "rpm"), ("Fan 3 duty", pytest.approx(40, rel=1.0 / 255), "%"), ("Fan 3 control mode", "DC", ""), ] got = mock_smart2.get_status() assert sorted(got) == sorted(expected)
def test_reads_status_directly(mock_psu, has_hwmon, direct_access): if has_hwmon: mock_psu._hwmon = HwmonDevice(None, None) got = mock_psu.get_status(direct_access=direct_access) expected = [ ('Current uptime', timedelta(seconds=5522), ''), ('Total uptime', timedelta(days=13, seconds=9122), ''), ('Temperature 1', approx(33.5, rel=1e-3), '°C'), ('Temperature 2', approx(26.5, rel=1e-3), '°C'), ('Fan control mode', FanControlMode.SOFTWARE, ''), ('Fan speed', approx(968, rel=1e-3), 'rpm'), ('Input voltage', approx(230, rel=1e-3), 'V'), ('Total power output', approx(140, rel=1e-3), 'W'), ('+12V OCP mode', OCPMode.MULTI_RAIL, ''), ('+12V output voltage', approx(11.98, rel=1e-3), 'V'), ('+12V output current', approx(10.75, rel=1e-3), 'A'), ('+12V output power', approx(124, rel=1e-3), 'W'), ('+5V output voltage', approx(5.016, rel=1e-3), 'V'), ('+5V output current', approx(1.688, rel=1e-3), 'A'), ('+5V output power', approx(8, rel=1e-3), 'W'), ('+3.3V output voltage', approx(3.297, rel=1e-3), 'V'), ('+3.3V output current', approx(0.562, rel=1e-3), 'A'), ('+3.3V output power', approx(1.5, rel=1e-3), 'W'), ('Estimated input power', approx(153, abs=1), 'W'), ('Estimated efficiency', approx(92, abs=1), '%'), ] assert sorted(got) == sorted(expected)
def test_smart_device_reads_status_directly(mockSmartDevice, has_hwmon, direct_access): dev = mockSmartDevice if has_hwmon: dev._hwmon = HwmonDevice(None, None) for _, capdata in enumerate(SAMPLE_RESPONSES): capdata = bytes.fromhex(capdata) dev.device.preload_read(Report(capdata[0], capdata[1:])) # skip initialize for now, we're not emulating the behavior precisely # enough to require it here expected = [ ('Fan 1 speed', 1461, 'rpm'), ('Fan 1 voltage', 11.91, 'V'), ('Fan 1 current', 0.02, 'A'), ('Fan 1 control mode', 'PWM', ''), ('Fan 2 speed', 1336, 'rpm'), ('Fan 2 voltage', 11.91, 'V'), ('Fan 2 current', 0.02, 'A'), ('Fan 2 control mode', 'PWM', ''), ('Fan 3 speed', 1390, 'rpm'), ('Fan 3 voltage', 11.91, 'V'), ('Fan 3 current', 0.03, 'A'), ('Fan 3 control mode', None, ''), ('Noise level', 63, 'dB') ] got = dev.get_status(direct_access=direct_access) assert expected == got
def test_smart_device_initializes(mockSmartDevice, has_hwmon, direct_access, tmp_path): dev = mockSmartDevice if has_hwmon: dev._hwmon = HwmonDevice('mock_module', tmp_path) for _, capdata in enumerate(SAMPLE_RESPONSES): capdata = bytes.fromhex(capdata) dev.device.preload_read(Report(capdata[0], capdata[1:])) expected = [ ('Firmware version', '1.0.7', ''), ('LED accessories', 2, ''), ('LED accessory type', 'HUE+ Strip', ''), ('LED count (total)', 20, ''), ] got = dev.initialize(direct_access=direct_access) assert expected == got writes = len(dev.device.sent) if not has_hwmon or direct_access: assert writes == 2 else: assert writes == 0
def test_krakenx3_warns_on_faulty_temperature(mock_krakenx3, has_hwmon, direct_access, caplog): if has_hwmon: mock_krakenx3._hwmon = HwmonDevice(None, None) mock_krakenx3.device.preload_read(Report(0, FAULTY_STATUS)) _ = mock_krakenx3.get_status(direct_access=direct_access) assert "unexpected temperature reading" in caplog.text
def mock_hwmon(tmp_path): hwmon = tmp_path / "hwmon7" hwmon.mkdir() (hwmon / "fan1_input").write_text("1499\n") (hwmon / "fan1_label").write_text("Pump Speed\n") return HwmonDevice("mock_module", hwmon)
def test_krakenx3_reads_status_from_hwmon(mock_krakenx3, tmp_path): mock_krakenx3._hwmon = HwmonDevice("mock_module", tmp_path) (tmp_path / "temp1_input").write_text("33100\n") (tmp_path / "fan1_input").write_text("1704\n") (tmp_path / "pwm1_input").write_text("135\n") temperature, pump_speed, pump_duty = mock_krakenx3.get_status() assert temperature == ("Liquid temperature", 33.1, "°C") assert pump_speed == ("Pump speed", 1704, "rpm") assert pump_duty == ("Pump duty", pytest.approx(53, rel=1.0 / 255), "%")
def test_krakenx3_reads_status_directly(mock_krakenx3, has_hwmon, direct_access): if has_hwmon: mock_krakenx3._hwmon = HwmonDevice(None, None) mock_krakenx3.device.preload_read(Report(0, SAMPLE_STATUS)) temperature, pump_speed, pump_duty = mock_krakenx3.get_status(direct_access=direct_access) assert temperature == ("Liquid temperature", 33.1, "°C") assert pump_speed == ("Pump speed", 1704, "rpm") assert pump_duty == ("Pump duty", 53, "%")
def test_krakenx3_initializes(mock_krakenx3, has_hwmon, direct_access, tmp_path): if has_hwmon: mock_krakenx3._hwmon = HwmonDevice("mock_module", tmp_path) # TODO check the result _ = mock_krakenx3.initialize(direct_access=direct_access) writes = len(mock_krakenx3.device.sent) if not has_hwmon or direct_access: assert writes == 4 else: assert writes == 2
def test_initializes(mock_psu, has_hwmon, direct_access, tmp_path): if has_hwmon: mock_psu._hwmon = HwmonDevice('mock_module', tmp_path) # TODO check the result _ = mock_psu.initialize(direct_access=direct_access) writes = len(mock_psu.device.sent) if not has_hwmon or direct_access: assert writes > 0 else: assert writes == 0
def test_kraken_get_status_directly(mockKrakenXDevice, has_hwmon, direct_access): if has_hwmon: mockKrakenXDevice._hwmon = HwmonDevice(None, None) got = mockKrakenXDevice.get_status(direct_access=direct_access) expected = [ ('Liquid temperature', pytest.approx(30.9), '°C'), ('Fan speed', 1499, 'rpm'), ('Pump speed', 2702, 'rpm'), ('Firmware version', (6, 0, 2), ''), ] assert sorted(got) == sorted(expected)
def test_kraken_get_status_from_hwmon(mockKrakenXDevice, tmp_path): mockKrakenXDevice._hwmon = HwmonDevice('mock_module', tmp_path) (tmp_path / 'temp1_input').write_text('20900\n') (tmp_path / 'fan1_input').write_text('2499\n') (tmp_path / 'fan2_input').write_text('1702\n') got = mockKrakenXDevice.get_status() expected = [ ('Liquid temperature', pytest.approx(20.9), '°C'), ('Fan speed', 2499, 'rpm'), ('Pump speed', 1702, 'rpm'), ('Firmware version', (6, 0, 2), ''), ] assert sorted(got) == sorted(expected)
def test_reads_status_from_hwmon(mock_psu, tmp_path): mock_psu.device.write = None # make sure we aren't writing to the mock device mock_psu._hwmon = HwmonDevice('mock_module', tmp_path) (tmp_path / 'temp1_input').write_text('33500\n') (tmp_path / 'temp2_input').write_text('26500\n') (tmp_path / 'fan1_input').write_text('968\n') (tmp_path / 'in0_input').write_text('230000\n') (tmp_path / 'power1_input').write_text('140000000\n') (tmp_path / 'in1_input').write_text('11980\n') (tmp_path / 'curr2_input').write_text('10750\n') (tmp_path / 'power2_input').write_text('124000000\n') (tmp_path / 'in2_input').write_text('5016\n') (tmp_path / 'curr3_input').write_text('1688\n') (tmp_path / 'power3_input').write_text('8000000\n') (tmp_path / 'in3_input').write_text('3297\n') (tmp_path / 'curr4_input').write_text('562\n') (tmp_path / 'power4_input').write_text('1500000\n') got = mock_psu.get_status() expected = [ ('Temperature 1', approx(33.5, rel=1e-3), '°C'), ('Temperature 2', approx(26.5, rel=1e-3), '°C'), ('Fan speed', approx(968, rel=1e-3), 'rpm'), ('Input voltage', approx(230, rel=1e-3), 'V'), ('Total power output', approx(140, rel=1e-3), 'W'), ('+12V output voltage', approx(11.98, rel=1e-3), 'V'), ('+12V output current', approx(10.75, rel=1e-3), 'A'), ('+12V output power', approx(124, rel=1e-3), 'W'), ('+5V output voltage', approx(5.016, rel=1e-3), 'V'), ('+5V output current', approx(1.688, rel=1e-3), 'A'), ('+5V output power', approx(8, rel=1e-3), 'W'), ('+3.3V output voltage', approx(3.297, rel=1e-3), 'V'), ('+3.3V output current', approx(0.562, rel=1e-3), 'A'), ('+3.3V output power', approx(1.5, rel=1e-3), 'W'), ('Estimated input power', approx(153, abs=1), 'W'), ('Estimated efficiency', approx(92, abs=1), '%'), ] assert sorted(got) == sorted(expected)
def __init__(self, device, description, **kwargs): # compatibility with v1.1.0 drivers, which could be directly # instantiated with a usb.core.Device if isinstance(device, usb.core.Device): clname = self.__class__.__name__ _LOGGER.warning( 'constructing a %s instance from a usb.core.Device has been deprecated, ' 'use %s.find_supported_devices() or pass a HidapiDevice handle', clname, clname) usbdev = device hidinfo = next( info for info in hid.enumerate(usbdev.idVendor, usbdev.idProduct) if info['serial_number'] == usbdev.serial_number) assert hidinfo, 'Could not find device in HID bus' device = HidapiDevice(hid, hidinfo) super().__init__(device, description, **kwargs) self._hwmon = HwmonDevice.from_hidraw(device.path) if self._hwmon: _LOGGER.debug('has kernel driver: %s (%s)', self._hwmon.module, self._hwmon.path)
def test_reads_status_directly(mock_smart2, has_hwmon, direct_access): if has_hwmon: mock_smart2._hwmon = HwmonDevice(None, None) mock_smart2.device.preload_read(Report(0, SAMPLE_STATUS)) expected = [ ("Fan 1 speed", 1020, "rpm"), ("Fan 1 duty", 50, "%"), ("Fan 1 control mode", "PWM", ""), ("Fan 2 speed", 0, "rpm"), ("Fan 2 duty", 40, "%"), ("Fan 2 control mode", None, ""), ("Fan 3 speed", 0, "rpm"), ("Fan 3 duty", 40, "%"), ("Fan 3 control mode", None, ""), ("Noise level", 48, "dB"), ] got = mock_smart2.get_status(direct_access=direct_access) assert sorted(got) == sorted(expected)
def test_smart_device_reads_status_from_hwmon(mockSmartDevice, tmp_path): dev = mockSmartDevice dev._hwmon = HwmonDevice('mock_module', tmp_path) (tmp_path / 'fan1_input').write_text('1461\n') (tmp_path / 'in0_input').write_text('11910\n') (tmp_path / 'curr1_input').write_text('20\n') (tmp_path / 'pwm1_mode').write_text('1\n') (tmp_path / 'fan2_input').write_text('1336\n') (tmp_path / 'in1_input').write_text('11910\n') (tmp_path / 'curr2_input').write_text('20\n') (tmp_path / 'pwm2_mode').write_text('0\n') (tmp_path / 'fan3_input').write_text('1390\n') (tmp_path / 'in2_input').write_text('11910\n') (tmp_path / 'curr3_input').write_text('30\n') (tmp_path / 'pwm3_mode').write_text('1\n') # skip initialize for now, we're not emulating the behavior precisely # enough to require it here expected = [ ('Fan 1 speed', 1461, 'rpm'), ('Fan 1 voltage', 11.91, 'V'), ('Fan 1 current', 0.02, 'A'), ('Fan 1 control mode', 'PWM', ''), ('Fan 2 speed', 1336, 'rpm'), ('Fan 2 voltage', 11.91, 'V'), ('Fan 2 current', 0.02, 'A'), ('Fan 2 control mode', 'DC', ''), ('Fan 3 speed', 1390, 'rpm'), ('Fan 3 voltage', 11.91, 'V'), ('Fan 3 current', 0.03, 'A'), ('Fan 3 control mode', 'PWM', ''), ] got = dev.get_status() assert expected == got
def test_get_status_commander_pro(commanderProDevice, has_hwmon, direct_access, tmp_path): if has_hwmon and not direct_access: commanderProDevice._hwmon = HwmonDevice('mock_module', tmp_path) (tmp_path / 'temp1_input').write_text('26910\n') (tmp_path / 'temp2_input').write_text('29220\n') (tmp_path / 'temp4_input').write_text('25740\n') (tmp_path / 'fan1_input').write_text('940\n') (tmp_path / 'fan1_label').write_text('fan1 3pin\n') (tmp_path / 'fan2_input').write_text('939\n') (tmp_path / 'fan2_label').write_text('fan1 3pin\n') (tmp_path / 'fan3_input').write_text('987\n') (tmp_path / 'fan3_label').write_text('fan1 4pin\n') (tmp_path / 'in0_input').write_text('12066\n') (tmp_path / 'in1_input').write_text('4965\n') (tmp_path / 'in2_input').write_text('3359\n') else: if has_hwmon: commanderProDevice._hwmon = HwmonDevice('invalid_module', None) responses = [ '000a8300000000000000000000000000', # temp sensor 1 '000b6a00000000000000000000000000', # temp sensor 2 '000a0e00000000000000000000000000', # temp sensor 4 '0003ac00000000000000000000000000', # fan speed 1 '0003ab00000000000000000000000000', # fan speed 2 '0003db00000000000000000000000000', # fan speed 3 '002f2200000000000000000000000000', # get 12v '00136500000000000000000000000000', # get 5v '000d1f00000000000000000000000000', # get 3.3v ] for d in responses: commanderProDevice.device.preload_read(Report(0, bytes.fromhex(d))) commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x02, 0x00, 0x00, 0x00]) commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x00, 0x01]) res = commanderProDevice.get_status(direct_access=direct_access) print(res) assert len(res) == 9 # temp probes assert res[0] == ('Temperature 1', pytest.approx(26.91, abs=1e-3), '°C') assert res[1] == ('Temperature 2', pytest.approx(29.22, abs=1e-3), '°C') assert res[2] == ('Temperature 4', pytest.approx(25.74, abs=1e-3), '°C') # fans rpm assert res[3] == ('Fan 1 speed', 940, 'rpm') assert res[4] == ('Fan 2 speed', 939, 'rpm') assert res[5] == ('Fan 3 speed', 987, 'rpm') # voltages assert res[6] == ('+12V rail', pytest.approx(12.066, abs=1e-3), 'V') assert res[7] == ('+5V rail', pytest.approx(4.965, abs=1e-3), 'V') assert res[8] == ('+3.3V rail', pytest.approx(3.359, abs=1e-3), 'V') if not has_hwmon or direct_access: # check the commands sent sent = commanderProDevice.device.sent assert len(sent) == 9 assert sent[0].data[0] == 0x11 assert sent[1].data[0] == 0x11 assert sent[2].data[0] == 0x11 assert sent[3].data[0] == 0x21 assert sent[4].data[0] == 0x21 assert sent[5].data[0] == 0x21 assert sent[6].data[0] == 0x12 assert sent[7].data[0] == 0x12 assert sent[8].data[0] == 0x12
def test_initialize_commander_pro(commanderProDevice, has_hwmon, direct_access, tmp_path): if has_hwmon and not direct_access: commanderProDevice._hwmon = HwmonDevice('mock_module', tmp_path) (tmp_path / 'temp1_input').write_text('10000\n') (tmp_path / 'temp2_input').write_text('20000\n') (tmp_path / 'temp4_input').write_text('40000\n') (tmp_path / 'fan1_input').write_text('1100\n') (tmp_path / 'fan1_label').write_text('fan1 3pin\n') (tmp_path / 'fan2_input').write_text('1200\n') (tmp_path / 'fan2_label').write_text('fan1 3pin\n') (tmp_path / 'fan3_input').write_text('1300\n') (tmp_path / 'fan3_label').write_text('fan1 4pin\n') else: if has_hwmon: commanderProDevice._hwmon = HwmonDevice('invalid_module', None) responses = [ '000009d4000000000000000000000000', # firmware '00000500000000000000000000000000', # bootloader '00010100010000000000000000000000', # temp probes '00010102000000000000000000000000' # fan probes ] for d in responses: commanderProDevice.device.preload_read(Report(0, bytes.fromhex(d))) res = commanderProDevice.initialize(direct_access=direct_access) if has_hwmon and not direct_access: assert len(res) == 10 i = 0 else: assert len(res) == 12 assert res[0] == ('Firmware version', '0.9.212', '') assert res[1] == ('Bootloader version', '0.5', '') i = 2 assert res[i + 0] == ('Temperature probe 1', True, '') assert res[i + 1] == ('Temperature probe 2', True, '') assert res[i + 2] == ('Temperature probe 3', False, '') assert res[i + 3] == ('Temperature probe 4', True, '') assert res[i + 4] == ('Fan 1 control mode', 'DC', '') assert res[i + 5] == ('Fan 2 control mode', 'DC', '') assert res[i + 6] == ('Fan 3 control mode', 'PWM', '') assert res[i + 7] == ('Fan 4 control mode', None, '') assert res[i + 8] == ('Fan 5 control mode', None, '') assert res[i + 9] == ('Fan 6 control mode', None, '') data = commanderProDevice._data.load('fan_modes', None) assert data is not None assert len(data) == 6 assert data[0] == 0x01 assert data[1] == 0x01 assert data[2] == 0x02 assert data[3] == 0x00 assert data[4] == 0x00 assert data[5] == 0x00 data = commanderProDevice._data.load('temp_sensors_connected', None) assert data is not None assert len(data) == 4 assert data[0] == 0x01 assert data[1] == 0x01 assert data[2] == 0x00 assert data[3] == 0x01