Introduction: Cheap Home Automation Using Wireless Outlet Modules

Picture of Cheap Home Automation Using Wireless Outlet Modules

It's that time of year again, when the stores are full of Christmas decorations and accessories.  Christmas may be months away yet, but never underestimate the power of hacking seasonal holiday accessories, one accessory in particular is incredibly useful year-round in home automation systems.  This is, of course, wireless remote-controlled outlets.  These are small boxes that plug in the wall with an outlet on them that act as switches.  Included is a wireless remote with on/off buttons for one or more outlet modules.  These often communicate on hacker-friendly radio frequencies with simple protocols that are easily reverse engineered.  By pairing these wireless outlet modules with a simple transmitter circuit, you can attach AC lights and appliances to a computer-controlled home automation network.

I had previously purchased a 5-pack of wireless DBTech outlets from Amazon and reversed their protocol, but found that they only offered one signal, which was a toggle command.  This is not ideal for home automation, where we want to explicitly send on or off to avoid issues caused by missed transmissions.  Fortunately, I found a 3-pack of "Holiday Time" outlets at Walmart for $15, quite a good deal for what you can do with them, and these have both on and off buttons on the remote.

Step 1: What You Will Need to Continue...

Picture of What You Will Need to Continue...

If you purchased the exact same outlets I did, you don't need to reverse engineer them as I did the work for you.  However, you likely didn't get the exact same ones as me, and there are tons of brands out there.  They are all similar, but you will likely need your own reverse-engineering tools and skills to crack the protocol.

First, get yourself a set of radio transmitters and receivers from SparkFun.  Get both the 315MHz and 434MHz versions of each, because these outlets can use either frequency (my 5-pack set uses 434, these use 315).  You need the receiver to decode the protocol unless you want to disassemble the remote and probe around inside it.  I'd still recommend the receivers to confirm your transmitter is transmitting.  If you use the receiver, you don't even have to risk voiding your warranty by opening up the remote.

315MHz Transmitter: https://www.sparkfun.com/products/10535
315MHz Receiver:      https://www.sparkfun.com/products/10533
434MHz Transmitter: https://www.sparkfun.com/products/10534
434MHz Receiver:      https://www.sparkfun.com/products/10532

You'll also want a microcontroller of some sort, I used ATTiny2313 but any AVR, PIC, Arduino, or similar should do.  You need to know how to use its microsecond and millisecond delay functions or write your own delay loops.  You also want a microcontroller that has a serial port so you can talk to the computer.

For the reverse engineering you will also need either an oscilloscope or a logic analyzer.  These can run at fairly high speeds so a DIY analyzer off an Arduino might not be fast enough for microsecond-scale pulses.  My Rigol DS1052E 100MHz scope works wonders for this.

Step 2: Look Buddy, I'm a Reverse Engineer!

Picture of Look Buddy, I'm a Reverse Engineer!

Now it's time to start reversing the protocol.  Power up your 315MHz and 434MHz receiver modules in a breadboard, insert antenna wires for each, and attach your scope/analyzer to one of the two receivers.  You should see random noise.  This is normal.

To see the signal the transmitter is sending, put your analyzer on auto mode or start capturing, then press and hold one of the buttons on the remote.  Pause your analyzer before releasing the button to ensure you have the sample captured.  These remotes send out a short message, repeated continuously as long as you are holding the button.  They usually leave a 5-10ms gap between transmissions which makes it easy to locate the message in the captured waveform.

The convention used for these modules is typically short pulses and long pulses.  I'm not sure which is supposed to represent 0 or 1, so I called them S (short) and L (long) to keep track of them.  Use your analyzer's cursor functionality to measure both the high and low times as well as the total pulse period.  This will be used when writing the code that creates these pulses.

Also, write down the sequences using S and L (or 1 and 0 if you want to assign them).  Repeat this for each button on the remote to get all the codes.  Typically there will be one code for ON and one code for OFF for each outlet module.  Some outlets, as I said before, only have one code which toggles the output.  Avoid these if you can.

