

# Pairing

Register and remove igloohome devices from your account.

---

## pair

Pairs an Igloo lock via Bluetooth and registers it on the server. Protocol (G2/G3) is auto-detected from the lock's firmware.

The SDK orchestrates the full flow: timezone resolution, DST data fetch, BLE handshake, server registration, and commit. If commit fails after server registration, the device is automatically rolled back (deleted from server).

### Signature

```kotlin
suspend fun pair(
    deviceId: String,
    name: String,
    propertyIds: List<String>,
    accessToken: String,
): PairResult
```

```swift
func pair(
    deviceId: String,
    lockName: String,
    propertyIds: [String],
    accessToken token: String
) async throws -> PairResult
```

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deviceId` | `String` | Yes | Bluetooth device name of the lock (e.g. `"SP2X01abc123"`). |
| `name` | `String` | Yes | User-assigned name for the lock. |
| `propertyIds` | `List<String>` | Yes | IDs of properties to assign this lock to. Must be non-empty. All properties must share the same timezone. |
| `accessToken` | `String` | Yes | OAuth access token for server calls. |

### Return Type

```kotlin
data class PairResult(
    val type: String,
    val deviceId: String,
    val name: String,
    val pairedAt: String,
    val properties: List<PairResultProperty>,
)

data class PairResultProperty(
    val name: String,
    val timezone: String,
    val id: String,
)
```

```swift
public struct PairResult: Sendable {
    public let type: String
    public let bluetoothDeviceName: String
    public let name: String
    public let pairedAt: String
    public let properties: [Property]
}

public struct Property: Sendable {
    public let name: String
    public let timezone: String
    public let id: String
}
```

### Error Codes

| Exception | Code | Description |
|-----------|------|-------------|
| `BluetoothException` | 708 | Bluetooth is off or unavailable. |
| `ConnectionException` | 12 | BLE connection failed or device disconnected during pairing. |
| `TimeoutException` | 703 | BLE operation exceeded the timeout. |
| `DevicePairedException` | 910 | Device is already paired (detected server-side or via BLE scan). |
| `ApiException` | varies | Server API call failed. |
| `GenericException` | 1 | Property IDs empty, timezone conflict, or unsupported protocol. |

### Example

```kotlin
try {
    val result = sdk.pair(
        deviceId = "SP2X01abc123",
        name = "Front Door Lock",
        propertyIds = listOf("prop-123"),
        accessToken = accessToken,
    )
    println("Paired: ${result.name} at ${result.pairedAt}")
    println("Properties: ${result.properties.map { it.name }}")
} catch (e: IglooHomeException.DevicePairedException) {
    showError("This lock is already paired")
} catch (e: IglooHomeException.HasLinkedDeviceException) {
    showError("Unlink accessories first: ${e.linkedDeviceIds}")
} catch (e: IglooHomeException) {
    showError("Pairing failed: ${e.message}")
}
```

```swift
do {
    let result = try await sdk.pair(
        deviceId: "SP2X01abc123",
        lockName: "Front Door Lock",
        propertyIds: ["prop-123"],
        accessToken: accessToken)
    print("Paired: \(result.name) at \(result.pairedAt)")
    print("Properties: \(result.properties.map(\.name))")
} catch IgloohomeError.devicePaired {
    showError(message: "This lock is already paired")
} catch IgloohomeError.hasLinkedDevice(let linkedDeviceIds) {
    showError(message: "Unlink accessories first: \(linkedDeviceIds)")
} catch {
    showError(message: "Pairing failed: \(error.localizedDescription)")
}
```

### Notes

- The device must be in pairing mode (unpaired state).
- All `propertyIds` must share the same timezone — the SDK fetches DST data based on this shared timezone.
- G3 locks (protocol version 2) use certificate-based pairing with an additional server round-trip.
- If the BLE commit step fails after server registration, the SDK automatically deletes the server record.

---

## unpair

Unpairs a lock via Bluetooth and removes it from the server.

The SDK checks for linked devices first. If the lock has linked accessories (keypads, fobs, bridges), it throws `HasLinkedDeviceException` — you must unlink them first.

### Signature

```kotlin
suspend fun unpair(
    deviceId: String,
    accessToken: String,
)
```

```swift
func unpair(
    deviceId: String, 
    accessToken token: String
) async throws
```

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deviceId` | `String` | Yes | Bluetooth device name of the lock. |
| `accessToken` | `String` | Yes | OAuth access token for server calls. |

