These instructions demonstrate how to do an RF replay "hack" against an unknown transmitter signal. This process may work for other types of signals as well.
First, gather details about the transmitter. In the US, the FCC publishes technical details regarding the radio signals used by each legal device. In the case of the Defiant 1, the RF keychain transmitter had a printed label with the code AG2AA-001. Googling this yielded a set of documents filed with the FCC.
This mentioned a frequency of 315MHz and a modulation technique of ASK, which is Amplitude Shift Keying. Basically the signal strength goes up or down based on a string of binary digits in a specific order. As AM audio, this sounds like a tone kind of like an old school modem. After some googling, I learned the signal for these type of transmitters is usually encoded using OOK (on-off keying). Based on this, we know there is an encoded string of bits being sent over 315MHz using some established standard. We an figure out what the string is and send it on the same frequency, to replace the transmitter key fob.
This particular receiver only gets one type of signal. For an on/off switch with two buttons, there would be two different signals. A fan controller or something like that could have a bunch of different signals.
There are a number of automated ways to demodulate the signal, including: rtl_433 (walkthrough) if you're on linux and your transmitter works on 443MHz, gnu radio (walkthrough) (walkthrough #2) (walkthrough #3) (video class on this), HDSDR, gqrx, OOKtools. This one is simple so we can do it visually. I happened to choose SDR# so here are the settings I used for that.
Let's record audio and see what the signal is. Change the SDR# settings to:
Settings (gear icon)
Sample rate: 1.8 MSPS
RF Gain: 0dB
Offset Tuning: Unchecked
RTL AGC: Unchecked
Tuner AGC: Unchecked
Frequency correction: 0
Tune to center of signal
Squelch: 47 (Checked)
Lock Carrier: Checked
Snap to Grid: Checked (12.5 kHz Step Size)
Correct IQ: Unchecked
Swap I and Q: Unchecked
Filter Audio: On
View: Spectrum Analyzer
Mode: Sample 32 bit IEEE Float
Click "record" then press the button a few times. This creates a file in the sdr# folder.
Open the audio file in Audacity. Note the waveforms and in particular that there are 3 repeating groups
In Audacity, choose the arrow by the upper left of the file and choose split stereo to mono.
Now remove one of the channels and zoom into one of the groups using control-mousewheel up. This is the signal the transmitter is sending.
Since I know this is ASK modulation, the linked PDF explains that a "1" is a big up and a small down, and a "0" is a big down and a small up. It took me a while to figure this out, and after trying a bunch of strings in RCSwitch (C++ code on the Raspberry Pi), the information made more sense. So encode the whole thing like that. In the case of Defiant 1, the string is 101010101001101101100100 (24 bits) It looks like maybe RFCat would decode this differently, as in 1110 0001 for the first set of signals, but I don't have one of those so I'm not exactly sure. This post suggests that, and I think I saw that in a Youtube video too.
Ok now wire up the 315MHz transmitter according to the Fritzing diagram on the project files.
Now that we have "the answer", follow the final steps in the project log to get the signal sending.
Aside: It looks like RFswitch handles encoding a "1" as a long up and short down, and a "0" as a long down and a short up. Other libraries send the more raw signal and that probably works too. You just have to figure out the timing. Some information about this is in the FCC document, but I had trouble translating units so I'm glad for RFSwitch's abstraction.
Now in order to make this part of a smart home, make it subscribe to an MQTT event which is the signal to toggle the switch. This assumes you're running mosquitto somewhere on your LAN and already know how that works and integrates with OpenHAB (if not, the OpenHAB MQTT binding docs may be a good starting point).
Use this code on your Pi
#!/usr/bin/python import serial, time, sys, os, syslog import paho.mqtt.client as mqtt # http://stackoverflow.com/a/33211980 def log_traceback(ex, ex_traceback=None): try: if ex_traceback is None: ex_traceback = ex.__traceback__ tb_lines = [ line.rstrip('\n') for line in traceback.format_exception(ex.__class__,ex,ex_traceback)] for line in tb_lines: syslog.syslog(line) except: syslog.syslog("Unhandled exception with sending exception to syslog") # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, rc): syslog.syslog("Connected with result code "+str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. client.subscribe("home/familyroomlights") # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): try: syslog.syslog(msg.topic+" "+str(msg.payload)) input = msg.payload syslog.syslog("Switching lights, input=" + input) os.system("/home/pi/Experiments/controlDefiant1Outlet/send 101010101001101101100100") except Exception as ex: try: _, _, ex_traceback = sys.exc_info() log_traceback(ex, ex_traceback) except: syslog.syslog("Unhandled exception trying to collect exception information") client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("hostname", 1883, 60) # Blocking call that processes network traffic, dispatches callbacks and # handles reconnecting. # Other loop*() functions are available that give a threaded interface and a # manual interface. client.loop_forever()