Once you have all the button codes down, line them up and look down the columns to find columns that are all the same.  You will likely find a set of bits at the beginning and at the end that are the same, with changes in the middle.  Mark these unchanging bits at both the beginning and end as the preamble and end sequence respectively.

Step 3: Re-implement the Protocol on Your Microcontroller

Picture of Re-implement the Protocol on Your Microcontroller

Once you've got the protocol extracted from the remote, you are now ready to re-implement it on your microcontroller.  First, note which receiver you got the data from.  Use that frequency transmitter in your circuit.  Wire it up to an available GPIO pin on your microcontroller and remember which pin it is.  Also make sure your microcontroller's programmer is connected and note the clock frequency of your microcontroller, which is used as the basis for accurate delays.

Start by writing functions for long and short pulses.  Below is some pseudocode to get you started, individual implementations may vary.

void bit_long()
{
      set_pin_high();
      delay(HIGH_TIME_LONG);
      set_pin_low();
      delay(LOW_TIME_LONG);
}

void bit_short()
{
      set_pin_high();
      delay(HIGH_TIME_SHORT);
      set_pin_low();
      delay(LOW_TIME_SHORT);
}

You get the time constants by measuring the pulse widths with your analyzer or scope's cursor functions.  Use the appropriate delay function (microsecond/millisecond) to best fit the measured width.  On AVR these are _delay_us() and _delay_ms(), both from the <util/delay.h> library.

Then, start implementing your transmissions.  Start by making a function for the preamble and a function for the end sequence, then make functions for each button's internal data.  You can either write a function for each button, or if you can figure out what the protocol is doing you can write one function that builds the appropriate message from outlet number and on/off inputs.  I chose the former, as the protocol did not seem to directly correlate outlet number and on/off state into its data, rather it was just one long pulse for the pressed button.  For example:

void send_preamble()
{
     bit_short();
     bit_long();
     bit_long();
     bit_short();
     bit_long();
     bit_short();
}

Finally, use these functions in a for loop to send them approximately 10-20 times, with the appropriate delay in between transmissions (you can measure this delay with your scope or analyzer).  For instance:

for(int i = 0; i < 10; i++)
{
     send_preamble();
     send_outlet_1_on();
     send_end_sequence();
     _delay_ms(10);
}

Then build a switch/case or cascading if/else statement with one of these blocks for each button, using outlet number and switch state as your if/else conditions.

Finally, import a serial library or write your own serial port interrupt routine.  In that interrupt routine, set both the outlet number and the switch state from received data.  Use volatile variables so that they can be changed from within an ISR, so that the main loop can pick up on the set variables and perform the desired transmission.  Remember to initialize your serial port and set your baud rate before starting your main loop!

Step 4: Testing 1...2...3...

Picture of Testing 1...2...3...

Plug in a serial level shifter or FTDI chip, connect it to your computer, and fire up a terminal program that can send the data in the format you chose.  I prefer RealTerm as it can send arbitrary bytes input as hex or decimal.  Plug in your outlet module and plug something such as a lamp into it.  Then send your ON packet for that outlet.  With any luck, your lamp will click on and shine brightly, indicating your code is a success.  Otherwise, it's time to stick the scope probe on the transmitter's data input and double check to make sure what you're outputting is the same as what you recorded earlier.  You may have to adjust the timing, as what you output may not be exactly the same as what the transmitter receives.  Make sure your transmissions match and that your timings are correct.  Adjust your antenna wire if necessary, and try to eliminate sources of electrical or radio interference (programmer, receiver, scope, analyzer) by removing unnecessary components from your breadboard and powering down equipment.  With a bit of diagnostics, you should be able to tweak your code into working state fairly easily.

If it works, test all combinations of on and off to make sure all your codes are correct.  If everything is good, it's time to move on to the computer side for integration into a networked system or home automation setup.

Step 5: [New!] Increase the Range!

Picture of [New!] Increase the Range!

I'm adding this new step a year after the initial project to remedy an issue I had with it. The functionality of wireless outlets is great, but I was having issues where outlets in rooms farther away from the server were not responding very often. This new step shows how you can increase the range of your transmitter for optimal performance.

