Controlling a ceiling fan and light with an Arduino

In this article I will describe how a wireless ceiling fan/light can be controlled by an Arduino. I will also describe the communication protocol used by the remote control to control the ceiling fan.

How the remote control works

The remote control is typically mounted on the wall and has several buttons that can be used to adjust the brightness of the light and the speed of the fan, as well as a set of switches that can be used to identify the remote control. When the user presses one of the buttons, a microcontroller inside the remote control generates a stream of ones and zeros based on the setting of the switches and the button pressed. For example, the code to toggle the state of the light is 1111111111111110000011010. Each one is then encoded as a short pulse, and each zero is encoded as a long pulse.

This waveform is then output to the RF oscillator. When the output signal is high, the RF oscillator is oscillating at around 304 MHz, and when the signal is low, the oscillator is off. The receiver in the ceiling fan will listen for this 304 MHz signal and decode the received instruction.

Reverse engineering the commands

When I replaced the ceiling fan controller, I kept the old one, as it used the same frequency. Inside the old controller, there was a receiver module which outputs a digital 1 if it detected the 304 MHz signal was detected, and a digital 0 otherwise. I was able to use this module to listen to the signal transmitted by the new remote control and determine the packet structure and timing for the signal.

Each packet consists of 25 bits. The first 13 bits are ones, the next 4 bits are the code as configured by the switches on the remote, and the last 8 are the command. Each packet is transmitted four times with a 12 millisecond delay in between.

CodeCommand
0001 1010Toggle lights
0000 0001Fan on high
0000 0010Fan on medium
0000 0011Fan on low
0000 0000Fan off
0001 1011Toggle lights (for some models this may be a different set of lights)
1001 1010Power button (switches fan and light)
0011 0000Variable/random fan speed
0001 1110Blink on, then off, then on
0001 1111Turn light off with 20s delay. Only works after 0001 1110
1001 1011Turn light and fan off

Using the old remote with an Arduino

As shown in the image above, the old remote control contained two circuit boards. The right half held the buttons and was mounted to the front of the remote control. The left half contained the regulator and the RF oscillator/transmitter. The circuit board on the right would generate the digital signal and feed it into the DOUT socket on the left board. Pin 7, +5V and GND on the Arduino were connected to the DOUT, VDD, and GND sockets on the left circuit board respectively. The Arduino was programmed to accept a serial command and send a command to the ceiling fan as described above. TODO: link code

This method worked, but I wanted to keep the old receiver and remote control together and intact, so I had to search for a different transmitter. Looking through my collection of old circuit boards, I found a wireless doorbell that operated at a frequency of 315 MHz.

Modifying and using the wireless doorbell

The wireless doorbell contained a main circuit board, which generated the binary stream, and a satellite board, that contained the RF oscillator and transmitter. The oscillator circuit was based on the PT4455 chip, which contains a phase-locked loop for generating the high frequency, as well as a power amplifier. The oscillator circuit also contained a 9.844 MHz crystal, which was multiplied by 32 by the PT4455 to get the 315 MHz needed for transmission. Thus, all that needed to be done to change the transmission frequency was to change the crystal frequency to 9.5 MHz (304 MHz / 32). I had no 9.5 MHz oscillator or crystal, but I was able to use my DE0-Nano FPGA module to synthesize the appropriate frequency using one of its internal phase-locked loops.

However, actually getting the PT4455 to output the 304MHz signal was much more difficult, as simply injecting the 9.5 MHz signal into the XIN input did not work. I also had to inject the complementary signal (180 degrees out of phase) to the XOUT pin. This was done with a transformer, with the primary connected to the output of the FPGA through a resistor and the secondary connected across the old 9.844 MHz crystal.

Despite the 100 MHz bandwidth of my oscilloscope, I was able to verify that the PT4455 was generating the correct frequencies by using the scope's FFT function. This lets me look at the frequencies present in a signal, even if they are not apparent in the signal itself. It was evident that the modification caused the output frequency to change from 315 MHz to 304 MHz.

Image of the setup

The red and green wires on the right side connect to the 9.5 MHz output of the FPGA. The white and black wires coming in from the top supply 12 volts to the wireless doorbell circuit. The trace connecting the digital input of the RF transmitter to the rest of the doorbell circuit was cut and was instead connected to the Arduino.

Comments

Popular posts from this blog

Improving and calibrating the capacitive water sensor

Turn a buck converter module into a buck-boost converter with only two components

Self-starting inverter