Close
0%
0%

Opensource HomeLink ecu for VAG

Open-source HomeLink module for VAG cars. Replaces the stock unit, working with standard LIN Bus and supporting various garage doors.

Similar projects worth following
I am developing an open-source HomeLink module for VAG cars. It will replace the stock unit and use the same LIN Bus communication. The module will work with various garage doors and gates. A separate LIN transceiver will ensure reliable operation. The goal is a plug-and-play solution without modifying the car’s system.

I have no experience writing interesting articles or stories, but the long story short is. I`m a Ukrainian who owns a US car after the incidents. I like Audi. My first car was a Q5 2015 MY. Logically (almost), the next choice happened to be an SQ5, preferably 20+ MY. After a few test drives, researching, and time, I was waiting for the new (used) car - Audi SQ5 Prestige 22MY.

I live in a flat room without parking, but I own an underground one in the neighbourhood building. It has 2 levels of security access: barrier and garage door with one remote. Also, my new car had a Homelink option, the purpose of which was to simplify life. Unfortunately, the remote system of my parking was not compatible with HomeLink. The project starts here.

BAP reverse engineering (volkswagen PQ) – Electronics Notes.pdf

Adobe Portable Document Format - 1.82 MB - 03/12/2025 at 10:24

Preview

476121999-BAP-FC-NAV-SD-P30DF48-v2-80-F-pdf.pdf

Adobe Portable Document Format - 3.57 MB - 03/12/2025 at 10:24

Preview

UGDO_UDS_Frames.xlsx

sheet - 340.86 kB - 03/11/2025 at 19:47

Download

MLBevo_Gen2_MLBevo_ICAN_KMatrix_V8.21.01F_20210129_EICR.dbc

CAN bus messages description file

dbc - 3.90 MB - 03/10/2025 at 13:30

Download

MLBevo_Konzern_MLBevo_BCM1_LIN2_KMatri_V8.11.00E_20160323.ldf.txt

LIN2 bus frames description file

plain - 63.54 kB - 03/10/2025 at 13:30

Download

View all 10 files

  • 1 × 8W0907063CB BCM1
  • 1 × 4M0907410A HomeLink module
  • 1 × 4M0959719A HomeLink buttons

  • UGDO BAP part.2

    Stepan Skopivskiy03/23/2025 at 19:32 0 comments

    After getting the list of elements (BAP Array) the structure of the item data is still unknown. During the testing of the actions and messages, a few actions were recorded. The next data is the pairs of ASG and FSG (request and response).

    • Create a new button on position 2:
      0x15020201
      0x15080202110201
    •  Create a new button on position 7:
      0x17020701
      0x17080207012000
    • Create a new button in D-mode:

      0x184505010560
      0x98084505010560 
    • Create a new button in UR-mode:

      0x1A4506010650
      0x9A084506010650
    • Rename the 2nd button to "Гар. 22222":

      0x1C440201020DD093D0B0D1802E203232323232
      0x9C08440201020DD093D0B0D1802E203232323232
    • Rename the 7th button to "7777777777":

      0x1D440701070A37373737373737373737
      0x9D08440701070A37373737373737373737
    • Save position:

      0x1C4102010228DEF80256A76E011001
      0x9C084102010228DEF80256A76E011001

    All this req/res comes to and from function id - 0x10. So, looks like all "CRUD" operations are done through that function. Also, if to do the HEX to Text conversion some RAW data can be extracted.

    After hours of "reading" the code, some details were discovered. For example, the classes from the found repository have a pretty same structure like the data in the CAN messages. Here the classes with their property members.

    public class UGDOButtonListRA0 {
        public int pos;
        public String name;
        public float positionLatitude;
        public float positionLongitude;
        public int learnedState;
        public int hardkey;
        public int softkey;
        public UGDOSpecialFeatures specialFeatures;
    }
    
    public class UGDOButtonListRA1 {
        public int pos;
        public float positionLatitude;
        public float positionLongitude;
        public int learnedState;
        public UGDOSpecialFeatures specialFeatures;
    }
    
    public class UGDOButtonListRA2 {
        public int pos;
        public int learnedState;
        public UGDOSpecialFeatures specialFeatures;
    }
    
    public class UGDOButtonListRA3 {
        public int pos;
        public UGDOSpecialFeatures specialFeatures;
    }
    
    public class UGDOButtonListRA4 {
        public int pos;
        public String name;
    }
    
    public class UGDOButtonListRA5 {
        public int pos;
        public int learnedState;
    }
    

    And here, let's remember the array header structure: Mode (4bit), RecordAddress (4bit), Start Number (1 byte), and Elements (1 byte). Do You see some relations? What if convert RecordAddress to RA?

    So, now, let's check rename and save position (both are requests from ASG):

    0x1D440701070A37373737373737373737
    0x1C4102010228DEF80256A76E011001

    Based on the structure, the ASG_IDTAIDArrayHeader: Mode (4bit), RecordAddress (4bit), Start Number (1 byte), and Elements (1 byte). And now, the record address for rename is 4, and for set position 1. And now, let's check the Java class once again:

    public class UGDOButtonListRA1 {
        public int pos;
        public float positionLatitude;
        public float positionLongitude;
        public int learnedState;
        public UGDOSpecialFeatures specialFeatures;
    }
    
    public class UGDOButtonListRA4 {
        public int pos;
        public String name;
    }

    And it is a win! It has a logic now. MMI input has a limit for names - 10 chars max. Also, the known information is that the rename was to "7777777777" for the 7th button, and based on class, it is the only information in the data "package". Using this knowledge let's parse the whole message:

    0x1D440701070A37373737373737373737
    • 0x1 - ASG_ID
    • 0xD - TAID
    • 0x4 - Mode
    • 0x4 - RecordAddress
    • 0x07 Start Number
    • 0x01 Elements
    • And data
      0x070A37373737373737373737
      
    • This is also pretty logical: char "7" in hex format is 0x37. So, the last 10 bytes is the "7". The first byte is the position, based on RA4 class. And, the last unrecognized byte is 0x0A. But what if you convert it to decimal? 0x0A = 10 (dec) Could it be the length of the string? It is! Because the parser should know how long the string is to know where the next data is starting (or ends current).

    And what about the save position action class? Which is RA1. Doing the same will add some details here:

    0x1C4102010228DEF80256A76E011001...
    Read more »

  • UGDO BAP

    Stepan Skopivskiy03/23/2025 at 10:55 0 comments

    Besides successfully discovering the communication between the hardware buttons, another problem remained — there was absolutely nothing about the UGDO (universal garage door opener) BAP (German: “Bedien- und Anzeigeprotokoll” ~ control- and display protocol).

    The only valuable paper I found was this one (from a web archive): https://web.archive.org/web/20241005094756/https://blog.dietmann.org/?p=324. I saved a copy in PDF format just in case. But even it did not have any mentions about the UGDO. Another interesting document I found was https://www.scribd.com/document/476121999/BAP-FC-NAV-SD-P30DF48-v2-80-F-pdf. It has also been saved as a pdf just for easy access. It describes how the other component (Navigation) communicates using BAP. Unfortunately, also it has a lot of references to other internal documents.

    Another way was to start from the MMI. But here is just a bit of information too. The only mention of software of the MMI I found was this repository - https://github.com/grajen3/mib2-lsd-patching. It has a lot of mentions about the UGDO but as the code is just a decompiled Java classes there are a lot of missed constants too. The one of files is - https://github.com/grajen3/mib2-lsd-patching/blob/aa-in-vc/lsd_java/org/dsi/ifc/carcomfort/UGDOButtonListRA0.java. And the other files are on the screenshot.

    But as there are no constant values it was not so valuable, at least for now. The last way left was sniffing. The MMI uses the CAN to communicate with the BCM (through the gateway), and then the BCM communicates to UGDO by LIN. So, instead of sniffing the LIN the CAN was chosen. Also, the DBC (CAN messages matrix) file helps to filter the necessary messages. Sniffing can be done with the cheap module - https://canable.io/.

    The first session was pretty useless. I start recording the CAN messages and start doing some actions like program, rename, delete buttons, etc. The result - just a mess of data and actions. Before the second session, an "action" plan was prepared.

    And now it is a valuable dataset. Using the BAP CAN message description mentioned at the log start, some data preparation was done. The screenshot shows the part of messages after the ignition turns on.

    It shows the initialization of the BAP, FCT_ID: 0x02 and 0x01. The information about those function IDs was found in both sources: the BAP description blog and the NAV_SD_Bap document. And it looks like the common structure for any BAP member. Then, the specific function id goes - 0x10, with a long amount of data and some interesting repeating in it. Using the same doc, the collapsed data is the next:

    0x1B084000030112D093D0B0D1803120D09AD0BED180D0B5D18948DDF80240A96E011001010200F0000000F00000000002000300F0000000F0000000000300

    So long data can be only in an array. Thankfully in the NAV_SD doc file, there is general information about the array formats, they are the same between the different functions.

    Based on found in Google information, BAP has four kinds of functions: property, method, array, and cache. Each of them has its own sets of op_codes.

    Opcode

    value

    Function class

    Property

    Function class

    Array

    Function class

    Method

    Function class

    Cache

    Direction

    0x0

    Set

    SetArray

    Start

    ASG -> FSG

    Reset

    FSG -> ASG

    0x1

    Get

    GetArray

    Abort

    GetAll

    ASG -> FSG

    0x2

    SetGet

    SetGetArray

    StartResult

    ASG -> FSG

    0x3

    HeartbeatStatus

    ChangeArray

    Processing

    FSG -> ASG

    0x4

    Status

    StatusArray

    Result

    StatusAll

    FSG -> ASG

    0x5

    StatusAck

    FSG -> ASG

    0x6

    Ack

    ASG -> FSG

    0x7

    Error

    Error

    Error

    Error

    FSG -> ASG

    Based on the information, the sequence is the next: after turning on the ignition, the MMI requests the information and waits for the array from the module. Skipping the BAP message header etc, the clear request-response data is the next:

    0x1B000003
    0x1B084000030112D093D0B0D1803120D09AD0BED180D0B5D18948DDF80240A96E011001010200F0000000F00000000002000300F0000000F0000000000300

    The get array op_code has the next format: ASG_IDTAIDArrayHeader. The ASG_ID (Identifies...

    Read more »

  • Rescuering the buttons

    Stepan Skopivskiy03/14/2025 at 15:36 0 comments

    After solving the ignition problem, the hardware buttons did not start to work. However, the bit responsible for the KL15 changed its value from 0 to 1. According to the LDF, in addition to the KL15 and Buttons, the frame also contains the ZV_auf_Funk, ESP_v_Signal_8Bit, and UGDO_Switchboard.

    UGDOe_02: 46, BCM1, 6 {
        UGDO_Buttons, 0 ;
        Klemme_15, 6 ;
        ZV_auf_Funk, 7 ;
        ESP_v_Signal_8Bit, 8 ;
        UGDO_Switchboard, 16 ;
        SM_Parken_UGDO_Anf, 24 ;
        SM_Parken_UGDO_Aktion, 28 ;
      }
    
    UGDOs_02: 47, UGDO_S, 8 {
        UGDO_LED_Code_01, 0 ;
        UGDO_Function_01, 5 ;
        UGDO_Failure_Antenne, 8 ;
        UGDO_Failure_Codierung, 9 ;
        UGDO_Failure_Hardware, 10 ;
        UGDO_ResponseError, 16 ;
        UGDO_Channel_1, 24 ;
        UGDO_Channel_2, 25 ;
        UGDO_Channel_3, 26 ;
        UGDO_Channel_4, 27 ;
        UGDO_Channel_5, 28 ;
        UGDO_Channel_6, 29 ;
        UGDO_Channel_7, 30 ;
        UGDO_Channel_8, 31 ;
        UGDO_Channel_9, 32 ;
        UGDO_Channel_10, 33 ;
        UGDO_Channel_11, 34 ;
        UGDO_Channel_12, 35 ;
        UGDO_Channel_13, 36 ;
        UGDO_Channel_14, 37 ;
        UGDO_Channel_15, 38 ;
        UGDO_DoorState, 40 ;
      }

    The example pair of the LIN bus request/response frames is the next two messages:

    0x2E70FFFC80FFFFE3
    0x2F00F9FE0080F0FFFF26

    From the previous experience, the first byte (0x2A and 0x2F) is the LIN frame ID. The last byte is the checksum (0x84 and 0x26). After converting 0x2E to decimals, it is 46, and 0x2F = 47. So, the clear data is:

    0x70FFFC80FFFF
    0x00F9FE0080F0FFFF

    When converting the HEX to bits, the bits will be inverted because of the LIN specification. In the LIN bus, the 0-bit goes first. 

    So, here we go. The "decoded" from the LIN frame data is now readable for us. The first byte is responsible for UGDO_Buttons, Klemme_15, and ZV_auf_Funk. It means that the state of the buttons is sent to the HomeLink as is, and they are zero. The next bit is responsible for the KL15 state. So, now it describes why putting the power to the BCM KL15 input is not enough. It looks like all digital communication about the KL15 is isolated from the hardware. The last one bit is the ZV_auf_Funk, but unfortunately, it had no description in the LDF. 

    The next byte is ESP_v_Signal_8Bit, and it is pretty self-explanatory. But why is it 0xFF? Maybe it is a problem why the buttons not reacts. Because the HomeLink module thinks that the car is speeding. And the LDF has information about that.

    ESP_v_Signal_8Bit_encoding {
      physical_value, 0, 253, 2.56, 0, "Unit_KiloMeterPerHour" ;
      logical_value, 254, "Init" ;
      logical_value, 255, "Error" ;
    }

    Now, it was necessary to tell BCM the Zero speed somehow. To do that, we can check the dbc file (CAN Matrix or CAN Database). Based on the name, it receives the speed from the ESP, but the ESP and BCM have different communication buses. VAG is using the module called "Gateway" to commutate that buses, so the information with the speed should come from it with high chance. And it is:

    BO_ 253 ESP_21: 8 Gateway
     SG_ ESP_21_CRC : 0|8@1+ (1,0) [0|255] ""  Vector__XXX
     SG_ ESP_21_BZ : 8|4@1+ (1,0) [0|15] ""  Vector__XXX
     SG_ BR_Eingriffsmoment : 12|10@1+ (1,-509) [-509|509] ""  Vector__XXX
     SG_ ESP_Diagnose : 23|1@1+ (1.0,0.0) [0.0|1] ""  ZR_High
     SG_ ESC_v_Signal_Qualifier_High_Low : 24|3@1+ (1.0,0.0) [0.0|7] ""  Vector__XXX
     SG_ ESP_Vorsteuerung : 28|1@1+ (1.0,0.0) [0.0|1] ""  Vector__XXX
     SG_ OBD_Schlechtweg : 30|1@1+ (1.0,0.0) [0.0|1] ""  ZR_High
     SG_ OBD_QBit_Schlechtweg : 31|1@1+ (1.0,0.0) [0.0|1] ""  ZR_High
     SG_ ESP_v_Signal : 32|16@1+ (0.01,0) [0.00|655.32] "Unit_KiloMeterPerHour"  BedienSG_hi,DDA,OTA_FC,ZR_High,ZR_LIMU,ZR_MIB_TOP_ab_Gen3,ZR_Standard
     SG_ ASR_Tastung_passiv : 48|1@1+ (1.0,0.0) [0.0|1] ""  OTA_FC
     SG_ ESP_Tastung_passiv : 49|1@1+ (1.0,0.0) [0.0|1] ""  OTA_FC,ZR_High,ZR_LIMU,ZR_MIB_TOP_ab_Gen3
     SG_ ESP_Systemstatus : 50|1@1+ (1.0,0.0) [0.0|1] ""  OTA_FC
     SG_ ASR_Schalteingriff : 51|2@1+ (1.0,0.0) [0.0|3] ""  Vector__XXX
     SG_ ESP_QBit_v_Signal : 55|1@1+ (1.0,0.0) [0.0|1] ""  ZR_High,ZR_LIMU,ZR_MIB_TOP_ab_Gen3,ZR_Standard
     SG_ ABS_Bremsung : 56|1@1+ (1.0,0.0) [0.0...
    Read more »

  • Another half a car

    Stepan Skopivskiy03/13/2025 at 21:34 0 comments

    The main obstacle to continuing the work has not yet been resolved. After powering on the BCM, including the ignition, the buttons did not respond. The first logical step was to read the errors in the block, and one error was present: external antenna malfunction. I also saw the adaptation called "Garage door opener, programming antenna," but I was not able to read the current value because ODIS requested the login. I tried every login (login-code) I found on forums, but none of them worked. ODIS says that the authorization was successful, but after that, it asked for login again. 

    Also, the BCM had an error regarding the CP (component protection). It was a problem, too, because the CP can block the working of the lot of functions to make your life harder and force you to remove the CP. It can be done only with ODIS online, and it requires to send all the identification information about your block to the VAG servers to check if the block is clean (e.g. not stollen, etc..). To remove the component protection, each block has its own guided function in ODIS and, of course, requires two other blocks: gateway and immobilizer. 

    On the b9 platform, the immobilizer is located in BCM2; also, it is responsible for access authorization and ignition (KL15). So, after contacting the seller who sold be the BCM, I was waiting for the 2 other blocks: 4M1907468D and 8W0907064EC. The original key fob has been ordered together with an antenna and start-stop button. All these components were from the same car. Unfortunately, the gateway was melted. So, I got only two BCMs from one car and "accessories" for them: key, antenna, and button. The gateway was exchanged to one from another car. It broke the whole idea and added another issue - 100% component protection in all blocks because the master block that checks component protection is exactly the gateway.

    Another issue was in BCM2 connection. By default, it has only 3 KL30 inputs:

    • Connector A:
      • pin 16
      • pin 17
    • Connector C:
      • pin 16

    The wiring diagram says that pin 17 is responsible for the keyless access and authorization. So, only that pin was connected to the power supply. And BCM2 starts to respond to ODIS. But the start stop button did not do anything, like the key was not recognized. A lot of checks by ODIS, measurements, etc. AND NOTHING. The remote buttons work. Diagnisis works. But the key has not been recognized after start-stop button clicks. The problem was with CP, too, because the key is required to remove CP.

    A big thanks to my friend, who gifted me his smashed taillight from an A4. It will save me a lot of time. I decided to check the taillight's reaction to the key buttons. I connected the left taillight and provided the power supply to both pin 16. I was frustrated after clicking on the start-stop button, but now it is working!

    Interesting fact here - if the 2 fuses responsible for the taillights have been removed, the car would never start the ignition!

    Ignition solved. But the buttons are not working anyway.

    During the investigation of the ignition issue, I accidentally tested different guided functions. I found the functions to adapt and replace the homelink module. And I decided to run them. The replacement is just a bit longer version that includes the adaptation function. Somehow, after running that function, I decided to try to read the adaptation that was just written. And what a miracle, ODIS read it without requesting the login. Looks like the guided function did the authorization in the background, and ODIS is keeping that authorization during the session. Theoretically, the login can be extracted using a CAN sniffer. Now, we can change the adaptation that interests us. And it was successful. The error becomes inactive and can be deleted. A bit later, I double-checked my theory with guided function, and it was confirmed.

    So, now we have the following conditions:

    • The ignition is on
    • No errors in the memory (regarding homelink)
    • Component protection...
    Read more »

  • Documentation found

    Stepan Skopivskiy03/11/2025 at 18:03 0 comments

    Besides the hardware investigation, I continued the Google research.

    1. The CAN bus matrix and Lin Description Files (next LDF) were found: https://openinverter.org/forum/viewtopic.php?t=3152
    2. The VAG BAP discover was to found at all unless the article in the web archive history: https://web.archive.org/web/20241005094756/https://blog.dietmann.org/?p=324
    3. Another document with the name 476121999-BAP-FC-NAV-SD-P30DF48-v2-80-F-pdf was found.

    It also sheds some light on the communication protocol. The UGDO_B is the HomeLink buttons. The UGDOe is the HomeLink module. Based on this, half of the shade was eliminated, and information about the buttons' communication was discovered. The BCM drives the LIN bus, it sends the *e_ messages to request information and the *s_ headers to receive the response. The details of the hardware level can be found here: https://www.csselectronics.com/pages/lin-bus-protocol-intro-basics.

      UGDO_Be_01: 4, BCM1, 6 {
        UGDO_SW_LED_Code, 0 ;
        UGDO_SW_Function, 5 ;
        DI_KL_58xs, 8 ;
      }
      UGDO_Bs_01: 3, UGDO_B, 6 {
        UGDO_SW_Buttons, 0 ;
        UGDO_SW_Switchboard, 4 ;
        UGDO_B_ResponseError, 16 ;
      }
      UGDOe_02: 46, BCM1, 6 {
        UGDO_Buttons, 0 ;
        Klemme_15, 6 ;
        ZV_auf_Funk, 7 ;
        ESP_v_Signal_8Bit, 8 ;
        UGDO_Switchboard, 16 ;
        SM_Parken_UGDO_Anf, 24 ;
        SM_Parken_UGDO_Aktion, 28 ;
      }
      UGDOe_BAP: 31, BCM1, 8 {
        BAPe_LSG_ID1, 0 ;
        BAPe_Opcode, 4 ;
        BAPe_Segment, 7 ;
        BAPe_FCT_ID, 8 ;
        BAPe_LSG_ID2, 14 ;
        BAPe_Data_Byte_1, 16 ;
        BAPe_Data_Byte_2, 24 ;
        BAPe_Data_Byte_3, 32 ;
        BAPe_Data_Byte_4, 40 ;
        BAPe_Data_Byte_5, 48 ;
        BAPe_Data_Byte_6, 56 ;
      }
      UGDOs_02: 47, UGDO_S, 8 {
        UGDO_LED_Code_01, 0 ;
        UGDO_Function_01, 5 ;
        UGDO_Failure_Antenne, 8 ;
        UGDO_Failure_Codierung, 9 ;
        UGDO_Failure_Hardware, 10 ;
        UGDO_ResponseError, 16 ;
        UGDO_Channel_1, 24 ;
        UGDO_Channel_2, 25 ;
        UGDO_Channel_3, 26 ;
        UGDO_Channel_4, 27 ;
        UGDO_Channel_5, 28 ;
        UGDO_Channel_6, 29 ;
        UGDO_Channel_7, 30 ;
        UGDO_Channel_8, 31 ;
        UGDO_Channel_9, 32 ;
        UGDO_Channel_10, 33 ;
        UGDO_Channel_11, 34 ;
        UGDO_Channel_12, 35 ;
        UGDO_Channel_13, 36 ;
        UGDO_Channel_14, 37 ;
        UGDO_Channel_15, 38 ;
        UGDO_DoorState, 40 ;
      }
      UGDOs_BAP: 32, UGDO_S, 8 {
        BAPs_LSG_ID1, 0 ;
        BAPs_Opcode, 4 ;
        BAPs_Segment, 7 ;
        BAPs_FCT_ID, 8 ;
        BAPs_LSG_ID2, 14 ;
        BAPs_Data_Byte_1, 16 ;
        BAPs_Data_Byte_2, 24 ;
        BAPs_Data_Byte_3, 32 ;
        BAPs_Data_Byte_4, 40 ;
        BAPs_Data_Byte_5, 48 ;
        BAPs_Data_Byte_6, 56 ;
      }

    Also, this file has a bit of info about the diagnosis frames used to work with ODIS. But unfortunately the amount of info was a bit.

    Diagnostic_frames {
      MasterReq: 0x3c {
        MasterReqB0, 0 ;
        MasterReqB1, 8 ;
        MasterReqB2, 16 ;
        MasterReqB3, 24 ;
        MasterReqB4, 32 ;
        MasterReqB5, 40 ;
        MasterReqB6, 48 ;
        MasterReqB7, 56 ;
      }
      SlaveResp: 0x3d {
        SlaveRespB0, 0 ;
        SlaveRespB1, 8 ;
        SlaveRespB2, 16 ;
        SlaveRespB3, 24 ;
        SlaveRespB4, 32 ;
        SlaveRespB5, 40 ;
        SlaveRespB6, 48 ;
        SlaveRespB7, 56 ;
      }
    }
    

    After capturing the LIN messages during the ODIS block identification procedure, I got a list of frames. It will be attached as a file. In that mess of frames, I was able to see the interesting frames that looked pretty known.

    • 0x3C0103226004FFFFFF75
    • 0x3D01066260042500000D

    What if we change the coding? And here we go:

    • 0x3C01062E600421000041
    • 0x3D01036E6004FFFFFF29

    Let's make the messages clearer. Based on the LDF, we can get the info about the bus. It is the LIN 2.0 version and works at 19.2 kbps.

    ...
    LIN_description_file;
    LIN_protocol_version = "2.0";
    LIN_language_version = "2.0";
    LIN_speed = 19.2 kbps;
    ...

    Also, based on the specification of the LIN, the first byte is the header, and the last one is the checksum. To get the checksum, https://linchecksumcalculator.machsystems.cz/ can be used.

    And it looks true. 0x 3C01062E600421000041, the frame ID matches with the LFD, and the checksum is the same. So, now the message looked less terrible. After sniffing a few more messages, they became more and more logical but still not clear....

    Read more »

  • One year after...

    Stepan Skopivskiy03/10/2025 at 11:55 0 comments

    For one year, I forgot about Homelink and just used the car until my colleague bought an A4 2018 MY and started searching for a solution to the same problem. And here's where the new story begins.

    We started by sharing what we had learned about Homelink. The amount of information was not large and helpful. With his car, we tried to do the same manipulation - coding and adaptation-  but it did not help either.

    We were able to change the coding, but the adaptations were secured with the security access login. After that, the idea comes. The HomeLink module is connected by the LIN bus. So, it should be pretty "stupid". It should do simple operations and not more. How wrong I was...

    The first idea was to test all the things right on my car. But it is totally useless because it requires running between the apartment and the parking a lot times. Also, I did not find a way to connect to the LIN bus in the car. All places are covered by trims. And that LIN bus is present only in a few places without any connectors on its way.

    I found and ordered the first two components of the HomeLink system - HomeLink physical buttons (4M0959719A) and the HomeLink module (4M0907410A). In parallel, I started to search for information on how the LIN bus works and information regarding the communication protocols. But during the investigation, I also found that the LIN bus requires the master, which is driving the bus. The details can be found here: https://www.csselectronics.com/pages/lin-bus-protocol-intro-basics.

    So, I also ordered the BCM (Body control module) (8W0907063CB). As I need it just for the experiments, I was searching for the cheapest one.

    The seller sent another one instead. And I start the experiments.

    BCM has 3 connectors:

    • -T54c- (A)
      •  KL31 (permanent negative)
        • pin 11
    • -T73a- (B)
      • KL30 (permanent positive) 
        • pin 2
        • pin 12
        • pin 66
        • pin 73
      • KL31 (permanent negative)
        • pin 40
        • pin 63
      • KL15 (ignition)
        • pin 7
        • pin 19
      • LIN bus
        • pin 24
    • -T73b- (C)
      • KL30 (permanent positive) 
        • pin 1
        • pin 12
        • pin 66
        • pin 73
      • KL31 (permanent negative)
        • pin 63
      • CAN bus
        • pin 40
        • pin 41

    The complete preparation for the setup looked next. The OBD2 was not connected yet because of a lack of the correct connector for BCM.

    After connecting all the pins (including the ignition one) and powering on the BCM from the laboratory power supply, nothing interesting happened. The buttons were not reacting on clicks. I connected the diagnostic device to the BCM CAN bus directly, and the ODIS recognized and even reported the clicks. The LIN bus got activity, too.

    As the LIN bus had activity, I did some capturing of the LIN. The Logic2 capture with hold buttons for the while is in the attached file. The logic analyzer was a cheap clone of the Logic2 devices from AliExpress.

    Besides that, the buttons were still not reacting to clicks.

  • Coding and adaptations

    Stepan Skopivskiy03/09/2025 at 14:46 0 comments

    Unforchunately the ODIS (VAG dealer/workshop software) has not any description of the coding bytes and homelink support only 3 bytes to code. The next step was to try to code the UGDO (universal garage door opener or homelink).

    Thankfully to googling, I found the next info:

    • 35 00 00 - for US cars, with physical Homelink buttons next to the roof control
    • 31 00 00 - for EU cars, with buttons
    • 25 00 00 - for US, without buttons
    • 21 00 00 - for EU, without buttons

    After trying each combination, I realized that the first 4 bits are responsible for the count of channels and the second 4 bits for the country. The interesting think is that I got only two kinds of answers: successful or unsuccessful coding results.

    But as the coding was discovered, I got the next:

    It was when I changed the 25 to 21. When I changed it back (21 to 25).

    (Sorry for the language; you can compare it to the previous screen as the order is the same.)

    Unfortunately, my remote was still not recognized by the car.

    More interesting things was under adaptations, but none of the known authorization codes was working. And because of lack of time, I forget about my idea for some time.

  • Discover the input

    Stepan Skopivskiy03/09/2025 at 11:40 0 comments

    I have no experience writing interesting articles or stories, but the long story short is. I`m a Ukrainian who owns a US car after the incidents. I like Audi. My first car was a Q5 2015 MY. Logically (almost), the next choice happened to be an SQ5, preferably 20+ MY. After a few test drives, researching, and time, I was waiting for the new (used) car - Audi SQ5 Prestige 22MY.

    I live in a flat room without parking, but I own an underground one in the neighbourhood building. It has 2 levels of security access: barrier and garage door with one remote. Also, my new car had a Homelink option, the purpose of which was to simplify life. Unfortunately, the remote system of my parking was not compatible with HomeLink. The investigation has already started here.

    The first idea was just to replace the Homelink module from the US to the EU one. And I started from here. By the VIN of my car, I found that the original module installed in my car is 4M0907410A. As VAG has two part numbers, the base one and end the end one. The base number was 4M0907410. It can mean different things like different options, functionality, firmware, and even different base characteristics. And it was. On the previous platform, called "B8", the garage door opener had two option codes: VC1 and VC2. VC2 is for 315Mhz transponders, and the VC1 is for 433 one. And both my cars had the VC2 option code, of course. It confirmed the necessity of the module replacement, except for one thing.

    The part numbers for the B8 platform are on the screen. As you can see, it has a separate part number for VC1 and VC2.

    BUT the B9 platform has a different situation. It does not have separate part numbers depending on the PR code. And it was weird.

    Another weird thing was the module supplier part number: NZLADHL5C. And by quick googling, I found the FCC report: https://fcc.report/FCC-ID/NZLADHL5C.

    The frequency range covers both ranges and even more. So, is the replacement needed? Or is the configuration enough?


View all 8 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates