BLE provisioning used protocomm Security1 with the device serial
number as proof-of-possession, on the reasoning that pairing should
require reading something off the physical unit. In practice the
companion app has no easy way to read that serial without a manual
step, so it was deriving the PoP from the BLE advertising name
instead (DigiRadio-XXXX -> XXXX) -- but that name is broadcast openly
to any scanner, so it was never actually secret. The PoP added
app/firmware coupling (an exact-match string derived independently on
both sides) without adding real secrecy, and a mismatch there was
silently blocking provisioning entirely. Switched to Security0 (no
PoP, no encryption) -- the same trust level as the SoftAP setup path
this runs alongside, which is already an open network.
Separately, bumped the nvs partition from 24 KiB to 64 KiB. The small
original size was a suspected contributor to intermittent
NvsAudioProfileStore::saveProfile() store_failed under this project's
accumulated write traffic (wifi creds, station_list,
audio_profile_json, last_preset) -- flagged but not applied in an
earlier commit today. otadata/nvs_keys/phy_init shift forward to make
room; they still fit before ota_0's existing 64 KiB alignment
boundary, so ota_0/ota_1/dsp stay at their original offsets. Applied
via idf.py erase-flash flash (required whenever partition offsets
move) and verified: fresh boot enters SoftAP + BLE setup mode with no
partition-table warnings, and the previously-saved FM ANTCAP
calibration (stored in the 24AA025E48 EEPROM, unaffected by the NVS
partition change) still applies automatically after re-provisioning
Wi-Fi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR
Wraps ESP-IDF's official wifi_provisioning manager (BLE transport,
protocomm Security1, NimBLE host) so a phone can join the device to
Wi-Fi over the ESP32-S3's own onboard BLE radio, without first
connecting to the 192.168.4.1 SoftAP. Chosen over a custom GATT
service specifically so the existing generic "ESP BLE Provisioning"
iOS/Android apps work today, before the dedicated DigiRadio app
exists — same standard protocol either app would speak.
net::ble_provisioning::start() is additive, not a replacement: it
runs next to the current SoftAP + POST /api/wifi HTTP route inside
NetBootstrap's startSetupMode(), and failing to start it is
non-fatal (same pattern already used there for the SigmaStudio TCP
bridge) — SoftAP setup keeps working either way. Proof-of-possession
is the device's own serial number (same source as the SoftAP SSID),
so pairing requires reading it off the unit rather than being wide
open. On WIFI_PROV_CRED_SUCCESS the received wifi_sta_config_t is
converted to the same core::WifiCredentials type the HTTP handler
uses and saved through the same ISecureStore, then the device
reboots into STA mode — one persistence path regardless of which
transport provisioned it.
BT1035 is unaffected: it's a separate UART-attached classic
Bluetooth module for A2DP output. This uses the ESP32-S3's
independent internal BLE controller, switched to NimBLE (smaller
footprint than Bluedroid, the only host stack needed for a single
peripheral-role GATT service). App binary still has 33% free flash
after pulling in wifi_provisioning/protocomm/NimBLE.
Verified: idf.py build, doxygen (0 warnings), check-manual-sync,
check_si4684_blobs, ctest (19/19) all green. Not yet tested with a
real BLE provisioning app or on hardware — board is disconnected
this session.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR