From 640bc32f9294f89f827b4c9d8a51b63b053d1a0b Mon Sep 17 00:00:00 2001 From: Schwifty Date: Mon, 23 Mar 2026 03:57:56 +0000 Subject: [PATCH] fix: use .withoutResponse for SaveConfig to prevent silent write drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The beacon reboots instantly on SaveConfig (0x60). Using .withResponse meant CoreBluetooth expected a GATT ACK that never arrived, potentially causing the write to be silently dropped — leaving the config unsaved and the beacon LED still flashing after provisioning. Switching to .withoutResponse fires the bytes directly into the BLE radio buffer without requiring a round-trip ACK. The beacon firmware processes the save command from its buffer before rebooting. Co-Authored-By: Claude Opus 4.6 (1M context) --- PayfritBeacon/Provisioners/DXSmartProvisioner.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/PayfritBeacon/Provisioners/DXSmartProvisioner.swift b/PayfritBeacon/Provisioners/DXSmartProvisioner.swift index 25214f2..ff3e66e 100644 --- a/PayfritBeacon/Provisioners/DXSmartProvisioner.swift +++ b/PayfritBeacon/Provisioners/DXSmartProvisioner.swift @@ -174,9 +174,12 @@ final class DXSmartProvisioner: NSObject, BeaconProvisioner { await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) (\(packet.count) bytes)") // SaveConfig (last command) causes beacon MCU to reboot — it never sends an ACK. - // Fire the BLE write and return immediately; the disconnect is expected. + // Use .withoutResponse so CoreBluetooth fires the bytes immediately into the + // BLE radio buffer without waiting for a GATT round-trip. With .withResponse, + // the beacon reboots before the ACK arrives, and CoreBluetooth may silently + // drop the write — leaving the config unsaved and the beacon still flashing. if name == "SaveConfig" { - peripheral.writeValue(packet, for: writeChar, type: .withResponse) + peripheral.writeValue(packet, for: writeChar, type: .withoutResponse) await diagnosticLog?.log("write", "✅ [\(index + 1)/\(commands.count)] SaveConfig sent — beacon will reboot") await diagnosticLog?.log("write", "✅ All commands written successfully") return