Martin's corner on the web

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.


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

  1. Frank Herrmann

    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. Mark S

    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?