Docs / iglooworks / BLE SDK / Sync & Jobs
Sync & Jobs
Synchronize device state and execute pending jobs.
sync
Syncs the lock via Bluetooth: sets the lock's internal clock, retrieves battery level, and uploads activity logs to the server.
Signature
suspend fun sync(
deviceId: String,
key: String,
timeInSeconds: Long? = null,
accessToken: String? = null,
operationId: Int? = null,
): SyncResult
func sync(
_ deviceId: String,
key: String,
timeInSeconds time: Int? = nil,
syncToken token: String? = 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. |
accessToken |
String? |
OAuth only |
OAuth access token for uploading activity logs. |
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 failed. |
Example
try {
val result = sdk.sync(
deviceId = "IGM4-XXXX",
key = guestKey,
)
println("Battery: ${result.batteryLevel}%")
} catch (e: IglooWorksException.ConnectionException) {
showError("unexpected bluetooth connection issue")
} catch (e: IglooWorksException.TimeoutException) {
showError("Timed out, try again")
} catch (e: IglooWorksException) {
showError("Sync failed: ${e.message}")
}
do {
let result = try await sdk.sync(
"IGM4-XXXX",
key: guestKey)
print("Battery: \(result.batteryLevel)%")
} catch LockManagerError.deviceDisconnected {
showError(message: "unexpected bluetooth connection issue")
} 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.
syncJob
Executes pending jobs (created via the API or IglooWorks Dashboard) on the lock. Results are emitted as a Flow — one SyncJobResult per job.
Supported job types: CREATE_PIN, DELETE_PIN, ADD_GROUP_KEY, DELETE_GROUP_KEY.
Signature
fun syncJob(
deviceId: String,
key: String,
jobIds: List<String>? = null,
accessToken: String?,
): Flow<SyncJobResult>
func syncJobs(
_ jobIds: [String] = [],
from deviceId: String,
key: String,
syncJobToken token: String? = nil
) async -> AsyncThrowingStream<SyncJobResult, Error>
Parameters
| Name |
Type |
Required |
Description |
deviceId |
String |
Yes |
Bluetooth device name of the lock. |
key |
String |
Yes |
Guest key with CREATE_PIN, DELETE_PIN, ADD_GROUP_KEY, DELETE_GROUP_KEY permissions. |
jobIds |
List<String>? |
No |
Specific job IDs to execute. If null, all pending jobs are fetched and executed. |
accessToken |
String? |
OAuth only |
OAuth access token for API calls. |
Return Type
data class SyncJobResult(
val jobId: String,
val jobType: String,
val status: JobStatus,
val remainingJobs: Int,
val reason: IglooWorksException? = null,
)
public struct SyncJobResult: Codable, Sendable {
public let jobId: String
public let jobType: String
public let status: SyncJobStatus
public let remainingJobs: Int
public var reason: String? = nil
}
public enum SyncJobStatus: String, Codable, Sendable {
case success = "success"
case failed = "failed"
case pending = "pending"
}
| Field |
Description |
jobId |
Server-assigned job identifier. |
jobType |
Job description string (e.g. "CREATE_PIN"). |
status |
COMPLETE, FAILED, or PENDING. |
remainingJobs |
Number of jobs remaining after this one. |
reason |
Exception if the job failed or was left pending (e.g. timeout). |
Error Codes
| Exception |
Code |
Description |
ApiException |
varies |
API call failed when fetching or updating job status. |
GenericException |
1 |
Unhandled error. |
Example
try {
sdk.syncJob(
deviceId = "IGM4-XXXX",
key = guestKey,
accessToken = token,
).collect { result ->
println("Job ${result.jobId}: ${result.status} (${result.remainingJobs} remaining)")
if (result.status == JobStatus.FAILED) {
println(" Reason: ${result.reason?.message}")
}
}
} catch (e: IglooWorksException.ApiException) {
showError("Server error: ${e.message}")
} catch (e: IglooWorksException) {
showError("Sync jobs failed: ${e.message}")
}
for try await result in await sdk.syncJobs(
from: "IGM4-XXXX",
key: guestKey,
syncJobToken: token
) {
print("Job \(result.jobId): \(result.status.rawValue) (\(result.remainingJobs) remaining)")
if result.status == .failed {
print(" Reason: \(result.reason ?? "unknown")")
}
}
Notes
- Jobs already marked
COMPLETE or FAILED on the server are emitted as-is without re-execution.
- If a BLE operation fails with
TimeoutException, ConnectionException, or BluetoothException, the job is left as PENDING (not marked failed on the server).
DuplicatePinException during CREATE_PIN is treated as success (job marked COMPLETE).
PinNotFoundException during DELETE_PIN is treated as success (PIN already removed).
- On iOS the method is named
syncJobs (plural), takes job IDs as the first positional parameter (_ jobIds: [String] = [], empty means "all pending"), and reason on SyncJobResult is a plain String?, not an Error/exception type.