Pairing via BLE

Pre-requisite: Ensure the app has all necessary runtime permissions to access Bluetooth services.

  • Android 11 (API 30) and below: the ACCESS_FINE_LOCATION runtime permission is required (the SDK manifest declares the legacy BLUETOOTH / BLUETOOTH_ADMIN permissions up to API 30).
  • Android 12 (API 31) and above: the BLUETOOTH_SCAN and BLUETOOTH_CONNECT runtime permissions are required.
  • Bluetooth must be enabled before starting BLE operations.
  • A pairing session key is required before the Wi-Fi configuration is sent. See Pairing a Camera.

The app connects to the camera over Bluetooth and writes the Wi-Fi credentials and the pairing session key to it. The camera then joins the network and claims the session.

The call order

The calls below are a sequence, and each step is driven by the callback of the one before it:

release() → registerCallback() → startScan() → collect scanResults → stopScan()
  → connectToDevice() → onConnected() → startServiceDiscovery()
  → onDeviceIdReceived() / onDeviceReady() → sendWifiScanCommand() → collect wifiNetworks
  → createPairingSession() → sendWifiConfig() → onWifiConfigSent()
  → poll getPairingSessionStatus() until PROCESSED

Best Practice: Call release() before registerCallback() when starting a flow. release() clears every registered callback, so registering first loses the callback.


Start Scanning for BLE Devices

To begin scanning for nearby BLE devices:

InstaVision.bleService.startScan()

Optional: Customize BLE Configuration You can configure BLE scan and connection behavior using BleConfig.

val config = BleConfig(
  scanTimeout = 90_000L,           // Scan timeout in ms, defaults to 90 seconds
  connectionTimeout = 90_000L,     // Connection timeout in ms, defaults to 90 seconds
)
InstaVision.bleService.startScan(bleConfig = config)

Observe Scan Results

You can observe the scan results using a Flow:

InstaVision.bleService.scanResults.collectLatest { deviceList ->
  // Filter or display device info
}

The SDK applies no scan filter, so the list contains every nearby BLE device. Filter it by device name yourself.


Stop BLE Scanning

BLE scan will automatically stop after the configured timeout (BleConfig.scanTimeout), defaulting to 90 seconds.

To manually stop scanning before timeout:

InstaVision.bleService.stopScan()

Best Practice: Always call stopScan() before initiating a connection.


Connect to BLE Device

Once you have selected a BluetoothDevice from scan results:

InstaVision.bleService.connectToDevice(device)

You will receive the onConnected() callback if the connection is successful.

Once the device ID is read off the connected device, you’ll receive onDeviceIdReceived(deviceId). You can also read the last known device ID at any time via:

val deviceId = InstaVision.bleService.connectedDID

Not every camera exposes the device ID characteristic. When it does not, only onDeviceReady() fires and connectedDID stays null.


Start Service Discovery

After connecting, initiate service discovery:

InstaVision.bleService.startServiceDiscovery()

This will trigger the BLE device to discover services and characteristics. Once completed, you’ll receive:

BleCallback.onDeviceReady()

Check Available Wifi (Optional)

After the device is connected and services are discovered, you can send a command to initiate a WiFi scan:

InstaVision.bleService.sendWifiScanCommand()

This triggers the BLE device to start scanning for available WiFi networks.

You can collect the list of available networks using:

InstaVision.bleService.wifiNetworks.collectLatest { networks ->
  networks.forEach { network ->
    Log.d("BLE", "SSID: ${network.ssid}")
  }
}

The list updates as new networks are discovered by the BLE device.


Send WiFi Configuration

To update WiFi credentials the device needs to connect to, use:

InstaVision.bleService.sendWifiConfig(
  ssid = "YourNetwork",
  password = "YourPassword",
  sessionKey = "session_key",
  region = ServerRegions.US,
  env = Environment.RELEASE
)

sessionKey is the PairingSession.sessionKey created earlier — see Pairing a Camera.

Upon success, the callback onWifiConfigSent() will be invoked — and the SDK then calls release() itself, clearing registered callbacks, the GATT connection and the scan / Wi-Fi flows.

Poll getPairingSessionStatus from here to learn whether the camera actually joined the network and claimed the session.


Release BLE Resources

The SDK releases everything automatically after onWifiConfigSent(). Call release() yourself only when abandoning a session early or restarting one:

InstaVision.bleService.release()

This ensures clean disconnection, cancels any timers, clears callbacks, and closes GATT connections.

Registering BLE Callback

To receive BLE state updates and responses, register your callback:

val bleCallback = object: BleCallback() {
  override fun onConnected() {
    Log.d("BLE", "Connected to BLE device")
  }

  override fun onDeviceReady() {
    Log.d("BLE", "Device is ready")
  }

  override fun onDeviceIdReceived(deviceId: String) {
    Log.d("BLE", "Device id received: $deviceId")
  }

  override fun onWifiConfigSent() {
    Log.d("BLE", "WiFi config successfully sent")
  }

  override fun onDeviceConnectionFailed() {
    Log.e("BLE", "Connection failed")
  }

  override fun onScanStopped() {
    Log.e("BLE", "Ble scanning stopped")
  }
}

InstaVision.bleService.registerCallback(bleCallback)

onDeviceConnectionFailed() is the single error channel for the whole flow — connection timeouts, GATT disconnects, failed service discovery and missing characteristics all arrive through it, with no error payload.

Best Practice: Track whether the Wi-Fi configuration has already been sent, and ignore onDeviceConnectionFailed() after that point. Because sendWifiConfig releases the connection on success, the disconnect that follows a successful write would otherwise be reported as a failure.


Unregistering BLE Callback

Once you no longer need BLE updates (for example, when the pairing screen is destroyed), unregister the callback to avoid leaks:

InstaVision.bleService.unregisterCallback(bleCallback)

This site uses Just the Docs, a documentation theme for Jekyll.