igloo
Docs / igloohome / BLE SDK / Sync

Sync

Synchronize device state via Bluetooth.


sync

Syncs the lock via Bluetooth: sets the lock's internal clock, retrieves battery level, uploads activity logs, and updates the device on the server.

Signature

suspend fun sync(
    deviceId: String,
    key: String,
    timeInSeconds: Long? = null,
    getDeviceToken: String,
    storeLogsToken: String,
    updateDeviceToken: String,
    operationId: Int? = null,
): SyncResult
@available(*, deprecated, message: "Use `syncWithStatus` instead")
func sync(
    _ deviceId: String,
    key: String,
    getDeviceToken deviceToken: String,
    storeLogsToken storeToken: String,
    updateDeviceToken updateToken: String,
    timeInSeconds time: Int? = nil
) async throws -> SyncResult

Parameters

Name Type Required Description
deviceId String Yes Bluetooth device name of the lock.
key String Yes Guest key with GET_TIME, SET_TIME, GET_BATTERY_LEVEL, GET_LOGS permissions.
timeInSeconds Long? No Unix timestamp (seconds) to set on the lock. If omitted, SDK uses last server time.
getDeviceToken String Yes OAuth access token for fetching device info.
storeLogsToken String Yes OAuth access token for uploading activity logs.
updateDeviceToken String Yes OAuth access token for updating device state on the server.
operationId Int? No Operation ID for tracking.

Return Type

data class SyncResult(val batteryLevel: Int)
public struct SyncResult: Sendable {
    public let batteryLevel: Int
}
Field Description
batteryLevel Battery level as percentage (0-100).

Error Codes

Exception Code Description
BluetoothException 708 Bluetooth is off or unavailable.
ConnectionException 12 Device disconnected during sync.
TimeoutException 703 BLE operation exceeded the timeout.
ApiException varies Activity log upload or device update failed.

Example

try {
    val result = sdk.sync(
        deviceId = "IGM4-XXXX",
        key = guestKey,
        getDeviceToken = accessToken,
        storeLogsToken = accessToken,
        updateDeviceToken = accessToken,
    )
    println("Battery: ${result.batteryLevel}%")
} catch (e: IglooHomeException.ConnectionException) {
    showError("unexpected bluetooth connection issue")
} catch (e: IglooHomeException.TimeoutException) {
    showError("Timed out, try again")
} catch (e: IglooHomeException) {
    showError("Sync failed: ${e.message}")
}
// Deprecated on iOS — prefer syncWithStatus below.
do {
    let result = try await sdk.sync(
        "IGM4-XXXX",
        key: guestKey,
        getDeviceToken: accessToken,
        storeLogsToken: accessToken,
        updateDeviceToken: accessToken)
    print("Battery: \(result.batteryLevel)%")
} catch {
    showError(message: "Sync failed: \(error.localizedDescription)")
}

Notes

  • Sync reads all pending activity logs from the lock in a loop until no more remain.
  • Logs are stored in a local database first, then batch-uploaded to the server.
  • If timeInSeconds is omitted and no cached server time is available, the lock time is not updated.
  • The three token parameters (getDeviceToken, storeLogsToken, updateDeviceToken) can be the same token if it has all required scopes, or different tokens with scoped permissions.

syncWithStatus

Syncs the lock via Bluetooth and emits granular status updates for each sync operation. Useful for showing per-step progress in the UI.

Signature

fun syncWithStatus(
    deviceId: String,
    key: String,
    timeInSeconds: Long? = null,
    getDeviceToken: String,
    storeLogsToken: String,
    updateDeviceToken: String,
    operationId: Int? = null,
): Flow<SyncResultStatus>
func syncWithStatus(
    _ deviceId: String,
    key: String,
    getDeviceToken deviceToken: String,
    storeLogsToken storeToken: String,
    updateDeviceToken updateToken: String,
    timeInSeconds time: Int? = nil
) -> AsyncStream<SyncResultStatus>

Parameters

Name Type Required Description
deviceId String Yes Bluetooth device name of the lock.
key String Yes Guest key with GET_TIME, SET_TIME, GET_BATTERY_LEVEL, GET_LOGS permissions.
timeInSeconds Long? No Unix timestamp (seconds) to set on the lock. If omitted, SDK uses last server time.
getDeviceToken String Yes OAuth access token for fetching device info.
storeLogsToken String Yes OAuth access token for uploading activity logs.
updateDeviceToken String Yes OAuth access token for updating device state on the server.
operationId Int? No Operation ID for tracking.

Return Type

data class SyncResultStatus(
    val operation: Operation,
    val isSuccess: Boolean,
    val error: IglooHomeException?,
) {
    enum class Operation {
        SET_TIME,
        GET_BATTERY_LEVEL,
        SYNC_ACTIVITY_LOGS,
    }
}
public struct SyncResultStatus: Sendable {
    public enum Operation: Sendable {
        case SET_TIME
        case GET_BATTERY_LEVEL
        case SYNC_ACTIVITY_LOGS
    }
    public let operation: SyncResultStatus.Operation
    public let isSuccess: Bool
    public let error: Error?
}
Field Description
operation The sync sub-operation that completed.
isSuccess true if the operation succeeded.
error The exception if the operation failed, null on success.

Example

try {
    sdk.syncWithStatus(
        deviceId = "IGM4-XXXX",
        key = guestKey,
        getDeviceToken = accessToken,
        storeLogsToken = accessToken,
        updateDeviceToken = accessToken,
    ).collect { status ->
        val label = when (status.operation) {
            SyncResultStatus.Operation.SET_TIME -> "Set time"
            SyncResultStatus.Operation.GET_BATTERY_LEVEL -> "Battery level"
            SyncResultStatus.Operation.SYNC_ACTIVITY_LOGS -> "Activity logs"
        }
        if (status.isSuccess) {
            println("$label: OK")
        } else {
            println("$label: FAILED — ${status.error?.message}")
        }
    }
} catch (e: IglooHomeException.ConnectionException) {
    showError("unexpected bluetooth connection issue")
} catch (e: IglooHomeException.BluetoothException) {
    showError("Please enable Bluetooth")
} catch (e: IglooHomeException) {
    showError("Sync failed: ${e.message}")
}
for await status in sdk.syncWithStatus(
    "IGM4-XXXX",
    key: guestKey,
    getDeviceToken: accessToken,
    storeLogsToken: accessToken,
    updateDeviceToken: accessToken
) {
    let label: String
    switch status.operation {
    case .SET_TIME: label = "Set time"
    case .GET_BATTERY_LEVEL: label = "Battery level"
    case .SYNC_ACTIVITY_LOGS: label = "Activity logs"
    }
    if status.isSuccess {
        print("\(label): OK")
    } else {
        print("\(label): FAILED — \(status.error?.localizedDescription ?? "unknown")")
    }
}

Notes

  • Each SyncResultStatus emission represents one completed sub-operation.
  • Unlike sync(), individual operation failures do not throw — they are reported via isSuccess = false and error.
  • The flow emits one status per operation in order: SET_TIME, GET_BATTERY_LEVEL, SYNC_ACTIVITY_LOGS.
  • Use this method when you need to show per-step progress or handle partial sync failures gracefully.
  • iOS doc comment notes: the stream finishes on the first failure, and battery level is not pushed to the server for Switch-type devices.