Maker Blog Series
Create an Intermittent Fan Controller With Python
Sep 27, 2022By Evelyn Boettcher
This could be you! Click here to submit an abstract for our Maker Blog Series.
I simply cannot sleep with a fan constantly blowing on me. My husband can not sleep without a fan on him. Initially, I thought we'd never be able to find a happy medium, since ceiling fans are designed to be either on or off all night. I realized that if I could find a way to turn our fan off after five minutes and then back on after another 20 minutes, we’d both be able to sleep well. So, I built an adjustable, intermittent fan controller with roughly $30 worth of electronics and two Python scripts.
This project uses a Raspberry Pi Zero, a low-pass filter, and about 20 cm of wire to control a ceiling fan. In addition, a custom Python Flask application allows you to set how long the fan stays on or off. The advantage of an intermittent fan is that it helps prevent the room from getting stuffy, without blowing so much air that you get cold.
WARNING: It might blow your mind to realize that a general-purpose input/output (GPIO) pin, when toggled from high to low really fast, can create radio frequencies (RF). These RF signals can in turn be used to power your fan without using its remote. Note that IT IS ILLEGAL to transmit at many frequencies. You must use a low-pass filter (a 433MHz low-pass filter will keep you legal).
A Python Flask app served on the Raspberry Pi Zero will be used to configure how long the fan stays on/off and to set the fan’s speed. Flask is a Python web framework that enables the user to easily develop web apps with minimal setup.
Serving a Flask app is as simple as typing python app.py in a terminal. In this web app, button presses trigger an async command on the Raspberry Pi Zero. This command sends an on-off keying (OOK) signal at the fan’s receiving frequency via rpiTX, which turns a GPIO pin 7 on/off. This process of turning the GPIO pin on/off is what generates the RF signal. The 20 cm of wire acts as an antenna, so the signal can reach the fan’s receiver.
Radio Frequency Commands
The OOK signal is transmitted at a main frequency. You must figure out the frequency at which the fan’s remote controller transmits, and how that OOK signal is encoded. The two main ways to figure out what frequency a remote uses is to either measure it or read the manual. A cheap way to measure it is to use a USB TV tuner as demonstrated in the “Hack My Ceiling Fan Radio Signal with a $15 USB TV Tuner” YouTube video. Or, refer to the FCC website. All transmitters have to report what frequency they use. Mine uses 304MHz (FCC ID: KUJCE1000)—I measured 304.2MHz, which is close enough. There is variation from remote to remote; I have three Minka Aire remotes, and some operate at a higher or lower frequency than stated on the FCC site.
To figure out how the RF signal is encoded, you can measure it with a USB TV tuner (see below) or refer to this River's Educational Channel YouTube video. The table below lists the OOK codes for Minka Aire fans.
OOK Codes for Minka Aire Fans
Fan Unique ID
Most remotes have toggle switches on the back, near the battery. The Minka Aire has two sets of four toggle switches (eight digits) that are used to set its unique ID, where up = 1 and down = 0.
Putting It All Together
Software Configurations for the Raspberry Pi Zero
Download this repo onto your Raspberry Pi Zero.
Download rpiTX and place it in the ./src folder.
Configure the Raspberry Pi Zero to activate its GPIO pins.
- Connect your Raspberry Pi Zero to your Wi-Fi network.
- To find the IP address, type in bash terminal: hostname -I.
- Update your library:
python3 -m pip install RPi.GPIO
conda install -c anaconda flask
Set the fan’s unique ID in the FanRemote class located in fan_controller.py.
This is two sets of four bits (binary digits).
Solder ~20 cm of wire to one end of a 433MHz low pass filter.
Solder two jumper cables to the other end of the filter: one to the data line and the other one to ground. The data line goes to the center pin.
Connect the signal/data line to GPIO pin 7 and the ground line to the Raspberry Pi Zero’s electrical ground.
433MHz low-pass filter ($5.50)
~20 cm of wire
Raspberry Pi Zero (~ $25)
SD card ($10)
nice to have USB TV Tuner (~ $30)
Run the Flask App
The Flask app has three main parts: app.py, index.html, and fan.css. The app.py file is the Python script that serves the Flask app and responds when a user presses a button in the web app. The web app consists of index.html and fan.css files. The fan.css file makes the app look pretty and was modeled after the css file in ESP32_IR Remote repository.
To run the app, go to the ./src folder and type in a terminal:
This will initialize a Flask app at the Raspberry Pi Zero’s IP address on port 5000. Mine was at http://192.168.2.80:5000.
The Flask app imports a fan class into the application. When a user presses a button in the app, the main method in the Flask app figures out how to respond and sends an async command to the fan.
WARNING: Again, IT IS ILLEGAL to transmit at many frequencies. You must use a low-pass filter (a 433MHz low-pass filter will keep you legal).
Bonus Material: Measuring the RF Command
Using the USB TV tuner and Universal Radio Hacker (URH) software,* I was able to capture the raw RF signal. The fan uses OOK and each bit is sent as 100 or 101: 1 = 101 and 0 = 100. The fan is expecting a signal at 304MHz, where the first eight bits are the fan’s ID and the next five are the fan remote command.
*Note: If you do want to play with a USB TV tuner and URH software, I recommend creating a conda environment and installing the URH within it. I also recommend installing miniconda on the Raspberry Pi Zero since it has a small processor.
By recording the signal when each button is pressed on the fan’s remote, you can then analyze each signal. This will enable you to build out an OOK codes table such as the one above. Note that different remotes may use different frequencies and encodings.
There you have it! You can create your own custom-defined remote controller using a Raspberry Pi Zero, some Python code, and a bit of wire. Note that if you are new to working with hardware and RF there can be a steep learning curve. Don’t worry if you can’t get the project to work the first or even the hundredth time; these things take practice.
About the Author
Evelyn Boettcher founded and leads DiDacTex, LLC (a small woman-owned business). Her experience spans over 20 years in the field of electro-optics and remote sensing, with working experience with electronics, modeling, and algorithm development. She received an MS in physics from the University of Maryland and a BS in physics from the University of Florida. She has been head author in respected peer-reviewed journals, presented findings at international and national meetings, and received patents for electro-optical devices (# 6,738,536 #; 6,944,372). She enjoys supporting STEM activities for youth in her personal time.
About the Maker Blog Series
Anaconda is amplifying the voices of some of its most active and cherished community members in a monthly blog series. If you’re a Maker who has been looking for a chance to tell your story, elaborate on a favorite project, educate your peers, and build your personal brand, consider submitting an abstract. For more details and to access a wealth of educational data science resources and discussion threads, visit Anaconda Nucleus.