Hacking a USB LED message Fan with a Raspberry Pi and web interface.
BUILD TIME: A few hours
DIFFICULTY RATING: Intermediate
We recently found an old novelty desk fan that could be programmed to display text and simple patterns. The fan had originally come with some proprietary software on an included CD that was designed for Windows 7. This CD had long been lost, and with our computers running newer operating systems, we could no longer program the fan’s display. We decided to investigate and see if we could get the fan working again and potentially add some smart functionality.
The fan appeared to be a generic item resold with some custom packaging by a distributor. The original tags on the rear side of the fan were unreadable and with no other visible markings, we decided to disassemble the fan to see if we could find any hints on the circuit board. The fan was easy to access with one bolt and nut securing the front grill which gave access to the blades.
The control circuitry could then be partially separated from the main body of the fan by removing the three screws on the back securing it in place. This released the blades and revealed the inner circuitry to control and program the fan. We noticed a model number printed behind the LED strip used to display the programmed text and on the circuit board.
The model number read UF-240-06, and after a quick search, confirmed our suspicions that the fan was indeed a generic widely available model. We found that the fan was sold by various companies under different names but all featured the same design. The product can even be ordered directly from the manufacturer with a custom logo if you are willing to order 2000.
This was promising as it increased the likelihood that we could find an existing solution to control the fan without the proprietary software. We spent some time searching if anyone had documented the protocol used to program the device and discovered a library that could be used to program a similar style fan.
The Micro Wave USB Fan software created by Fergus Symon was designed to program the Jaycar RGB USB LED fan which also features the same LED arrangement. We tried the software with our fan to see if they used the same protocol for programming.
We wanted to test if the usbfan software would work with our fan before we proceeded to create a custom device and program for it, so we decided to test a prototype on a Windows machine. We installed the application on our computer using...
pip install microwave-usbfan
and then opened the provided text message example code. The fan needed to be set to programming mode, and then after running the program and observing a blinking red LED, we switched the fan to text mode.
The fan displayed the text, however, it was displayed incorrectly, appearing horizontally flipped. We then took a closer look at the program code to see if we could adjust the image so that it would display as expected.
We managed to modify the code which converts the text input into a 144x8 pixel image that can be programmed to the fan. We flipped the image and adjusted the draw direction until the text displayed correctly on the fan.
Using a Raspberry Pi
Our next step was to test if the code worked on a Raspberry Pi. At first, it only partially worked. We would often run into an issue when uploading our programmed text to the fan, however, this was easily solved by retrying the upload. We could then continue to create the program and hardware required for the final build.
We decided to use a spare Raspberry Pi 3 as it could run native Python programs and featured integrated WiFi connectivity. The Raspberry Pi 4 and earlier revisions with an external WiFi or wired Ethernet connection will also work fine.
The Raspberry Pi will require an adequate power supply as the fan will also be taking its power from the same supply. We recommend the official Raspberry Pi Power supply as it has been tested to meet this requirement.
The USB fan we used in this project is not available from any of our partners, however, Jaycar does sell a similar programmable USB fan (GH1031) which has been reported to be compatible with the same library we will be using. This option may involve some minor modifications to the code to ensure the text is displayed correctly.
The Build: Hacking the USB Fan
Note: These assembly instructions will differ slightly if you have chosen to use a different LED fan or Raspberry Pi revision.
|1 x Raspberry Pi 4 or equivalent||XC9102||Z6302G||PAKR-A0287|
|1 x Raspberry Pi Power Supply||XC9122||M8821||PAKR-A0291|
|1 x microSD Card||XC4992||DA0365||ADA2693|
|1 x 5V Relay||XC4419||Z6325||SS103020005|
|1 x Jumper Cables||WC6028||P1021||-|
|1 x USB Fan||GH1031||-|
Note: Our build photos show the Raspberry Pi with heatsinks but these are not required for this project.
The USB fan features an internal three-way switch that is wired to a connector on the internal circuit board. The three wires coming from the connector each attach to one leg of the switch and the combination of connected wires determines the fan mode. These modes are printed on the case of the fan as FAN, EDIT, and LED. We determined that the FAN mode runs the fan without any LED text, EDIT mode allows us to upload a new pattern to the device, and LED enables the text and fan.
The switch leaves all three internal wires disconnected when in the neutral EDIT mode, allowing the user to upload and program a new sequence onto the device. The FAN, and LED modes are both enabled by connecting one of the outer leads with the centre lead. These three states can be controlled automatically by replacing the physical switch with a digital relay.
We can use a mechanical relay to open and close any electrical connection with simple 5V logic while ensuring no risk to the board. The original functionality could be emulated completely with the use of two relays each connected to the centre wire and one external wire. This would allow the automatic selection of all three modes from the Raspberry Pi.
We decided that the FAN mode would not be required so we opted to simplify the design by removing one relay which was connected to the centre and corresponding side wire. The FAN mode wire was terminated to ensure it wouldn’t short any of the other electrical connections.
The original wires had to be extended so that they could be routed out of the fan’s enclosure and to our relay. We simply stripped the ends of the wire and soldered on some connections, securing the solder joints with some electrical tape. These wires were attached to our relay’s normally open N.O. connections. This means that when the relay is not powered and switched, the two wires will be disconnected, leaving the fan in programming mode.
The relay needs to be attached to the Raspberry Pi so that we can control its state to switch the fan between EDIT and LED modes. The relay requires a 5V power supply, which we can take directly from the Raspberry Pi, and a single data pin that can be used to control the relay. These connections were made with some jumper cables directly from the relay to the Raspberry Pi.
We decided to use the Raspberry Pi 3 official case as it was large enough to house the single relay and Raspberry Pi. We removed the GPIO side cover to allow room to route the cables from the relay to the fan. The fan’s USB was also attached to a spare port on the Raspberry Pi which would supply power and data to the fan.
With the hardware side of the project sorted, we were ready to begin creating our program.
We chose to use the default Raspberry Pi OS on our device, which we could install using the Raspberry Pi Imager.
We downloaded and installed the Raspberry Pi Imager onto our computer from: https://www.raspberrypi.org/software/
We attached the microSD card to our computer and ran the Imager, selecting the default Raspberry Pi OS option and our microSD card. The Imager then proceeded to format and install the OS on the microSD card.
We need to configure network connectivity on our Raspberry Pi to avoid the need for manual setup with a keyboard and mouse. We created a wpa_supplicant.conf in the root directory of the microSD card flashed with Raspberry Pi OS. The file needed to contain the following text where we entered our network name and password.
This will automatically enable WiFi and connect to our network when the device is booted. We will also need to enable SSH so that we can remotely access and configure the Raspberry Pi. This can be enabled by creating an empty file named ssh with no file extension also in the root microSD card directory.
The microSD card is now ready so we can attach it to the Raspberry Pi and power the device. The Raspberry Pi will boot and connect to the network we defined with SSH enabled. To connect to the device, we will use the PuTTY SSH client, which can be downloaded here: https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
We need to find the IP address of our Raspberry Pi so that we can connect to it over SSH. This information can often be found in your Router configuration page or with a network scan. We can enter this address into PuTTY and select SSH before opening the connection. PuTTY will attempt to connect with our Raspberry Pi on the specified IP address, and if successful, will ask for a username and password to login.
We can login to the Pi with the default credentials of pi and raspberry for the username and password. This will allow us to access the terminal and begin the installation of all the required dependencies to interface and control the fan.
The first step was to ensure that all existing packages were up to date by running...
sudo apt-get update
sudo apt-get upgrade
The next step is to install the development build of libusb with...
sudo apt-get install libusb-1.0-0.dev
which will allow us to communicate with the fan over USB. We need to get the development version as the main version does not install on Raspberry Pi unlike on our Windows machine.
To create the correct commands to send to the fan, we install our modified usbfan library. This can be installed by linking directly to our Github fork of the original project, if you are using the Jaycar fan you can install the original project. This can be done with the following command:
sudo pip3 install git+https://github.com/
Finally, we install the Python Flask web application framework that will allow us to create a web interface, allowing the user to easily control and program the fan. This can also be installed using pip with the following command:
sudo pip3 install Flask
The Raspberry Pi should now have all the required libraries to interface with our fan, so we can proceed to install our software to expose these programs to the user with a web interface, accessible from any local device. We chose to use Flask to host our web interface as it made it easy to interface with the Python libraries used.
The code consists of two files; main.py which contains the Python scripts to interface with the fan and serve our webpage, along with main.html which contains the buttons and styling for the web interface. The Python script starts the webserver on start and exposes various local endpoints for controlling the power states and programming of the fan.
When the user navigates to the local web interface, the Python code will initialise the relay and serve the main.html web page. The webpage contains options to turn the fan on/off in addition to setting the text to be displayed. These options each trigger an associated sequence of commands in the Python file which execute these requests with the fan.
The main.html file must be stored within a folder named templates in the same directory as the main.py file so that Flask can correctly find and serve the web page. The code can be downloaded from our website or installed from Github using: git clone https://github.com/LukePrior/RGB-Text-Fan-Controller.git
This will download the code to the root directory of your Raspberry Pi and can be navigated to using...
The main.py file can now be run using...
sudo python3 main.py
This will start the web server, which can be navigated to and will allow you to control and program the fan. The web-server will only stay open until the Raspberry Pi is powered off so we will want to set it to automatically run on start-up.
This can be done using crontab, which is a scheduling feature that allows the Pi to run specific scripts at various times. We can access the crontab list using...
sudo crontab -e
and select nano as our editor using 1. We will add a new entry to the bottom of the file of...
@reboot python3 /home/pi/RGB-Text-Fan-Controller/code/main.py
This will start the webserver each time the Raspberry Pi is powered on.
The Web Interface
The web interface can be accessed by navigating to the IP address of the Raspberry Pi in a browser of a device connected to the same local network. The interface consists of two power buttons to turn the fan on/off triggering the relay. These happen almost instantly, resulting in an extremely responsive experience.
The interface also contains a field to enter some text up to 18 characters long which will be programmed onto the fan. The text will take some time to upload to the fan as it needs to be programmed twice, so the entire process can take up to 20 seconds. The page will be loading during this process, and once the page has reloaded, that is confirmation the text has been set.
Where to from here?
The modified usbfan library we are using to control our fan supports various other options which we didn’t explore in this project, including multi-colour support and custom transitions. The fan can set each pixel to be any of the 7 available colours, including red, green, blue, yellow, pink, and cyan, in addition to the default white used currently. The usbfan repository contains various examples of how to use this capability.
The library also contains support to choose the opening, closing, and main effects on how to display the programmed message or pattern. The fan supports nine opening and closing transitions, in addition to four main effects. The program is currently configured to use the default transitions, writing the text, rotating it, then erasing it. The available transitions are all documented in the repository and can easily be used by passing them through to the library with the TextMessage command.
The web server application can easily be extended to make these features user-selectable, and could also receive support for predefined patterns such as the rainbow example provided with usbfan. The application could also be modified to accept other input forms such as linking with a smart home platform for voice control and automation.
The physical build could also be modified with two relays to include support for the FAN only mode as we described earlier. This functionality could be integrated with the web interface to include another option that would allow the fan to run without any LED effects.