How to hack a doorbell and connect it to Twitter - Part 4: Using an Arduino to detect a wireless RF signal

The following sketch prints a message to the serial output when it detects the doorbell signal.

/* DoorbellReceiver.ino - Detects signal from Grundig wireless doorbell (model QH-831A).
   
   Modified sketch (unknown licence) from Riva, to be found at
   http://forum.arduino.cc/index.php?topic=110662.msg1094167#msg1094167
      
   DBAD Public Licence (http://www.dbad-license.org/)
   crutzen.eu - July 2013
   
   Connect data pin of RF receiver to digital pin 2 of the Arduino.

  The signal exists of 24 bits.
  1 means: long  ON followed by short OFF
  0 means: short ON followed by long  OFF
   __                       _____________      _____              __
     |                     |            |     |     |            |
     |_____________________|            |_____|     |____________|

     |     19760us         |    1480    | 464 | 464 |    1480    |
     |                     |            |     |     |            |
     |<--------Sync------->|<--------1------->|<--------0------->|

   To detect the delay values for your device, use the DeurbelSniffer.ino sketch
   and read the instructions at http://blog.crutzen.eu
*/

#define SHORT_DELAY 464
#define SHORT_DEV   12
#define SHORT_MIN   (SHORT_DELAY - SHORT_DEV)
#define SHORT_MAX   (SHORT_DELAY + SHORT_DEV)
#define LONG_DELAY  1480
#define LONG_DEV    12
#define LONG_MIN    (LONG_DELAY - LONG_DEV)
#define LONG_MAX    (LONG_DELAY + LONG_DEV)
#define SYNC_DELAY  19788
#define SYNC_DEV    8
#define SYNC_MIN    (SYNC_DELAY - SYNC_DEV)
#define SYNC_MAX    (SYNC_DELAY + SYNC_DEV)

#define F_WAITING         1               // 1 = waiting for sync     0 = receiving data
#define F_SIGNAL          2               // 1 = a signal found       0 = no signal found
#define F_RIGHT_SIGNAL    3               // 1 = right signal found   0 = incorrect signal

#define RF_DATA_PIN 2

const unsigned long glitch_length = 150;  // Anything below this value is a glitch and will be ignored.

unsigned long fall_time = 0;              // Microsecond time when last falling edge occured.
unsigned long rise_time = 0;              // Microsecond time when last rising edge occured.

unsigned long length_low = 0;
unsigned long length_high = 0;
unsigned long length_sync = 0;

unsigned long buffer = 0;
byte bitCount = 0;
const unsigned long signal = 0b01011111011000100000100;        // The doorbell signal to look for: 0101 1111 0110 0010 0000 100
const byte nBits = 23;

volatile byte flags = 0;

void change() {
  unsigned long time = micros();
  
  if (bitRead(flags,F_WAITING)) { // waiting for sync
  
    if (digitalRead(RF_DATA_PIN) == LOW) { // falling
      if (time > (rise_time + glitch_length)) { // no glitch
        fall_time = time;
      }
    }
    
    else { // Rising - digitalRead(2) == HIGH
      if (time > (fall_time + glitch_length)) { // no glitch
        rise_time = time;
        length_low = rise_time - fall_time;
        if ((length_low >= SYNC_MIN) && (length_low <= SYNC_MAX)) { // found sync, start receiving data
          length_sync = length_low;
          bitClear(flags, F_WAITING);
        }
      }
    }
  }
  
  else { //receiving data
    
    if (digitalRead(RF_DATA_PIN) == LOW) { // falling
      
      if (time > (rise_time + glitch_length)) { // no glitch
        
        fall_time = time;
        length_high = fall_time - rise_time;
        
        if ((length_high >= SHORT_MIN) && (length_high <= SHORT_MAX)) { // found short high = 0
          bitCount++;
          buffer = buffer << 1;
        }
        else if ((length_high >= LONG_MIN) && (length_high <= LONG_MAX)) { // found long high = 1
          bitCount++;
          buffer = buffer << 1;
          bitSet(buffer,0); // set rightmost bit to 1
        }
        else { // found nothing - start waiting for sync again
          bitClear(flags, F_SIGNAL);
          bitClear(flags, F_RIGHT_SIGNAL);
          buffer = 0;
          bitCount = 0;
          bitSet(flags, F_WAITING);
        }
        
        if (bitCount == nBits) {
          bitSet(flags, F_SIGNAL);
          if (buffer == signal) {
            bitSet(flags, F_RIGHT_SIGNAL);
          }
        }
      }
    }
    
    else { // Rising - digitalRead(2) == HIGH
      if (time > (fall_time + glitch_length)) { // no glitch
        rise_time = time;
      }
    }        
  }  

}

void setup() {                
  pinMode(13, OUTPUT); // for debugging
  pinMode(RF_DATA_PIN, INPUT);
  
  bitSet(flags, F_WAITING);  // waiting for sync
  bitClear(flags, F_SIGNAL); // no signal found yet
  bitClear(flags, F_RIGHT_SIGNAL); // right signal not found yet
  
  attachInterrupt(0, change, CHANGE);
  Serial.begin(9600);
}


