03 Apr 2017

The Fan Controller of My Dreams

My computer is loud. The fans whir constantly, and if there's one thing I hate above all else, it's doing too much work. The problem was my fans are 3 pin fans, one pin for power, one for the tachometer, and the final one for ground. They span full on, all the time.

The simple solution was to buy a fan controller, my best friend has one, my housemate has one, they work great. But what's the fun in that? No I sensed scope for a project.

How Hard Can This Be?

I did some reading, and people had done similar projects before. I mean I'm not the first person to hook a motor up to an Arduino? I routed around my electronics box for a transistor, a diode, and an Arduino. Hooking them up I sent a pwm signal into the 12v input of an old 120mm fan I had laying around. Success. It span. Faster with a higher pwm and lower otherwise. This fan was as controllable as a Victorian Housewife.

There was but one slight problem. Voltage drop. This is the difference in voltage before and after a component, and the larger the voltage drop across my transistor, the lower the voltage that my fan receives and the slower it spins. I was using a 2N2222 transistor and the voltage drop was almost 3 volts. This limited my fan to 75% of it's maximum speed. Utterly unusable.

Fortunately the solution was simple. Use a Mosfet These typically have a much lower internal resistance, and therefore a much lower voltage drop. I chose the STD12NF06L which boasted an internal resistance of 0.09Ω. After substituting it into the circuit I was seeing the full 12V being applied to my fan.

Micro controller

My micro-controller of choice is normally the Arduino Nano (or Chinese clones of it at least). It's compact, it's capable, it's simple. It's boring. I wanted something interesting. I'm an idiot. That aside I went with the NodeMcu Esp8266 12E. It's an Arduino compatible board, meaning that I can use C++ along with the standard Arduino IDE, that wraps the functionality of the Esp 8266, i.e. gives me a wifi capabilities, alongside power regulation similar to an Arduino, and a single wire usb interface, again the same as Arduino. Maybe the project would have ended up more efficient had I used a bare Esp8266 board, but I'm a software engineer, not an electrical engineer, I'm keeping this part simple.

The downside of the Esp8266 is that it only has a single ADC (analogue) input compared to the Arduino Nano's 8. These pins are required for any input that varies in signal such as light sensors, volume meters, or perhaps the all important to this project; thermistor. This wasn't a major problem however. Only one thermistor had to be on at any one time and by feeding power to a single one, taking the measurement, and then switching it off, I could read from multiple thermistors with only one input used.

Another problem is pwm noise. This is noise created when a circuit that is rapidly switching on and off. This problem was solved simply by raising the pwm frequency until it's out of the audible range via analogWriteFreq(30 * 1000).

Putting Everything Together

Two problems still remained. What was I going to attach all of this to, and how would the attached things connect to each other. The first problem was handily solved by my housemate, being new to electronics I had never heard of these, but stripboard is perfect.

For connecting the fans to the board I bought some Molex KK 4 pin pcb headers. They required some cutting to fit a fan, but allowed for a 4 pin fan to be controlled by the pwm header. These also worked to attach the Molex power supply from the pc to the board.


A few ideas went through my head for the interface. I considered an oled screen, a simple knob, maybe even an elegant single light. Of the three the knob and the light were my favourite. I liked the knob because it gave me some control, and I like the light (although the stylistic choice wasn't final) for aesthetic reasons. In the end I dropped the idea of a knob in favour of full automation via thermistors.

I had a few ideas for the light. Maybe a simple led where brightness would indicate temperature? But I also wanted something for the speed. Maybe multiple leds that could animated to display the speed? But I also wanted it too look pretty. In the end I chose an led ring that would shine through the front of my case, and bought some perspex to diffuse the light that it produced. The LED right was a WS2811 Based circuit that I bought cheap from Ebay. This means that I can control the entire ring from a single data pin, saving me many precious pins.


The light was lit, the circuits were soldered, and the transistors were doing transistory things. But one thing was remaining. The software. I considered Micropython, Lua, and Rust, but eventually chose the simple option of using the Arduino IDE with C++. All code can be found in the Fan_Controller directory within the project.

As an experiment I used the ArduinoThread library. This is a protothreading library to enable a faux concurrency in Arduino's single core environment. In essence it's a function callback manager that attempts to run a function every x milliseconds.


It's now been over a year since I created my fan controller. Overall I'm happy with it. It's still in my computer, it's still controlling my fans perfectly, and it's still got that soft; slowly spinning glow that I love so much. Would I have done things differently though? Of Course.

WiFi was always the big sticking point. My original plan was to control it via MQTT to enable some sort of quiet mode. I then decided to go with full automation via themistors. I kept the WiFi around for debugging purposes, which manifested in the form of pushing stats to influxDB. These were interesting, but never useful. If I were to restart this I would go with a simple Arduino Nano or Micro.