In this July project, we will gather what we have learned to build an IoT controlled fan using a Raspberry Pi and some simple circuitry.
The IoT Fan takes advantage of the Python library to produce PWM signals on GPIO pins and while utilizing the Adafruit IO library. An Adafruit IO dashboard has a slider control for deciding the fan speed between 0% and 100%. Upon a value change message via MQTT, the Raspberry Pi then adjust the output of the PWM signal to match the message from Adafruit IO.
The fan used in this project is one typically found on desktop PCs. It operates at 12V, needing a driver circuit. Raspberry Pi GPIO’s have an output voltage of 3.3V, but even if the Raspberry Pi could output 12V, a driver would still be needed. Most microprocessors and microcontrollers can only output a few mA on an I/O pin, whereas the fan needs excess of 100mA.
The MOSFET shown in this circuit is the IRF830 which can be switched on with a voltage of 5V. For applications where larger currents are needed, a higher voltage is more appropriate as this ensures that the MOSFET is fully conducting. Therefore, a BJT transistor is also used, driven by the Raspberry Pi. When the Pi outputs a 1 on its GPIO pin the BJT turns on and pulls down the gate of the MOSFET. The BJT in this circuit acts like a NOT gate. It’s important to keep in mind that the fan will be inverting, hence turning on the GPIO will turn the fan off!
The Raspberry Pi Code
The code run on the Raspberry Pi is written in Python and uses the RPi.GPIO and Adafruit IO library. The first few lines of code import the needed libraries, including time, the GPIO, and Adafruit_IO. The next line creates an Adafruit IO object that requires an AIO Key - this would be your own key - and then GPIO14 is configured as an output. Next, a PWM object is created and attached to GPIO14, which is set to use a frequency of 200Hz.
import RPi.GPIO as GPIO
from Adafruit_IO import Client, Feed, Data
# Put your AIO client key here
aio = Client("ff90f47949f149979f38c9001499a131")
# Configure GPIO14 as an output
# Create a PWM object
pwmOut = GPIO.PWM(14, 200)
With the pins and libraries configured, two variables are declared: oldSpeed and fanSpeedStr. oldSpeed is an integer variable that stores the previous speed setting and the purpose of this is to indicate if a speed change is needed. The variable fanSpeedStr is a string that is used to receive the Adafruit IO feed “fanSpeed.” Values from Adafruit feeds are strings and not integers, so they need to be converted into an integer if an integer is needed.
# Variable used to hold the previous recorded number
# fanSpeedStr is needed as values from Adafruit_IO are strings
oldSpeed = 0
fanSpeedStr = ""
The main loop starts by receiving the current value of the feed called “fanSpeed” and storing this value into the variable “fanSpeedStr”. From there, the string is then converted into an integer and stored into the variable “fanSpeed”. This value is then compared to the previous speed and if there is a discrepancy, then the fan speed is adjusted. Note that the duty cycle is set to 100 – fanSpeed because our driver is inverting by nature. Therefore, a duty cycle of 90 would correspond to a duty cycle of 10 on the fan.
# Main program loop
# Fan speed is 0 - 100
fanSpeedStr = aio.receive("fanSpeed").value
fanSpeed = int(fanSpeedStr)
# If there is a speed change, make the change
# Also remember that the output is inverted so do 100 - speed instead ;)
if(fanSpeed != oldSpeed):
oldSpeed = fanSpeed
pwmOut.ChangeDutyCycle(100 - fanSpeed)
# Prevent the system
Adafruit IO Dashboard
The Adafruit IO dashboard has a single slider that is used to select the duty cycle of the fan. This slider is linked to a feed called “fanSpeed” and the minimum/maximum values of the feed are 0 and 100 respectively. While the dashboard can be made public, values of sliders and buttons cannot be changed.
This project can be taken much further in a number of ways. Firstly, a pair of Arduinos with 433MHz transceivers can be integrated with one connecting to the Raspberry Pi and the other connected to a thermistor remotely. The remote Arduino could be made to transmit the current temperature to the other Arduino, which could then send this reading to the Raspberry Pi. The value of the temperature could be mapped to a linear scale such that the hotter it gets the faster the fan spins. This data could also be transmitted to Adafruit IO with graphs plotting the temperature and fan speed over time.