void loop() {
  
  if (bitRead(flags, F_SIGNAL) == 1) {
 
    Serial.println(buffer);
    
    if (bitRead(flags, F_RIGHT_SIGNAL) == 1) {
      Serial.println("Ding dong!");
    }
    
    bitClear(flags, F_SIGNAL);
    bitClear(flags, F_RIGHT_SIGNAL);
    buffer = 0;
    bitCount = 0;    
    bitSet(flags, F_WAITING);
 
  }
}

As you might have noticed, I used other delay values than those I found with Audacity and used in the sketch to activate the doorbell. That's because it turned out that those values did not work for detecting the doorbell signal. I'm not exactly sure what the reason for this strange behaviour is, but I guess it has to do with the way the RF receiver component with the Arduino detects the signal in a different kind of way than the "Audacity-circuit" does.

My solution to this problem was to make a "sniffer" program for the RF receiver on the Arduino. This program writes the received values to the serial output window:

/* DoorbellSniffer.ino - Prints lengths of received RF values.
   
   Modified sketch (unknown licence) from Riva, to be found at
   http://forum.arduino.cc/index.php?topic=110662.msg1094167#msg1094167
      
   DBAD Public Licence (http://www.dbad-license.org/)
   crutzen.eu - July 2013
   
   Connect data pin of RF receiver to digital pin 2 of the Arduino.
   
   Usage:
   
   This sketch prints the lengths of the periods of time
   of which the RF receiver picks up a signal.
   
   The sketch can either pick up high signals OR low signals.
   
   See the comments in the code to select the kind of signal
   you want to pick up.
   
   Copy the output of the serial monitor to a spreadsheet to
   analyse which durations are most commom. Use those durations
   in the DeurbelOntvanger.ino sketch.
   
   Detailed instructions at http://blog.crutzen.eu
*/

#define RF_DATA_PIN 2

const unsigned long glitch_length = 150;  // Anything below this value is a glitch and will be ignored.

unsigned long fall_time = 0;              // Microsecond time when last falling edge occured.
unsigned long rise_time = 0;              // Microsecond time when last rising edge occured.

unsigned long length_low  = 0;
unsigned long length_high = 0;

void change() {
  
  unsigned long time = micros();
   
  if (digitalRead(2) == LOW) { // falling
    if (time > (rise_time + glitch_length)) { // no glitch
      fall_time = time;
      //length_high = fall_time - rise_time; // comment out to measure length_low
    }
  }
  
  else { // Rising - digitalRead(2) == HIGH
    if (time > (fall_time + glitch_length)) { // no glitch
      rise_time = time;
      length_low = rise_time - fall_time; // comment out to measure length_high
    }
  }  
    
}

void setup() {
  pinMode(RF_DATA_PIN, INPUT);
  attachInterrupt(0, change, CHANGE);
  Serial.begin(9600);
}


void loop() {
  
  Serial.println(length_low); // comment out to measure length_high
  //Serial.println(length_high);  // comment out to measure length_low

}

After letting this program run for approximately 30 second while pressing the doorbell button continuously, I copied the numbers in the serial window to a text file and imported this file into a spreadsheet. I used the spreadsheet to analyse which values were the most frequent. I my case, these were 464, 1480 and 19788, or slightly more or less. This way I figured out that the short delay had to be 464 microseconds, the long delay had to be 1480 microseconds and the sync delay (between to signals) had to be 19788 microseconds.

When you also want to use the sniffer program, bear in mind:

  • to measure the long and the short delays: comment out the right lines so you detect the length of the high signals;
  • to measure the sync delay: comment out the right lines so you detect the length of the low signals.

Source:

Share Button

4 gedachten over “How to hack a doorbell and connect it to Twitter - Part 4: Using an Arduino to detect a wireless RF signal”

  1. Hello!

    This is a great article about receiving/transmitting 433Mhz.

    I've tried your sniffer but I didn't manage to capture the correct signal as the receiver I have gets a lot of noise (it's the same you used).

    Could you give me a hand? The sensor I'm trying to play with it's a water leak detector. I've sniffed the signal it broadcasts when the TEST button is pressed: http://www.ciproconsulting.it/pdf/Soundcard_TEST.wav (using a soundcard).

    I'd practically want to use Arduino listening to this sensor and, in case of water leak detected to send me an email or something.

    Thanks in advance!

  2. Hi,
    I noticed that the pattern in the wav file doesn't really consist of straight lines like the signal of my doorbell has, but curved ones. Maybe the signal of your detector is of a different type? I'm sorry, but I'm no expert and all I know is what I learned myself from the links in the articles.
    When I use the sniffer program, I also get a lot of noise. But some numbers in the serial monitor appear much more often than others. You have to use the sniffer sketch and then copy a list of approximately 5000 numbers to Excel to determine which ones appear the most. Did you do that?
    Sorry for my late and short reply, but I'm having trouble with my internet connection so I'm typing this on my phone and haven't got the patience to to elaborate on my explanation.
    Good luck!

    1. Thanks Ralph!

      I've already analysed the numbers but there are too many sequences tat could match. I'm trying to figure it using Protocol Analyzer and, in case I'll succeed, I'll use then your "listener" for the Arduino part.

  3. very interesting series. sadly the sniffer program didnt prove of much use: right from the start there is a tremendous output of what i presume to be noise

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze website gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.