Fan Control for Raspberry Pi
Hardware
I got this Raspberry Pi case from eBay. There are various sellers; I paid about $9 for it. The fan hooks up to 5v and ground GPIO pins, and is intended to run continuously.
I decided I would rather that the fan was on only when necessary. Nicely enough, the Raspbian OS provides a command that reports the CPU temperature:
$ vcgencmd measure_temp
temp=30.0'C
So only a little bit of additional hardware was necessary to enable temperature-based software control of the fan.
The BC337-25 NPN switching transistor can handle up to 500 mA of collector current and was available on eBay for $3.20 for a bag of 50 (shipping included). Typical fan current is under 200 mA. Assuming a 0.7v base-emitter voltage drop, a 3.3v GPIO output though 560 ohms results in a 4.6 mA current. With a typical transistor beta over 100, this should be plenty to control the fan, while still being safe for the GPIO pin.
I assembled the circuit on a little chip of stripboard:
The fan connectors attach to the two header pins, and and the other end of the circuit board wires (not shown) have connectors to attach to the GPIO header.
I put a little clear nail polish over the wires to hold them down onto the circuit board. I wrapped the circuit board in silicone tape and stuck it to the side of the fan with some silicone caulk. The red and black wires from the circuit board were attached to 5v and ground (pins 4 and 6 - see GPIO pinout) as before. I wasn't using BCM 17 (pin 11) for anything else, so I attached the green wire there.
[Updated 2022-12-28: WiringPi is no longer supported; replaced with pigpio.]
I made sure that the WiringPi library was installed.
I installed the pigpio library.
I could then turn the fan on and off from the command line:
# set GPIO pin BCM 17 to output mode
gpio -g mode 17 out
# turn on fan
gpio -g write 17 1
# turn off fan
gpio -g write 17 0
# install
sudo apt install pigpio
# auto-start pigpiod at boot
sudo systemctl enable pigpiod
# start pigpiod
sudo systemctl start pigpiod
# set GPIO pin BCM 17 to output mode
pigs m 17 w
# turn on fan
pigs w 17 1
# turn off fan
pigs w 17 0
Software
The following assumes that Raspbian Stretch Bullseye is installed.
To automate the fan control, I created three shell scripts.
Make script to turn on fan
sudo vi /usr/local/bin/fanon
Insert text:
#!/bin/bash
gpio -g mode 17 out
gpio -g write 17 1
#!/bin/bash
pigs m 17 w
pigs w 17 1
Save and make executable:
sudo chmod +x /usr/local/bin/fanon
Make script to turn off fan
sudo vi /usr/local/bin/fanoff
Insert text:
#!/bin/bash
gpio -g mode 17 out
gpio -g write 17 0
#!/bin/bash
pigs m 17 w
pigs w 17 0
Save and make executable:
sudo chmod +x /usr/local/bin/fanoff
Make script to check temperature and call fanon or fanoff
sudo vi /usr/local/bin/runfan
Insert text:
while :
do
sleep 15
TEMP=$(printf "%.0f" `vcgencmd measure_temp | tr -d "temp='C"`)
if [ $TEMP -ge 40 ]; then /usr/local/bin/fanon; fi
if [ $TEMP -le 35 ]; then /usr/local/bin/fanoff; fi
done
Save and make executable:
sudo chmod +x /usr/local/bin/runfan
This script turns on the fan at 40°C or higher and turns it off at 35°C or lower. (This is better than having a single theshold temperature for turning the fan on and off, since it prevents the fan from continually turning on and off if the temperature fluctuates around the threshold.)
Test scripts
To test the scripts, open three ssh terminals to the Raspberry Pi.
In the first terminal, run the monitoring script:
runfan
In the second terminal, watch the CPU temperature:
watch vcgencmd measure_temp
In the third terminal, run a program to stress the CPU (which will increase the temperature):
sudo apt-get install sysbench
sysbench --num-threads=4 --validate=on --test=cpu --cpu-max-prime=200000 run
sysbench --threads=4 --cpu-max-prime=2000000 cpu run
Watch the CPU temperature, and observe that the fan turns on within 15 seconds of the temperature exceeding 40°C. Stop the sysbench program by typing Ctrl-C, and observe that the fan turns off within 15 seconds of the temperature falling below 35°C.
Make service for automatic fan control
To have the runfan
tool run automatically as daemon,
I created a systemd unit file.
(Note that online references
to rc.local as the way to do this are now
obsolete.)
sudo vi /etc/systemd/system/runfan.service
Insert text:
[Unit]
After=default.target
[Service]
Type=simple
ExecStart=/bin/bash /usr/local/bin/runfan
RemainAfterExit=yes
[Install]
WantedBy=default.target
Save, enable service, restart:
sudo systemctl enable runfan.service
sudo reboot
Open two ssh terminals to the Raspberry Pi. Run
watch vcgencmd measure_temp
in one window and
sysbench --num-threads=4 --validate=on --test=cpu --cpu-max-prime=200000 run
sysbench --threads=4 --cpu-max-prime=2000000 cpu run
in the other. Verify that the fan turns on and off automatically at 40°C and 35°C. To disable the automatic fan service, use:
sudo systemctl disable runfan.service
sudo reboot