This is a follow-up (yet a prequel) to a previous project -- Particle Internet Button 434 MHz Remote.
IntroductionFor starters, this is not for the faint of heart. It's not difficult, but it is tedious. Getting the drivers and software installed can be a little confusing, too. That is something that I will not cover in this project as many places have done it already. Instead, I invite you to check out the excellent article in the Adafruit Learning System -- https://learn.adafruit.com/getting-started-with-rtl-sdr-and-sdr-sharp/overview. And, yes, you will probably want to do it with Windows. I use a MacBook for everything, but used Windows in Boot Camp to do all of this. I couldn't find any Mac-based software that worked as well. There are many amazing resources at http://www.rtl-sdr.com, so you may want to browse around there, too. I am also assuming you know how to use an Arduino and either know how to or can find resources on using a 434 MHz RF transmitter with one.
There are two pieces of software that you will need for this. The first is (Airspy) SDR# for monitoring and recording waveform data from the SDR. You should be able to download a free copy from their web site. Next is Audacity for viewing and manipulating the recorded data. Audacity is free/open source. Using both pieces of software is fairly intuitive. Give yourself some time to get a feel for both pieces of software as you come to them.
To begin, launch SDR# and tune the radio to 434 MHz. Grab your remote and press one of the buttons. You should see some spikes and some red blips in the waterfall. Fine-tune the radio on that frequency and press a button on the remote again to tune the frequency as close as possible. Once tuned, open the Recording section in the left section of SDR#. Make sure the sample format is 16 bit PCM. Click the Record button, press a button on the remote, and then end the recording. This will output a standard .wav
file in the SDR# directory. Pretty easy, right?
Here comes the tedium! Open the .wav
file that SDR# sharp recorded. It should look a little something like this:
Here you can see two tracks in a stereo recording. We only need one of these. You can keep them both without any problems, but I like to clean up a little. If you want to clean up, click on the down arrow in the box to the left of the audio tracks and select the "Split Stereo to Mono" option. Once split, delete one of the tracks by clicking the X in the upper-left corner of the box next to the track.
Another not-necessary-but-nice-to-keep-things-clean option is to trim the blank space before and after the real data in the audio. Highlight the blank space and then hit the Delete key on your keyboard.
If you start to zoom in on the audio, you can make out blips of data. Continue zooming in and you will be able to see the 1's and 0's of the data!
I'm simply assuming the longer pulses represent 1's and the shorter pulses represent 0's. I could be entirely wrong about this, but since my only concern with this project is repeating the transmission, it didn't matter as long as I could duplicate the pulse lengths.
Before we get too far into this, you'll want to change the unit of measure to "samples" instead of "seconds" or any other unit of time. To do this, look in the bottom left corner of Audacity for "Selection Start", "End/Length", and "Audio Position". Click on one of the little down arrows in any of those three fields and change the option to "samples".
I originally hoped to use milliseconds as a unit of measurement, but the resolution in Audacity doesn't seem to go down to the pulse durations we want. Using samples instead gives us an easier number to work with. You can also use math to convert the samples to units of time based on the sample rate, but that was too much math for late at night when I usually hack on these things!
Now go back up to your audio track and zoom in until a pulse takes up the entire width of the screen. Start from the beginning of the pulse and highlight to the end of the pulse. This will change the "End/Length" value (we want the length) to the number of samples you highlighted. Make note of this number and do the same for the other pulse. Then measure the time between pulses. In my particular case, the signal consisted of 3 sets of pulses with slightly longer delays between each set and then another 3 sets of pulses. If you have a similar case, measure the delay between sets as well. Make sure you save all of this data to disk as you will need to reference it later.
Now that you know the sample length of each pulse (and delays between them), it's time to zoom back out and make notes of the actual data sent. Once written down, you may see patterns start to emerge. In my case, there was only one common pattern, and that was the preamble (the bits at the beginning of each transmission). If you spend more time with it, you might even be able to completely decode the transmission to replicate the entire signal in code. Unfortunately, I couldn't find any other patterns in the data, so I just recorded the raw bits.
Now get out your Arduino and 434 MHz transmitter (TX) and wire it up with the transmitter:
- Arduino GND --> TX GND (pin 1)
- Arduino pin 2 --> TX Data In (pin 2)
- Arduino 5V --> TX VCC (pin 3)
- 17cm wire (or antenna) --> TX ANT (pin 4)
It's time to tinker with the bits and see if we can get the Arduino to replicate them. The code for the project is pretty simple once you look at it. The remote I used has 5 on and 5 off buttons (the 5th of each button is "All On" or "All Off"). The first 27 lines of code are simply the patterns I wrote down stored in arrays. I separated out the preamble into its own array to keep the code a little leaner since it's duplicated in front of 10 sets pulses. Below the arrays are the lengths and delays of the pulses and time between pulses. The rest of the code is commented so that you can follow the logic and see how each pulse and delay is handled. The values in my code are what I managed to calculate after some trial and error. That is the tedious part!
To start experimenting, set the values of the variables to something arbitrary (maybe just the sample lengths you calculated before). Fire up SDR# and get ready to start recording. Once you upload the code to the Arduino, monitor what it transmits in SDR# and record it to disk. You'll want to open the resulting recording in Audacity and check the sample lengths like you did for the original transmission earlier. Now, divide your new sample lengths by the original sample lengths. Take the result of that and multiply it by the corresponding variable value in your Arduino code. Do it for each pulse and delay and update the variables accordingly. At this point, go ahead and plug in the remote outlet. Upload the updated code to your Arduino and monitor the transmission again. If your remote outlet did not turn on, repeat the process again. Each step, you should be tweaking less and less until the outlet eventually comes on.
I repeated that process about 4-5 times before I could consistently turn the outlet on and off. Once you get one button figured out, it should work for all buttons.
This is probably not the best way to go about the process, but it worked and I learned a lot in the process. It is a decent starting point into the world of SDR and getting comfortable with some steps of the process that can shed light on more advanced sniffing. Ideally, you may be able to skip the SDR process entirely and use a proper 434 MHz receiver connected to a microcontroller to learn the data in code.
I highly recommend visiting RTL-SDR.com. There is tons of information there to consume and learn. I also recommend watching some of the Hak5: Intro to Software Defined Radio (SDR) YouTube playlist to learn even more. I've only watched a few episodes so far, but will continue watching to see if I can figure out how to decode a set of 434 MHz thermometers that broadcast their data back to a base station (my next RF project).
The second part of this project (Particle Internet Button 434 MHz Remote) puts these sniffed codes to work so that you can use buttons (or Particle cloud functions) to toggle the remote outlets from a microcontroller.
Comments