fix: treat post-SaveConfig disconnect as expected, not an error

After all 23 commands write successfully, the DX-Smart beacon reboots
to apply config — dropping the BLE connection. ScanView's disconnect
handler was racing the async writeConfig return and logging this as
"Unexpected disconnect: beacon timed out" even though provisioning
succeeded.

Added writesCompleted flag so the disconnect handler knows writes
finished and logs it as expected behavior instead of an error.
This commit is contained in:
Schwifty 2026-03-23 03:32:21 +00:00
parent 9ce7b9571a
commit a82a3697da

View file

@ -23,6 +23,7 @@ struct ScanView: View {
// Provisioning flow
@State private var selectedBeacon: DiscoveredBeacon?
@State private var provisioningState: ProvisioningState = .idle
@State private var writesCompleted = false
@State private var statusMessage = ""
@State private var errorMessage: String?
@State private var showQRScanner = false
@ -628,9 +629,17 @@ struct ScanView: View {
bleManager.onPeripheralDisconnected = { [weak provisionLog] peripheral, error in
if peripheral.identifier == beacon.peripheral.identifier {
DispatchQueue.main.async { [weak self] in
let reason = error?.localizedDescription ?? "beacon timed out"
provisionLog?.log("disconnect", "Unexpected disconnect: \(reason)", isError: true)
guard let self = self else { return }
let reason = error?.localizedDescription ?? "beacon timed out"
// Writes already finished beacon rebooted after SaveConfig, this is expected
if self.writesCompleted {
provisionLog?.log("disconnect", "Post-write disconnect (expected — beacon rebooted after save)")
return
}
provisionLog?.log("disconnect", "Unexpected disconnect: \(reason)", isError: true)
// CP-28: disconnect during .connected is expected beacon keeps
// flashing after BLE drops. We'll reconnect when user taps Write Config.
if self.provisioningState == .connected {
@ -674,6 +683,7 @@ struct ScanView: View {
let token = appState.token else { return }
provisioningState = .writing
writesCompleted = false
statusMessage = "Writing config to DX-Smart…"
do {
@ -687,6 +697,7 @@ struct ScanView: View {
}
try await provisioner.writeConfig(config)
writesCompleted = true
provisioner.disconnect()
try await APIClient.shared.registerBeaconHardware(