This project provides a lightweight and efficient solution for controlling 5V PWM fans (such as the Noctua NF-A4x10) on a Raspberry Pi 4.
Written in C and leveraging the pigpio library, it offers precise fan speed regulation based on CPU temperature, real-time tachometer feedback (RPM monitoring), and configurable hysteresis for smooth operation.
It comes with a systemd service file to ensure the fan controller starts immediately during early boot.
- Lightweight & Fast: Written in pure C for minimal resource usage.
- Smart Control: Adjusts fan speed dynamically based on CPU temperature.
- RPM Monitoring: Reads fan speed via the tachometer pin (GPIO17).
- Smooth Operation: Implements hysteresis to prevent rapid speed switching.
- Systemd Integration: Includes a service unit for automatic startup at boot.
- Hardware Support: Optimized for Raspberry Pi 4 and 5V PWM fans.
- Raspberry Pi 4
- 5V PWM Fan (e.g. Noctua NF-A4x10 5V PWM)
- Connections:
- 🔵 GPIO18 (Pin 12) (PWM) → blue wire
- 🟢 GPIO17 (Pin 11) (Tachometer) → green wire
- 🟡 5V (Pin 4) → yellow wire
- ⚫ GND (Pin 6) → black wire
- Raspberry Pi OS (Raspbian)
pigpiodactive at boot (pigpio daemon)
Open a terminal and run:
sudo apt update
sudo apt install build-essential libpigpiod-if2-1 libpigpiod-if2-dev pigpiobuild-essential→ C compiler and make utilitieslibpigpiod-if2-dev→ headers and C library to interface withpigpiodpigpio→ daemon for GPIO/PWM management
sudo mkdir -p /opt/fancontrol
sudo chown $(whoami):$(whoami) /opt/fancontrolCopy the source files into the folder:
cp fan_control.c /opt/fancontrol/Enter the folder:
cd /opt/fancontrolCompile the C code using the pigpiod_if2 library:
gcc fan_control.c -lpigpiod_if2 -o fan_controlMake it executable:
chmod +x fan_controlStart the pigpiod daemon (if it is not already running):
sudo systemctl start pigpiodRun the program manually for a quick test:
./fan_controlYou should see output similar to:
Temp: 51.2°C | Fan: 20% | RPM: 3500
Temp: 53.0°C | Fan: 35% | RPM: 4200
...
To stop manually: Ctrl+C (the program will perform a clean shutdown of the fan before exiting).
Create the systemd unit file /etc/systemd/system/fancontrol.service using nano:
sudo nano /etc/systemd/system/fancontrol.servicePaste the following content into the file:
[Unit]
Description=Custom PWM Fan Controller Service for Raspberry Pi
Requires=pigpiod.service
After=pigpiod.service
Before=multi-user.target
DefaultDependencies=no
[Service]
Type=simple
ExecStart=/opt/fancontrol/fan_control
ExecStartPre=/bin/sh -c 'for i in 0 1 2 3 4; do systemctl is-active --quiet pigpiod && exit 0 || sleep 1; done; exit 1'
WorkingDirectory=/opt/fancontrol
User=pi
Group=pi
Restart=always
RestartSec=2
SyslogIdentifier=fancontrol
ProtectHome=true
NoNewPrivileges=true
[Install]
WantedBy=sysinit.targetSave and exit (Ctrl+O, Enter, Ctrl+X).
Note: if you use a user other than pi, modify User= and Group= accordingly.
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable fancontrol
sudo systemctl start fancontrolCheck the status:
systemctl status fancontrol
journalctl -u fancontrol -fCheck that pigpiod is active:
systemctl status pigpiodReal-time service logs:
journalctl -u fancontrol -fIf the service crashes repeatedly, check journalctl -xe for error messages and the executable's logs.
To stop temporarily:
sudo systemctl stop fancontrolTo disable at startup:
sudo systemctl disable fancontrolTo remove the unit file:
sudo rm /etc/systemd/system/fancontrol.service
sudo systemctl daemon-reload- Code parameters: hysteresis, thresholds, ramp step, and MIN_TIME_AT_LEVEL are defined in the C source as
#define— modifyfan_control.cand recompile to change behavior. - Executable path: change it to
/opt/fancontrolor wherever you prefer, but updateExecStartin the.servicefile. - Logging to file: if you want logs in
/var/log/fancontrol.logas well, you can add to the[Service]block:and create the file with correct permissions:StandardOutput=append:/var/log/fancontrol.log StandardError=inherit
sudo touch /var/log/fancontrol.log sudo chown pi:pi /var/log/fancontrol.log
- RPM Test: if the tachometer does not provide pulses, check wiring (pull-up) and that the configured pin is correct.
Compile, copy, and install service (quick example):
# from the folder containing fan_control.c
gcc fan_control.c -lpigpiod_if2 -o fan_control
sudo mkdir -p /opt/fancontrol
sudo cp fan_control /opt/fancontrol/
sudo chown -R pi:pi /opt/fancontrol
sudo chmod +x /opt/fancontrol/fan_control
# copy the service (assuming fancontrol.service already created in cwd)
sudo cp fancontrol.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now fancontrol