diff --git a/PayfritBeacon/Views/ScanView.swift b/PayfritBeacon/Views/ScanView.swift index a259bf1..4210268 100644 --- a/PayfritBeacon/Views/ScanView.swift +++ b/PayfritBeacon/Views/ScanView.swift @@ -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(