Specification#
Every number the lock ships with. The radios and the protocol, the boards, the memory budget on the smallest part, the obstruction classifier, the side-of-door routes, and how a running lock is updated. The landing page says what the lock does; this page says exactly how.
Radios and protocol#
| UWB | DS-TWR under an STS session, channels 5 and 9 |
| Resolution | one timestamp tick is about 15.65 ps, which light crosses in 4.692 mm |
| Unlock bound | 1.00 m, from ULTRAWIDELOCK_UNLOCK_RANGE_CM |
| BLE | credential service 0xFFF2, AUTH0 / AUTH1 / EXCHANGE |
| NFC | ECP, on the nRF5340 DK target |
| Side of door | a second UWB anchor in the same ranging round, or two BLE witnesses |
| Matter | hand-written node over Thread, or over Wi-Fi on ESP32 |
| Door Lock cluster | LockOperation events, AutoRelockTime, DoorLockAlarm, Approach Direction |
| Matter client | CASE as initiator and the Binding cluster, to open a second lock. Off by default |
| Updates | signed delta over BLE or USB, applied from inside MCUboot; whole signed image on ESP32 |
| Ports | Zephyr, ESP-IDF, and a Zephyr-free FreeRTOS port |
| Tests | 9,608 host checks across 18 suites, no hardware needed |
| License | ISC. The vendored Qorvo UWB driver is LicenseRef-QORVO-2 |
How a door opens#
Five steps, in the order they happen.
- BLE. The phone finds the credential service
0xFFF2. - Authenticate. AUTH0, AUTH1 and EXCHANGE run, and both ends hold the URSK.
- Range. The key ladder seeds an STS session, then a DS-TWR round measures the distance from the lock.
- Gate. A trusted range inside the bound moves the bolt.
- Matter. Lock state goes out over Thread, into Apple Home.
The credential is verified on the lock itself, so there is no remote verifier to compromise.
Why time of flight#
One timestamp tick is 15.65 ps, which light crosses in 4.692 mm. A relay can add delay and nothing else, which is why a relayed round measures longer than the true distance rather than shorter: there is no attack that makes light arrive early. The landing page's ranging instrument computes its readings from the firmware's own constants, and web/site/check_hero_constants.py fails the site build when they drift from the C tree.
Hardware targets#
| Application | Hardware | Connectivity |
|---|---|---|
dwm3001cdk-lock | DWM3001CDK, nRF52833 + DW3110 | UWB, Matter over Thread |
dwm3001cdk-lock-freertos | the same board, no Zephyr | UWB, Matter over Thread |
nrf5340dk-lock | nRF5340 DK, DWM3000EVB, NFC12A1 | UWB and NFC, Matter over Thread |
esp32-matter-lock | ESP32-S3 / C5 / C6 with DWM3000EVB | UWB, Matter over Wi-Fi |
satellite | CDK, nRF5340 DK, or the ESP32 tier | UWB responder, sealed link to the lock |
Bare make targets mean the DWM3001CDK; the nRF5340 DK is nrf- prefixed and the ESP32 esp-. Configuring lists every option.
All of it on one nRF52833#
512 KB of flash and 128 KB of RAM carry the reader, the DW3110 radio, an OpenThread MTD and a Matter node at the same time. A hand-written Matter node, rather than CHIP, is what makes it fit.
| Part | What it carries |
|---|---|
| reader | AUTH0 / AUTH1 / EXCHANGE, key ladder, STS, DS-TWR |
| matter | hand-written node, Door Lock cluster, five fabrics |
| thread | OpenThread MTD, joins a real network |
| classifier | line-of-sight vs obstructed, 776 B of flash |
| Budget | Used | Of | Share |
|---|---|---|---|
| Flash | 417,684 B | 433,664 B | 96.31% |
| RAM | 118,312 B | 131,072 B | 90.26% |
Both are tight, and flash is the tighter. make cdk-size reports them and make cdk-size-check fails the build when the headroom is gone.
| Toolchain | NCS v3.3.0, Zephyr 4.3.99 |
| Signing | ECDSA-P256, verified by MCUboot |
Repository defaults are bench defaults. Keys and identities in the tree are for development. Do not secure valuables with it.
The nRF5340 DK image has its own budget: memory usage.
Obstruction detection#
A phone in a hand and a phone through a wall both measure one metre. The shape of the arrival separates them: a direct path lands as one sharp edge, a path through a door arrives late, spread and weaker.
A decision tree reads the DW3000's own receive diagnostics in 776 bytes of flash, with no interpreter and no allocation.
| Model | depth-2 decision tree, generated by emlearn |
| Cost | 776 B flash, 0 B RAM, 28 B stack |
| Input | five CIA registers plus the measured range |
| Gate | the host suite certifies the C matches the trained model |
The site draws this pair as two signals everywhere it appears: mint is the first path, direct and trusted; amber is the late path, obstructed or carrying a relay's added delay. make mlgate runs the certification.
Side of the door#
A phone on the couch and a phone on the porch can be the same distance from the door. Only one of them should open it. The question is answered by either of two routes, and both fail closed.
A second UWB anchor. The satellite joins the phone's own ranging round as responder 1, so both distances come from one round rather than two guesses stitched together. It reports its distance sealed and bound to the block it was measured in, and the lock fuses the pair only when both halves carry the same block. It builds for the DWM3001CDK, the nRF5340 DK, and the ESP32 tier over an ESP-NOW carrier.
make anchorlink # the lock half
make sat-build SAT_THREAD=1 # the satellite halfTwo BLE witnesses. One nRF52840 dongle inside, one outside, a differential read consulted at the one moment it is reliable, and a door-transition latch that holds the answer between crossings. One image, role set at install.
make witness-build
make witness-flash # over USB DFU, no probeThe side gate fails closed for passive unlock: no agreeing second opinion, no walk-up open. A dead dongle, a dropped mesh, a reboot or corrupt storage each leave the lock refusing to open from inside. Outside, the recovery is a retry, an NFC tap, or the app.
The design is in inside latch, the ranging route in second anchor, and both are proved on a bench in the runbook.
Update over the air#
Either chip, from a browser. The flash page finds the board, reads what it is running, and sends the one update that applies.
| DWM3001CDK | ESP32-S3 / C5 / C6 | |
|---|---|---|
| Transport | mcumgr, over BLE or USB | native GATT frames |
| Payload | signed delta, about 11 KB | signed whole image, about 2 MB |
| Why | one MCUboot slot in 512 KB | two full OTA slots |
| Time | seconds | several minutes over BLE |
Writing starts once the update window is open on the board: SW2 on the CDK, a double-click on the ESP32's button. That press is the whole availability gate; authenticity is a P-256 signature, checked before the first byte is written and again by the bootloader. The CDK can also be reinstalled whole over the cable through MCUboot serial recovery, which runs from the bootloader alone.
Chrome or Edge on a computer, or Chrome on Android. Neither Web Bluetooth nor WebSerial exists in Safari, so not from an iPhone.
make fota # CDK: one file a phone can install
make fota-done # after every phone push, to record what the board runs
make ota-fan PREV_HEXES=… # the delta fan and the index the web page reads
make release RELEASE_KEY=… # the published bundleWithout hardware#
| Page | What it runs |
|---|---|
| Digital twin | the untouched ultrawidelock_uwb sources compiled to WASM against the same shim the host suite links. Every block is a real CCM*-encrypted exchange decoded by the firmware's own RX state machine |
| Web flasher | installs a merged ESP32 image over WebSerial with no toolchain, and updates either board over the air once one is running |
| Subsystem graph | what depends on what, extracted from the source tree: 17 subsystems and 49 edges, or 393 files with their symbols and 703 links |
git clone https://github.com/ultrawidelock/ultrawidelock.git
cd ultrawidelock
make check # 18 suites, 9,608 checks, no hardware