igloo
Docs / iglooworks / BLE SDK / Scanning

Scanning

Discover nearby Igloohome smart locks via Bluetooth.


scanDevice

Scans for nearby Igloo locks via Bluetooth. Emits a ScanResult for each discovered device. The scan runs for as long as the Flow has active collectors.

Signature

fun scanDevice(): Flow<ScanResult>
func scansLock() -> AsyncThrowingStream<ScanResult, Error>
func stopScan()

Return Type

data class ScanResult(
    val deviceId: String,
    val isPaired: Boolean,
    val isActive: Boolean,
    val rssi: Int,
)
public struct ScanResult: Identifiable, Hashable, Sendable {
    public var id: String { bluetoothDeviceName }
    public let bluetoothDeviceName: String
    public let isActive: Bool
    public let isPaired: Bool
    public let isG3: Bool
}
Field Description
deviceId Bluetooth device name (e.g. "IGM4-XXXX", "SP2Xo01231").
isPaired true if the device is already paired with an account.
isActive true if the device is actively broadcasting.
rssi Signal strength in dBm. Higher (closer to 0) means closer.

Error Codes

Exception Code Description
BluetoothException 708 Bluetooth is off or unavailable.

Example

val scanJob = viewModelScope.launch {
    try {
        sdk.scanDevice().collect { result ->
            println("Found: ${result.deviceId}")
            println("  paired=${result.isPaired}, active=${result.isActive}, rssi=${result.rssi}")
        }
    } catch (e: IglooWorksException.BluetoothException) {
        showError("Please enable Bluetooth")
    } catch (e: IglooWorksException) {
        showError("Scan failed: ${e.message}")
    }
}

// Stop scanning
scanJob.cancel()
let scanTask = Task {
    do {
        for try await result in sdk.scansLock() {
            print("Found: \(result.bluetoothDeviceName)")
            print("  paired=\(result.isPaired), active=\(result.isActive), type=\(result.type)")
        }
    } catch LockManagerError.bluetoothIsTurnedOff {
        showError(message: "Please enable Bluetooth")
    } catch {
        showError(message: "Scan failed: \(error.localizedDescription)")
    }
}

// Stop scanning
sdk.stopScan()
scanTask.cancel()

Notes

  • The scan runs indefinitely until the collecting coroutine is cancelled (Android) or stopScan() is called and the enclosing Task is cancelled (iOS).
  • Ensure BLE permissions are granted before calling scanDevice() / scansLock(). On iOS this means NSBluetoothAlwaysUsageDescription is set in Info.plist — there is no runtime permission prompt to request explicitly.
  • The deviceId / bluetoothDeviceName prefix indicates the lock type (e.g. IGM4 = mortise lock, SP2X = smart padlock, EB1 = bridge). On iOS this is also exposed structurally via ScanResult.type: LockType.
  • Unpaired devices (isPaired = false) can be registered via pair().
  • Filter by rssi to find nearby devices — typical threshold is -70 for "close enough to connect". Not available on iOS (no rssi field).