Giter VIP home page Giter VIP logo

secplus's Introduction

secplus

This project is a software implementation of the Security+ and Security+ 2.0 rolling code systems used in garage door openers made by Chamberlain, LiftMaster, Craftsman and others.

Encoding and decoding functionality is implemented in a MicroPython-compatible Python module (secplus.py) as well as an Arduino-compatible C library (secplus.c & secplus.h).

Sample GNU Radio flowgraphs for receiving and transmitting codes are also provided.

Requirements

The following components are required to run the sample GNU Radio flowgraphs:

  • GNU Radio 3.8 or later
  • gr-osmosdr
  • SDR hardware supported by gr-osmosdr (e.g. RTL-SDR, HackRF)

Usage

Receiving:

$ ./secplus_rx.py

Security+:  rolling=2320616982  fixed=876029923  (id1=2 id0=0 switch=1 remote_id=32445552 button=left)
Security+:  rolling=3869428094  fixed=876029922  (id1=2 id0=0 switch=0 remote_id=32445552 button=middle)
Security+:  rolling=2731817112  fixed=876029924  (id1=2 id0=0 switch=2 remote_id=32445552 button=right)
Security+:  rolling=2731817116  fixed=876029924  (id1=2 id0=0 switch=2 remote_id=32445552 button=right)
Security+:  rolling=2615434900  fixed=72906373  (id1=0 id0=0 switch=1 pad_id=1478 pin=1234)
Security+:  rolling=2615434904  fixed=595608121  (id1=0 id0=0 switch=1 pad_id=1478 pin=enter)
Security+ 2.0:  rolling=240124680  fixed=70678577664  (button=16 remote_id=1959100928)
Security+ 2.0:  rolling=240124681  fixed=70678577664  (button=16 remote_id=1959100928)
Security+ 2.0:  rolling=240124682  fixed=62088643072  (button=14 remote_id=1959100928)
Security+ 2.0:  rolling=240124683  fixed=66383610368  (button=15 remote_id=1959100928)
Security+ 2.0:  rolling=240124684  fixed=74973544960  (button=17 remote_id=1959100928)

Transmitting Security+:

$ ./secplus_tx.py --freq 315150000 --rolling 2731817118 --fixed 876029924

The rolling code should be at least 2 higher than the previously transmitted rolling code.

Transmitting Security+ 2.0:

With rolling and fixed codes only:

$ ./secplus_v2_tx.py --freq 315000000 --rolling 0xe50030d --fixed 0x1074c58200

With optional supplemental data (e.g. PIN):

$ ./secplus_v2_tx.py --freq 315000000 --rolling 0xe50030d --fixed 0x1074c58200 --data 0xd204b000

The rolling code should be at least 1 higher than the previously transmitted rolling code.

secplus.py

This Python module encodes and decodes the rolling and fixed codes, provides utility functions to prepare on-off keying sequences for transmission, and pretty-print the codes. It can be used to build stand-alone applications. It uses a limited subset of Python so that it can be executed in MicroPython.

secplus.c & secplus.h

This C library implements encoding & decoding of Security+ & Security+ 2.0 messages (both wireless & wireline). It it suitable for use in Arduino and other microcontrollers.

Protocol details

Security+

Much of the Security+ system is described in US patent 6,980,655; the remaining details were determined by analyzing the data transmitted by Security+ remotes.

Transmissions use on-off keying, with an alphabet of three symbols (0, 1, 2) corresponding to three different pulse widths:

  • 0: 1.5ms off, 0.5ms on
  • 1: 1ms off, 1ms on
  • 2: 0.5ms off, 1.5ms on

The payload consists of 40 symbols, which are transmitted in two frames of 20 symbols each. A single synchronization symbol is prepended to each frame: 0 for the first frame, and 2 for the second. 58ms of silence occurs after each frame, but the receiver I tested with accepts as little as 20ms. Remotes repeat the frame pair a minimum of four times, or continuously for as long as the button is held down.

The payload consists of a rolling code and a fixed code, each approximately 32 bits long. These values are combined and encoded into 40 ternary symbols for transmission. Despite being described as such in patents, the encoding is not encryption as there is no key.

