From 972291e93b6cdd9077420b26a8522e44bee71151 Mon Sep 17 00:00:00 2001 From: Schwifty Date: Sun, 22 Mar 2026 04:28:52 +0000 Subject: [PATCH] fix: add pre-auth stabilization delay to prevent disconnect during authentication DX-Smart beacons drop the BLE connection when a password write (FFE3) arrives too quickly after service/characteristic discovery. The v2 refactor had a POST_AUTH_DELAY (1.5s) before writes, but nothing before the auth attempt itself. Adds PRE_AUTH_DELAY (0.8s) after characteristic discovery + FFE1 subscription before the first password write. This gives the beacon MCU time to stabilize after the discovery handshake. Co-Authored-By: Claude Opus 4.6 (1M context) --- PayfritBeacon/BeaconProvisioner.swift | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/PayfritBeacon/BeaconProvisioner.swift b/PayfritBeacon/BeaconProvisioner.swift index 8d101df..82617ba 100644 --- a/PayfritBeacon/BeaconProvisioner.swift +++ b/PayfritBeacon/BeaconProvisioner.swift @@ -198,7 +198,8 @@ class BeaconProvisioner: NSObject, ObservableObject { // Prevention > recovery: generous delays prevent supervision timeouts. private static let INTER_COMMAND_DELAY: Double = 0.5 private static let HEAVY_COMMAND_DELAY: Double = 1.0 // After frame select/type changes - private static let POST_AUTH_DELAY: Double = 1.5 // After auth, before first write + private static let PRE_AUTH_DELAY: Double = 0.8 // After discovery, before first auth write + private static let POST_AUTH_DELAY: Double = 1.5 // After auth, before first write // Readiness gate — don't start writing until we've confirmed all 3 chars private var requiredCharsConfirmed = false @@ -409,9 +410,13 @@ class BeaconProvisioner: NSObject, ObservableObject { DebugLog.shared.log("BLE: Subscribing to FFE1 notifications") peripheral?.setNotifyValue(true, for: characteristics[BeaconProvisioner.DXSMART_NOTIFY_CHAR]!) } else { - DebugLog.shared.log("BLE: FFE1 not found, proceeding to auth directly") + DebugLog.shared.log("BLE: FFE1 not found, proceeding to auth after stabilization delay") dxSmartNotifySubscribed = true - dxSmartAuthenticate() + // Same pre-auth delay even without FFE1 — beacon still needs time after discovery + DebugLog.shared.log("BLE: Waiting \(BeaconProvisioner.PRE_AUTH_DELAY)s before auth...") + DispatchQueue.main.asyncAfter(deadline: .now() + BeaconProvisioner.PRE_AUTH_DELAY) { [weak self] in + self?.dxSmartAuthenticate() + } } } @@ -1264,7 +1269,13 @@ extension BeaconProvisioner: CBPeripheralDelegate { if operationMode == .readingConfig { dxSmartReadAuth() } else { - dxSmartAuthenticate() + // Give the beacon a moment to stabilize after discovery + notification subscribe + // before we hit it with a password write. Without this, DX-Smart beacons drop + // the connection during auth (supervision timeout). + DebugLog.shared.log("BLE: Waiting \(BeaconProvisioner.PRE_AUTH_DELAY)s before auth...") + DispatchQueue.main.asyncAfter(deadline: .now() + BeaconProvisioner.PRE_AUTH_DELAY) { [weak self] in + self?.dxSmartAuthenticate() + } } } }