The range is basically determined by two things - transmitter voltage and antenna. I haven't messed with computing the optimal antenna length but I do know that a transmitter capable of operating up to 12V DC is not going to be performing at its best on 5V from a USB port. In the original remotes, the transmitter uses a 12V mini-battery (which is 6 1.5V button cells stacked) and has great range. It easily switches outlets on the other side of the house reliably so I figured I needed to increase my voltage.

Problem. I'm using USB power provided by a USB to serial board (Prolific PL2303 based) and it provides only two voltage outputs - 5V directly from USB and 3.3V regulated. I'm running everything off of 5V but it's not enough. The answer? Use a voltage doubler circuit to boost the 5V up to 10V and power the transmitter off of 10V.

A voltage doubler is a simple diode and capacitor circuit that can double an input voltage using a PWM pin on a microcontroller. Basically you charge up the capacitor by driving the pin low, then "pump" the voltage by driving the pin high and adding the capacitor's charge voltage on top of your 5V microcontroller pin. That output goes through another diode to charge another capacitor to 10V. I had no issues running the transmitter as fast as I needed to off of the supply and managed to get around 8V under load. Not bad!

I learned of the technique via Dave Jones' EEVBlog in this video:

Definitely give that a full watch if you're interested in the theory behind it.

Step 6: Computer Coding - Control Your Lamps From the Internet!

Picture of Computer Coding - Control Your Lamps From the Internet!

For starters, write a simple command line utility that opens the serial port at the appropriate baud rate, forms a packet based on outlet number and switch status, and transmits it to the microcontroller.  This gives you a command line utility to turn your lights on and off.  You can use it in scripts or call it from other utilities.  Here is mine:

#include <cstdlib>
#include "serial_port.h"

using namespace std;

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        return 0;
    }

    serial_port port("/dev/ttyUSB0", 38400);

    char pkt[] = {0x00, (char)atoi(argv[1]), 0xAA, (char)atoi(argv[2]), 0xFF};
    port.serial_write(pkt, 5);
    port.serial_close();
    return 0;
}

That's all there is to it!  We now have a command line utility, lampctl, to turn the lamps on and off from the command line.  As a test, I remoted in on my Android phone and was able to turn the lamps on and off from my phone.  How awesome is that!

I haven't looked into larger home automation setups yet, but I really want to.  This Instructable is only one small part of what could be a much larger setup.  If I find any more cool home automation stuff I will make more Instructables on it.  It will be fun turning my living room lights on and off from halfway across the country this week!

Attached are the code files for this project.  The OutletControl.c, fanbus.c, and fanbus.h files are the AVR files to compile with AVR-GCC or AVR Studio while the lampctl.cpp, serial_port.cpp, and serial_port.h files are the PC code for the lampctl command line utility.  Note that my serial_port function doesn't set the baudrate properly, so set it using stty -F /dev/ttyX 38400 where ttyX is your serial port (USB0 for me).

Comments

aarone (author)2016-02-01

Thank you for writing this up - it served as excellent direction to implement this with my wireless outlets. The most useful part to me was the Oscilloscope stuff, I finally got to use mine! :)

I wrote up my experience at my website: https://aaroneiche.com/2016/01/31/weekend-project-...

I posted my Arduino code if anyone is interested, adjust your timings and codes as appropriate. :)

Here: https://gist.github.com/aaroneiche/9b6baf999467a26...

Mine was built with a Teensy, but I've since built a variation on an ESP8266 that runs a web server to switch channels on an off.

themuffinman22 (author)2015-08-19

this is so much harder than it needs to be. I have the exact same switches and remote and i just soldered outputs to the actual remote. less than half the work and cost under $40. but this method does have it plusses, like a working remote and size.

TimL5 (author)2014-12-06

I wrote a post describing in detail how I created this without using an oscilloscope: http://timleland.com/wireless-power-outlets/

CalcProgrammer1 (author)2013-12-14

Works perfectly with the Verdant Electronics sets from Home Depot as well! I bought their CH C outdoor set today to run some outdoor Christmas lights. I now have 12 outlets (CH A, B, C, and D) all working at once! I've revised my bit timings again as well to get rid of some flaky behavior I was seeing on some of the modules.

