Local Wi-Fi configuration¶
Local configuration¶
Set the password for the ears' own AP from either phone app under Settings → Wi-Fi, or Set up recovery Wi-Fi in recovery. Pair over bonded BLE with a fresh headset click; enter 8–63 printable ASCII characters or generate a password. Blank NVS starts without an AP password and can be provisioned this way. Recovery can also accept a normal app directly over BLE without Wi-Fi setup.
A private Espurr cat ears → Private configuration AP password menuconfig value remains an optional fallback; keep generated configs/passwords private. The separate versioned AP record overrides legacy settings and private defaults. The browser has no password editor. Passwords are stored in NVS, omitted from public JSON/logs and not saved by the provisioning UI. NVS is not encrypted. See the storage contract.
With a valid effective password (saved NVS settings take precedence over Kconfig),
triple-click on a single-button profile, or hold v2 button 1 for five seconds,
to switch between BLE control and Wi-Fi configuration. Boot-held recovery also requests Wi-Fi.
After a boot hold, release and make the next press a five-second hold to run LED
diagnostics while keeping the AP available. A shorter first press cancels that sequence.
Join WPA2 AP espurr-XXXXXX, then open
http://192.168.4.1/. The page is embedded and works without internet. No mDNS or
captive-portal discovery is required. Wi-Fi is initialized on first configuration use
and stopped on exit. The AP closes after five minutes with no associated Wi-Fi client
by default (remote.timeout_s, editable on phone). It stays open while any client is connected,
even with the browser closed; after the last disconnect, a fresh timeout begins.
HTTP polling does not reset that timer. Active OTA suspends expiration and a failed
upload gets a fresh window once the transfer ends and no client remains. LED/motion
operation continues while configuring. Radio initialization briefly clears/pauses the
ears to avoid flash-sensitive RMT activity.
Failed AP teardown retains exclusive Wi-Fi ownership and retries on the supervisor's existing 250 ms cycle. HTTP must stop before Wi-Fi; once HTTP stops successfully, only Wi-Fi shutdown is retried. BLE and a new AP entry wait until cleanup completes. A configuration request during incomplete teardown does not cancel cleanup; request configuration again after it completes. Active OTA prevents closure, including retries.
Apply & Save validates the entire submission before applying it. Runtime application and NVS save failures are distinct: a save failure may leave a new setting active but unsaved, explicitly shown as applied/save failed. Button changes coalesce after ten idle seconds. Stored records use a split storage layout: controls, saved palettes, calibration and hardware are compared/written separately, with a final marker selecting one coherent snapshot. Legacy records migrate on their next save. JSON import/export remains schema 22; the NVS selection marker is schema 23. Calibration is bound to the target, sensor, bus pins and address; a different identity clears calibration while preserving other settings. Older calibration is attributed to the original Atom MPU6886 bus. Version 1 records migrate in memory, inferring long-edge length from a 2:1 ratio (18 becomes 12+6), while preserving saved directions, colours, credentials and matching-IMU calibration. Version 2 records also load; missing background fields use defaults. Version 4 settings already use normalised controls; missing dithering defaults to the new Kconfig setting. Versions 1–3 stored physical brightness percentages. Migration converts both controls directly to the current 100% ceiling: 20% main remains 20%, and 2% background remains 2%. Schema 4–7 controls use the former 40% ceiling; schema 8–12 use 80%. Migration preserves requested PWM within 0.5 percentage points. Main 0% suppresses the foreground; an independently configured background can remain visible. The power switch turns both layers off. The new record is written on the next settings save. Missing/corrupt fields default safely, and older firmware will not overwrite an unknown newer schema during rollback. No automatic whole-NVS erase occurs.
runtime owns the render/output task, 50 Hz effect calculations, LED reconfiguration/transmission and settings writes.
The IMU owner publishes a latest sample; input and transport callbacks submit work
to the owners. NVS writes happen between completed LED transactions, holding the latched
frame briefly. Radio initialization, OTA writes and rollback metadata use a render pause
with black output (OTA may latch progress between completed writes). settings, input, imu, effects, web, ota and ble contain
their respective logic; main starts them and performs the boot health check.
The JSON API accepts bodies up to 4096 bytes, with bounded nesting and strict types, ranges, known fields and duplicate-key rejection. Browser writes require the local AP origin and the exact content type below. There are no CORS permissions.
| Endpoint | Behaviour |
|---|---|
GET /api/catalogue |
immutable catalogue JSON and hash header |
GET /api/settings |
coherent catalogue values, state revision and catalogue hash |
PUT /api/settings |
sparse named-control patch plus catalogue hash; apply/save result; application/json |
GET /api/status |
motion, current estimate, heap, frame count, settings/OTA status |
POST /api/control |
JSON action: exit or reboot |
POST /api/ota |
raw application binary; application/octet-stream |
The page fetches the catalogue once on load, renders common controls and parameters
for the selected effect, then sends only edited values on Apply & Save. PUT bodies
are {"catalogue_hash":"...","values":{"brightness":15,"power":true}}.
A stale hash is refused; application and save success are separate fields. Full-settings
JSON remains an NVS format, independent of this HTTP API. Palette libraries, overlays,
calibration, topology, output tuning and large diagnostics are configured on phone.
The browser computes no SHA-256 and keeps no persistent descriptor cache.