This checklist is the acceptance test for the Hub's BLE setup service (AD-25) on a real ESP32-S3.
CI runs every session rule on the host (tests/rs/setup); what happens over the air, on the chip
and in its flash is checked here, by hand, with the desktop client coldframe-setup-client. What
the Hub does after setup (heartbeats, re-joining) is the
uplink checklist.
Since Story 3.5, CONNECTED also means the Server accepted the Hub: after the join the Hub sets its
clock and sends one signed heartbeat to the --server address, so Part D needs a reachable Server
that knows the Hub (the client waits for you to enrol it first). Without one, Part D ends in
NO_SERVER, which is itself a result worth recording.
Note
Use a dev-mode build on a board that must never burn an eFuse (board D of the identity checklist). A release build works the same way but burns an eFuse key block on its first boot, if it has none yet.
Warning
Never paste a real Wi-Fi password or a real setup code into this file, a commit or an issue. The Result table records outcomes only.
- An ESP32-S3 board with the Hub firmware, the
esptoolchain andespflash4.x, as inapps/rs/hub/README.md. - A Linux machine with Bluetooth LE (BlueZ) for the client. The client builds its own libdbus
(
libdbus-sysvendored), so only a C compiler is needed. - A 2.4 GHz WPA2 network the Hub may join, and, for Part E, a WPA3-only network if one is at hand.
- The Server's enrolment key:
publicKeyfromGET /enrolment-key(base64url, 43 characters). Any 32-byte X25519 public key works for the BLE part; only a real one lets the Server accept the printed enrolment body. - A Site ID to bind to (any non-empty string of at most 36 bytes for the BLE part; a real Site of the Server, where you are an Administrator, for Part D).
- The Server's address for
--server:https://+ its DNS name + an optional:port, no path (for examplehttps://coldframe.example.org). The Hub trusts public roots only, so the Server needs its real certificate (AD-13).
Build the client once, from the repository root:
cargo build -p coldframe-setup-client
alias cfsetup="$PWD/target/debug/coldframe-setup-client"Run the Hub commands from apps/rs/hub after source ~/export-esp.sh. Record the port, the board
and the date for each run.
-
./check-image.shpasses: no Wi-Fi credential canary in the ELF or the flash image. - Erase the setup partition so the run starts unprovisioned:
espflash erase-region 0xC000 0x2000. This is required before the first flash of a board that ran a build with the older partition table (Story 3.2), where this range belonged tonvs. - Flash and monitor, for example
cargo run --features dev-mode. - The boot shows the identity line, then exactly one line
setup code=XXXXXXXX: 8 characters from0123456789ABCDEFGHJKMNPQRSTVWXYZ. Write the code on a sticker for the board, not here. - Then
ble advertising setup service as Coldframe Hub XXXX, whereXXXXare the first four digits of the Device ID, uppercase. - Reset the board. The same
setup code=line appears with the same code. - No other line contains the code.
-
cfsetup scanlists the Hub with its address,Coldframe Hub XXXXand an RSSI.
- Run
cfsetup setup --code <the code with its last character changed> --ssid <ssid> --password <password> --site <site> --server <server> --enrolment-key <key>. - The client prints
wrong setup codeand exits non-zero (echo $?is not 0). - The Hub logs
ble connectedthenble disconnectedat once, and advertises again. - Nothing was stored: a reset still prints
setup code=and advertises.
- Connect without writing anything, for example with
bluetoothctl(connect <address>), and wait. After 300 s the Hub drops the connection (ble disconnected) and logsble advertising setup service as Coldframe Hub XXXXagain;cfsetup scanfinds it again.
- Run
cfsetup setup --code <code> --ssid <ssid> --password <password> --site <site> --server <server> --enrolment-key <key>. Lowercase code input works too. - The client prints, in order:
session open, mtu=…;identity device_id=<the Device ID of the boot log> kind=1 firmware=<version>;- the networks the Hub hears, one line per SSID, strongest first, WPA3-only ones marked
wpa3-only (unsupported); site binding sent site=<site> server=<server>,enrolment sealed device_id=<same ID>;POST /sites/<site>/devicesand a JSON body withdeviceId,kind: "hub",enc(43 characters) andciphertext(64 characters), thenpost it, then press Enter ….
-
POSTthe printed body to/sites/<site>/devicesas an Administrator of the Site. The Server answers 201. Press Enter within 300 s (the session's idle timeout). - The client prints
wifi result CONNECTEDand exits 0. - The Hub logs
setup provisioned, with no SSID, password or Site on the line. - The BLE connection survived the Wi-Fi scan and the join while both radios shared the chip:
the client received the scan list and
CONNECTEDover the same connection, so a completed run is the evidence. - Right after, in the same boot,
cfsetup scanno longer finds the Hub: advertising stopped at provisioning. - The next line is
heap free=… used=… min_free=…. Recordmin_freein the Result table. Pass: at least 32768 (32 KiB): the lowest point covers BLE, Wi-Fi and the Server check's TLS connection at once. Theuptimelines repeatheap_min_free=once a minute; it must stay at or above 32768. - Optional: a wrong password in a first run gives
wifi result WRONG_PASSWORD; nothing is stored (a reset still shows the code). A second run with the right password givesCONNECTED. - Optional: skip the
POST(press Enter at once, with a fresh Hub the Server does not know). The client printswifi result NO_SERVERand exits non-zero; the Hub left the network and stored nothing (a reset still shows the code).POSTthe body, run again with--enrolled yes:CONNECTED.
After CONNECTED the session refuses further Wi-Fi configuration, and the provisioned Hub stops
advertising, so run these first, or after erasing cf_setup again.
-
--ssid <a WPA3-only network>giveswifi result UNSUPPORTED_SECURITY, and the Hub does not try to join. -
--ssid <an SSID that is not in range>giveswifi result NETWORK_NOT_FOUND.
- Reset the board after Part D.
- The boot shows the identity line and
setup provisioned earlier; not advertising, then re-joins its Wi-Fi and heartbeats (uplink checklist, Part E). - No
setup code=line appears. -
cfsetup scanno longer lists the Hub. - To set the Hub up again, erase
cf_setup(espflash erase-region 0xC000 0x2000): the next boot draws a new code.
Story 3.5 stores a version 2 provisioning record with the Server address. A version 1 record from a Story 3.4 setup has none, so the new firmware does not use it.
- Flash the Story 3.5 firmware onto a Hub provisioned by Story 3.4 firmware, without erasing.
- The boot logs
corrupt provisioning record, then the samesetup code=line as before andble advertising setup service …: the Hub counts as unprovisioned and keeps its code. - Set it up again with Part D, now with
--server.
| Date | Board | Build | Part | Pass / fail | Device ID | Heap min free after setup (bytes) | Notes |
|---|---|---|---|---|---|---|---|