PWM Regulated Fan Based on CPU Temperature for Raspberry Pi





Introduction: PWM Regulated Fan Based on CPU Temperature for Raspberry Pi

About: Student in engineering

Many cases for Raspberry Pi come with a little 5V fan in order to help cooling the CPU. However, these fans are usually pretty noisy and many people plug it on the 3V3 pin to reduce the noise. These fans are usually rated for 200mA which is pretty high for the 3V3 regulator on the RPi. This project will teach you how to regulate the fan speed based on CPU temperature. Unlike most of tutorials covering this subject, we won't only turn on or off the fan, but will control its speed like it's done on mainstream PC, using Python.

Step 1: Parts Needed

For this project, we will use only a few components that are usually included in electronics kits for hobbyist that you can find on Amazon, like this one.

  • Raspberry Pi running Raspbian (but should work with other distribs).
  • 5V Fan (but a 12V fan could be used with an adapted transistor and a 12V power supply).
  • NPN transistor that supports at least 300mA, like a 2N2222A.
  • 1K resistor.
  • 1 diode.

Optional, to put the components inside the case (but not done yet):

  • A little piece of protoboard, to solder the components.
  • Large heat shrink, to protect the board.

Step 2: Electrical Connections

Resistor can be plug in either way, but be careful about transistor's and diode's direction. Diode's cathode must be connected to the +5V (red) wire, and anode must be connected to the GND (black) wire. Check your transistor doc for Emitter, Base and Collector pins. Fan's ground must be connected to the Collector, and Rpi's ground must be connected to Emitter.

In order to control the fan, we need to use a transistor that will be used inopen collector configuration. By doing this, we have a switch that will connect or disconnect the ground wire from the fan to the ground of the raspberry pi.

A NPN BJT transistor conducts depending on the current that flows in its gate. The current that will be allowed to flow from the collector (C) to the emitter (E) is:

Ic = B * Ib

Ic is the current that flows through the collector the emitter, Ib is the current that flows through the base to the emitter, and B (beta) is a value depending on each transistor. We approximate B = 100.

As our fan is rated as 200mA, we need at least 2mA through the base of the transistor. The tension between the base and the emitter (Vbe) is considered constant and Vbe = 0,7V. This means that when the GPIO is on, we have 3.3 - 0.7 = 2.6V at the resistor. To have 2mA through that resistor, we need a resistor of, maximum, 2.6 / 0.002 = 1300 ohm. We use a resistor of 1000 ohm to simplify and keep a margin of error. We will have 2.6mA through the GPIO pin which is totally safe.

As a fan is basically an electrical motor, it is an inductive charge. This means when the transistor stops conducting, the current in the fan will continue flowing as an inductive charge tries to keep the current constant. This would results in a high voltage on the ground pin of the fan and could damage the transistor. That's why we need a diode in parallel with the fan which will make the current flow constantly through the motor. This type of diode setup is called a Flywheel diode

Step 3: Program to Control the Fan Speed

To control fan speed, we use a software PWM signal from the RPi.GPIO library. A PWM Signal is well adapted to drive electric motors, as their reaction time is very high compared to the PWM frequency.

Use the program to find the FAN_MIN value by running in the terminal:


Check several values between 0 and 100% (should be around 20%) and see what is the minimum value for your fan to turn on.

You can change the correspondence between temperature and fan speed at the beginning of the code. There must be as many tempSteps as speedSteps values. This is the method that is generally used in PC motherboards, moving points on a Temp / Speed 2-axis graph.

Step 4: Run the Program at Startup

To run the program automatically at startup, I made a bash script where I put all the programs I want to launch, and then I launch this bash script at startup with rc.locale

  1. Create a directory /home/pi/Scripts/ and place the file inside that directory.
  2. In the same directory, create a file named and copy the script bellow.
  3. Edit the /etc/rc.locale file and add a new line before the "exit 0": sudo sh '/home/pi/Scripts/' script:

#!/bin/sh # navigate to home directory, then to this directory, then execute python script, then back home
cd /
cd /home/pi/Scripts/
sudo python3 ./ &
cd /

If you want to use it with OSMC for example, you need to start it as a service with systemd.

  1. Download the fanctrl.service file
  2. Check the path to your python file,
  3. Place fanctrl.service in /lib/systemd/system
  4. Finally, enable the service with sudo systemctl enable fanctrl.service

This method is safer, as the program will be automatically restarted if killed by the user or the system.



  • Creative Misuse Contest

    Creative Misuse Contest
  • Oil Contest

    Oil Contest
  • Clocks Contest

    Clocks Contest

15 Discussions

Hello. I am curious as to what the diode is used for? I've seen several sets of instructions that don't use them.

2 replies


The diode is used to protect the transistor. When the PWM signal is low, the fan works as a generator due to it's inertia. This raises the voltage at the transistor's collector and can damage it. The diode allows the current to pass through it and go back to the positive terminal of the fan and pass through it again.

Your code is nice, it helped me achieve what I wanted to do. from what I remember from high school computer class is most fans have a diode built in, so im gonna bank on that fact and not add a 30cent diode. the N2222, should on paper act as a resistor (I MIGHT BE WRONG), either way, the fans only gonna draw the amperage it needs. and thats lower then the gpio capability.

also, i removed the use for, can you tell me why you used it when

sudo python /home/pi/Scripts/ &

would probably do the same thing.

i would really be interested in some criticism on my setup.

thank you and ultimatly, good job.

1 reply

It's very easy to check if your fan does have a diode built-in or not, with a simple multimeter. I doubt it does.

Basically any diode you have will work. the current that pass through it when the transistor is closed should be very low. I use a 1N4001.


Question 2 months ago

Hi! Good tutorial. I am currently gathering parts for implementing. However.. I do not see any calculation of the dissipated power. The transistor that you have there (2n2222a) only dissipates about 600mW.. The fan that I found (and it's the smallest possible) takes 200mA at 5v.. this means 1W.
Did this work for you? or it got magic smoke after a while? :D

1 more answer

Hi ! A transistor dissipates power only during switching. When it's open, V=0 so as P=I*V, P=0. When the transistor is closed, I=0 so P=0 too. As the switching frequency is pretty low, and I don't have a scope to check the current and voltage during switching, I ignored it. But the transistor stays perfectly cold. The more important thing to check is the max current that can pass through the collector when the transistor is open, and the maximum voltage when it's closed (but transistors usually resists voltage far higher than 5V).

You're right, this should work, but I prefer to edit the bash script to modify or add other programs that need to be launched at startup, than the rc.local file. But your method should work fine!

Nice one! Thanks you sir.
Here I changed the transistor: NPN BC337-25 (had no other to use :P )
The fan start working at 50%.
I don't know if it will be enough for cooling the raspi if I run something heavy.
On the bright side, I have almost 0 noises :D


5 months ago

Hi! in step 4 is order 2 and 3 correct?