argilo / secplus

A software implementation of the Security+ system used by garage door openers
GNU General Public License v3.0
235 stars 31 forks source link

Security+ 2.0 wireline usage? #5

Open dcode opened 3 years ago

dcode commented 3 years ago

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?

argilo commented 3 years ago

Unfortunately I don't know anything about the wireline protocol, and I don't have any equipment that uses it. If you can probe the data lines using a logic analyzer, that would be a good way to start reverse engineering the system.

PaulWieland commented 2 years ago

I am investigating this very same thing. Just found this repo and am hoping to find answers.

Here is the original post I started on stack exchange. https://electronics.stackexchange.com/questions/598717/reverse-engineering-garage-door-opener-signal

I now have a bunch of recorded signals that I have decoded, but I do not know how to interpret them. I am hoping that someone here might recognize whether the wired signal is the same as the wireless one and that this library might give some clues as to how to interpret the data.

PaulWieland commented 2 years ago

Here's my gist with some of the recorded signals and my attempt at decoding them (can be executed in your web browser's console).

I've made a lot of assumptions so far. One of them is that there are three messages with each event and that the first and third messages are sent by the button, and the second message is some sort of response from the opener. This assumption may be totally wrong.

You can see the middle message is pulled closer to 0v than the first and third - which is where i came up with the theory about it being two different devices sending the signals. Anyway, the decoding effort in the gist focuses on that first message of the three.

And here's the result of the decoding one of the "handshake" signals (just the first of three). This handshake happens whenever the wired button is powered on. A different message is sent every time the button is powered on. 01010101011 01000000011 00000000011 00101000011 00011110011 00110101011 01101010011 01011010011 00110110111 01111101111 01011111011 00010010111 01110100011 00101110011 00111100111 00111101111 01011000111 01101111011 01001010111

A few ms later, another message comes through, then a short pause of a few ms then a final message.

