Compare commits
No commits in common. "5678256356aa740d584ae9b515c4a67dc3befc24" and "b88dded928cbcaac83215c4363d99824a358573d" have entirely different histories.
5678256356
...
b88dded928
4 changed files with 14 additions and 43 deletions
|
|
@ -172,30 +172,14 @@ final class DXSmartProvisioner: NSObject, BeaconProvisioner {
|
||||||
|
|
||||||
for (index, (name, packet)) in commands.enumerated() {
|
for (index, (name, packet)) in commands.enumerated() {
|
||||||
await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) (\(packet.count) bytes)")
|
await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) (\(packet.count) bytes)")
|
||||||
|
|
||||||
// Retry each command up to 2 times — beacon BLE stack can be flaky after KBeacon fallback
|
|
||||||
var lastError: Error?
|
|
||||||
for writeAttempt in 1...2 {
|
|
||||||
do {
|
do {
|
||||||
try await writeToCharAndWaitACK(writeChar, data: packet, label: name)
|
try await writeToCharAndWaitACK(writeChar, data: packet, label: name)
|
||||||
lastError = nil
|
|
||||||
break
|
|
||||||
} catch {
|
} catch {
|
||||||
lastError = error
|
await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) FAILED: \(error.localizedDescription)", isError: true)
|
||||||
if writeAttempt == 1 {
|
throw error
|
||||||
await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) retry after: \(error.localizedDescription)")
|
|
||||||
try await Task.sleep(nanoseconds: 500_000_000) // 500ms before retry
|
|
||||||
}
|
}
|
||||||
}
|
// 200ms between commands (matches Android SDK timer interval)
|
||||||
}
|
try await Task.sleep(nanoseconds: 200_000_000)
|
||||||
if let lastError {
|
|
||||||
await diagnosticLog?.log("write", "[\(index + 1)/\(commands.count)] \(name) FAILED: \(lastError.localizedDescription)", isError: true)
|
|
||||||
throw lastError
|
|
||||||
}
|
|
||||||
|
|
||||||
// 500ms between commands — beacon needs time to process, especially after
|
|
||||||
// prior KBeacon auth attempts that may have stressed the BLE stack
|
|
||||||
try await Task.sleep(nanoseconds: 500_000_000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,9 +320,7 @@ final class DXSmartProvisioner: NSObject, BeaconProvisioner {
|
||||||
// Step 2: Auth password — fire and forget
|
// Step 2: Auth password — fire and forget
|
||||||
if let authData = Self.defaultPassword.data(using: .utf8) {
|
if let authData = Self.defaultPassword.data(using: .utf8) {
|
||||||
peripheral.writeValue(authData, for: ffe3, type: .withoutResponse)
|
peripheral.writeValue(authData, for: ffe3, type: .withoutResponse)
|
||||||
// 500ms settle after auth — beacon needs time to enter config mode,
|
try await Task.sleep(nanoseconds: 100_000_000) // 100ms settle
|
||||||
// especially if BLE stack was stressed by prior provisioner attempts
|
|
||||||
try await Task.sleep(nanoseconds: 500_000_000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,6 @@ final class FallbackProvisioner: BeaconProvisioner {
|
||||||
provisioner.disconnect()
|
provisioner.disconnect()
|
||||||
lastError = error
|
lastError = error
|
||||||
await diagnosticLog?.log("fallback", "\(typeNames[index]) failed: \(error.localizedDescription)", isError: true)
|
await diagnosticLog?.log("fallback", "\(typeNames[index]) failed: \(error.localizedDescription)", isError: true)
|
||||||
// 2s cooldown between provisioner attempts — let the beacon's BLE stack recover
|
|
||||||
// from failed auth/connection before the next provisioner hammers it
|
|
||||||
if index < provisioners.count - 1 {
|
|
||||||
await diagnosticLog?.log("fallback", "Cooling down 2s before next provisioner…")
|
|
||||||
try? await Task.sleep(nanoseconds: 2_000_000_000)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,12 @@ final class KBeaconProvisioner: NSObject, BeaconProvisioner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Known passwords (tried in order, matching Android)
|
// MARK: - Known passwords (tried in order, matching Android)
|
||||||
// Known KBeacon default passwords (tried in order)
|
|
||||||
// Note: password 5 was previously a duplicate of password 3 — replaced with "000000" (6-char variant)
|
|
||||||
private static let passwords: [Data] = [
|
private static let passwords: [Data] = [
|
||||||
"kd1234".data(using: .utf8)!, // KBeacon factory default
|
"kd1234".data(using: .utf8)!,
|
||||||
Data(repeating: 0, count: 16), // Binary zeros (16 bytes)
|
Data(repeating: 0, count: 16),
|
||||||
Data([0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x31,0x32,0x33,0x34,0x35,0x36]), // "1234567890123456"
|
Data([0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30,0x31,0x32,0x33,0x34,0x35,0x36]),
|
||||||
"0000000000000000".data(using: .utf8)!, // ASCII zeros (16 bytes)
|
"0000000000000000".data(using: .utf8)!,
|
||||||
"000000".data(using: .utf8)!, // Short zero default (6 bytes)
|
"1234567890123456".data(using: .utf8)!
|
||||||
]
|
]
|
||||||
|
|
||||||
// MARK: - State
|
// MARK: - State
|
||||||
|
|
|
||||||
|
|
@ -201,10 +201,7 @@ actor APIClient {
|
||||||
guard resp.OK else {
|
guard resp.OK else {
|
||||||
throw APIError.serverError(resp.MESSAGE ?? resp.ERROR ?? "Failed to allocate minor")
|
throw APIError.serverError(resp.MESSAGE ?? resp.ERROR ?? "Failed to allocate minor")
|
||||||
}
|
}
|
||||||
guard let minor = resp.BeaconMinor, minor > 0 else {
|
return resp.BeaconMinor ?? 0
|
||||||
throw APIError.serverError("API returned invalid minor value: \(resp.BeaconMinor ?? 0). Service point may not be configured correctly.")
|
|
||||||
}
|
|
||||||
return minor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// API returns: { "OK": true, "BeaconHardwareID": 42, ... }
|
/// API returns: { "OK": true, "BeaconHardwareID": 42, ... }
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue