A Linux daemon that automatically controls Lian-Li UNI FAN speed based on CPU temperature, communicating with the official USB controller via HID.
- Temperature-based fan speed control with linear interpolation
- Three built-in profiles: silent, balanced, performance
- Hysteresis to prevent rapid speed oscillations
- Automatic USB controller reconnection on disconnect
- Safe fan speed on daemon shutdown (default: 90%)
- Runtime configuration reload via SIGHUP
- Hardware-agnostic design with YAML-based protocol definitions
Protocol definitions are stored in protocols.yaml. The active protocol is selected via the PROTOCOL configuration parameter.
| Key | Model | Status |
|---|---|---|
lian-li-sl-inf |
Lian-Li UNI FAN SL-INF | Fully Supported |
lian-li-sl-v1 |
Lian-Li UNI FAN SL V1 | Fully Supported |
lian-li-al-v1 |
Lian-Li UNI FAN AL V1 | Untested |
Adding a new controller model only requires a new entry in protocols.yaml.
- Python 3.10+
pipx— available viaapton Ubuntu 22.04 and lateracl— providessetfacl, used by the udev rule; pre-installed on most Ubuntu systems
sudo apt install pipx aclThe
hidapiPyPI package ships as a self-contained manylinux wheel with all HID libraries bundled. No system HID packages (libhidapi-*,libusb-*) are required.
# From a local clone
sudo PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install .
# Or directly from the repository
sudo PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install git+https://github.com/yannlambret/ll-uni-fan-linux.gitThe PIPX_HOME and PIPX_BIN_DIR overrides ensure the binary lands in /usr/local/bin
rather than /root/.local/bin, which is required for the systemd service to find it.
The daemon runs as an unprivileged user and needs read/write access to the USB HID device:
sudo cp system/99-lian-li.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger# Create a dedicated system user
sudo useradd --system --no-create-home --shell /usr/sbin/nologin -G plugdev fanctl
# Install the service and default configuration
sudo cp system/ll-uni-fan-linux.service /etc/systemd/system/
sudo cp system/ll-uni-fan-linux.default /etc/default/ll-uni-fan-linux
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now ll-uni-fan-linuxThe daemon reads its configuration from three sources, in order of priority:
- CLI arguments (highest)
- Environment variables (set by systemd
EnvironmentFile) /etc/default/ll-uni-fan-linux- Built-in defaults (lowest)
Edit /etc/default/ll-uni-fan-linux:
# Fan controller protocol (see protocols.yaml for available keys)
PROTOCOL=lian-li-sl-inf
# Fan profile: silent, balanced, performance
PROFILE=balanced
# Temperature polling interval in seconds
POLL_INTERVAL=3
# Active fan channels (comma-separated, 0-3)
CHANNELS=0,1,2,3
# Fan speed set on daemon shutdown (0-100%)
SAFE_SPEED=90
# Logging level: DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO
# Enable debug mode (overrides LOG_LEVEL to DEBUG)
DEBUG=falseReload at runtime without restarting the service:
systemctl kill -s HUP ll-uni-fan-linuxll-uni-fan-linux --profile performance --debug
ll-uni-fan-linux --protocol lian-li-sl-v1 --channels 0,1 --poll-interval 5| Profile | 40°C | 80°C | Description |
|---|---|---|---|
silent |
20% | 80% | Prioritizes low noise |
balanced |
30% | 100% | Default, balanced |
performance |
50% | 100% | Maximum cooling |
Fan speed is linearly interpolated between the two temperature anchor points. Below 40°C, the minimum speed is held; above 80°C, the maximum speed is held. A 2°C hysteresis prevents rapid oscillations near temperature thresholds.
Check that the controller is visible on the USB bus:
lsusb | grep 0cf2The daemon automatically retries the connection every 10 seconds.
Install the udev rule (see Installation) and make sure the fanctl user belongs to the plugdev group.
Ensure your CPU thermal driver is loaded. The daemon reads temperatures via psutil, which uses the kernel's hwmon interface (/sys/class/hwmon/):
python3 -c "import psutil; print(psutil.sensors_temperatures())"# Set up the virtual environment
poetry install
# Run the daemon locally
poetry run ll-uni-fan-linux --debug --profile performance
# Run tests
poetry run pytest
# Lint
poetry run ruff check .USB HID protocol reverse-engineered from uni-sync.