Sunday, January 27, 2013

Controlling Smart Outlet with Arduino

Smart outlets are becoming all the rage. But nobody is opening up an api that can be used by programmers to automate things. I need a smart outlet that I can control with my arduino, so I am going to reverse engineer one of the smart outlets.

I found one on ebay:



Its called "Outdoor Wireless Remote Control AC Power Outlet Plug Switch" and I got mine from ebay seller 'emilyandlily'.

It comes with a remote:


I have connected the outlet to my surge protector and lamp:





When you press the on button on the remote the outlet turns on with a green led.



When you press off the outlet turns off with a red led.


What just happens to be convenient about this outlet for reverse engineering is that the remote runs at 433.92mhz ASK radio frequency. This is convenient because there are tons of cheap off the shelf parts for receiving and transmitting 433.92mhz signals.

We could butcher the remote and then attach it to the arduino frankenstein style but it's not very elegant. 

I'll see what the remote transmits by using an off the shelf 433.92mhz receiver and logic analyzer. Then I will duplicate the signal by writing a code for arduino that sends the same signal through an off the shelf 433.92mhz transmitter.


To see what the remote sends, I have setup a 433.92mhz receiver(Digikey part number AMHRR30-433-ND) on my breadboard.

Pin 1 is connected to 5v
Pin 2 is connected to GND
Pin 3 is left alone
Pin 4 is GND
Pin 5 is GND
Pin 7 is 5v
Pin 8 you can connect to an oscilloscope to see the signal if you want to. I haven't connected it to anything.
Pin 9 is where the signal that the receiver sees is outputted. This is where I will connect my logic analyzer.
Pin 10 is connected to 5v



For my logic analyzer I am using a "Saelae Logic", it has OSX compatibility, so I can connect it to my mac mini. I got the logic analyzer because I already have an oscilloscope, but if I were to start over again(no scope + no logic analyzer), I would get the "QA100 USB Oscilloscope." You can google them to see.

So below I have attached my logic analyzer yellow lead to the receiver's data out pin 9. I have attached the ground lead to GND. Also I have placed the rest of the wires away from the sensing wires because they can cause erroneous readings if they are too close.



So with the logic analyzer software running and the circuit powered, I press "ON" on the remote. Here is what comes up:



Here is what comes up when I press OFF:



So all I need to do is make my Arduino send the same signals to turn the outlet on and off. I will use another off the shelf transmitter to do this.

Where do you get the 433.92mhz transmitter? Well I got mine from ebay. Search "arduino 433mhz transmitter." They come in a pair, one receiver one transmitter.  Below are the ones I bought.


Here is a pic of the arduino connected to the transmitter. The transmitter has 5v, GND, then it's data pin is connected to arduino digital pin 2.




I need to note two things, first you need to use a 6.8inch antenna, it is the orange wire above. This makes the transmission so much more effective and reliable. The second is that the power to the transmitter needs to be clean, USB power is too noisy. You can see I am using a 9v ac/dc adapter for the arduino.

I already know what I want from looking at what the logic analyzer showed me, so I just programmed:


int transmitPin = 2; 

void setup()
{
  pinMode(transmitPin,OUTPUT);
  digitalWrite(transmitPin,LOW);
}

void loop()
{
     turnOn();
     turnOn();
     turnOn();
     turnOn();
     delay(1000);
     turnOff();
     turnOff();
     turnOff();
     turnOff();
     delay(1000);

  
}


void customDelay(unsigned long time) 
{
    unsigned long end_time = micros() + time;
    while(micros() < end_time);
}

//1000=1ms
void setStateWithDelay(int pin, int state,int delayTime)
{
  if(state==1)
    digitalWrite(pin,HIGH);
  else
    digitalWrite(pin,LOW);
    
  customDelay(delayTime);
}

void turnOn()
{
    
  setStateWithDelay(transmitPin,0,13000);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
   
   digitalWrite(transmitPin,LOW);
}

void turnOff()
{
  setStateWithDelay(transmitPin,0,13000);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,1270);
  setStateWithDelay(transmitPin,0,430);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
   setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
 
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
 
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
 
  setStateWithDelay(transmitPin,1,430);
  setStateWithDelay(transmitPin,0,1270);
 
  setStateWithDelay(transmitPin,1,430);
 
    digitalWrite(transmitPin,LOW);
 
  
}




This turns my lamp on and off. You may have noticed that I send turnOn() 4 times, it seems that the outlet wants 4 signals to turn on before it does. Same for the off signal.

Here is a video of the whole circuit working

I don't know if all of the outlets sold have a unique remote id or if they all have one command. I axed the ebay item seller if they know the answer to this question but haven't gotten a reply yet.

Here are the exported output signals

Here are the signals that you can open in the Saelae logic analyzer program.







