# PineVoice WiFi Setup Tool Local Improv-BLE provisioning page for the Pine64 PineVoice smart speaker. Serves from localhost so Web Bluetooth works and no VPN/proxy can interfere. ## Run ```sh python3 -m http.server 8377 --bind 127.0.0.1 -d ~/Projects/pine ``` Then open in Chrome (needs Web Bluetooth — Chrome/Edge, not Safari/Firefox). ## Use 1. Put the speaker in provisioning mode: ring LED blinking yellow (hold the • dot button 15 s to reset if needed). 2. Enter SSID + password, click **Connect PineVoice**, pick *PineVoice* in the Bluetooth chooser. 3. If the log says *authorization required*, **press the centre button** on the speaker. The page waits for this and only sends credentials once the device reports `authorized`. Authorization lapses after ~1 min, so don't linger. 4. Success: log shows `✓ PROVISIONED`, speaker plays a chime, LED breathes dim magenta. Failure: speaker plays a failure sound within ~20 s and the log shows the reason. ## After WiFi: add to Home Assistant Settings → Devices & services → discovered **Wyoming Protocol** device → Configure. If not auto-discovered: Add integration → Wyoming Protocol → host = speaker IP, port `10700`. Requires an Assist pipeline with Whisper (STT) and Piper (TTS). Wake word: "Hey Jarvis", or press the center button. ## The gotchas this tool fixes **Authorization ordering.** Per the [Improv BLE spec](https://www.improv-wifi.com/ble/), a device in `AUTHORIZATION_REQUIRED` (`0x01`) rejects a `WIFI_SETTINGS` RPC with error `0x04`. The client must wait for the state to become `AUTHORIZED` (`0x02`) — i.e. for the physical button press — before writing. Sending immediately looks like a successful write (the device ACKs the GATT write) but provisioning never starts. **Write-with-response.** The PineVoice firmware declares its Improv RPC characteristic as write-WITH-response only (`GATT_CHRC_PROP_WRITE` in `pinevoice_fw_e907/app/src/improv/improv.c`). Anything that sends credentials as an unacknowledged BLE Write Command is **silently ignored** — no error, no state change. This page uses `writeValueWithResponse` explicitly. Firmware source: