Decoding 433MHz RF data from wireless switches

[Update 2013-03-01] I have added more documentation on the codes these remotes use in a different post.

I’m starting to move towards not only gathering information but also acting. My first project in this subject will be controlling some lights and the house heaters. So last week I visited the urban market of “Els Encants” in Barcelona and bought some very cheap wireless outlets.

Two different remotes

I bought two sets of three wall plugs, each set with it’s own remote. They all transmit in the 433MHz frequency and I already had a set of transmitter and receiver for that frequency so as soon as I had some time I started trying to intercept and reproduce the codes the remotes were sending.

Sample outlets from each set plus remotes

Sample outlets from each set plus remotes

In the image above you can see an outlet and the remote for each of the sets. The left one is branded “Noru” and each outlet is rated 3kW (good for the heaters) and it features auto switch off time (1, 2, 4 or 8 hours). The remote can control a maximum of 3 outlets and apparently it is programmable, since you first have to sync the outlets with the remote.

The right one is branded “Avidsen”, also 433Mhz but rated 1000W, just below the consumption of my house electrical heaters, but good to control lights and other appliances. It’s got the very common dip switch to sync the remote and up to five outlets. There are 32 different channels available. So if your lights switch on and off randomly maybe you neighbour is using the same channel you are, then you better change the channel.

Available libraries for Arduino

I started reading documentation about the protocol these devices use and found out there is some very useful information out there. In fact there are even a couple of libraries for Arduino. The first one is called RemoteSwitch and it is a little old, it has not been ported to Arduino 1.0 but if you are like me you will keep a copy of Arduino 0023 just for this kind of situations.

The second library is called RCSwitch and I have to say it is a neat piece of code. It has been ported to the Raspberry Pi, although the port is not as updated as the original Arduino library.

My first tests with the RemoteSwitch library were encouraging. The Show_received_code sketch dumped the codes for the Avidsen remote one by one. I though: if it can decode it, it should be able to recreate it. And it worked from scratch. Good!

But by then I knew I wanted to use the newer library. There were several reason for this: it is being actively developed, it supports more protocols, the code is much more elegant and object oriented and it has a port to RPi, which I plan to use as a central gateway soon. So I checked which one of the RCSwitch protocols matched the one I had successfully used with RemoteSwitch and started doing some more tests…

Slightly different protocol

Here was when things started to get complicated. The thing did not work. So I spent a couple of hours studying the code for both libraries, decoding the codes the RemoteSwitch library had dumped before and trying to find the difference. Until I found it: RCSwitch.cpp, line 239, that ‘0’ should be a ‘1’… and everything started working again. Very good! I started a thread in the library forum to find out whether this is a bug or a slightly different protocol.

Index: RCSwitch.cpp
===================================================================
--- RCSwitch.cpp	(revision 219)
+++ RCSwitch.cpp	(working copy)
@@ -284,7 +284,7 @@
         if (sGroup[i] == '0') {
             sDipSwitches[j++] = 'F';
         } else {
-            sDipSwitches[j++] = '0';
+            sDipSwitches[j++] = '1';
         }
     }

By the way, the protocol of these things is pretty interesting. It’s worth a look at Sui’s post to get an overview of the implementation. The tri-bit concept is really awkward.

Using the Bus Pirate and OLS Logic Analyser

Then I moved to the other set of outlets. These are rated 3000W so I plan to use them to control my house heaters, which is the main reason for all this work. I followed the same steps, starting with getting the codes with the Show_received_code sketch. But weird enough the library was only able to decode some of the button presses… Only the SET button for outlet #1, the ON and OFF buttons for outlet #2, the ALL OFF button or the 2, 4 and 8H timeout buttons seemed to work.

This time it was going to be harder, since I didn’t even have all the codes. Well, a good opportunity to use my Bus Pirate!

Bus Pirate to the rescue!

Bus Pirate to the rescue!

So I plugged the RF receiver to the Bus Pirate and launched the OLS Logic Analyser to capture the signal from the remote.

