Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ subjective "from more to less liquid control-ly" order.
| AIO liquid cooler | [NZXT Kraken Z53, Z63, Z73](docs/kraken-x3-z3-guide.md) | USB & USB HID | <sup>_p_</sup> |
| Pump controller | [Aquacomputer D5 Next](docs/aquacomputer-d5next-guide.md) | USB HID | <sup>_ehnp_</sup> |
| Fan/LED controller | [Aquacomputer Octo](docs/aquacomputer-octo-guide.md) | USB HID | <sup>_ehnp_</sup> |
| Fan/LED controller | [Aquacomputer Quadro](docs/aquacomputer-quadro-guide.md) | USB HID | <sup>_ehnp_</sup> |
| Fan/LED controller | [Corsair Commander Pro](docs/corsair-commander-guide.md) | USB HID | <sup>_h_</sup> |
| Fan/LED controller | [Corsair Commander Core](docs/corsair-commander-core-guide.md) | USB HID | <sup>_ep_</sup> |
| Fan/LED controller | [Corsair Commander Core XT](docs/corsair-commander-core-guide.md) | USB HID | <sup>_enp_</sup> |
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Device guides
- [Aquacomputer D5 Next watercooling pump](aquacomputer-d5next-guide.md)
- [Aquacomputer Farbwerk 360 RGB controller](aquacomputer-farbwerk360-guide.md)
- [Aquacomputer Octo fan controller](aquacomputer-octo-guide.md)
- [Aquacomputer Quadro fan controller](aquacomputer-quadro-guide.md)
- [Asetek 690LC liquid coolers](asetek-690lc-guide.md)
- [Asetek Pro liquid coolers](asetek-pro-guide.md)
- [Corsair Commander Core and Core XT](corsair-commander-core-guide.md)
Expand Down
58 changes: 58 additions & 0 deletions docs/aquacomputer-quadro-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Aquacomputer Quadro fan controller
_Driver API and source code available in [`liquidctl.driver.aquacomputer`](../liquidctl/driver/aquacomputer.py)._

_New in 1.11.0._

## Initialization

Initialization is _currently_ not required, but is recommended. It outputs the firmware version:

```
# liquidctl initialize
Aquacomputer Quadro
├── Firmware version 1032
└── Serial number 23410-65344
```

The Quadro automatically sends a status HID report every second as soon as it's connected.

## Monitoring

The Quadro exposes four temperature sensors and four groups of fan sensors for optionally connected fans. These groups provide RPM speed, voltage, current and power readings:

```
# liquidctl status
Aquacomputer Quadro
├── Sensor 3 15.9 °C
├── Fan 1 speed 0 rpm
├── Fan 1 power 0.00 W
├── Fan 1 voltage 0.00 V
├── Fan 1 current 0.00 A
├── Fan 2 speed 0 rpm
├── Fan 2 power 0.00 W
├── Fan 2 voltage 12.07 V
├── Fan 2 current 0.00 A
├── Fan 3 speed 360 rpm
├── Fan 3 power 0.00 W
├── Fan 3 voltage 12.07 V
├── Fan 3 current 0.00 A
├── Fan 4 speed 0 rpm
├── Fan 4 power 0.00 W
├── Fan 4 voltage 12.07 V
├── Fan 4 current 0.00 A
└── Flow sensor 0 dL/h
```

## Interaction with Linux hwmon drivers
[Linux hwmon]: #interaction-with-linux-hwmon-drivers

Aquacomputer devices are supported by the mainline Linux kernel with its
[`aquacomputer_d5next`] driver, and status data is provided through a standard
hwmon sysfs interface.

Liquidctl automatically detects when a kernel driver is bound to the device
and, whenever possible, uses it instead of directly accessing the device.
Alternatively, direct access to the device can be forced with
`--direct-access`.

