penguin/homekey-go

homekey-go

drivers/sesame/README.md

raw · 6931 bytes

Sesame OS3 driver

This directory contains the Sesame protocol, BlueZ transport and hardware-free tests. Supported advertised models: Sesame 5, 5 Pro, 6 and 6 Pro. It does not implement Sesame OS2, Hub/Matter setup, cloud guest-key signing or firmware updates.

The protocol is adapted from the MIT-licensed CANDY HOUSE Android SDK at d12f23c25bffd5adf6361abd0db82bb144441875. See LICENSE and the root NOTICE.

Integration

Discover scans powered local BlueZ adapters. Devices are matched by their advertised Sesame UUID and supported product ID, not by a friendly name or fixed Bluetooth MAC. The web UI scans on page load and on Scan for locks. During that scan, DiscoverWithCallback starts PrepareRegistration for unregistered locks before the scan finishes. Each preparation connects, subscribes, receives the initial token, and retains the link in Ready to register without sending a registration command. Repeated scans reuse preparations and deduplicate a physical UUID across adapters. Bluetooth connections lists these preparations alongside all connected Sesame links; Register is enabled only for a ready link. The separate Register button opens a name/confirmation form. Submitting it uses that same link and original token; it never dials a second connection. The 10-second registration deadline starts at submission, not while waiting for the user. Disconnect and service shutdown release waiting links. Failed registration is never replayed automatically; scan again to prepare a new link.

Registration uses P-256 ECDH and calls a persistence callback as soon as the 16-byte credential is available. It then loads status/settings from the reply, creates the cipher from the original token and hands the live session to Client.Run, with no disconnect or additional login. If the registry cannot be saved, the handoff is closed and the saved key remains available for recovery. The standalone Register helper remains available for one-shot callers. It never issues a reset. Registration here provisions BLE access, not a Sesame cloud account. Probe validates an imported local key by logging in without moving the motor. Cloud-only guest keys are not supported.

Client.Run maintains a connection and reconnects after transport or crypto failure. Action serializes operations on that connection and waits for the lock's result code. Failed/timed-out operations are not replayed after reconnect. State returns the latest immutable snapshot; pointers in snapshots must not be modified by callers. Each reconnect clears state until new publications arrive. Discovery prefers advertisements received in the current scan when BlueZ has cached multiple addresses for one UUID. Scans request LE transport, the FD81 service and duplicate manufacturer reports, and connection setup requires a report from the current scan (there is no cached-address fallback). This follows the Android SDK's ReceivedAdV → connectGatt(TRANSPORT_LE) → service discovery → notifications → initial-token/login sequence. BlueZ handles the platform-specific GATT setup. Connect has an 8-second limit and GATT setup has a 45-second limit; transient setup failures close the failed link and rescan, up to three attempts within the 60-second setup deadline, plus bounded scan/disconnect cleanup. Commands and registration exchanges are never automatically replayed. Disconnect releases notifications before closing the device. Connection setup and login have separate deadlines; errors identify discovery, connection, GATT services, notification subscription or initial-token/login waits, and connection failures are logged without keys.

Commands: lock, unlock, set-lock, set-unlock, set-boundary. Calibration captures the current reported position; saving either endpoint preserves the other endpoint. Boundary capture is allowed only after firmware has published its boundary capability. Positions use the SDK's signed 16-bit angle values; negative values, including -1, are valid.

OS3 framing uses 19 payload bytes per GATT fragment. Local login uses AES-CMAC. The fixed CCM profile is 13-byte nonce, 4-byte tag, AAD 00; the nonce contains an 8-byte LE counter, zero, and a 4-byte token. Unsupported token lengths fail explicitly. No keys, authentication data or decrypted packets are logged.

Link/Dialer separate the session protocol from BlueZ so a future ESP32 GATT tunnel can reuse this implementation. This release requires the HA/server's local Bluetooth adapter to reach the lock; it does not use HA Bluetooth proxies or add an ESP32 central role.

Validation

Run go test -race ./... and go vet ./... at repository root. Tests cover RFC 4493 CMAC vectors, independently generated OpenSSL/Python CCM vectors with high counter bytes, tampering, framing, P-256 registration, commands, calibration, unsupported boundary settings, cancellation, private storage and HTTP validation. Prepared-registration tests verify no write before confirmation, original-token cipher use for subsequent encrypted commands/notifications, one dial across registration, duplicate scans, disconnects, timeouts and registry-write cleanup.

Still requires real hardware validation: local BLE registration/login, initial token length and response encryption, notifications during manual movement, calibration/motor behavior, coexistence with the phone app, and battery impact of a persistent connection. Unit tests do not establish those device behaviors.

Connection workflow reference

Transport lifecycle was compared with SDK commit 61e2a6a (mirror of 8887141f1b5482451442647ff455313b755a8655), especially CHBleManager.kt, CHSesameOS3.kt, CHBaseDevice.kt, and the app's BleController.kt. The SDK also reconnects from newly received advertisements; its Android callbacks are mapped to BlueZ discovery reports and GATT properties here. Bounded transport retries are a Go/BlueZ policy, not an SDK timeout value. The existing local-key login algorithm already matches this SDK.

The private D-Bus test runs a simulated BlueZ service and verifies LE scan filters, rescan after a failed connection, write-without-response selection, buffering of an initial token emitted during StartNotify, and StopNotify before Disconnect. It does not emulate controller radio behavior or establish that Android and a Linux USB dongle have equivalent connection reliability.

A real Sesame 6 Pro trace showed successful ATT responses roughly one second apart at a 500 ms connection interval, with discovery still progressing when the old 8-second GATT budget expired. GATT now allows 45 seconds within a 60-second scan/connect/setup budget. Enrollment allows 90 seconds overall so setup does not consume the separate initial-token and registration budgets. Login and command timeouts are unchanged. The private-bus regression test also simulates discovery lasting longer than eight seconds.