RF-based home automation using Raspberry Pi (Part 1)
While researching around on how the small sensors on doors/windows and motion detectors work, I found out that they are based on a radio frequency protocol which is typically on the 433 Mhz, 315 MHz or 868 MHz bands. The control hubs that link all of these sensors also operate on the same frequency and usually comes with a key fob that can be used to do things like activate/deactivate it or sound the alarm.
How this usually works is that the sensors are first paired with the hub and then they send a signal every time they’re triggered. The whole system can be activated or deactivated by the key fob provided. Some have the alarm system built-in or they can signal a wireless alarm located somewhere else. In this sense, the sensors and key fob are RF transmitters and the hub is both a receiver and a transmitter. I will not digress into the details of those.
What I really wanted to do was getting an RPi to work as the hub and also to control the actual hub which’ll still be around as a backup. To achieve this, the RPi must be able to receive and transmit RF signals. Thankfully this is a popular thing in the Arduino world and there are plenty of guides that help us get started. Afterwards, we can experiment with a plethora of home automation devices that are using these protocols.
The Hardware
Of course, this cannot be done without the help of some dedicated hardware. We would need a transmitter (TX) and a receiver (RX) module that operate on the correct frequency (433 MHz being the most common one). These are available in various types and usually a pair of the simplest ones are priced under a dollar or two. I have tried a generic version as well as a “superheterodyne” variant and for all of them, the transmitter worked well but the receivers werehit or miss due to signal noise. I bought two normal pairs from local electronics shops and the superheterodyne from AliExpress.
Some of them come with a coiled antenna or it’s possible to solder a suitable wire (shortest length being 173mm for this frequency). Using the antenna helps improve the range. The superheterodynes came with a short antenna for TX and a long one for RX.
The TX and RX modules connect to the RPi’s GPIO pins. I have used jumper cables and made a splitter to connect both modules to one 3.3V pin (yes, there are two of these but I had an RGB indicator LED on the other one). Plenty of ground pins to connect the negative terminals and then we can choose the GPIO pins we want to use for data transmission. The pins are marked on each of the modules, usually with text like DATA or similar for the data pin, G/GND/- for negative terminal and VCC/+ for the positive. It may differ from module to module so do a bit of research and connect them correctly (they’re cheap to replace but let’s try to get it right the first time itself).
The Software
Before we get to programming the system to send signals, we need to know what signals are typically being sent and received. To automate a sort-of-dumb control hub, we need to identify the signals transmitted by the key fob. And similarly, from each of the sensors too. This can be achieved by using the RF RX connected to the RPi and the rpi-rf Python library (which supports 433 MHz and 315 MHz bands). Note that these cheap RX modules capture a lot of noise so there’s a bit of experimentation involved. The library can be installed using “pip3” and if pip3 isn’t also installed yet, both can be acquired by using the commands below (sudo may be needed).
apt-get install python3-pip
pip3 install rpi-rf
I found a good working example that uses the library, from a website called Piddler in the Root. Both the scripts they have written to send and receive are embedded below for easy reference. All credits to the original author. You can clone that repository too if needed.
We can see that each of these scripts take in a set of arguments. The receive script is what we’ll run first and it only needs the GPIO pin number as an input. If you edit the script itself and replace the number there (line 22), then we don’t have to pass anything.
There’s also a video by the author on YouTube to better understand this.
Let’s run it with a GPIO pin set to 23 as an example (this must be where the RX module’s data pin is connected to).
python3 /home/xxxxxx/rpi-rf/receive.py -g 23
When it starts running, we will see an output similar to below in the terminal.
2021-07-03 09:28:33 - [INFO] receive: Listening for codes on GPIO 23
2021-07-03 09:28:33 - [INFO] receive: 1 [pulselength 15, protocol 3]
2021-07-03 09:28:34 - [INFO] receive: 14 [pulselength 12, protocol 1]
2021-07-03 09:28:34 - [INFO] receive: 284 [pulselength 500, protocol 1]
Now these seemingly random numbers are shown due to the noisiness of the radio frequencies around us. Even if we’re not doing anything with the key fob or sensors, these lines will keep on appearing in the terminal. To determine exactly what signals are being transmitted by the key fob, bring it close to the RX module and press each button. After doing that for several times, you’ll see the more consistent signals in the output. Each button will have a unique combination of these code, pulse length and protocol values. Make a note of those for each button you need to program for.
For the sensors, it’s the same story. Activate the sensor and make note of the values for the signal it sends out. For a motion sensor, you can move in front of it and a door/window sensor can be activated by simply opening or closing the door/window. Other sensors such as smoke detectors would be a bit tricky so continue at your own risk. Signal range might be an issue depending on the quality of the hardware used so you might have to bring the sensor and RX module closer.
The second part involves sending the same signals out, from the RPi. The send script takes a few arguments as you can see from the code. We’ll have to send the code, GPIO pin, pulse length, protocol and limit the number of times the signals are sent to just one as the default emits 10 times. Taking an example to have the code as 384, pulse length as 400 and protocol as 2, we can pass these on to the send script. Assume the data pin of the TX module is connected to GPIO pin 17. We’re skipping the “length” argument and using the default value for that. The signal should do something that you can notice. For example, pick the signal sent out by the key fob to activate the control hub.
python3 /home/xxxxxx/rpi-rf/send.py -g 17 -p 400 -t 2 -r 1 384
If everything goes well, this will transmit the signal from the RPi and you will see that the control hub gets activated. Similarly, once you figure out the signal to deactivate it, try it out too. We can save both of these commands as shell scripts for ease of use.
Scheduling the Signals
Once we have the shell scripts, the easiest way to send signals on a schedule to activate/deactivate the control hub is by using cron. Let’s say we want to activate the system at 8 PM and deactivate at 7 AM, then we can add these to the crontab.
0 20 * * * /home/xxxxxx/activate.sh
0 7 * * * /home/xxxxxx/deactivate.sh
Future Improvements
With the ability to send RF signals, it’s possible to control many more devices and it’s something to discuss in detail separately. The reception part can be used to send out alerts or set up scenarios like switching on a set of lamps when motion is detected by a PIR sensor. Since the RPi can be connected to the internet, all of these can be controlled from anywhere in the world (with a little more work and cybersecurity measures of course). If you think creatively, there are a lot of possibilities!
Hope you learned something from this article and thanks for reading!