Problem / motivation
There used to be an "auf Original zurücksetzen" button per speaker. It was removed when SixBack became the only viable cloud — the Bose cloud is offline since 2026-05-06, so reverting envswitch boseurls to the original Bose URL is no longer meaningful (it would just point the speaker at a dead endpoint).
But a useful form of "back to original" is still possible: restoring the pre-migration preset state on the speaker, while keeping SixBack as the cloud. This is a recovery path for users who have inadvertently overwritten or lost presets while experimenting with SixBack.
Asked indirectly by @fred_feuerstein in the FHEM forum thread: "Aber kann es sein, dass man anfangs die Lautsprecher wieder auf 'original' zurücksetzen konnte und das aktuell in SixBack nicht mehr per 'Knopf' geht?"
What is already there
SixBack already captures and persists everything needed for a restore, locally on the ESP:
- During first migrate,
auto_mode.cpp:292 sets setState_("pre-migrate-snapshot") and writes a JSON snapshot via speaker_diagnostic.cpp
- Storage: local LittleFS
/snapshots/<dev>.json, rotated as .prev.json, .prev2.json (see speaker_diagnostic.cpp:78)
- Snapshot content (verified on a real sample,
snapshot_kind: "pre_migrate"):
speaker.{device_id, ip, name, model, firmware, cloud_url}
bmx.presets ← all 6 slots, complete pre-migration ContentItems
bmx.sources ← sources.xml including STORED_MUSIC (DLNA)
bmx.{now_playing, getZone, getGroup, listMediaServers, sourceServiceList}
telnet.getpdo_currentsystemconfiguration
- Existing read endpoint:
GET /api/speaker/{id}/diagnostic-snapshot (api_endpoints.cpp:2065+) — exposes both live and stored snapshots
What is missing
No restore code path exists. Grep for restoreSnapshot|restorePreset|/restore in src/ returns zero. Snapshots are read-only today.
Proposed solution
- Backend: new
POST /api/speaker/{id}/restore-pre-migration
- Reads
/snapshots/<dev>.json (or .prev.json if a newer post-migration snapshot has already overwritten it)
- For each of the 6 slots, extracts
bmx.presets[N].ContentItem
- Pushes through the existing
doPush_ pipeline (same path as the manual push-to-device button)
- OPAQUE / DLNA slots use the same
rawContentItem passthrough that is already wired
- UI: per-speaker card →
⏮ Restore pre-migration button (only enabled when a snapshot_kind=pre_migrate snapshot is present locally). Confirm dialog with slot-by-slot diff before pushing.
- Out of scope for v1: rewriting
telnet.getpdo-based cloud URL (envswitch). Just preset state.
Alternatives considered
- Cross-speaker DLNA source transplant (Fred's actual underlying need: get STORED_MUSIC onto a virgin speaker by injecting another speaker's
bmx.sources): related but separate problem — source IDs are speaker-specific positional indices, not 1:1 transplantable. Separate experiment.
- "Back to Bose Cloud" button: pointless since the cloud is dead — would just brick the speaker against unreachable endpoints.
Acceptance
- A speaker that has lost a slot via SixBack edits can be restored to its pre-migration state with one button + confirm
- Works for TUNEIN, LOCAL_INTERNET_RADIO, and OPAQUE (DLNA) slots equivalently
- No regression on speakers without a pre-migration snapshot (button just disabled)
Problem / motivation
There used to be an "auf Original zurücksetzen" button per speaker. It was removed when SixBack became the only viable cloud — the Bose cloud is offline since 2026-05-06, so reverting
envswitch boseurlsto the original Bose URL is no longer meaningful (it would just point the speaker at a dead endpoint).But a useful form of "back to original" is still possible: restoring the pre-migration preset state on the speaker, while keeping SixBack as the cloud. This is a recovery path for users who have inadvertently overwritten or lost presets while experimenting with SixBack.
Asked indirectly by @fred_feuerstein in the FHEM forum thread: "Aber kann es sein, dass man anfangs die Lautsprecher wieder auf 'original' zurücksetzen konnte und das aktuell in SixBack nicht mehr per 'Knopf' geht?"
What is already there
SixBack already captures and persists everything needed for a restore, locally on the ESP:
auto_mode.cpp:292setssetState_("pre-migrate-snapshot")and writes a JSON snapshot viaspeaker_diagnostic.cpp/snapshots/<dev>.json, rotated as.prev.json,.prev2.json(seespeaker_diagnostic.cpp:78)snapshot_kind: "pre_migrate"):GET /api/speaker/{id}/diagnostic-snapshot(api_endpoints.cpp:2065+) — exposes both live and stored snapshotsWhat is missing
No restore code path exists. Grep for
restoreSnapshot|restorePreset|/restoreinsrc/returns zero. Snapshots are read-only today.Proposed solution
POST /api/speaker/{id}/restore-pre-migration/snapshots/<dev>.json(or.prev.jsonif a newer post-migration snapshot has already overwritten it)bmx.presets[N].ContentItemdoPush_pipeline (same path as the manual push-to-device button)rawContentItempassthrough that is already wired⏮ Restore pre-migrationbutton (only enabled when asnapshot_kind=pre_migratesnapshot is present locally). Confirm dialog with slot-by-slot diff before pushing.telnet.getpdo-based cloud URL (envswitch). Just preset state.Alternatives considered
bmx.sources): related but separate problem — source IDs are speaker-specific positional indices, not 1:1 transplantable. Separate experiment.Acceptance