Temperature-Based Smart Fan
Mornings too cold, but gets too hot by noon? By hooking up a temperature sensor to the Omega, we can use the data it provides to modulate the speed of a fan - cooling us down only when we need it!
This kind of setup is used in many places: the cooling fans in your laptop or desktop computer operate in the same way. Other applications include home-brewing beer or wine kegs and anywhere temperature control is required.
Skill Level: Intermediate ~ Advanced
Time Required: 40 Minutes
There’s a lot of implementation details in this project that will change depend on the exact hardware you have access to. We used a D18B20 1Wire temperature sensor, for example. For the fan, we recommend a computer case fan, since those are quite easy to come by and works decently well.
We also cooked up a DC motor with a 3D printed rotor setup just like in the Omega2 Maker Kit since we had all of those handy.
To control the fan, we’ll be using a python script and the Onion PWM Expansion Python Module to control the fan speed. We also use a library to operate the 1Wire sensor, but your methods may vary depending on your exact sensor.
All the code we used is written for a case fan with a transistor switching it. It can be found in Onion’s
iot-smart-fan repository on GitHub.
- Onion Omega2 or Omega2+
- Any Onion Dock that supports Expansions: Expansion Dock, Power Dock, Arduino Dock 2
- Onion Servo (PWM) Expansion
- Breadboard (optional, but it helps a lot)
- Computer case fan
- Note that we used a fan that was roughly double the size!
- D18B20 1-Wire Temperature Sensor
- The Omega accepts I2C, 1Wire, and SPI, among other protocols, so other digital sensors will work as well.
- 12V DC power supply
- Must be capable of supplying at least 0.5A
- 1x 5.1kΩ
- 1x 1kΩ
- 1x 47 μF Capacitor
- NPN Transistor rated for 12V at 0.5A
- 2x M-F
- 4x M-M
Follow these instructions to set this project up on your very own Omega!
First let’s get the Omega ready to go. if you haven’t already, complete the First Time Setup Guide to connect your Omega to WiFi and update to the latest firmware.
Plug in the PWM Expansion to the Dock and grab all the components:
2. Install the Required Software
We need Python and the Onion PWM Expansion Python Module to make this work:
opkg update opkg install python-light pyPwmExp
Everything else will be included in the GitHub repo.
3. Connect the Fan
Computer case fans are voltage driven, but we can cheat by using PWM with a transistor to switch the supply voltage.
If you have jumpers handy, we recommend using them as a bridge between the header of the fan and the PWM expansion.
First, we’ll have to set up the transistor. For our lab setup, we used an S9014 NPN transistor with a 2-wire PC case fan. If you use a different model, make sure to note which pin is the base/collector/emitter.
If you use a PNP transistor, your fan will automatically turn on unless you set the PWM output to 100%. This is because PNP transistors turn ‘on’ when the base draws current, when the PWM channel is at 0% duty, it draws a tiny bit of current - enough to turn on the transistor!
Most commonly, case fans have three pins/wires - one of which is a tachometer output. If you’re using one of these, make sure there’s no power being supplied to the output pin, this will cause damage to the fan.
The output pin sends the current speed of the fan, it can be used in your code to check if the fan is working as a bonus!
We connected the power supply to the PWM expansion for cleaner wiring.
- Connect the transistor to the breadboard across 3 empty rows.
- Connect the
(-)(usually black) wire of the fan to the transistor’s collector pin (right pin when looking at the flat front).
- Connect the
(+)(usually red) wire of the fan to an empty row a few spaces away.
Vccpin on the PWM Expansion’s
S0channel to the
(+)pin of the fan using a M-F jumper wire.
- Connect one end of the 1kΩ resistor to the transistor’s base pin (middle).
- Connect the other end of the resistor to the
SIGNALpin on the PWM Expansion’s
S0channel using a M-F jumper.
Connect the transistor’s emitter pin (left pin when looking at the flat front) to one of the Expansion Dock’s
GNDpins using a M-M jumper.
- Connect the capacitor across the fan’s
(-)wires where they are connected to the breadboard.
- If you have a polarized capacitor with the
(+)side clearly marked, make sure to match the terminals with the fan’s (
- If you have a polarized capacitor with the
This circuit will now switch the Fan’s voltage based on the PWM signal from channel 0!
The capacitor acts as a simple low-pass filter to supply the fan with a smooth analog voltage.
4. Wire up the Temperature Sensor
This part is written assuming you’re working with the D18B20, if your sensor is different, you may have to find a guide elsewhere on wiring it properly.
The D18B20 has a pinout that looks like this:
NOTE: the second graphic is a bottom view, where the pins are pointing towards you (we may have fried a sensor by misreading this one).
Now we can connect the sensor to the Expansion Headers.
- First, connect the temperature sensor to the breadboard across another three empty rows.
- Leave some space from the transistor so you can easily interact with it!
- Connect the
GNDpin of the sensor to a
GNDpin on the Expansion Header using a M-M jumper wire.
- Next, connect the middle pin (
DQ) to GPIO1 on the Expansion Header using a M-M jumper.
- Connect the
VDDpin to a
3.3Vpin on the Expansion Header using a M-M jumper.
- Finally, connect the 5.1kΩ resistor across the sensor’s
DQpins (right and middle respectively).
Your setup is now complete!
5. Get the Project Code
cd /root git clone https://github.com/OnionIoT/iot-smart-fan.git
5.5. Using a Different Sensor
There’s a good bit of setup for the temperature sensor - initialization, communicating, and parsing.
If you have a different sensor than the the one we’re using, you’ll have to modify the project code. The code that sets up the D18B20 1-wire sensor can be found in the lines between
#~~~ SENSOR SETUP BEGIN and
#~~~ SENSOR SETUP END.
Additionally, you’d probably need to change the function used to get the sensor data:
One important thing to note is that the values assigned to the
temp variable must be integer or float.
6. Calibrate and Customize
You can edit the
config.json to change the possible speed range of the fan and restrict the temperature range to which the fan reacts:
dutyMax parameters control the minimum and maximum duty cycle of the signal being sent to the fan, thereby controlling the fan speed. The
tempMax parameters specify the temperature range in which to enable the fan. The fan speed has a linear relationship with the temperature when it is between the min and max temperature.
If you find that the fan does not spin when current is applied, you may have to increase the
dutyMin to overcome the static friction in the fan’s shaft bearing. Once it gets up to speed, you can then lower the duty and the fan will still be able to spin.
Using A Different Fan
If you would rather use the H-Bridge and DC Motor setup, you’ll have to make some changes to the code. Namely, you’ll have to swap out the
OmegaPwm class with the
hBridgeMotor class from
omegaMotors.py. Check the pin-outs that we’ve put in by default in
iotSmartFan.py to make sure you’re correctly connecting the H-Bridge to the Servo Expansion.
For a detailed guide on how to set this up, check out the wiring instructions in the Maker Kit DC Motor experiment.
To change up the code, open up
iotSmartFan.py and change this line:
And this line:
Two of the key components in this project are the temperature sensor and the motor drivers, found in
The output from the 1-Wire temperature sensor contains a lot of unnecessary information such as the device address, connection acknowledgements, and other fields. The
__readOneWire() internal method of the
TemperatureSensor class extracts the temperature value and converts it to degrees Celsius:
def __readOneWire(self): # device typically prints 2 lines, the 2nd line has the temperature sensor at the end # eg. a6 01 4b 46 7f ff 0c 10 5c t=26375 rawValue = self.driver.readDevice() # grab the 2nd line, then read the last entry in the line, then get everything after the "=" sign value = rawValue.split()[-1].split("=") # convert value from string to number value = int(value) # DS18B20 outputs in 1/1000ths of a degree C, so convert to standard units value /= 1000.0 return value
The method to set the duty cycle for a servo fan,
setDutyCycle() uses the Onion
pwmExp class to easily control it: