This documentation is intended only for educational purposes. All information provided here is based on reverse engineering and guessing which means information might be incomplete or straight up missing .
Keypads are supported by Homekit as an authentication mechanism for a HomeKit compatible lock that also implement Guest Sharing, which means you can assign access codes to people that are not part of your Apple Home.
A lock with access codes support is just a simple HomeKit Lock with the additional Service and Characteristics.
The required Services and Characteristics are already present in well-known projects like HAP-Python or HAP-NodeJS and this documentation will attempt to clarify their use.
Note that all Services and Characteristics defined in HAP follow the below format for their UUID:
00000263-0000-1000-8000-0026BB765291
| | | |
------ -------------------------
ID Base(HomeKit ID?)
The base is a constant for all defined Services and Characteristics and only the first 8 characters change which their actual ID. In this Documentation only the ID will be mentioned.
Name | ID |
---|---|
Access Code | 260 |
Name | ID | Type | Purpose |
---|---|---|---|
Configuration State | 263 | UINT16 | unknown |
Access Code Control Point | 262 | TLV8 | Access Code Provisioning |
Access Code Supported Configuration | 261 | TLV8 | Allowed Character Set, Min & Max Value for the PIN and maximum allowed Access Codes |
This characteristic will initially be read during pairing to acquire the required configuration like the minimum and maximum characters allowed for an Access Code. This will also be read randomly(presumably) by the controller, assuming to check if something changed following a software update or something.
Name | Type | Length | Value |
---|---|---|---|
Allow Character Set | 1 | TLV8 | 1: Arabic Numerals , other values are not known, it defaults to arabic numerals if not present |
Minimum Length Access Code | 2 | TLV8 | Minimum length for the Access Code |
Maximum Length Access Code | 3 | TLV8 | Maximum length for the Access Code |
Maximum Allowed Access Codes | 4 | TLV8 | Maximum amount of access codes that should be stored on the lock |
This where most of the communication will take place besides the initial query to "Access Code Supported Configuration" upon pairing and at random to get the configuration.
The controller always sends a Write Request containing TLV8 object encoded in Base64 to the lock and expects a direct response to this request.
Root TLV8:
Description | Type | Length | Value | Presence |
---|---|---|---|---|
Operation | 1 | 1 | 1: List 2: Read 3: Add 4: Update 5: Remove |
Request and Response |
Access Code Control Request | 2 | N | Sub-TLV8, see table "Access Code Request" | Request Only |
Access Code Control Response | 3 | N | Sub-TLV8, see table "Access Code Response" | Response Only |
Important Note: The operation received in the request has to be included in the response at least for the Add operation as the HomeKit Daemon will just crash if not present, wild i know.
Description | Type | Length | Value | Presence |
---|---|---|---|---|
Identifier | 1 | N | The identifier of the Access Code | Read & Remove Operation |
Access Code | 2 | N(Access Code Length) | The actual Access Code in ASCII Format | Add Operation |
Description | Type | Length | Value | Presence |
---|---|---|---|---|
Identifier | 1 | N | The identifier of the Access Code | All Operations |
Access Code | 2 | N(Access Code Length) | The actual Access Code in ASCII Format | All Operations |
Flags | 3 | 1 | Seems to be used to set up restrictions, values not known | All Operations |
Status Code | 4 | 1 | See Table "Response Status Codes" | All Operations |
Note For the Read and List Operation the Controller expects to receive all access codes in one response, this is achieved by Bulk Operations, multiple "Access Code Control Response" TLV Tags separated by a padding of 2 bytes of 0x0 will be sent out as a response for each access code.
ID | Description |
---|---|
0 | Success |
1 | Unknown |
2 | Exceeded Maximum Allowed AccessCodes |
3 | Too Many Bulk Operations |
4 | Duplicate Access Code Configuration |
5 | Smaller than Min Length |
6 | Larger than Max Length |
7 | Invalid Character |
8 | Invalid Request |
9 | Does not exist |
01 01 03 --> Add Operation (0x3)
02 06 --> Access Code Control Request (0x2)
02 04 31 32 33 34 --> Access Code (1234 - ASCII Format)
01 01 03 --> Add Operation (0x3)
03 0F --> Access Code Control Response (0x3)
01 01 01 --> Access Code Identifier (0x1)
02 04 31 32 33 34 --> Access Code (1234 - ASCII Format)
03 01 00 --> Access Code Flags (0x0)
04 01 00 --> Status Code (0x0)
01 01 01 --> List Operation (0x1)
01 01 01 --> List Operation
03 0f --> Access Code Control Response
01 01 00 --> Identifier
02 04 31 32 33 34 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status
00 00 --> Padding
03 10 --> Access Code Control Response
01 01 01 --> Identifier
02 05 35 36 37 38 39 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status
00 00 --> Padding
03 0f --> Access Code Control Response
01 01 02 --> Identifier
02 04 32 34 36 38 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status
01 01 02 --> Read Operation
02 03 --> Access Code Control Request
01 01 00 --> Access Code Identifier
00 00 --> Padding
02 03 --> Access Code Control Request
01 01 01 --> Access Code Identifier
00 00 --> Padding
02 03 --> Access Code Control Request
01 01 02 --> Access Code Identifier
01 01 02 --> Read Operation
03 0f --> Access Code Control Response
01 01 00 --> Access Code Identifier
02 04 31 32 33 34 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status Code
00 00 --> Padding
03 10 --> Access Code Control Response
01 01 01 --> Access Code Identifier
02 05 35 36 37 38 39 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status Code
00 00 --> Padding
03 0f --> Access Code Control Response
01 01 02 --> Access Code Identifier
02 04 32 34 36 38 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status Code
01 01 05 --> Remove Operation
02 03 --> Access Control Request
01 01 02 --> Access Code Identifier
01 01 05 --> Remove Operation
03 0f
01 01 02 --> Access Code Identifier
02 04 32 34 36 38 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status Code
Oddly, even though the Update operation (0x4) exists, for updating the access code it's using the Remove and Add operation.
01 01 03 --> Add Operation
02 06 --> Access Code Request
02 04 39 39 39 39 --> Access Code
01 01 03 --> Add Operation
03 0f --> Access Code Response
01 01 02 --> Access Code Identifier
02 04 39 39 39 39 --> Access Code
03 01 00 --> Flags
04 01 00 --> Status Code
You can find a demo written in JavaScript in the demo
folder, just make sure to have nodejs and npm installed and then run npm run serve
.