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) <noreply@anthropic.com>
This commit is contained in:
Schwifty 2026-03-23 00:48:09 +00:00
parent 61862adfa8
commit 8f8fcba9c0

View file

@ -634,9 +634,15 @@ struct ScanView: View {
Task { @MainActor [weak self] in Task { @MainActor [weak self] in
let reason = error?.localizedDescription ?? "beacon timed out" let reason = error?.localizedDescription ?? "beacon timed out"
provisionLog?.log("disconnect", "Unexpected disconnect: \(reason)", isError: true) provisionLog?.log("disconnect", "Unexpected disconnect: \(reason)", isError: true)
// If we're in any active provisioning state, show failure guard let self = self else { return }
if let self = self, // DXSmart: disconnect during .connected is expected beacon keeps
self.provisioningState == .connecting || self.provisioningState == .connected || // 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 == .writing || self.provisioningState == .verifying {
self.provisioningState = .failed self.provisioningState = .failed
self.errorMessage = "Beacon disconnected: \(reason)" self.errorMessage = "Beacon disconnected: \(reason)"
@ -718,6 +724,15 @@ struct ScanView: View {
statusMessage = "Writing config to DX-Smart…" statusMessage = "Writing config to DX-Smart…"
do { 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) try await provisioner.writeConfig(config)
provisioner.disconnect() provisioner.disconnect()