Interfacing with Paradox home security system attempt 2

I toyed a bit with the Paradox security protocol last year, tapping into the keypad’s interface in an attempt to decode the messages being exchanged between the base station and the keypads. I had some success: I was able to see the keys being pressed, but what was more important to me was the state of the alarm system and each room’s PIR + each door/window’s reed switch. That didn’t work out very well and I quickly abandoned the project.

Until today. I decided to revisit my work and inspect the options at the base station Spectra SP7000. I noticed a 4 pin port labeled ‘Serial’ and hooked my oscilloscope to identify what’s on there. Looked like the port provides ~13V and TX/RX lines at 5V. I hooked my FTDI cable  set to 9600 Baud, 1 start bit, 8 data bits, 1 stop bit and no parity and it started spitting out chunks of 37 bytes. I then remembered that someone sent me a Paradox protocol documentation over the email following my last year’s attempt to hack in, but it seemed quite different from what I was getting at the keypad level and I just ignored it. Looking at it again today showed me exactly what I was looking for: the 37 bytes protocol:


I am interested in the event group, event sub-group and the command byte.

Event codes 00 and 01 are zone closed and zone opened respectively and the event sub-group specifies the zone. There are other event codes as well, but I am only interested in these.

I decided to use a JeeNode v6 to tap into the serial port and transmit the event to my home automation system. The JeeNode runs on 3.3V so I had to create a voltage divider (used 10K:10K, one of the resistors isn’t clearly visible on the picture below) to bring down the 5V to more Jee-friendly levels:


The MCP1702 on the JeeNode will handle the ~13V that the serial port is providing (it is at the limit indeed). Some more pictures of the setup:

IMG_3665 IMG_3663 IMG_3662

Finally here is my code:

#include <JeeLib.h>      //
#define myNodeID 3       // RF12 node ID in the range 1-30
#define network 210      // RF12 Network group
#define freq RF12_868MHZ // Frequency of RFM12B module

#define RETRY_PERIOD 250    // How soon to retry (in ms) if ACK didn't come in
#define RETRY_LIMIT 5     // Maximum number of times to retry
#define ACK_TIME 25       // Number of milliseconds to wait for an ack

char inData[38]; // Allocate some space for the string
byte index = 0; // Index into array; where to store the character

#define LED 6

typedef struct {
     byte armstatus;
     byte event;
     byte sub_event;    
     byte dummy;
 } Payload;
 Payload paradox;
void setup() {
    rf12_initialize(myNodeID,freq,network); // Initialize RFM12 with settings defined above 

    Serial.flush(); // Clean up the serial buffer in case previous junk is there
    Serial.println("Paradox serial monitor is up");


void readSerial() {
    while (Serial.available()<37 )  {} // wait for a serial packet                                   
        while(index < 37) // Paradox packet is 37 bytes 
            inData[++index]=0x00; // Make it print-friendly


void loop()

  if((inData[0] & 0xF0)==0xE0){ // Does it look like a valid packet?
    rfwrite(); // Send data via RF  
  else //re-align buffer

void serial_flush_buffer()
  while ( >= 0)
   ; // do nothing

void blink(int duration) {


// Wait a few milliseconds for proper ACK
  static byte waitForAck() {
   MilliTimer ackTimer;
   while (!ackTimer.poll(ACK_TIME)) {
     if (rf12_recvDone() && rf12_crc == 0 &&
        rf12_hdr == (RF12_HDR_DST | RF12_HDR_CTL | myNodeID))
        return 1;
   return 0;

// Send payload data via RF
 static void rfwrite(){

   for (byte i = 0; i <= RETRY_LIMIT; ++i) {  // tx and wait for ack up to RETRY_LIMIT times
      while (!rf12_canSend())
      rf12_sendStart(RF12_HDR_ACK, &paradox, sizeof paradox); 
      rf12_sendWait(0);           // Wait for RF to finish sending 
      byte acked = waitForAck();  // Wait for ACK
      if (acked) {       
      }      // Return if ACK received
   delay(RETRY_PERIOD);     // If no ack received wait and try again

The code is running for few hours already and all is as expected.

I have a Raspberry Pi with RFM2Pi board running a read-only Raspbian that does my home automation, it captures the wireless packets using a node-red flow. With this new data available, my smart house will be able to know where its inhabitants are (PIR) and take various decisions based on that. I can also use the window/door state information (Reed switches) for smarter climate control, i.e. turn off the thermostat in a room that has the window open.


Page views: 43463

2 thoughts on “Interfacing with Paradox home security system attempt 2

  1. I see you never use special register after rf_initialize for less baudrate and other. I use the 433 MHz Modules, but i have only connect for some meters (3-4) and after that, no connect. If you use some tricks or if your connect better cuz you use the 868 MHz modules. At your photo on top of every website i see you build the antenna as a spiral, if this better to connect the RFM Modules or just for fun? 🙂

  2. Great work!
    I’m looking to build a similar system but with an ethernet interface on arduino.
    Could you possibly send me the Paradox protocol documentation doc you have?
    Have you perhaps gotten any further with this project?

Comments are closed.