UltraWideLock implements Aliro, the CSA's door-lock credential standard, on real hardware: BLE, NFC (ECP), and UWB ranging. Three complete locks, plus reader, initiator, and anchor examples.
No hardware. A C compiler and python3 is the whole list.
git clone https://github.com/ultrawidelock/ultrawidelock.git
cd ultrawidelock
make check # 8 host suites, about 2 minutesWith a board. Default is the Qorvo DWM3001CDK: nRF52833, DW3110 radio, and a J-Link, all on one part. Nothing to wire.
make dfu-key # once per clone · image-signing key, gitignored
make bootstrap # once per machine · NCS v3.3.0, several GB
make build # -> build/cdk-matter
make flash # over the on-board J-Link
make monitor # console, over RTTmake help lists every target. make tools says what this machine is missing.
iPhone / Apple Watch UltraWideLock on one board
┌────────────────────┐ ┌──────────────────────┐
│ Wallet home key │ │ nRF52833 + DW3110 │
└──────────┬─────────┘ └───────────┬──────────┘
│ │
1 BLE │ credential service 0xFFF2 │
│ ─────────────────────────────────▶│
2 Auth │ AUTH0 → AUTH1 → EXCHANGE │
│ ◀────────────────────────────────▶│
│ both ends now hold the URSK │
3 UWB │ key ladder → STS → DS-TWR │
│ ◀────────── ranging ─────────────▶│
4 Gate │ range consistency agrees │
│ ── U N L O C K ── │
5 Matter │ lock state over Thread └──▶ Apple Home
╵
Local only. No app, no account, no cloud round trip.
One nRF52833, 512 KB flash and 128 KB RAM, runs all of this at once:
| On the same part | |
|---|---|
| 📶 | BLE peripheral the iPhone talks the credential protocol to |
| 🔑 | Reader: AUTH0 / AUTH1 / EXCHANGE, key ladder, STS, DS-TWR |
| 🏠 | Hand-written Matter node (modules/ultrawidelock_matter), not CHIP |
| 🧵 | OpenThread MTD, so it joins a real Thread network |
| 📏 | DW3110 UWB ranging, over the module's internal SPI |
| 🧠 | Obstruction classifier (modules/ultrawidelock_ml), 776 B of flash |
It fits in 379,332 of 433,664 B flash and 111,012 of 131,072 B RAM.
make cdk-size-check fails if that regresses.
No tap on this board. No NFC reader IC, and the nRF52833's own NFC is tag emulation only. Walk-up only here; for a tap use the nRF5340 DK.
Also builds: make reader (radio alone, no Matter) and make selftest
(DW3110 device ID over SPI at boot).
Distance alone cannot tell a phone in your hand from a phone through a wall. A decision tree reads the DW3000's own receive diagnostics and answers:
make mlgate # the classifier, in the unlock pathDepth 2, generated by emlearn, no interpreter and no allocation: 776 B of
flash, 0 B of RAM, 28 B of stack. tests/host/test_ultrawidelock_ml.c
certifies the C classifies identically to the trained model.
| Application | Hardware | Connectivity |
|---|---|---|
apps/dwm3001cdk-lock/ |
DWM3001CDK | UWB, Matter over Thread |
apps/dwm3001cdk-lock-freertos/ |
DWM3001CDK, no Zephyr | UWB, Matter over Thread |
apps/nrf5340dk-lock/ |
nRF5340 DK, DWM3000EVB, NFC12A1 | UWB and NFC, Matter over Thread |
apps/esp32-matter-lock/ |
ESP32-S3 / C5 / C6 with DWM3000EVB | UWB, Matter over Wi-Fi |
make nrf-build && make nrf-flash && make nrf-term # nRF5340 DK
make esp-go APP=matter-lock TARGET=esp32s3 # ESP32: build, flash, monitor
make freertos-build && make freertos-flash # the Zephyr-free port
make hitl # unattended end-to-end benchESP32 toolchain paths
ESP32 needs an installed ESP-IDF, and the Matter lock also needs esp-matter.
Neither is pinned here; both default under $HOME/esp, overridden with
IDF_EXPORT and ESP_MATTER_PATH. The bench builds against ESP-IDF v5.5.4 and
esp-matter 93b1680.
- A Zephyr-free FreeRTOS port of the same lock on the nRF52833: NimBLE, MPSL and the SoftDevice Controller, OpenThread, Mbed TLS, and the Matter node, added a layer at a time and measured as each one lands.
- The obstruction classifier above, and
make mlgateto run it live. - Matter Door Lock grew up:
LockOperationevents,AutoRelockTime, persisted writable attributes, and Apple's Approach Direction cluster. - Signed updates over BLE on the FreeRTOS port, proven on hardware.
- Inside and outside BLE witnesses, with a fail-closed side gate for
passive unlock (
make witness-trio). make sdk-exportfor the hardware-agnostic SDK, and a size gate on every port.
No cable, no probe. Two MCUboot slots do not fit on a 512 KB part, so what travels is a signed delta.
make dfu # build, diff, sign, push
make fota # instead: one file a phone can install
make fota-done # after every phone pushmake fota-done is not optional. The delta is cut against the exact bytes on
the board, and only the build host keeps that record.
- Console is RTT, not UART.
make monitorattaches with the ELF you flashed. The ring survives reset, so the first block is the previous run. make flash-erasecosts the commissioning. Apple Home has to add the lock again.- Never lock APPROTECT. Recovery needs a mass erase, which takes the
reader's private key and every phone key on it.
scripts/check-approtect.shchecks a part. - These are bench defaults. Do not secure valuables with it.
Include only your role:
#include <ultrawidelock/reader.h> // reader
#include <ultrawidelock/device.h> // initiator
#include <ultrawidelock/tlv.h> // codec onlyPorts implement the five seams in <ultrawidelock/ultrawidelock_hal.h>: DW3000
GPIO/IRQ, DW3000 SPI, reader BLE, central BLE, credential storage. New board or
chipset: PORTING.md.
Plain CMake consumers
cmake -S . -B build/sdk -DCMAKE_INSTALL_PREFIX="$PWD/build/sdk-install"
cmake --build build/sdk
cmake --install build/sdkExports UltraWideLock::headers and UltraWideLock::tlv; version comes from
the root VERSION. Working example in
examples/cmake/consumer/, and add_subdirectory
works too. make sdk-check verifies both paths.
Full firmware is consumed through the Zephyr module or the ESP-IDF components.
The all-in-one <ultrawidelock/ultrawidelock.h> pulls in every declaration.
ultrawidelock/
├── apps/ complete lock products
├── examples/ independently buildable role and bench examples
├── modules/ the portable protocol, with no OS in it
│ ├── ultrawidelock_cred/ credential sessions, TLV, key ladder
│ ├── ultrawidelock_uwb/ ranging engine behind the STS seam
│ ├── ultrawidelock_dw3000/ DW3000 driver integration
│ ├── ultrawidelock_matter/ the hand-written Matter node
│ ├── ultrawidelock_ml/ on-device classifiers
│ ├── ultrawidelock_nfc/ ECP and reader transports
│ └── ultrawidelock_dfu/ signed delta updates
├── ports/ zephyr · esp32 · freertos-nrf52833
├── integrations/ patches for external upstream applications
├── tests/ host, shared, port, tooling, on-target
├── include/ SDK umbrella and public-API ownership
├── cmake/ shared CMake helpers
├── mk/ what sits behind each Make target
├── scripts/ setup, release, DFU, sizing, device utilities
└── release/ templates and scripts for release bundles
Contributing: CONTRIBUTING.md. Coding agents:
AGENTS.md.
Project-original code is Copyright (c) 2026 asxeem and UltraWideLock
contributors under the ISC license (LICENSE). The DW3000 integration
in modules/ultrawidelock_dw3000 is ISC (Bruno Randolf).
The vendored Qorvo UWB driver it wraps is LicenseRef-QORVO-2, which permits use only with Qorvo integrated circuits, so binaries built with UWB support inherit that hardware restriction. Full mapping: THIRD_PARTY_NOTICES.

