fix(setup): gate setup pair --mode=full on configuration status (#615)

A speaker can be reachable, named, and already account-paired yet still
report SOUNDTOUCH_NOT_CONFIGURED, leaving the "install the Bose app"
prompt on screen (reported for ST30 Series II/III in #615). Only a full
pass through the WebSocket setup state machine clears it, but running
that unconditionally risks re-running the bracket on speakers that
don't need or support it.

Add Manager.PreflightInitPlan: checks /supportedURLs for
/setMargeAccount, then requires /soundTouchConfigurationStatus to read
exactly SOUNDTOUCH_NOT_CONFIGURED before ExecuteInitPlan runs.
Already-configured devices are a no-op; an unsupported route or an
unrecognised status value aborts instead of guessing.
This commit is contained in:
Tobias Gesellchen
2026-08-17 21:29:39 +02:00
parent d873d88b4f
commit e57708ea11
6 changed files with 241 additions and 8 deletions
@@ -112,6 +112,14 @@ Factory-reset the same speaker again and run the full state machine — the same
This drives `setup.Manager.ExecuteInitPlan` with `SkipURLRewrite=true`, which runs:
> **Update (#615):** `--mode=full` now preflights via `Manager.PreflightInitPlan`
> before opening the WebSocket — it checks `/supportedURLs` for
> `/setMargeAccount` and requires `/soundTouchConfigurationStatus` to read
> `SOUNDTOUCH_NOT_CONFIGURED`, and no-ops on an already-configured device.
> A freshly factory-reset speaker (as in this experiment) reports
> `SOUNDTOUCH_NOT_CONFIGURED`, so the preflight passes through unchanged;
> see `docs/content/docs/reference/DEVICE-PAIRING-FLOW.md`.
```
SETUP_START
SETUP_IDENTIFY_DEVICE_ENTER
@@ -1427,6 +1427,15 @@ name during pairing (empty keeps current). `--language` defaults to `2`
(English). `--token` defaults to a built-in placeholder matching the Bose
app's token shape.
`--mode=full` first reads `/supportedURLs` and `/soundTouchConfigurationStatus`
and only runs the state machine when the device reports
`SOUNDTOUCH_NOT_CONFIGURED` (see [#615](https://github.com/gesellix/Bose-SoundTouch/issues/615):
a speaker can be reachable, named, and already account-paired yet still
report `SOUNDTOUCH_NOT_CONFIGURED`, leaving the "install the Bose app"
prompt on screen — only a full pass through the state machine clears it).
An already-configured device is a no-op; an unsupported route or an
unrecognised status value fails the command instead of guessing.
#### `setup sync`
Pulls presets, recents, and sources from the speaker into AfterTouch's
@@ -100,6 +100,20 @@ All subsequent messages (except `selectLastWiFiSource`, see below) use this enve
## Phase 2 — Pairing a New Speaker
> **Preflight (AfterTouch's `setup pair --mode=full`).** Before opening the
> WebSocket, AfterTouch reads `GET /supportedURLs` (must list
> `/setMargeAccount`) and `GET /soundTouchConfigurationStatus`, and only
> runs the state machine below when the status is exactly
> `SOUNDTOUCH_NOT_CONFIGURED`. This matters because a speaker can be
> reachable, named, and already have a `margeAccountUUID` set, yet still
> report `SOUNDTOUCH_NOT_CONFIGURED` — the firmware keeps prompting to
> install the Bose app until a full acknowledged pass through this state
> machine runs, not just `setMargeAccount` on its own. Already-configured
> devices are a no-op; an unsupported route or an unrecognised status value
> aborts without writing anything. See
> [#615](https://github.com/gesellix/Bose-SoundTouch/issues/615) and
> `Manager.PreflightInitPlan` (`pkg/service/setup/marge_pairing.go`).
### 2.1 Setup State Machine
The pairing flow uses a setup state machine on the device. States must be sent in order.