A variable-speed PWM fan controller for Raspberry Pi, driven by CPU temperature.
- Hardware PWM — uses the native GPU PWM (BCM chip), not software PWM
- Proportional control — fan speed scales smoothly with temperature
- Configurable hysteresis — prevents oscillation near the temperature threshold
- systemd service — starts automatically with the system and restarts on failure
- syslog logging — all events are logged to the system log
- Raspberry Pi (any model with GPIO header)
- 5V fan with PWM control
- Python 3
- Libraries:
rpi-hardware-pwm,psutil
pip3 install rpi-hardware-pwm psutilEdit temperature_pwm_controller.ini:
[config]
intervalo_de_prueba = 5 # Seconds between checks
canal_pwm = 0 # PWM channel (GPIO 18 = channel 0)
frecuencia = 25000 # PWM frequency in Hz
temp_min = 45 # Minimum temperature (°C) — below this, fan OFF
temp_max = 65 # Maximum temperature (°C) — above this, fan 100%
ciclo_min = 60 # Minimum duty cycle (%)
ciclo_max = 100 # Maximum duty cycle (%)
histeresis = 2 # Hysteresis margin (°C)
debug = False # True = detailed syslog output
as_a_service = TrueTemp < temp_min (45°C) → Fan OFF (0%)
Temp = temp_min → Fan ON (duty_min = 60%)
Temp = temp_max (65°C) → Fan 100%
Intermediate range → Linear interpolation between duty_min and duty_max
# Copy the service file
sudo cp temperature_pwm_controller.service /etc/systemd/system/
# Reload systemd
sudo systemctl daemon-reload
# Enable to start at boot
sudo systemctl enable temperature_pwm_controller.service
# Start the service
sudo systemctl start temperature_pwm_controller.service
# Verify it's running
sudo systemctl status temperature_pwm_controller.service# View service logs
sudo journalctl -u temperature_pwm_controller.service -f
# Stop the service
sudo systemctl stop temperature_pwm_controller.service
# Restart the service
sudo systemctl restart temperature_pwm_controller.service
# Uninstall
sudo systemctl stop temperature_pwm_controller.service
sudo systemctl disable temperature_pwm_controller.service
sudo rm /etc/systemd/system/temperature_pwm_controller.service
sudo rm -rf /home/pi/raspberry-fanraspberry-fan/
├── temperature_pwm_controller.py # Main script
├── temperature_pwm_controller.ini # Configuration file
├── temperature_reader.py # Temperature reader utility
├── hardware_pwm_generator.py # PWM generator utility
├── pwm_cycle.py # Fan test cycle utility
└── temperature_pwm_controller.service # systemd unit file
- 1 × MOSFET transistor (e.g. IRLZ44N or AO3400)
- 1 × Diode 1N4001 (reverse peak protection)
- 1 × 5V fan with PWM pin (yellow wire)
- Jumper wires
Raspberry Pi GPIO 18 (PWM) ─── Base transistor (G)
|
5V Fan ──────────────────────── Drain transistor (D)
| |
GND ────────── Source transistor (S)
|
Diode (reverse-biased between fan + and GND)
Note: The fan PWM wire (yellow) connects directly to GPIO 18. The transistor amplifies the control signal.
See the full article at eMariete.com for a detailed explanation of the hardware and wiring.
The script needs root permissions to write to /sys/class/pwm/.
Run with sudo or verify the service is properly configured.
-
Verify the script is running:
ps aux | grep temperature_pwm -
Check PWM is exported:
ls /sys/class/pwm/pwmchip0/
-
Test the fan manually:
python3 hardware_pwm_generator.py 0 25000 100
(Sets fan to 100% for 10 seconds)
python3 temperature_reader.pyMIT License
Controlador de velocidad variable para ventilador de Raspberry Pi mediante PWM, basado en la temperatura de la CPU.
- PWM por hardware — usa el PWM nativo de la GPU (BCM chip), no software PWM
- Control proporcional — la velocidad del ventilador escala suavemente con la temperatura
- Histéresis configurable — evita oscilaciones cerca del umbral de temperatura
- Servicio systemd — se inicia automáticamente con el sistema y se rearranca si falla
- Logging a syslog — todos los eventos se registran en el log del sistema
- Raspberry Pi (cualquier modelo con GPIO header)
- Ventilador de 5V con control PWM
- Python 3
- Librerías:
rpi-hardware-pwm,psutil
pip3 install rpi-hardware-pwm psutilEdita temperature_pwm_controller.ini:
[config]
intervalo_de_prueba = 5 # Segundos entre comprobaciones
canal_pwm = 0 # Canal PWM (GPIO 18 = canal 0)
frecuencia = 25000 # Frecuencia PWM en Hz
temp_min = 45 # Temperatura mínima (°C) — por debajo, ventilador OFF
temp_max = 65 # Temperatura máxima (°C) — a partir de aquí, ventilador 100%
ciclo_min = 60 # Ciclo de trabajo mínimo (%)
ciclo_max = 100 # Ciclo de trabajo máximo (%)
histeresis = 2 # Margen de histéresis (°C)
debug = False # True = logs detallados a syslog
as_a_service = TrueTemp < temp_min (45°C) → Ventilador OFF (0%)
Temp = temp_min → Ventilador ON (ciclo_min = 60%)
Temp = temp_max (65°C) → Ventilador 100%
Rango intermedio → Interpolación lineal entre ciclo_min y ciclo_max
# Copia el archivo de servicio
sudo cp temperature_pwm_controller.service /etc/systemd/system/
# Recarga systemd
sudo systemctl daemon-reload
# Habilita para que arranque con el sistema
sudo systemctl enable temperature_pwm_controller.service
# Arranca el servicio
sudo systemctl start temperature_pwm_controller.service
# Verifica que funciona
sudo systemctl status temperature_pwm_controller.service# Ver logs del servicio
sudo journalctl -u temperature_pwm_controller.service -f
# Detener el servicio
sudo systemctl stop temperature_pwm_controller.service
# Reiniciar el servicio
sudo systemctl restart temperature_pwm_controller.service
# Desinstalar
sudo systemctl stop temperature_pwm_controller.service
sudo systemctl disable temperature_pwm_controller.service
sudo rm /etc/systemd/system/temperature_pwm_controller.service
sudo rm -rf /home/pi/raspberry-fanraspberry-fan/
├── temperature_pwm_controller.py # Script principal
├── temperature_pwm_controller.ini # Archivo de configuración
├── temperature_reader.py # Utilidad de lectura de temperatura
├── hardware_pwm_generator.py # Utilidad generador PWM
├── pwm_cycle.py # Utilidad de ciclo de prueba del ventilador
└── temperature_pwm_controller.service # Archivo systemd
- 1 × Transistor MOSFET (por ejemplo IRLZ44N o AO3400)
- 1 × Diodo 1N4001 (protección de pico inverso)
- 1 × Ventilador de 5V con pin PWM (cable amarillo)
- Cables de conexión
Raspberry Pi GPIO 18 (PWM) ─── Base transistor (G)
|
Ventilador 5V ──────────────── Drenador transistor (D)
| |
GND ────────── Surtidor transistor (S)
|
Diodo (polarizado en inversa entre + y GND del ventilador)
Nota: El cable PWM (amarillo) del ventilador va conectado directamente al GPIO 18 de la Raspberry Pi. El transistor amplifica la señal de control.
Consulta el artículo completo en eMariete.com para una explicación detallada del hardware y el esquema de conexión.
El script necesita permisos de root para escribir en /sys/class/pwm/.
Ejecuta con sudo o verifica que el servicio está configurado correctamente.
-
Verifica que el script está corriendo:
ps aux | grep temperature_pwm -
Comprueba que el PWM está exportado:
ls /sys/class/pwm/pwmchip0/
-
Prueba el ventilador manualmente:
python3 hardware_pwm_generator.py 0 25000 100
(Pone el fan al 100% durante 10 segundos)
python3 temperature_reader.pyMIT License