It is quite common that you can find some devices that are intended to be scrapped, but after speaking to the correct person you can intercept that process. I had a similar situation with sensors for alarm systems, to be precisely - glass break and PIR sensors that operates wirelessly. Unfortunately, I received only devices; no documentation, no specs, no gateway that works with them. Nevertheless, I decided to do a little reverse engineering and try to build such a gateway by my own.
I have started with glass break sensor and in this post I will try to briefly describe my findings.
Sensor is dedicated to European market, so it is highly possible that it uses one of the common ISM bands - 433MHz or 868MHz. To confirm that I dismantled it and look for RF part. Without much effort I found crystal oscillator rated at 433MHz so it looks like that my predictions regarding communication frequency were correct.
After short analysis of RF part I discovered that it is very simple and there is no receiving module. Sensor only transmits its current state and whole communication is one-way. That makes my work much simpler than I expected.
I need only a receiver that has enough bandwidth to cover 433MHz band, ideal solution for this is very common and cheap SDR dongle based on RTL2832U chip. After configuring it to proper frequency I was able to see signal from the sensor.
I passed received signal through AM demodulator and record output to wav file.
To continue my analysis I opened recorded file with Audacity to check how its waveform looks like. Without much effort I get an image where single bits are clearly visible. Looking at entropy of that data it is obvious that some kind of coding is applied. This is an expected operation when sending data using RF.
Now it’s time to solve a puzzle. First part of received signal is likely a
preamble, so I don’t look at it. I expect that somewhere should be an ID of the
sensor that is printed on the box: 0975F0D
. After a few minutes of
investigation I figured out the coding. It’s very simple - it is based on
position of the pulses. If distance from previous pulse (time of low state) is
long, this is 1
, if short - 0
. This a variation of PPM (pulse position
modulation).
Here is the signal from previous picture with annotated decoded values. After a preamble there is an expected sensor ID transmitted.
I can now receive, demodulate and decode data from sensor. I don’t want to use RTL2832 in final solution because it requires PC to operate. It’s time to build a receiver based on transceiver IC. I decided to use CC1101 chip as I am quite familiar with it.
Following CC1101 configuration allows to properly receive data:
PPM decoding and framing will be done by software.
Next step is to assign decoded values to the numbers and define a frame. Here are few consecutive frames received after triggering tamper alarm on the sensor.
0D 5F 97 A0 AF 00 0D
0D 5F 97 A1 A0 01 07
0D 5F 97 A2 2F 00 0F
0D 5F 97 A3 20 01 09
0D 5F 97 A4 AF 01 0F
0D 5F 97 A5 A0 00 09
0D 5F 97 A6 2F 01 01
0D 5F 97 A7 20 00 0B
0D 5F 97 A0 AF 00 0D
0D 5F 97 A1 A0 01 07
0D 5F 97 A2 2F 00 0F
0D 5F 97 A3 20 01 09
First 3 bytes are device ID as shown before. Next 4 bits look like frame counter from 0 to 7. Then there is something that I called state (12 bits) and ending 2 bytes are parity and checksum.
Here is the code that extracts values from the frame:
State value is a combination of 2 bit values for each input pin of the IC in the sensor. There is also an information about low battery. Each 2 bit values holds two information: 1. actual state of the pin and 2. if the state has been changed since previous transmission. Transmission is triggered by pin level change.
Parity and checksum is a different story. I don’t know what both values are present, maybe for some backward compatibility reason. Parity was easy to calculate, however I spent much of time to figure out how checksum is generated. Finally I ended up with the following code:
Here are data received and interpreted.
Frame { dev_id : 9920269 , seq : 3 , state : 522 }
GlassState { in0_state : false , in0_change : false ,
in1_state : false , in1_change : false ,
in2_state : true , in2_change : false ,
in3_state : true , in3_change : false ,
in4_state : false , in4_change : false }
Frame { dev_id : 9920269 , seq : 4 , state : 762 }
GlassState { in0_state : true , in0_change : true ,
in1_state : true , in1_change : true ,
in2_state : true , in2_change : false ,
in3_state : true , in3_change : false ,
in4_state : false , in4_change : false }
At this point I have fully working receiver for this type of sensors, it receives data, validates if checksum is correct and recognizes tamper or glass break alarm.