The rolling code is incremented by three each time the remote button is pressed, and the fixed code remains the same. PIN pads use half of the fixed code symbols to transmit the four-digit PIN that was entered. Receivers accept codes so long as the fixed code corresponds to a programmed remote, and the current rolling code is less than 3072 above the last rolling code. Receivers will also accept any two consecutive rolling codes (and adjust the stored rolling code accordingly) so long as the two codes are not within 1024 below the last rolling code.

Security+ 2.0

Security+ 2.0 is an updated (and incompatible) version released around 2011. Many of the details are described in US patent application US20110317835A1, and the remainder was determined by analyzing packets transmitted by Security+ 2.0 remotes and wireline devices.

The payload consists of 80 or 128 bits, which are split into two 40- or 64-bit halves transmitted in separate packets. Each packet consists of a 20-bit preamble, a two-bit frame ID (which is 00 for the first packet, and 01 for the second), and 40 or 64 payload bits. Each packet is Manchester encoded (with a falling edge representing 0, and a rising edge representing 1).

The fixed code is 40 bits long, and the rolling code is 28 bits. The longer 64-bit packets also carry 32 supplemental data bits; PIN pads use these bits to convey the PIN entered by the user. The rolling code is "encrypted" by reversing its binary bits, then converting the resulting number to base 3. Each base-3 digit is converted to 2 binary bits. The fixed code and encrypted rolling code are then interleaved. Finally, the bits are permuted and inverted, with the permutation and inversion pattern depending on the values of particular base-3 digits of the encrypted rolling code.

The rolling code increases by one with each button press, and is sometimes shared across all buttons on a given remote.

secplus's People

Contributors

argilo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

secplus's Issues

Error on opening secplus_rx.grc

Error: too many values to unpack

I'm new to GRC and no python wizard - could this simply be an issue with my environment?

Protocol Question: Rollover

Is the entirety of the rolling piece the count? Its not right? I am trying to get a better understanding of the components in the rolling part to prevent an overflow when incrementing the count.

For instance with Keeloq there are also two pieces; the fixed comprised of 8 hex digits, and the rolling part which is also 8 hex digits; however of the rolling part, only the last 4 hex digits are the count. So ignoring overflow bits, the keeloq count rolls over after FFFF.

Incompatilibity with gnuradio 3.8.2.0 (latest on Debian)

Hi,

I'm getting the following error on Debian:

$ python3  ./secplus_rx.py 
Warning: failed to XInitThreads()
Traceback (most recent call last):
  File "/mnt/a/projects/sdr/secplus/./secplus_rx.py", line 295, in <module>
    main()
  File "/mnt/a/projects/sdr/secplus/./secplus_rx.py", line 273, in main
    tb = top_block_cls()
  File "/mnt/a/projects/sdr/secplus/./secplus_rx.py", line 50, in __init__
    gr.top_block.__init__(self, "Secplus Rx", catch_exceptions=True)
TypeError: __init__() got an unexpected keyword argument 'catch_exceptions'

Is this an incompatibility with my GNURadio?

I'm testing this verion:

