blog

2018-03-15

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.

raspberry pi case

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:

circuit board circuit diagram

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