[`aquacomputer_d5next`]: https://www.kernel.org/doc/html/latest/hwmon/aquacomputer_d5next.html
34 changes: 33 additions & 1 deletion docs/developer/protocol/aquacomputer.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,36 @@ Here is what it's currently known to contain:
| Fan 5 substructure | 0xB1 |
| Fan 6 substructure | 0xBE |
| Fan 7 substructure | 0xCB |
| Fan 8 substructure | 0xD8 |
| Fan 8 substructure | 0xD8 |

## Quadro

The Quadro exposes four temperature sensors and four groups of fan sensor data (outlined in the preamble) through its sensor report.

### Sensor report

An example sensor report of the Quadro looks like this:

```
01 00 03 5B 72 FF 40 00 01 00 00 00 65 04 08 00 00 00 01 00 00 00 13 C5 00 00 00 91 00 32 CB B0 00 00 00 00 00 00 00 00 FF D5 FF D6 9B 54 FF D8 A6 FD 5B 97 7F FF 7F FF 06 51 7F FF 09 59 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 7F FF 13 88 7F FF 7F FF 7F FF 03 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 B9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 27 10 04 B9 00 00 00 00 00 00 00 00 08 05 BB 04 B9 00 00 00 00 01 64 00 00 00 15 E0 04 B9 00 00 00 00 00 00 00 00 08 00 00 00 00 03 E8 00 00 00 00 00 00 03 E8 27 10 00 00 00 00 03 E8 05 BB 00 00 00 00 03 E8 15 E0 00 00 00 00 03 E8 27 10 00 0A 00 00 00 0E 00 00 00 00 27 10 FF 00 00 01
```

Its ID is `0x01` and its length is `0xDC`.

Here is what it's currently known to contain:

| What | Where/starts at (offset) |
|------------------------------------|--------------------------|
| Serial number (first part) | 0x03 |
| Serial number (second part) | 0x05 |
| Firmware version | 0xD |
| Number of power cycles *[4 bytes]* | 0x18 |
| Temp sensor 1 | 0x34 |
| Temp sensor 2 | 0x36 |
| Temp sensor 3 | 0x38 |
| Temp sensor 4 | 0x3A |
| Fan 1 substructure | 0x70 |
| Fan 2 substructure | 0x7D |
| Fan 3 substructure | 0x8A |
| Fan 4 substructure | 0x97 |
| Flow sensor | 0x6E |
3 changes: 3 additions & 0 deletions extra/linux/71-liquidctl.rules
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f010", TAG+="uacc
# Aquacomputer Octo
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f011", TAG+="uaccess"

# Aquacomputer Quadro
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f00d", TAG+="uaccess"

# Asetek 690LC (assuming EVGA CLC)
# Asetek 690LC (assuming NZXT Kraken X)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2433", ATTRS{idProduct}=="b200", TAG+="uaccess"
Expand Down
3 changes: 2 additions & 1 deletion liquidctl.8
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ Internal data used by some drivers.
.SS Aquacomputer D5 Next
.SS Aquacomputer Farbwerk 360
.SS Aquacomputer Octo
Cooling channels: (D5 Next, Octo:) not yet supported; (Farbwerk 360:) not applicable.
.SS Aquacomputer Quadro
Cooling channels: (D5 Next, Octo, Quadro:) not yet supported; (Farbwerk 360:) not applicable.
.PP
Lighting channels: not yet supported.
.SS Corsair Commander Core
Expand Down
42 changes: 42 additions & 0 deletions liquidctl/driver/aquacomputer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
The status HID report exposes four temperature sensor values and eight groups
of fan sensors for optionally connected fans.

Aquacomputer Quadro
-------------------------
Quadro is a fan/RGB controller and sends a status HID report every second with
no initialization being required.

The status HID report exposes four temperature sensor values and four groups
of fan sensors for optionally connected fans.