I'm assuming the first bit is a start bit (it's always LOW) and the last two bits are stop (they're always HIGH). The 8 in the middle become: 10101010 10000000 00000000 01010000 00111100 01101010 11010100 10110100 01101101 11111011 10111110 00100101 11101000 01011100 01111001 01111011 10110001 11011110 10010101

Converted to HEX: AA 80 00 50 3C 6A D4 B4 6D FB BE 25 E8 5C 79 7B B1 DE 95

@argilo - if you have any insight into this, it would be really appreciated!

PaulWieland commented 2 years ago

Here is a capture straight from my scope of the first message: https://pastebin.com/raw/hibfC5L5

And here is a zoomed out capture which contains all three messages (at lower resolution though) https://pastebin.com/raw/aP1BwsV9

Right now I am trying to load these into PulseView to see if it can decode them, but so far I haven't had any lucky importing the CSV.

@argilo Is there any better approach to this?

PaulWieland commented 2 years ago

I solved this. Here is my project which gives wireline control over the door.

argilo commented 1 year ago

I now have some wireline equipment to experiment with, and I've added support to secplus.

The devices use 9600 baud serial (8 data bits, no parity, 1 stop bit). I used a voltage divider to drop the 12V signal down to 3.3V, which I could easily decode and log on a Raspberry Pi Pico. (I expect it will be possible to transmit with a Pico as well, by running the UART output pin to a transistor which would short the data wires.)

The packets are 19 bytes long. The first byte (0x55) probably signals the start of a packet, the second byte (0x01) may indicate the payload type (1 = "supplemental data payload"), and I'm not sure what the third byte (\x00) means. The remaining 16 bytes are the two halves of a Security+ 2.0 packet. As noted in #6, secplus can now handle the supplemental data payload. I also added encode_wireline and decode_wireline functions to encode and decode 19-byte serial packets.

The next task is to determine what the 32-bit "data" payloads (and 8 upper bits of the "fixed" data) mean.

PaulWieland commented 1 year ago

I ported the code generator over from stm8 assembler. The problem is that it’s copyrighted so I cannot publish the source code. That’s why ratgdo uses a database of pre-generated codes.

But if you have any questions I’m sure I can help.

EDIT: every wireline message starts with 0x55, 0x01, 0x00. This is just a header of some kind.

argilo commented 1 year ago

@PaulWieland I decoded the hard-coded packets from ratgdo, and noticed a couple unusual things:

  1. The remote_id value is zero.
  2. The rolling code for DOOR2 is out of sequence. The rolling codes for DOOR1 - DOOR7 are: 41045, 75440214, 41047, 41048, 41049, 41050, 41051.
argilo commented 1 year ago

Do you have any useful insights into the meanings of the data bits? At the moment I'm just pushing buttons and writing down which bits come out.

Interestingly, it seems like the opener is also a transmitter, and it sends out status messages.

PaulWieland commented 1 year ago

I should mention that the rolling code version is on a different branch at the moment. There you will find the database with 64,000 pre-generated codes.

You are correct that the opener transmits data, but these messages do not seem to be needed by the wired button. As long as you transmit the right messages, the opener will respond.

When the button is rebooted, it will send a sequence of messages to the opener. I am calling these "reboot" or "sync" messages as they seem to be used to tell the opener what counter value the button is on and they are sent when the button is rebooted. After the reboot/sync happens, the light on the button will stop flashing and the door opener will begin responding to light or door open commands.

On 50 series logic boards, you can send the sync message and the door opener will then accept an open or light command. In effect, its a simple replay attack (this is how ratgdo 1.0 works). What I found out though is that older door openers with 45 series logic boards do not accept sync messages if the counter value is re-used.

Each 16 byte code is generated from a 32 bit counter combined with a message type. The message types are as follows:

reboot1 = 0x0100908000;
reboot2 = 0x0000618b04;
reboot3 = 0x0000b18000;
reboot4 = 0x0000809203;
reboot5 = 0x0000809203; // repeat of reboot4, but with next counter sequence
light = 0x0000928102;
door1 = 0x0101828002;
door2 = 0x0100928002; // not needed

Four 32 bit numbers are then generated and then assembled in an out of order sequence. The numbers are stored at memory addresses:

0x67
0x6b
0x73
0x77

Those four 32 bit numbers + the 3 fixed header values are then assembled into a 19 byte code as follows:

0x55 // 0
0x01 // 1
0x00 // 2

mem[0x6f] // 3

mem[0x6b] // 4
mem[0x6c] // 5
mem[0x6d] // 6
mem[0x6e] // 7

mem[0x68] // 8
mem[0x69] // 9
mem[0x6a] // 10

mem[0x7b] // 11

mem[0x77] // 12
mem[0x78] // 13
mem[0x79] // 14
mem[0x7a] // 15

mem[0x74] // 16
mem[0x75] // 17
mem[0x76] // 18
PaulWieland commented 1 year ago

I just remembered two of the bytes (position 3 & 11) are not from the 4 32 bit numbers.

I'll have to dig through the code again to refresh my memory on what 0x6f and 0x7b are based on.

PaulWieland commented 1 year ago

@argilo can you post an example of how to use your library to generate or decode wireline messages?

argilo commented 1 year ago
$ python3
>>> import secplus
>>> packet = bytes.fromhex("550100453df7db6dbedbee943ffffeff1faeff")
>>> rolling, fixed, data = secplus.decode_wireline(packet)
>>> print(rolling, fixed, data)
128 0 16814208

>>> new_packet = secplus.encode_wireline(rolling + 1, fixed, data)
>>> print(new_packet)
b'U\x01\x00D=\xf6\xff\xff\xf7\xff~\x85-\xbe\xdfoV\xcb\xef'
>>> print(new_packet.hex())
550100443df6fffff7ff7e852dbedf6f56cbef
argilo commented 1 year ago

Here's an example that can reproduce ratgdo_codes.hex:

import secplus

fixed = [0x0000000000, 0x0400000000, 0x0000000000, 0x0300000000, 0x0200000000, 0x0200000000]
data = [0x01009080, 0x0000618b, 0x0000b180, 0x00008092, 0x01018280, 0x00009281]

with open("ratgdo_codes.hex", "wb") as f:
    for rolling in range(128, 128+64000):
        packet = secplus.encode_wireline(rolling, fixed[0], data[0])
        f.write(packet[3:])

        for i in range(1, 6):
            packet = secplus.encode_wireline(rolling, fixed[i], data[i])
            f.write(packet[6:8] + packet[10:11] + packet[16:])
argilo commented 1 year ago

I've added a wireline packet decoder in a700dbd87861f2338075475cd5720146f031107e. It can only decode packet types that I've observed so far, and the fields represent my best guesses so far of what the various bits mean. My assumptions may well be incorrect.

A packet can be decoded like so:

rolling, fixed, data = secplus.decode_wireline(packet)
pretty = secplus.pretty_wireline(rolling, fixed, data)
print(pretty)

Decoded packets look like this:

rolling=0x000079a fixed=0xc21895590c data=0x01018280 cmd=0x280 open pressed
rolling=0x000079a fixed=0xc21895590c data=0x01009280 cmd=0x280 open released
rolling=0x00004b4 fixed=0x10aad8002e data=0x02609481 cmd=0x081 status door=opening learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x00004b4 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x00004b4 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x00004b4 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x00004b5 fixed=0x10aad8002e data=0x0260c181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x000079b fixed=0xc21895590c data=0x01018280 cmd=0x280 open pressed
rolling=0x000079b fixed=0xc21895590c data=0x01009280 cmd=0x280 open released
rolling=0x00004b5 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x00004b6 fixed=0x10aad8002e data=0x02608581 cmd=0x081 status door=closing learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x00004b6 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x000079c fixed=0xc21895590c data=0x01018280 cmd=0x280 open pressed
rolling=0x000079c fixed=0xc21895590c data=0x01009280 cmd=0x280 open released
rolling=0x00004b7 fixed=0x10aad8002e data=0x02609481 cmd=0x081 status door=opening learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x000079d fixed=0xc21895590c data=0x01018280 cmd=0x280 open pressed
rolling=0x000079d fixed=0xc21895590c data=0x01009280 cmd=0x280 open released
rolling=0x00004b8 fixed=0x10aad8002e data=0x0260e381 cmd=0x081 status door=stopped learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x000079e fixed=0xc21895590c data=0x01018280 cmd=0x280 open pressed
rolling=0x000079e fixed=0xc21895590c data=0x01009280 cmd=0x280 open released
rolling=0x00004b9 fixed=0x10aad8002e data=0x02608581 cmd=0x081 status door=closing learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x00004b9 fixed=0x12aad8002e data=0x0000e084 cmd=0x284 motor_on
rolling=0x00004ba fixed=0x10aad8002e data=0x0260f281 cmd=0x081 status door=closed learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=0 unk3=1
rolling=0x00004bb fixed=0x10aad8002e data=0x0060d281 cmd=0x081 status door=closed learn=0 light=0 lock=0 blocked=0 unk1=0 unk2=0 unk3=1

I'd appreciate packet dumps, as well as help deciphering the meanings of the various packet types.

argilo commented 1 year ago

I'm using the following script to receive and transmit packets using the UART pins on a Raspberry Pi:

#!/usr/bin/env python3

import csv
import secplus
import serial
import sys
import threading
import time

def receive(ser):
    global finished

    PREAMBLE = bytes([0x55, 0x01, 0x00])

    with open("packets.csv", "a") as f:
        writer = csv.writer(f)

        while not finished:
            data = ser.read()
            if data != PREAMBLE[0:1]:
                continue

            data = ser.read()
            if data != PREAMBLE[1:2]:
                continue

            data = ser.read()
            if data != PREAMBLE[2:3]:
                continue

            data = ser.read(16)
            if len(data) != 16:
                continue

            end_time = time.time()
            packet = PREAMBLE + data

            try:
                rolling, fixed, data = secplus.decode_wireline(packet)
                pretty = secplus.pretty_wireline(rolling, fixed, data)

                time_str = f"{end_time:.3f}"
                writer.writerow([time_str, packet.hex(), pretty])
                f.flush()
                print(f"{time_str} {pretty}")
            except ValueError as e:
                print(e)

finished = False
ser = serial.Serial("/dev/serial0", timeout=0.1)

receive_thread = threading.Thread(target=receive, args=(ser,))
receive_thread.start()

if sys.stdin.isatty():
    while True:
        try:
            message = input()
        except KeyboardInterrupt:
            break

        parts = message.split()
        if len(parts) != 3:
            print("Invalid input")
            continue

        try:
            rolling = int(parts[0], 16)
            fixed = int(parts[1], 16)
            data = int(parts[2], 16)
            packet = secplus.encode_wireline(rolling, fixed, data)
        except ValueError:
            print("Invalid input")
            continue

        ser.baudrate = 4800
        ser.write(bytes([0x00]))
        time.sleep(0.001)
        ser.baudrate = 9600
        ser.write(packet)

    finished = True

receive_thread.join()
ser.close()
PaulWieland commented 1 year ago

Here are some message logs:

powering on opener with no controller, obstruction sensors plugged in and not blocked:

5501008839904923D04D24891060FD22E48502 :  rolling=0x00029d3 fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
5501008839904923D24D24891060FD22E41506 :  rolling=0x00029d3 fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
55010056054F369C63A6836824B2BCB4E44127 :  rolling=0x00029d4 fixed=0xc05212c01e data=0x4220c181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=0 unk3=1

obstruction:

550100990B810123814804990420B594E4C884 :  rolling=0x00029db fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
550100990B810123804804990420B594E45886 :  rolling=0x00029db fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
550100990B81012385484C990420B594E04807 :  rolling=0x00029db fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
550100682B8141238045B48826BA9004544D21 :  rolling=0x00029dc fixed=0xc05212c01e data=0x000e41a1 cmd=0x0a1 pair_3_resp byte1=14
550100682B8141238141248826BA900476CC24 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
550100682B8141238041248826BA9004765C20 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
550100682B81412385416C8826BA9004724D21 :  rolling=0x00029dc fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1

message timing:

image

clearing obstruction:

550100682B8141238141248826BA900476CC24 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
550100682B8141238041248826BA9004765C20 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
550100682B81412385416C8826BA9004724D21 :  rolling=0x00029dc fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
550100682B8141238141248826BA900476CC24 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
550100682B8141238041248826BA9004765C20 :  rolling=0x00029dc fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
550100682B81412385416C8826BA9004724D21 :  rolling=0x00029dc fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1

message timing:

image

Plugging in control button:

550100152DA4DB69B69A6B0110490410E96490 :  rolling=0x000202d fixed=0x0000000000 data=0x01009080 cmd=0x080 get_status byte2=1
55010080269B7D269B6DB66016CB2DB68DE9A5 :  rolling=0x000202e fixed=0x0400000000 data=0x0000618b cmd=0x48b get_openings
55010066106EAEDC7B37F26904A0B594560C85 :  rolling=0x00029dd fixed=0xc45212c01e data=0x6300418c cmd=0x48c openings number=99
55010080269B6D269B6DB76016CB2DB6A97DB6 :  rolling=0x000202e fixed=0x0000000000 data=0x01009080 cmd=0x080 get_status byte2=1
55010080269B6D269B6DB76016CB2DB6A97DB6 :  rolling=0x000202e fixed=0x0000000000 data=0x01009080 cmd=0x080 get_status byte2=1
5501006A29A6CA4DA4D34D511A6934D3C43CB5 :  rolling=0x000202f fixed=0x0400000000 data=0x0000618b cmd=0x48b get_openings
550100112159C591406484190041324C284A46 :  rolling=0x00029de fixed=0xc45212c01e data=0x6300418c cmd=0x48c openings number=99

timing:

image

At this point the control button is flashing. Clicking door open to "sync":

55010099200040008048052A2D96C96D761965 :  rolling=0x0002030 fixed=0x0000000000 data=0x01009080 cmd=0x080 get_status byte2=1
550100112159E59141E406190041324C604807 :  rolling=0x00029de fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
55010098241209241201242037DBEDB718ADB2 :  rolling=0x0002031 fixed=0x0000000000 data=0x0000b1a0 cmd=0x0a0 pair_3
5501001021DBACB5DB2FFE0A2D3C89B5865F78 :  rolling=0x00029df fixed=0xc05212c01e data=0x000e41a1 cmd=0x0a1 pair_3_resp byte1=14
55010042196592CB2C92589016CB25B63B3DB6 :  rolling=0x0002032 fixed=0x0000000000 data=0x01009080 cmd=0x080 get_status byte2=1
5501001021DBACB5D3AD260A2D3C89B516DF78 :  rolling=0x00029df fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
5501001021DBACB5D3AD260A2D3C89B516DF78 :  rolling=0x00029df fixed=0xc05212c01e data=0x46208181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
55010041104026504124908102082490A964B0 :  rolling=0x0002033 fixed=0x0300000000 data=0x00008092 cmd=0x392 learn_3
5501001016CB2132DB2DB66036DB25B6A94DA6 :  rolling=0x0002034 fixed=0x0300000000 data=0x00008092 cmd=0x392 learn_3
55010086062F909E2DB64B1112185EDA29549F :  rolling=0x00029e0 fixed=0xc35212c01e data=0x00009093 cmd=0x393 learn_3_resp nibble=0
5501008522BCFD28F6DBEF0209E7C00384C250 :  rolling=0x00029e1 fixed=0xc35212c01e data=0x00009093 cmd=0x393 learn_3_resp nibble=0

timing:

image

Clicking door button. The opener started, then stopped, then reversed direction.

5501000A2FB6F76FB6DF7851124DA4938D3483 :  rolling=0x0002035 fixed=0x0200000000 data=0x01018280 cmd=0x280 open pressed
5501000A2FB6F76FB6DF7951124DA4938D1483 :  rolling=0x0002035 fixed=0x0200000000 data=0x01009280 cmd=0x280 open released
5501001A1EA65F6AB6934D5437BA16DE32EEBF :  rolling=0x00029e3 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
550100A926018046318321410228FDB2E524D5 :  rolling=0x00029e4 fixed=0xc05212c01e data=0x4620c581 cmd=0x081 status door=closing learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
550100A926018846208201410228FDB2E5A590 :  rolling=0x00029e4 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
550100A926018046218201410228FDB2E5A590 :  rolling=0x00029e4 fixed=0xc05212c01e data=0x0020e084 cmd=0x084 unknown_1
550100A926018046208205410228FDB2E52594 :  rolling=0x00029e4 fixed=0xc05212c01e data=0x0100c085 cmd=0x085 unknown_2
550100A803B3C963A3CA042209A676D8F45343 :  rolling=0x00029e5 fixed=0xc05212c01e data=0x4620d481 cmd=0x081 status door=opening learn=0 light=1 lock=0 blocked=1 unk1=0 unk2=1 unk3=1
550100A803B3C163B2CB242209A676D8F612C1 :  rolling=0x00029e5 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
550100A803B3C163B2CB242209A676D8F612C1 :  rolling=0x00029e5 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
550100521E269047208241920D1626D9C0D2E9 :  rolling=0x00029e6 fixed=0xc05212c01e data=0x0000c084 cmd=0x084 unknown_1
550100521E269047208243920D1626D9C0D2EB :  rolling=0x00029e6 fixed=0xc05212c01e data=0x0100c085 cmd=0x085 unknown_2
550100510C6B269C573403843D9E26DD1FEF3B :  rolling=0x00029e7 fixed=0xc05212c01e data=0x46609481 cmd=0x081 status door=opening learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=1 unk3=1
550100510C6B229C4D3493843D9E26DD1B7E7F :  rolling=0x00029e7 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
550100982B8149271F016C2113EB404299A495 :  rolling=0x00029e8 fixed=0xc05212c01e data=0x4660c181 cmd=0x081 status door=open learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=1 unk3=1

timing:

image

Clicking door button again (opener ran in one direction until limit and stopped)

550100652DA6D84DA4DA6A00349A6DB67B6D96 :  rolling=0x0002036 fixed=0x0200000000 data=0x01018280 cmd=0x280 open pressed
550100652DA6D84DA4DA6800349A6DB67B2D96 :  rolling=0x0002036 fixed=0x0200000000 data=0x01009280 cmd=0x280 open released
55010096106EB6D8E0F7B3122965A80544D2EA :  rolling=0x00029e9 fixed=0xc05212c01e data=0x46608581 cmd=0x081 status door=closing learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=1 unk3=1
55010096106EB4D8EDF7FB122965A8054DD229 :  rolling=0x00029e9 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
55010096106EB4D8EDF7FB122965A8054DD229 :  rolling=0x00029e9 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
55010096106EB4D8EDF7FB122965A8054DD229 :  rolling=0x00029e9 fixed=0xc25212c01e data=0x0000e084 cmd=0x284 motor_on
55010096106EB6D8EDF7FB122965A8054CD229 :  rolling=0x00029e9 fixed=0xc05212c01e data=0x0000c084 cmd=0x084 unknown_1
55010096106EB6D8EDF7FB122965A8054CF228 :  rolling=0x00029e9 fixed=0xc05212c01e data=0x0000d085 cmd=0x085 unknown_2
550100410F4324075724D882090C4BE9C00255 :  rolling=0x00029ea fixed=0xc05212c01e data=0x4660f281 cmd=0x081 status door=closed learn=0 light=1 lock=0 blocked=0 unk1=0 unk2=1 unk3=1

timing:

image
mumixam commented 1 year ago

I'm using the following script to receive and transmit packets using the UART pins on a Raspberry Pi:

@argilo just wanted to confirm. Is all that is needed to read wireline packets from a Pi a voltage divided to go from 12v to 3.3v?

Thanks

argilo commented 1 year ago

That's correct. I'm using a voltage divider of 2000 & 5700 ohms.

mumixam commented 2 months ago

@argilo i see you have been pushing some commits for wireline and mqtt. any chance you give me a wiring guide and a parts list for TX on a raspberry pi? are you using a 2n7000?

argilo commented 2 months ago

Here's the circuit I'm using:

secplus_mqtt

I'm not much of a hardware person, so any suggestions for improvement are welcome.

argilo commented 2 months ago

I made a small mistake in the schematic. It's now updated to what I hope is correct.

mumixam commented 2 months ago

@argilo ok i got around to trying to make this circuit work but i'm running into a issue where Q1 is pulling down the 12volt source constantly. I'm less of a hareware person than you and I'm having trouble understanding the purpose of Q1. It seems like the idle high 12volt signal is triggering my 2n2222 constantly causing it to pull down to ground which causes the wall button to no longer illuminate the led. Also i realize these comments are a little bit off topic of the issue. Would it be ok to email you (using the email that shows up in the commits) or librechat (irc) or something?

argilo commented 2 months ago

It's fine to continue the discussion here, since others may be interested.

Do you have the Raspberry Pi's TXD pin connected to the base of Q2? That pin is normally high, which keeps Q2 on, grounding the collector. That in turn keeps Q1 off.

When TXD goes low (during transmit) Q2 switches off, which turns on Q1 and shorts the 12V line.

mumixam commented 2 months ago

when i did my initial testing the tx pin was not connected to anything. i was just probing around with a multimeter making sure im not going to overvolt the pi. i will make sure i have tx connected at all times before connecting 12volt source. one thing i did notice was without tx connected i fired a 2n2222 @ Q1. would it make sense to add a resistor to limit current in the event of loss of power to the pi but GDO still has power to protect the 2n2222? Thank you for your time and help

argilo commented 2 months ago

My garage door opener limits current to about 150 mA, so I didn't bother adding a current-limiting resistor on the 12V line.

Perhaps a pull-up resistor on the base of Q2 could prevent Q1 from shorting the 12V line when the Raspberry Pi is disconnected.