### Error Codes

| Exception | Code | Description |
|-----------|------|-------------|
| `BluetoothException` | 708 | Bluetooth is off or unavailable. |
| `ConnectionException` | 12 | Device disconnected during unpair. |
| `TimeoutException` | 703 | BLE operation exceeded the timeout. |
| `HasLinkedDeviceException` | 910 | Device has linked accessories. Contains `linkedDeviceIds: List<String>`. |
| `ApiException` | varies | Server API call failed. |

### Example

```kotlin
try {
    sdk.unpair(
        deviceId = "SP2X01abc123",
        accessToken = accessToken,
    )
    showSuccess("Lock removed")
} catch (e: IglooHomeException.HasLinkedDeviceException) {
    showError("Unlink these devices first: ${e.linkedDeviceIds}")
} catch (e: IglooHomeException) {
    showError("Unpair failed: ${e.message}")
}
```

```swift
do {
    try await sdk.unpair(deviceId: "SP2X01abc123", accessToken: accessToken)
    showSuccess(message: "Lock removed")
} catch IgloohomeError.hasLinkedDevice(let linkedDeviceIds) {
    showError(message: "Unlink these devices first: \(linkedDeviceIds)")
} catch {
    showError(message: "Unpair failed: \(error.localizedDescription)")
}
```

### Notes

- The SDK automatically fetches the correct key for BLE unpair (eKey for G3, admin key for G2). Unlike `lock`/`unlock`, `unpair` on both platforms does not take a `key` parameter — it is resolved internally.
- Server deletion retries up to 3 times with 5-second delays on failure.
- After unpair, all access credentials (PINs, keycards, fingerprints) are removed.

---

## setWifiConfig

Configures WiFi on an Igloo Bridge device via Bluetooth.

After sending WiFi credentials via BLE, the SDK generates a CSR on the bridge and polls the server until the bridge is provisioned and online.

### Signature

```kotlin
suspend fun setWifiConfig(
    deviceId: String,
    key: String,
    ssid: String,
    networkPassword: String,
    accessToken: String,
)
```

```swift
func setWifiConfig(
    deviceId: String,
    key: String,
    ssid: String,
    networkPassword: String,
    accessToken token: String
) async throws
```

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deviceId` | `String` | Yes | Bluetooth device name of the bridge (e.g. `"EB1X01abc123"`). |
| `key` | `String` | Yes | Admin key for BLE authentication. |
| `ssid` | `String` | Yes | WiFi network SSID. |
| `networkPassword` | `String` | Yes | WiFi network password. |
| `accessToken` | `String` | Yes | OAuth access token for server calls. |

### Error Codes

| Exception | Code | Description |
|-----------|------|-------------|
| `BluetoothException` | 708 | Bluetooth is off or unavailable. |
| `ConnectionException` | 12 | Device disconnected during setup. |
| `TimeoutException` | 703 | Bridge was not provisioned or online after all polling retries (15s, 30s, 45s). |

### Example

```kotlin
try {
    sdk.setWifiConfig(
        deviceId = "EB1X01abc123",
        key = adminKey,
        ssid = "Office-WiFi",
        networkPassword = "password123",
        accessToken = accessToken,
    )
    showSuccess("Bridge WiFi configured and online")
} catch (e: IglooHomeException.TimeoutException) {
    showError("Bridge did not come online — check WiFi credentials")
} catch (e: IglooHomeException) {
    showError("WiFi setup failed: ${e.message}")
}
```

```swift
do {
    try await sdk.setWifiConfig(
        deviceId: "EB1X01abc123",
        key: adminKey,
        ssid: "Office-WiFi",
        networkPassword: "password123",
        accessToken: accessToken)
    showSuccess(message: "Bridge WiFi configured and online")
} catch IgloohomeError.timeout {
    showError(message: "Bridge did not come online — check WiFi credentials")
} catch {
    showError(message: "WiFi setup failed: \(error.localizedDescription)")
}
```

### Notes

- The SDK sends WiFi credentials + MQTT broker config to the bridge in a single BLE command.
- After the BLE write, the SDK generates a private key CSR on the bridge.
- The SDK then polls the server at 15s, 30s, and 45s intervals until `isProvisioned` and `isOnline` are both `true`.
- If the bridge doesn't come online after all retries, `TimeoutException` (Android) / `IgloohomeError.timeout` (iOS) is thrown.