CalcProgrammer1 (author)2013-12-07

I just bought a new set, CH D, at WalMart. It looks like they've changed the design but from my initial first glance the electronics are probably the same as before. I'll post pictures and a teardown after confirming that they do in fact work with the protocol I've implemented.

Here are some pics of the new outlets.  I didn't bother reverse engineering their protocol as I figured they'd be the same and lo and behold they were.  I added support for the 'D' channel code (SSSL) and tested to see if it would just work and it did.  All three of these outlets work perfectly just like the old ones.  They're kinda ugly though.  They still have the red LED but it's not exposed through a window so the whole plastic sorta glows red.  At least the price stayed the same!

sarthur (author)2013-01-01

While the ones I purchased looked exactly the same, they were rebranded and also flashed with a different pulse lengths. The codes were the same, but long/1 is 1800/600 us, and short/0 is 600/1800 us. Full writeup and arduino code on my blog: http://www.33snowflakes.com/blog/arduino-wireless-outlet/

CalcProgrammer1 (author)sarthur2013-01-02

I'm guessing they were the same ones after looking through your code, If you were looking at the comments in my code (640us per frame) that's for a different set of outlets I had purchased and did not end up using (they ran at 434MHz). My timings are 1700/900 and 500/2100, though there's probably a good margin of tolerance on these numbers as I remember adjusting them up and down by a few hundred us to get them reliable for all my outlets. I'm using the 8MHz internal RC oscillator on my ATTiny2313 as well, which is not the most accurate clock source at all. If you're using an Arduino with a proper 16MHz crystal your timings are probably more accurate.

sarthur (author)2012-12-24

Cool -- I happened to find all 4 channels A,B,C,D at Big Lots and picked them up. Are there other differences besides the END code? Your methods are named like ch_b_out_1_on and I'm not sure if that was just future-proofing, or if the preamble or on/off code varies as well.

CalcProgrammer1 (author)sarthur2012-12-29

I'm guessing it's only the end code, I changed my code to just have one set of outlet on/off and one start code function, then have end code functions for A and B. It worked with my A and B sets but you're on your own with C and D. I'd try the assumption that 1000 0100 0010 0001 corresponds to A B C D and if that doesn't work then you'll need to scope it.

endolith (author)2012-12-15

Wouldn't it be simpler to just control the switch that it comes with? No reverse engineering of the protocol necessary.

CalcProgrammer1 (author)endolith2012-12-17

That would be a much uglier and hackier hack though, sacrificing the remotes and voiding any warranty. I wanted to do this cleanly and not modify the remotes (as I still use them, they sit on my table for when I don't want to use my phone/PC). You could if you were in a pinch or didn't have the tools to reverse the protocol, but what fun is that? The parts to build a complete remote are cheap anyways, and you could program multiple different sets as long as they use the same frequency using this technique.

CalcProgrammer1 (author)2012-11-30

For the CH A set replace the END code with LSSS, now you have 6 outlets! Looking at that code, it could very well be the case that A is LSSS, B is SLSS, C is SSLS, and D is SSSL but I'm just guessing based on A and B which are known.

Treknology (author)2012-10-22

I have been looking at X-10 equipment for my own home, however, most of the "switches" cannot handle heavy inductive loads. Starting up a heater or a light is no problem, but the heavy draw of a fan-motor starting up can destroy the receiver/switch. Does the product you have hacked survive under such conditions?

Haven't tried it but I would assume so. These modules are relay based which is the same as a physical switch as two contacts are connected and disconnected to swirch the load. Those X10 units are likely using solid state relays based on TRIACs which do not take inductive loads well.

Thank you. I now have to find a 250V version.... :)

About This Instructable

41,492views

86favorites

License:

Bio: I finally graduated from Missouri University of Science and Technology (Missouri S&T, formerly University of Missouri Rolla) with a computer engineering degree. Originally from ... More »
More by CalcProgrammer1:Cheap and Easy Tachometer (RPM Sensor) for Brushed DC MotorsCheap Home Automation using Wireless Outlet ModulesATTiny USI I2C Introduction - A powerful, fast, and convenient communication interface for your ATTiny projects!
Add instructable to: