Alexa-RR/ultrawidelock

Apple Wallet UWB/NFC compatible firmware for smart locks. No app. No cloud. Works on a $20 chip. Handsfree. With a dead phone.

★ 0Forks 0GitHub ↗Compare

Project website ↗

README

UltraWideLock: an Apple UWB digital key lock that an iPhone or Apple Watch unlocks on approach over UWB or on tap over NFC

Portable firmware for NFC and UWB smart locks.

v0.3.0 · ISC license · Zephyr, ESP-IDF and FreeRTOS ports · 7,766 host tests

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.

Quick start

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 minutes

With 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 RTT

make help lists every target. make tools says what this machine is missing.

How a door opens

    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.

A Wallet home key unlocking the lock on approach, recorded on real hardware

Real hardware. A real Wallet key. A real walk-up unlock.

The board

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).

Is the door in the way?

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 path

Depth 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.

Other boards

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 bench
ESP32 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.

Home Key setup, Approach Direction, provisioning, NFC tap, and lock-state notifications on live hardware
Home Key · Approach Direction · provisioning · NFC tap · live lock state

New since v0.3.0

  • 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 mlgate to run it live.
  • Matter Door Lock grew up: LockOperation events, 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-export for the hardware-agnostic SDK, and a size gate on every port.

Update over the air

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 push

make fota-done is not optional. The delta is cut against the exact bytes on the board, and only the build host keeps that record.

Before you rely on it

  • Console is RTT, not UART. make monitor attaches with the ELF you flashed. The ring survives reset, so the first block is the previous run.
  • make flash-erase costs 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.sh checks a part.
  • These are bench defaults. Do not secure valuables with it.

Use as an SDK

Include only your role:

#include <ultrawidelock/reader.h>     // reader
#include <ultrawidelock/device.h>     // initiator
#include <ultrawidelock/tlv.h>        // codec only

Ports 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/sdk

Exports 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.

Repository layout

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.

License

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.

Contributors

deadcaf3dependabot[bot]scottjg

Issues