truefan
Fan control daemon for TrueNAS SCALE systems on Supermicro X11 boards. Takes over fan control from the BMC so you can tune noise vs. cooling to your environment. Reads temperatures from IPMI, SMART, NVMe, and lm-sensors, then sets fan duty cycles via IPMI raw commands. Metrics go to Netdata via statsd.
Features
- Auto-detection of sensors and fans — classifies by type (cpu, drive, nvme, ambient, other) and applies per-class interpolation curves.
- Self-calibrating — learns each fan's setpoint table by ramping duty down and recording RPMs. Can be recalibrated as fans age or collect dust.
- Failsafe — fans go to 100% on crash, total sensor class failure, or stalled fan. The watchdog parent restarts the daemon automatically.
- Config validation — startup, reload, and the
checkcommand validate config syntax, values, and hardware match before touching any fans. - Syslog logging — the daemon logs to syslog;
truefan logswraps journalctl for easy access. - Netdata metrics — per-sensor temperature and thermal load, per-zone duty, per-fan target RPM, daemon uptime, and restart count via statsd. Optional alert configs included.
Requirements
- Python 3.11+
ipmitoolsmartctl(smartmontools) — for SATA/SAS drive tempsnvme-cli— for NVMe tempslm-sensors— for kernel-exposed sensors- Supermicro X11 motherboard with IPMI
Install
TrueNAS SCALE doesn't ship ensurepip, so create the venv without it and
bootstrap pip manually:
python3 -m venv --without-pip /mnt/pool1/venvs/truefan
source /mnt/pool1/venvs/truefan/bin/activate
curl -sS https://bootstrap.pypa.io/get-pip.py | python3
pip install truefan
Put the venv on a pool — the boot drive is wiped on OS updates.
Quick start
# Detect sensors, calibrate fans, write config
# (ramps fans up and down for a few minutes)
sudo truefan init
# Start the daemon (daemonizes and returns immediately)
sudo truefan start
# Check if it's running
truefan status
# Show detected sensors and current readings
truefan sensors
# Follow daemon logs
truefan logs -f
# Reload config without restarting
sudo truefan reload
# Re-calibrate after cleaning or replacing fans
sudo truefan recalibrate
# Stop the daemon
sudo truefan stop
To get Netdata dashboards and alerts, install the bundled configs:
truefan netdata install
Use truefan netdata uninstall to remove them. Use truefan netdata check to verify
configs are up to date.
Configuration
truefan init generates a truefan.toml with sensible defaults. Example:
poll_interval_seconds = 15
spindown_window_seconds = 180
[thermal.class.drive]
no_cooling_temp = 30
max_cooling_temp = 45
fan_zones = ["peripheral"]
# Per-sensor overrides for components that run hotter than their class
[thermal.sensor.lmsensors_mlx5_pci_0200_sensor0]
no_cooling_temp = 60
max_cooling_temp = 95
# Learned via calibration — duty % = expected RPM
[fans.FAN1]
zone = "cpu"
[fans.FAN1.setpoints]
25 = 320
30 = 450
40 = 620
50 = 780
100 = 1500
Use --config PATH with any command to specify an alternate config location.
Running on boot
TrueNAS SCALE's Init/Shutdown Scripts (under System > Advanced) run commands at boot and shutdown.
Add a script (Type: Command, When: Post Init):
/mnt/pool1/venvs/truefan/bin/truefan start
No tmux or nohup needed — start forks into the background on its own.
Use truefan logs -f to follow output and truefan status to check if
it's running.
How it works
Each sensor class has a temperature-to-duty curve. Between no_cooling_temp
and max_cooling_temp, duty is linearly interpolated from 0% to 100%;
hardware-reported thermal limits override max_cooling_temp when available.
The hottest sensor in each fan zone sets the duty, which is then snapped to
the nearest calibrated fan setpoint. A spindown window prevents rapid cycling.
If a fan stalls, the zone goes to 100% and the lowest setpoint is removed so the minimum duty rises going forward.
Send SIGUSR1 to dump current sensor readings, thermal loads, and zone
duties to syslog (kill -USR1 $(cat /var/run/truefan.pid); view with
truefan logs).
License
MIT
Metadata
Release files for truefan 1.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| truefan-1.6.0.tar.gz | 86.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| truefan-1.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 132.1 kB
Release files / truefan-1.6.0.tar.gz
| Download URL | truefan-1.6.0.tar.gz |
|---|---|
| Size | 86.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7acf6ac0384ec6cf9071597640d2b1c9c21c3d57f60d3b5347db01a2e98dd140
|
|
BLAKE2b-256 checksum How to use checksums |
a16f527ae42e2b422c91e19c8bee5fc60f5a8361681083f00253794d5d444ded
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 6, 2026.
Transparency logRelease files / truefan-1.6.0-py3-none-any.whl
| Download URL | truefan-1.6.0-py3-none-any.whl |
|---|---|
| Size | 45.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
800e40298f020fdcc3f7f606fe2a4cdc5bb6a63e914f4eab7f19a4b5d59a887a
|
|
BLAKE2b-256 checksum How to use checksums |
62ae21ca23be19a16d9775215d85327144453262136f98ca1d0d0619177c6753
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 6, 2026.
Transparency log