You don’t have to configure anything to use the Bus Pirate as a (low speed) logic analyser. But since I wanted to power the radio receiver with the BP I had to enable the Power Supply mode. To do so you have to open a terminal session, type ‘?’ to get a prompt, select one of the modes that allow enabling the power supply typing ‘m’ and selecting the mode (like UART, for instance) and then type ‘W’ (uppercase to enable, lowercase to disable). Then you can close the session and it will keep the power on the 5V and 3V3 lines as long as it is plugged to the computer. Mind you have to free the port so the logic analyser software can use it. I had problems doing it with screen or minicom, but it worked great with picocom.

After some tests with the Avidsen remote (I knew what the codes were so I could compare the signal output with the actual code) I started getting the signals for each and every button in the Noru remote.

The image below shows the signal for the ON button for the outlet #1.

Signal for the #1 ON button of the Noru remote

Signal for the #1 ON button of the Noru remote

Now, since the RemoteSwitch library was able to decode some of the signals, the protocol could not be that different. So I started to decode manually all the signals applying the same protocol. The signal is a series of 12 tri-bits plus a sync-bit. For the Avidsen-like remotes there are 3 different tri-bit values (logically), they are called 0, 1 and F, for “floating”. Each tri-bit has a pulses shape. The following tables describes the pulses:

Tri-bit Pulses
0 short high + long low + short high + long low
1 long high + short low + long high + short low
F short high + long low + long high + short low

The long pulses are about 3 times the length of the sort ones. The overall period is a characteristic of each remote. There is also a trailing high pulse followed by a long low which is called “sync bit”.

A fourth tri-bit?

Decoding the signals from the Noru remote I found out that there was a fourth tri-bit value (well maybe I should call them tetra-bits now). In fact it is obvious since there is a forth option for an alternate sequence of 4 highs and lows. I’ve named the new tetra-bit X (for unknown, but also after my name :P). The full table for the Noru remotes is:

Tretra-bit Pulses
0 short high + long low + short high + long low
1 long high + short low + long high + short low
F short high + long low + long high + short low
X long high + short low + short high + long low

Now the previous image for the ON#1 button can be decoded as 1F000001FFX0S. With a small patch I could make this work with the RCSwitch library. The library cannot create the code but you can feed it to the sendTriState method to generate the signal.

Index: RCSwitch.h
===================================================================
--- RCSwitch.h	(revision 219)
+++ RCSwitch.h	(working copy)
@@ -106,6 +106,7 @@
     void sendT0();
     void sendT1();
     void sendTF();
+    void sendTX();
     void send0();
     void send1();
     void sendSync();
Index: RCSwitch.cpp
===================================================================
--- RCSwitch.cpp	(revision 219)
+++ RCSwitch.cpp	(working copy)
@@ -441,6 +441,9 @@
         case '1':
           this->sendT1();
         break;
+        case 'X':
+          this->sendTX();
+        break;
       }
       i++;
     }
