Surfing on radio waves

Our next journey with the doorbell takes us to the wonderful world of radio signals

In the last post, it was mentioned that you don't have to disassemble your indoor unit and resolder it. You can also build your own radio receiver. Today we will examine this option a bit more.

This approach is so far from hardware-hacking that we don't even need to take apart the device. In the product's technical specification, we can find all the information we need, like that it's sending the signals on 433.9 MHz. You can buy a 433.9 MHz receiver on your favorite Chinese webshop, I've chosen this model without any serious research, but luckily it worked well.

And now we wait a month or so for the package to arrive. In the meantime, we can take the doorbell apart and wire it up with a Raspberry Pi. :)

After the package arrived, we opened it with much excitement just to see that the antennas were not soldered into the modules, so we had to get the soldering iron out. Then I connected a LED to the data output of the receiver just to see if anything would happen if I pushed the doorbell.

It's worth checking out in the video that the LED blinks randomly at first, then we only see a slight, more orderly flickering, then a longer off state and a longer on state, and it goes back to the random blinking. So the signal that the outdoor unit sends could be the more orderly flickering with the longer off/on state. The rest of the noise is a bit concerning. There will be a lot of garbage we have to ignore.

More detailed analysis

It would be nice to see more precisely what's going on. We could hook up a logic analyzer to the data output. Maybe it could help to find some useful information. Luckily there are cheap Chinese models we could order (I went with this one, but there is a lot to choose from). Another month of waiting and we can continue with the project.

On my computer, I used PulseView to display the incoming data. Below you can see the signal for a doorbell button press.

It correlates nicely with our experience with the LED. The random parts are at the beginning and the end, the more orderly part in the middle that is closed by the long off/on state. Let's zoom into the more orderly part:

This is the part where we go from random to less random. It looks like the transmitter repeats the same pattern with small pauses around a hundred times.

If we zoom in a little bit more, we can identify two distinct patterns inside this repeating pattern. The first one is when a longer high state is followed by a shorter low state. We could name this binary one. The other is when a shorter high state is followed by a longer low state, which could be binary zero.

We couldn't be sure what these 17 bits meant. Maybe it's an identifier for the receiver, maybe the 17. bit is not part of the data, and it's the part of the separators between data packs. In this case, we have 16 bits, which sounds a lot better. The good news is that we don't really care about the meaning of the data. It's always the same for every button press, so we just need to match this meaningless pattern for our project.

The device

I tried to replace the indoor receiver with an Arduino Uno, but I couldn't get the same pattern out of it as the logic analyzer showed before. Maybe the hardware is too slow to handle such a dense signal, or I messed up something, but the point is that I switched to a Teensy 3.1, and things got a lot better.

Fortunately, my Arduino code didn't need a lot of change to run on the new hardware. First, I wrote a program to print out how long the signal is in the high and low states to the serial console.

unsigned long high_value = 0;
unsigned long low_value = 0;
unsigned long prev_time = 0;

void setup() {

  attachInterrupt(23, rising, RISING);

void loop() {}

void rising() {
  low_value = micros() - prev_time;
  prev_time = micros();

  Serial.print(", L");

  attachInterrupt(23, falling, FALLING);

void falling() {
  high_value = micros() - prev_time;
  prev_time = micros();

  attachInterrupt(23, rising, RISING);

It was pretty easy to spot the repeating pattern:

H631, L140
H632, L142
H630, L144
H242, L533
H626, L145
H629, L146
H239, L536
H239, L532
H627, L143
H627, L146
H239, L536
H238, L535
H240, L532
H627, L143
H241, L534
H241, L534
H626, L1683

It has some variance, but we can see the pattern for the binary ones and zeroes and the bigger pause after the last bit. Next, we need to replace the printing out to the detection of the ringing signal, and we are done:

const unsigned short target = 60612;
unsigned short value = 0;

void rising() {
  // [...]

  if (high_value >= 620 && high_value <= 640 && low_value >= 130 && low_value <= 150) {
    value = (value << 1) + 1;
  else if (high_value >= 230 && high_value <= 250 && low_value >= 520 && low_value <= 550) {
    value = value << 1;
  else if (low_value > 1500) {
    value = 0;

  if (value == target) {

  // [...]

This works, but it has some naughtiness in it. For example we don't read the 17. bit (if it's part of the data what we don't know), it uses the longer pause after it to zero out the current value. But it's better this way because it wouldn't fit in a short.

Next is that it's a repeating pattern, so we get multiple "Ding-Dong" messages during a ringing. But not as many as we would need to get if we successfully matched every pattern. We can tweak the limits a little bit to have more freedom, or we could somehow detect the bigger gap between the patterns, but I leave this as an exercise to the reader.

If you are still not fed up with radio signals after this, then it could be an interesting project to create a custom transmitter as well. For example, creating your own doorbell button for your indoor unit or a universal button that sends every possible pattern and rings all the indoor units. :)

Ez a bejegyzés magyar nyelven is elérhető: Az éter hullámain

Have a comment?

Send an email to the blog at deadlime dot hu address.

Want to subscribe?

We have a good old fashioned RSS feed if you're into that.