From 8f8fcba9c015adec07db9ee56be180b5bf77f287 Mon Sep 17 00:00:00 2001 From: Schwifty Date: Mon, 23 Mar 2026 00:48:09 +0000 Subject: [PATCH] fix: prevent DXSmart disconnect race killing the "Write Config" screen After DXSmart auth completes, the beacon often drops BLE connection due to aggressive timeouts. The disconnect handler was treating this as a failure, stomping the .connected state before the user could see the "Write Config" button. Changes: - Ignore BLE disconnects during .connected state for DXSmart beacons (the LED keeps flashing regardless of BLE connection) - Auto-reconnect in writeConfigToConnectedBeacon() if BLE dropped while waiting for user confirmation Co-Authored-By: Claude Opus 4.6 (1M context) --- PayfritBeacon/Views/ScanView.swift | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/PayfritBeacon/Views/ScanView.swift b/PayfritBeacon/Views/ScanView.swift index 6a02741..416e0ec 100644 --- a/PayfritBeacon/Views/ScanView.swift +++ b/PayfritBeacon/Views/ScanView.swift @@ -634,9 +634,15 @@ struct ScanView: View { Task { @MainActor [weak self] in let reason = error?.localizedDescription ?? "beacon timed out" provisionLog?.log("disconnect", "Unexpected disconnect: \(reason)", isError: true) - // If we're in any active provisioning state, show failure - if let self = self, - self.provisioningState == .connecting || self.provisioningState == .connected || + guard let self = self else { return } + // DXSmart: disconnect during .connected is expected — beacon keeps + // flashing after BLE drops. We'll reconnect when user taps Write Config. + if self.provisioningState == .connected && beacon.type == .dxsmart { + provisionLog?.log("disconnect", "DXSmart idle disconnect — beacon still flashing, ignoring") + return + } + // For all other active states, treat disconnect as failure + if self.provisioningState == .connecting || self.provisioningState == .connected || self.provisioningState == .writing || self.provisioningState == .verifying { self.provisioningState = .failed self.errorMessage = "Beacon disconnected: \(reason)" @@ -718,6 +724,15 @@ struct ScanView: View { statusMessage = "Writing config to DX-Smart…" do { + // Reconnect if the beacon dropped BLE during the "confirm flashing" wait + if !provisioner.isConnected { + provisionLog.log("write", "Beacon disconnected while waiting — reconnecting…") + statusMessage = "Reconnecting to beacon…" + try await provisioner.connect() + provisionLog.log("write", "Reconnected — writing config…") + statusMessage = "Writing config to DX-Smart…" + } + try await provisioner.writeConfig(config) provisioner.disconnect()