bggardner / simplisafe-rf

The application-layer protocol used by SimpliSafe devices over RF
The Unlicense
19 stars 13 forks source link

This repository is no longer being maintained. - I no longer have the V2 hardware, so please fork the project and continue development. I will provide support as best I can.

simplisafe-rf

Protocols used by SimpliSafe (v2) devices over RF, implemented in Python.

Introduction

Being a SimpliSafe customer for many years, I have found some shortcomings, and have always wanted to find a way to remedy them. However, I had never delved into wireless communication before and wasn't tempted to start, until I came across this article that quickly went viral. It unveiled that the wireless communication protocol used by SimpliSafe is unencrypted, which makes some customers feel unsafe or cheated, but in my case, it allows for some relatively easy "customization" of the system. Also inspired by this follow-up and this thread, I decided it was time to give it a shot.

The aforementioned shortcomings that bothered me are as follows:

As pointed out by the articles mentioned above, reverse engineering the RF protocol used by the SimpliSafe devices was not very difficult, but the articles failed to disclose any details. The basics of the low-level protocol can be found in the SimpliSafe, Inc. FCC Wireless Applications timing diagrams. From there, all it takes it sniffing the data and doing some some decoding. I used a Raspberry Pi and inexpensive (<$10) 315MHz and 433MHz transmitter/receiver pairs (RF hardware). The pigpio library was used for interfacing with the RF hardware. I wrote a crude Python module (pigpio.py) that decodes/encodes the waveforms to/from bytes using pigpio. They key module in this repository, messages.py, is what transforms the bytes to/from human-readable messages for use in applications. The other module, devices.py, allows the user to emulate any SimpliSafe device.

It should be noted that the Raspberry Pi may not be the best selection for interfacing with the RF hardware as it does not execute in real-time. I have issues when trying to transmit messages using pigpio, as I believe interrupts may be causing errors in the bit timing. A microcontroller or FPGA would be a better choice, but then it would need to interface with a device that could support the Python module and perform more complex functions, like interfacing with the web, databases, or home automation systems. Therefore, these Python modules are to serve as a guide for further development. See the wiki for details.

Requirements

Usage Examples

NOTE: This is not meant to be a script, as each code block is an individual example

#!/usr/bin/python3
from simplisafe import DeviceType
from simplisafe.devices import Keypad
from simplisafe.messages import EntrySensorMessage, MotionSensorMessage, KeychainRemoteMessage, DisarmPinRequest, BaseStationKeypadDisarmPinResponse
from simplisafe.pigpio import Transceiver

RX_315MHZ_GPIO = 17 # Connected to DATA pin of 315MHz receiver
RX_433MHZ_GPIO = 27 # Connected to DATA pin of 433MHz receiver
TX_315MHZ_GPIO = 16 # Connected to DATA pin of 315MHz transmitter
TX_433MHZ_GPIO = 20 # Connected to DATA pin of 433MHz transmitter

# 433MHz traffic monitor:
with Transceiver(rx=RX_433MHZ_GPIO) as txr:
    while True:
        msg = txr.recv() # Returns when a valid message is received and parsed
        print(str(msg))

# Simulated entry sensor "open":
with Transceiver(tx=TX_433MHZ_GPIO) as txr:
    sn = "123AZ" # Serial number of simulated entry sensor (must be added to base station list of sensors)
    sequence = 0x0 # Should be incremented after each send by this sensor
    event_type = EntrySensorMessage.EventType.OPEN # OPEN or CLOSED
    msg = EntrySensorMessage(sn, sequence, event_type)
    txr.send(msg)

# Simulated motion sensor "trip":
with Transceiver(tx=TX_433MHZ_GPIO) as txr:
    sn = "456JK" # Serial number of simulated motion sensor (must be added to base station list of sensors)
    sequence = 0xA # Should be incremented after each send by this sensor
    event_type = MotionSensorMessage.EventType.MOTION # HEARTBEAT or MOTION
    msg = MotionSensorMessage(sn, sequence, event_type)
    txr.send(msg)

# Simulated keychain remote "off":
with RFUtils.Transceiver(tx=TX_433MHZ_GPIO) as txr:
    sn = "789BG" # Serial number of simulated keychain (must be added to base station list of sensors)
    sequence = 0x7 # Should be incremented after each send by this sensor
    event_type = KeychainRemoteMessage.EventType.OFF # PANIC, AWAY, or OFF
    msg = KeychainRemoteMessage(sn, sequence, event_type)
    txr.send(msg)

# Simulated keypad disarm PIN request:
with RFUtils.Transceiver(tx=TX_433MHZ_GPIO) as txr:
    sn = "159MP" # Serial number of simulated keypad (must be added to base station list of sensors)
    sequence = 0x3 # Should be incremented after each send by this sensor
    pin = "1379" # Can be 4-digit string or integer
    msg = KeypadDisarmPinRequest(sn, sequence, pin)
    txr.send(msg) # Base station will respond on 315MHz with "VALID" or "INVALID"

# Simulated base station valid disarm PIN response:
with RFUtils.Transceiver(tx=TX_433MHZ_GPIO) as txr:
    kp_sn = "159MP" # Serial number of keypad that send disarm PIN request
    sequence = 0xF # Should be incremented after each send by this base station
    bs_sn = "456JK" # Serial number of simulated base station
    response_type = BaseStationKeypadDisarmPinResponse.ResponseType.VALID # VALID or INVALID
    msg = BaseStationKeypadDisarmPinResponse(kp_sn, sequence, bs_sn, resposne_type)
    txr.send(msg)