@@ -561,6 +564,16 @@
 void RCSwitch::sendTF() {
   this->transmit(1,3);
   this->transmit(3,1);
+}
+
+/**
+ * Sends a Tri-State "X" Bit
+ *            ___   _
+ * Waveform: |   |_| |___
+ */
+void RCSwitch::sendTX() {
+  this->transmit(3,1);
+  this->transmit(1,3);
 }

 /**

And this is a sample code for Arduino that switches on and off outlet #1 every 2 seconds.

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {

  Serial.begin(9600);

  // Transmitter is connected to Arduino Pin #11
  mySwitch.enableTransmit(11);

  // Optional set pulse length.
  mySwitch.setPulseLength(302);

  // Optional set protocol (default is 1, will work for most outlets)
  mySwitch.setProtocol(1);

  // Optional set number of transmission repetitions.
  mySwitch.setRepeatTransmit(6);

}

void loop() {
    mySwitch.sendTriState("1F000001FFX0");
    delay(2000);
    mySwitch.sendTriState("1F000001FFFX");
    delay(2000);
}

Again, comments are more than welcome!

CC BY-SA 4.0 Decoding 433MHz RF data from wireless switches by Tinkerman is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

22 thoughts on “Decoding 433MHz RF data from wireless switches

  1. sui

    Actually the Tri/tetra-state format can be simply substituted to binary:

    1 = 11
    0 = 00
    F = 01
    X = 10

    and thus you should also be able to use

    mySwitch.send(“110100000000001101011000”);

    instead of

    mySwitch.sendTriState(“1F000001FFX0”);

    Reply
    1. xose Post author

      Off course, but I’d like to move in the opposite direction, to a higher level of abstraction. Instead of sending bit streams it will be great to be able to send something like channel-sensor-state, like for the Avidsen remote.
      The problem is that I don’t have enough information to decipher the different parts of the signal. The 14 different buttons the Noru remote has send the same stream of tri/tetra-bits except for the last two, and I have not been able to identify any pattern in the way this two last bits change…
      I’m writing a new post with all the data I have so maybe some one can compare this information with his own remote signals.

      Reply
  2. Pingback: Decoding 433MHz RF data from wireless switches. The data | Tinkerman

  3. Sam Hunt

    Hi,

    I have been trying to do a similar thing with a cheap remote I purchased. However I have been unable to get bus pirate to adequately connect to the OLS software. I am able to configure the bus pirate and interact in serial terminal. But I have never used the logic sniffer before. Any suggestions?

    Reply
    1. xose Post author

      Hi Sam

      Have you checked if the receiver is being powered? You can do it with BP from the terminal, it’s explained in the post, or with an external power supply (be sure to share ground with BP). If that’s not the reason you can try the windows way: disconnect everything, close OLS and start over again 🙂

      Reply
  4. Fernando Coelho

    Dear Tinkerman,

    First of all you have a very good article about the RF433 and arduino.
    I read this article and i am in same state like you in the beginning to put put AVIDSEN with RCSwitch .
    I cant put AVIDSEN working with RCSwitch 2.5.1.
    i made de modifications in the RC library that you sugested but no way to work .
    Can you please send to me the RCswitch modified ?
    note: in the ten dip switch of the outlet i have (on=1 and off=0) 11111 10000 how should be the command for that configuration .

    thanks in advance
    F. Coelho

    Reply
    1. xose Post author

      Hi Fernando

      All the modifications I did to the code are in the post as diffs.

      But maybe you should first try a lower level approach to check that everything is working fine. Sui’s comment above suggests sending the binary raw data. I cannot recall the DIP positions right now but assuming you are on channel 31 (11111), outlet A (10000) your message should be:

      mySwitch.send(“111111111100010101010100″);

      to switch it on and

      mySwitch.send(“111111111100010101010001″);

      to switch it off. If you get it working then you can go back to higher level code to find out where the problem is.

      Reply
  5. noimat

    Hi Tinkerman, i trying to decode my remote control (433mhz) but i am a apprentice and I do not know how to capture data from OLS client, I do not know specifically what parameters I have to to enter to start capturing OLS eg what options I enter for the trigger.

    appreciate it if you could help me

    Reply
  6. Vincent Bentley

    Thank you for sharing your ideas. I have been thinking about how I can intercept the signal from my heating oil tank sensor. I currently have a proprietory ultrasonic tank sensor that communicates with a LCD gauge in my house via 433Mhz.

    I am assuming that the gauge is going to be receiving a regular burst of information from the sensor. The sensor’s battery lasts about seven years so I don’t think that the signal is going to be a continuous stream. Hopefully I will be able to decode it.

    I have never tried a project like this before and your blog has inspired me to look into this further. I am assuming OLS is Open Bench Logic Sniffer. I’m pleased to see that it has Linux software. http://dangerousprototypes.com/docs/Logic_Sniffer_quick_start_guide#Linux . Is this the best way for an absolute beginner to get started or should I be looking at some other tools instead?

    Reply
    1. xose Post author

      Hi Daedalus

      These two receiver/transmitter bundles use the same frequency (433MHz) and modulation (ASK/OOK).
      As long as the clicker uses the same frequency and modulation any of the two bundles will do the job (there are other thinks to take into account, like pulse timings or radio range).
      Now, I don’t know much about this clicker, but some googling indicates that there are other frequencies and modulations commonly used by the ICs these clickers have, like the MAX7042 (datasheet PDF).
      So to be save I would try to get more info about the clicker: open it to see what IC uses, contact your provider or search for it on the Internet…

      Reply
  7. Pingback: DEF CON vs IoT: On Hackability and Security | Hackaday

  8. Pingback: Adding RF to a non-RF ITEAD Sonoff | Tinkerman

  9. johnny cat

    thanks so much for this. I just got into these rf modules, playing around with a teensy microcontroller for a couple of years. one thing ive started to kind of wonder though is if you send a stronger signal thats incorrect to the encode/decode signal the receiver is listening for then you could potentially bypass the transceiver? like on your reed/magnet door thing? just a thought.. thanks again

    Reply
    1. Xose Post author

      Hi
      I’m glad you found it useful. I’m not sure I understand your question about bypassing the transceiver…

      Reply
      1. johnny cat

        transceiver isnt probably the correct word, i just meant if you downed out the transmitter with a higher wattage from another transmitter it could potentially make the receiver unable to get you an alert.

        Reply
        1. Xose Post author

          If you emit a strong enough signal or noise you potentially disable the receiver ability to listen for any message. That pretty much applies to any RF system. The trick here, like in many alert systems, is to design it as a normally closed switch: you expect to receive a heartbeat from your device every X seconds. If you don’t then there’s something going on…

          Reply
  10. Kess

    Hi Xose,

    Nice page 🙂

    I am trying to pair my remote with the sonoff rf which has the custom firmware.

    I have a 433MHz standard “garage” remote, identical to the sonoff supplied remote but my remote does not have an acceptable sonoff code sequence on it, so the sonoff rejects learning this code when I ask it to suck it up.

    If I had the structure of the right code I could re-program the remote.

    I know the sonoff won’t learn the code I give it from the remote because when I press the sonoff on board button twice quickly, so that it flashes red indicating it is attempting to suck up the remote code, and press the 433MHz remote button to send the code at the same time, nothing happens.
    The sonof does not blink red 3 times to confirm it has sucked up or learned the code.

    The remote I am using is programmed with 24-bits serial; a mixture of high-to-low or low-to-high each forming a 1 or 0 serial radio signal.

    I think the sonoff is looking for a particular starting code sequence, or perhaps tri-state, or some other sequence type, which is not how my remote is currently programmed.

    I have a bag full of these remotes from aliexpress and spending on a sonoff one seems rediculous!

    If you have a sonoff remote can you sniff the code and publish the code sequence. I will buy you a coffee.

    That way I can send it from software to my 433 TX device and thus program my 433 remote and thus in turn pair the remote with the sonoff receiver.

    I will then by trial and error learn all the sonoff codes and publish these so that anyone else may use them.

    We are watching the oppressive Spanish Government carefully from Scotland and wish the very best for your nation on October 1st. Si.

    Reply
    1. Xose Pérez Post author

      Hi
      Thanks. I’ll try to do it when I have time. But maybe you can try with the codes I sniffed with the Sonoff RF Bridge. They should be compatible. Check my post about it. Those code are 9bytes long, the first 2 bytes is the sync length in us, the second the low time and the third the high time. The other 3 bytes (24 bits) are the code itself.

      Edit Here you have the codes from my Sonoff remote: 2D46017C0460B2A811, 2D64017C046AB2A812, 2D6E017C046AB2A814, 2D82017C046AB2A818. I just copy-pasted them as they showed in the Sonoff RFBridge web UI, so there are minor differences between them in the timings. I guess the decoder is tolerant to those differences. The codes mean:

      • 11.59ms (0x2D46) sync pulse
      • 0.38ms (0x017C) low pulse
      • 1.13ms (0x046A) high pulse
      • The codes are B2A811, B2A812, B2A814 and B2A818 for buttons A, B, C and D
      Reply

Leave a Reply (all comments are moderated, be patient)