36 comments:

  1. Thanks for this. If only this was easily feasible with 2.4 GHz modules as well! Can you please post a session of your logic analyzer capture?

    ReplyDelete
  2. Hello, I have posted the signals. Don't worry, I am looking into the feasibility of a smart wifi outlet :)

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. I'm thinking of ordering the 433 receiver's module because I picked up a 433Mhz remote at a yard sale that I'll like to use for a project. Would the one from digikey work? or should I look for something specific on he receiver's end? Can you please add the session file from saleae logic (I mean the .logic file) if you still have it around. Would like to explore it and "see" how you derived the state and timing from it.

    ReplyDelete
    Replies
    1. Got it, I uploaded the .logic files. If you are going to use a 433mhz receiver to sniff your remotes signal then it will be fine to use the digikey one. But if you want to use it as a receiver to a microcontroller in a project then you will need a 50ohm sma connector and 433mhz antenna for the antenna pin to use with that digikey receiver.

      Delete
  5. I did reverse engineer a similar rf outlet last year, your scope traces look similar.
    First, signal is sampled at 5 or so khz. A "1" bit is made of the ---_ sequence, and a 0 is encoded -___ then a frame consisted of data bits interleaved with synchronisation bits like the following:
    A 1 B 1 C 1 D 1 E 1 0 F 0 G 0 H 0 I 0 J 0 K 0 L
    ABCDE : house id, dip-switch encoder in both emitter and outlet
    FGHIJ : device id, correspond to the 5 buttons on emitter
    KL : 01 or 10 for on/off command.
    Maybe i can look for the encoding/decoding i implemented on a microchip pic.

    Anyway, that's a nice project, have fun!

    ReplyDelete
  6. This looks similar to the signals for HomeEasy branded equipment.

    http://playground.arduino.cc/Code/HomeEasy

    ReplyDelete
  7. Can the ebay receiver not be used to capture the signal too?

    ReplyDelete
    Replies
    1. Yes, the ebay receiver has the same functionality, so you can use that. I just have the other one already breadboarded.

      Delete
  8. Great job. Nice & clear explanations.
    I am willing to do something similar, but in 868 Mhz (I live in Europe) for domotic application.
    I planned to use the arduino as listener to decrypt the sender signals.
    Do you think this is realistic ?
    Thank you for your answer.

    ReplyDelete
    Replies
    1. Yes, it is easily doable. You will need to find a 868Mhz receiver, but after that it is a simple matter of having the arduino sample one of the pins periodically to an array and then spit them out to the arduino ide serial console. Let me know if you need help.

      Delete
    2. Hi, thank you for your reply.
      I have got this board (http://jeelabs.com/products/rfm12b-board). It can send and receive RF at 868 Mhz.
      I am more a programmer than a physicist. Do you think that I will have to decode the whole protocol ?
      I hope that I can just the arduino learn some messages, and echoing them on needs.

      Delete
    3. Yep, you can just duplicate the signal by making the arduino 'memorize' then echo them out. This module works at 868 FSK, you must make sure that the system you are interfacing to is also 868 FSK(Frequency shift keying) as opposed to 868 ASK(amplitude shift keying).

      Although the memorize/echo approach will not work on some things like car/garage door remotes, they use a 'rolling' id in their transmissions.

      Delete
    4. Oh no. I did not know that there are FSK ans ASK. Plus, the device I am trying to sniff out, is a central ventilation system. Does it have something to do with pairing the devices ? Do you have any advice ??

      Delete
    5. I don't know what they use in Europe. If it matches then your FSK receiver will output some data that you can copy, other wise it is probably ASK. Try to get as close to the central ventilation transmitter as you can, and also make sure you have the appropriate length wire antenna attached. Sorry for the late reply.

      Delete
    6. No problem for the delay; any information is gold for me, so thank you.
      In the arduino sketch, the init statement look like this :
      short int nodeID = 26; // range (0-31)
      short int group = 4; // range (0-255)
      rf12_initialize (nodeID, RF12_868MHZ, group);

      Do you have any idea about what to set as NodeId and Group values ?

      Delete
    7. Hello Michel,

      I looked at the code, nodeID is just for identifying your transceiver. It says that if you set the nodeid to 0 it broadcasts on all nodeIDs, so for sniffing it might listen to all nodeIDs if you set it to zero. I do not know what should be used for group.

      All the best,

      Delete
    8. Thank for the info. It is already good to know where to start.

      Delete
  9. Thanks again for the logic files. Was definitely helpful.

    ReplyDelete
    Replies
    1. So, I got one of the ebay modules and breadboarded. I wanted to reproduce the logic files using the arduino as a transmitter(with your code) and connecting the receiver to the logic analyzer. As soon as I connect the analyzer to the data pin of the receiver, it start collecting garbage from (probably) neighboring 433 transmissions. I haven't even turned the transmitter on yet. The signal capture trigger of the logic analyzer is not really helpful here. Did you have a similar issue? If yes, how did you go around it?

      Delete

    2. The usb cable from the logic analyzer going into the computer needs to have no other usb cables overlapping it. Do you have a pic? Also, is the gnd lead of the logic analyzer connected? You should connect it, then start the logic analyzer.

      Also, in the Logic software, turn off all of the channels except the one you are using. Leaving them on produces erroneous results for me too.

      But a pic would help me see the best.

      Delete
  10. You were right. After I removed all the crossing wires, most of the noise disappeared. I can actually see my signal now.

    ReplyDelete
  11. Nice work!
    I managed to figure out how to control three different brands of RF-controls and a few IR ones, after reading your blog! After being half-successful building my own Atmega88-logic analyzer i ordered one like this:

    http://www.ebay.co.uk/sch/i.html?_nkw=CY7C68013A+%2B+board+-core&_sacat=0&_odkw=CY7C68013A+%2B+board&LH_BIN=1&_sop=15&_jgr=1&_fcid=192&gbr=1&_osacat=0&LH_PrefLoc=2&_sc=1

    It works rely well (on a 32 bit computer) for the prize of £7.64!
    If u are interested in how i did it: (google translated from Swedish)

    http://translate.google.se/translate?sl=auto&tl=en&js=n&prev=_t&hl=sv&ie=UTF-8&eotf=1&u=http%3A%2F%2Fgizmosnack.blogspot.se%2F2013%2F03%2Frf-fjarrstrombrytare-hack.html

    /Kalle

    ReplyDelete
    Replies
    1. Posts like this make my day! 7.64 pounds is the cheapest I have seen a logic analyzer.

      Delete
    2. I have found a new version of the logical analyzer (£5.89).

      http://www.ebay.co.uk/itm/New-USB-Logic-Analyzer-Device-Set-24MHz-8CH-/191036155696?pt=UK_BOI_Electrical_Components_Supplies_ET&hash=item2c7aa46730

      It works with the latest software from saleae, and on a 64bit computer!

      Delete
  12. Hi,

    I'm currently working on quite the same project, but it's a gate opener remote that I want to simulate. I use PIC and an array containing the low/high times, but it's not relevant I guess.

    I do exactly what you do (check all timings with oscilloscope/logic analyzer) then send it using the same ebay module...

    Have you experienced any problem using the transmitter module?
    I mean I can't believe that I send out exactly the same data as the original RC but it doesn't work. I tried it with antenna too, and using +12V for the tx module to extend the range (that's supported) and tried from ~1m distance with no success...

    The annoying part is that I can see the same data on the receiver that I transmit (sure, incoming data is not processed during transmission... and there is a safety delay between recognizing incoming trigger and activating tx part...)
    You repeat your signal 4 times, I tried 3-32x... no joy :(
    Also tried to adjust gap between the code sequences...
    Sure, replaced transmitter if the "untouched" one is better but not...

    Kinda out of ideas.. :(
    Hope you have one! :)

    ps. I can upload logicdata is you want to take a closer look

    Thanks,
    BR,
    Bela

    ReplyDelete
    Replies
    1. Wow, sorry for the late reply! I just noticed this.

      Usually gate openers use rolling codes, which means it changes each time you press the button. Did you check if your gate opener uses a rolling code?

      Delete
  13. Hi,

    Thanks for the reply.

    It's kind a dumb gate opener using fix code...
    I spent some night pressing the buttons on the remote and checking the signal :)

    BTW, I found the error: of course human :)
    I copy-pasted the array that contains the high/low times and configured the DIP switches several times on the RC so finally I ended up using the wrong code. But using the same on the Rx an the Tx side as well. So all my circuit was working fine, but the gate opener ignored my signal rightly...

    Thanks again,
    BR,
    Bela

    ReplyDelete
  14. Can the SparkFun product at http://www.youtube.com/watch?v=3Ve1dsLf364&feature=youtu.be&t=2m23s do the work of the QA100 USB Oscilloscope?

    Also, would you entertain the idea of building the project shown at:

    http://translate.google.se/translate?sl=auto&tl=en&js=n&prev=_t&hl=sv&ie=UTF-8&eotf=1&u=http%3A%2F%2Fgizmosnack.blogspot.se%2F2013%2F03%2Frf-fjarrstrombrytare-hack.html

    ReplyDelete
    Replies
    1. Hello, yes that one will work too. Unfortunately I cannot build the listed project because of time constraints.

      Delete
  15. How did you know your remote's base frequency (433.92mhz) and encoding scheme (ASK) in order to start this process? (I'm trying to follow this process for a remote to multiple DB-Tech 99365 units.)

    ReplyDelete
    Replies
    1. Hello,

      It said in the manual that came with the unit. Its a very common short range frequency+encoding

      Delete
  16. I need a smart outlet that I can control with my arduino, so I am ... usboutlet.blogspot.com

    ReplyDelete