Driver
------
Linux has the aquacomputer_d5next driver available since v5.15. Subsequent
Expand All @@ -36,6 +44,7 @@
- D5 Next watercooling pump: sensors - 5.15+
- Farbwerk 360: sensors - 5.18+
- Octo: sensors - 5.19+
- Quadro: sensors - 6.0+

Copyright (C) 2022 - Aleksa Savic

Expand Down Expand Up @@ -65,6 +74,7 @@ class Aquacomputer(UsbHidDriver):
_DEVICE_D5NEXT = "D5 Next"
_DEVICE_FARBWERK360 = "Farbwerk 360"
_DEVICE_OCTO = "Octo"
_DEVICE_QUADRO = "Quadro"

_DEVICE_INFO = {
_DEVICE_D5NEXT: {
Expand Down Expand Up @@ -97,6 +107,18 @@ class Aquacomputer(UsbHidDriver):
"fan_current_label": [f"Fan {num} current" for num in range(1, 8 + 1)],
"status_report_length": 0x147,
},
_DEVICE_QUADRO: {
"type": _DEVICE_QUADRO,
"fan_sensors": [0x70, 0x7D, 0x8A, 0x97],
"temp_sensors": [0x34, 0x36, 0x38, 0x3A],
"temp_sensors_label": ["Sensor 1", "Sensor 2", "Sensor 3", "Sensor 4"],
"fan_speed_label": [f"Fan {num} speed" for num in range(1, 4 + 1)],
"fan_power_label": [f"Fan {num} power" for num in range(1, 4 + 1)],
"fan_voltage_label": [f"Fan {num} voltage" for num in range(1, 4 + 1)],
"fan_current_label": [f"Fan {num} current" for num in range(1, 4 + 1)],
"flow_sensor_offset": 0x6E,
"status_report_length": 0xDC,
},
}

_MATCHES = [
Expand All @@ -118,6 +140,12 @@ class Aquacomputer(UsbHidDriver):
"Aquacomputer Octo",
{"device_info": _DEVICE_INFO[_DEVICE_OCTO]},
),
(
0x0C70,
0xF00D,
"Aquacomputer Quadro",
{"device_info": _DEVICE_INFO[_DEVICE_QUADRO]},
),
]

def __init__(self, device, description, device_info, **kwargs):
Expand Down Expand Up @@ -210,6 +238,14 @@ def _get_status_directly(self):
"V",
)
sensor_readings.append(plus_12v_voltage)
elif self._device_info["type"] == self._DEVICE_QUADRO:
# Read flow sensor value
flow_sensor_value = (
"Flow sensor",
u16be_from(msg, self._device_info["flow_sensor_offset"]),
"dL/h",
)
sensor_readings.append(flow_sensor_value)

return sensor_readings

Expand Down Expand Up @@ -269,6 +305,10 @@ def _get_status_from_hwmon(self):
_LOGGER.warning(
"some attributes cannot be read from %s kernel driver", self._hwmon.module
)
elif self._device_info["type"] == self._DEVICE_QUADRO:
# Read flow sensor value
flow_sensor_value = ("Flow sensor", self._hwmon.get_int("fan5_input"), "dL/h")
sensor_readings.append(flow_sensor_value)

return sensor_readings

Expand All @@ -293,6 +333,7 @@ def set_speed_profile(self, channel, profile, **kwargs):
if (
self._device_info["type"] == self._DEVICE_D5NEXT
or self._device_info["type"] == self._DEVICE_OCTO
or self._device_info["type"] == self._DEVICE_QUADRO
):
# Not yet reverse engineered / implemented
raise NotSupportedByDriver()
Expand All @@ -303,6 +344,7 @@ def set_fixed_speed(self, channel, duty, **kwargs):
if (
self._device_info["type"] == self._DEVICE_D5NEXT
or self._device_info["type"] == self._DEVICE_OCTO
or self._device_info["type"] == self._DEVICE_QUADRO
):
# Not yet implemented
raise NotSupportedByDriver()
Expand Down
Loading