$ gnuradio-config-info --version
3.8.2.0```

Security+ 2.0?

I've got my LimeSDR Mini picking up a remote

image

However, no serial output from secplus_rx.py.

Opened is an 895MAX. Compatible with all LiftMaster, Chamberlain, Sears Craftsman garage door openers manufactured since January 1993. If your garage door opener has a Green, Orange Red, Purple or Yellow round learn button with a Yellow antenna wire, this remote will work

Some light googling brings me to https://www.stardoorparts.com/Liftmaster-895MAX-Elite-Remote-Control-p/895max.htm

With that compatibility chart, I fail to see how they could deviate from the standard and stay compatible going back to 1993 such that there is no output from your tool?

encode_ook datarate?

Cool project, I was hoping you might be able to tell me what the datarate is for both fast and slow encode_ook?

Weird "Security+ 2.0®" signal

I'm getting a signal from my gate opener remote that doesn't decode properly. I'm planning on trying to figure it out myself, but thought you might be interested.

I have an 811LM remote control, which claims to be Security+ 2.0®. The gate opener is an LA412, which also claims to be Security+ 2.0®.

I can't figure out how to run secplus properly on my Mac (brew install gnuradio worked, /usr/local/Cellar/gnuradio/3.9.2.0_2/libexec/venv/bin/activate gets me most of the way, but I still get Symbol not found: __ZN13QwtPlotPicker7setAxisEii), but I took some captures with rtl_sdr, and decoded them with inspectrum.

They're weird. First, they're far longer than the codes you describe. Second, secplus thinks the bursts are in opposite order (second burst first). Third, secplus doesn't like decoding them.

I added print debugging to secplus_v2_decode and tried calling it directly:

    def process_buffer(self):
        manchester = "".join(str(b) for b in self.buffer)
        start = manchester.find("1010101010101010101010101010101001010101")
        if start == -1:
            return
        manchester = manchester[start:start+124]
        baseband = []
        for i in range(0, len(manchester), 2):
            if manchester[i:i+2] == "01":
                baseband.append(1)
            elif manchester[i:i+2] == "10":
                baseband.append(0)
            else:
                return
    
        if baseband[21] == 0:
            print('first part')
            self.pair = baseband[22:]
        elif baseband[21] == 1 and len(self.pair) == 40:
            print('second part')
            self.pair += baseband[22:]
        else:
            print('weird')

        if len(self.pair) == 80 and self.pair != self.last_pair:
            try:
                rolling, fixed = secplus.decode_v2(self.pair)
                print(secplus.pretty_v2(rolling, fixed))
                self.last_pair = self.pair
            except ValueError as e:
                print(e)
                pass


if __name__ == '__main__':
    c1 = [
        '1010101010101010101010101010101001010101100110011010011010101001010110100110100110010110100101100110100101010110100110100101010110010110100101010110100110100110100110100101',
        '1010101010101010101010101010101001010101101010011010100110101010011001011001011010101001011001100110101001010101100110010101011010011010011010101010011010010110011001011001',
    ]
    c2 = [
        '1010101010101010101010101010101001010101100110011010101001100110101001011001011001100101010101011001011001100101011001011001101001101001011001101001010101011001010101011001',
        '1010101010101010101010101010101001010101101010010110100101100110010110100110011010100110010110101001010110010101011001100101101010011010011010101010101010011001100110010110',
    ]
    c3 = [
        '1010101010101010101010101010101001010101100110011010101010101010100110010110011010100110011010010110011010100110010110011010100110100110010110100110010110010110010110010110',
        '1010101010101010101010101010101001010101101010010110100101101001100101100101101001100101100101011010100101100110101010010110011001101001101001011001011001101010100101010101',
    ]

    b = blk()
    for capture in [c1, c2, c3]:
        for burst in capture:
            b.buffer = burst
            b.process_buffer()

Here's the output:

$ python secplus_v2_decode.py 
weird
first part
second part
First two bits of packet were not zero
first part
second part
First two bits of packet were not zero
first part

If it helps, I've attached three captures. I got all eight bursts from 1 and 3, but only 6 from 2. Even and odd bursts decode identically.

captures.zip

secplus Transmit with rpitx

Have you ever used secplus with a Raspberry Pi using rpitx for transmitting? I saw that there is a "encode_ook" method for Security+ and I figure that could somehow be written to a .iq file and transmitted with rpitx.

Also, I noticed this isn't an "encode_ook" method for Security+ 2.0. Could the "encode_ook" method be adapted for Security+ 2.0 or is it quite a bit different?

RX Codes

I may be missing the mark entirely here. When running ./secplus_rx.py I get the flow graph, but no other outputs. What is the method to retrieve the bits to decode from the flow graph as it seems the sample data is just the graph and nothing is output beyond that.

Small side note, could a C1101 be used to transmit or must an SDR be used?

I'm attempting to create a RPi touchscreen device to open my garage and gates.

How to use on a non GUI platform?

Reading your documentation, it shows to be all command line but the commands seems to have changed to be all GUI, as shown below:

image

How can I use this with a non GUI platform? If I run it with X11 forwarding disabled, I get a core dump:

image

status of garage door

I've been casually looking for a way to do local control of my liftmaster (security+ v2) for a while now. Today I use their wifi bridge and a myq account but I'd like to go local only. The one thing that's been holding me back is the state of the garage door. MyQ (and MyQ integration with Home Assistant) gives me open/opening, closed/closing states natively. Most if not all the alternatives use a switch or sensor to detect the angle, and while that would work, I am striving to do this first party from the opener since it already knows. I looked at their homekit option but but it seems that may require Internet as well, even if the communication is local, also those may be discontinued or on their way out.

I started researching again and came across this project as well as @PaulWieland 's ratgdo project and it looks like what I'm looking for maybe achievable. His project is compelling but it dawned on me, this info should be wirelessly transmitted as well, my wifi bridge somehow knows the state and is able to transmit it to the MyQ cloud offering. I'm not sure if there is a difference in how the bridge is paired and what info it receives wirelessly or if the current decodes in this project and rtl_433 just don't handle those bits yet. Does anyone have any thoughts on the state info being transmitted wirelessly?

I think my ideal situation would be to use my sdr to transmit to the garage to open/close and also know status to reporting back to Home Assistant. That may need some type of wrapper to present an api for tx/rx. In the long run ratgdo may make more sense/be more reliable, but in the meantime this is something I'd like to see if it is possible.

TX gets a "no supported device" where RX does not

when I run the RX command, it finds the RTL2838 device

when I run the TX command, I get a 'No supported devices found' error.

ksaye@up1:~$ cd /opt/gdoor/secplus/
ksaye@up1:/opt/gdoor/secplus$ ./secplus_rx.py
Warning: failed to XInitThreads()
gr-osmosdr 0.2.0.0 (0.2.0) gnuradio 3.10.5.0
built-in source types: file rtl rtl_tcp rfspace redpitaya
Using device #0 Realtek RTL2838UHIDIR SN: 00000001
Found Rafael Micro R820T tuner
[R82XX] PLL not locked!
Exact sample rate is: 2000000.052982 Hz
[R82XX] PLL not locked!
ksaye@up1:/opt/gdoor/secplus$ ./secplus_tx.py --freq 315150000 --rolling 2731817118 --fixed 876029924
gr-osmosdr 0.2.0.0 (0.2.0) gnuradio 3.10.5.0
built-in sink types: redpitaya file
Traceback (most recent call last):
File "./secplus_tx.py", line 152, in
main()
File "./secplus_tx.py", line 135, in main
tb = top_block_cls(fixed=options.fixed, freq=options.freq, rolling=options.rolling)
File "./secplus_tx.py", line 51, in init
self.osmosdr_sink_0 = osmosdr.sink(
RuntimeError: No supported devices found (check the connection and/or udev rules).

Device selection

Would it be possible to provide a command line switch for device selection between osmo/rtlsdr and LimeSDR?

I was previously doing this manually in GRC, but now I'm in a situation where I'd like to have my RTLSDR receiving to verify codes being sent by LimeSDR. (This is for investigation into HomeLink, which will learn the codes of a remote)

Can't import secplus module from within GNU Radio Companion

After opening secplus_rx.grc in GNU Radio Companion, the following error sometimes appears:

Can't interpret source code: No module named 'secplus'

And for secplus_tx.grc and secplus_v2_tx.grc, the following error message sometimes appears:

Import "import secplus" failed.

This happens because the current directory may not be part Python's module search path. (PyBOMBS adds the empty string to PYTHONPATH, but native installations do not have this.)

For the time being, a workaround is to run sudo cp secplus.py /usr/local/lib/python3.*/dist-packages/.

Secplus for 433Mhz?

hi!
I would like to use 433Mhz in Europe.
Would that be possible?
thanks!

Security+ 2.0 wireline usage?

I'm interested in implementing a device that can interact with the Liftmaster systems that use Security+ 2.0, but from a wired interface. Looking at the patent application you linked, it reads:

[0097] So configured, a given movable barrier operator, using a single protocol, can Successfully communicate with
both wireless and wireline-based user interfaces.

So, seemingly the encoding would be the same, but how would you interact with the two-wire interfaces? Namely, I'm interested in receiving state information that is presumably transmitted by the wall-mounted opener. My garage door opener has a wireless light, a wall mounted operating panel, a deadbolt, and a battery backup. Presumably all the state information is transmitted using the wireline protocol.

Any ideas how one might transmit and recieve those wireline signals?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.