Skip to main content

BLE SDK

Core module that provides low-level API for connecting to Corsano bracelets, performing commands on the bracelet, and getting raw data.

Main interfaces

The main entry point of BLE SDK is interface BleSdk. Its instance can be obtained by calling BleSdk.getInstance(). This method will always return the same (singleton) instance, so it is safe to keep a reference to it in the scope of your app.

Note: Make sure that CorsanoSdk.initialize() is called before accessing any other methods.

BleSdk – API surface of the BLE module, which provides access to other interfaces listed in the table below.

InterfaceDescriptionHow to obtain
BleScannerAn abstraction around Android BLE Scanner for performing Corsano device lookup.BleSdk.getScanner()
BleDeviceRepresents physical Bluetooth device (bracelet) and provides methods for interaction with it.BleSdk.getDevice(address)
BleRequestRepresents an intent to execute a command on the bracelet. Contains a command ID and parameters.Create using public constructor, e.g. GetBatteryLevelRequest()
BleCommandRepresents an executable command.BleDevice.newCommand(request)
BleFileTransferSpecial type of BleCommand for data streaming.BleDevice.newFileTransfer(request)
NotificationSourceInterface for listening to Notifications from the device.BleDevice.notifications
BluetoothUtility interface for working with Android BluetoothAdapterBleSdk.getBluetooth()

BleSdk also exposes getBpCuffDevice(address) for an external blood pressure cuff, getRecentDevices() for previously seen bracelets, and removeDevice(address) to unpair.

Note: getWatch() and removeWatch() are deprecated in favour of getDevice() and removeDevice().

Executing commands

Every interaction with the bracelet follows the same shape: you build a request, turn it into a command on a device, and enqueue it.

BleDevice
.newCommand(BleCommandRequest<T>) -> BleCommand<T>
.newFileTransfer(FileTransferRequest<T>) -> BleFileTransfer<T>

You rarely call newCommand directly — the extension functions below wrap it.

Callback style

enqueueCommand for a single value, enqueueFileTransfer for a file, which additionally reports progress:

bleDevice.enqueueCommand(
request = GetBatteryLevelRequest(),
onSuccess = { level -> Log.d("Corsano-SDK", "Battery: $level") },
onError = { error -> Log.e("Corsano-SDK", "Failed: $error") }
)
bleDevice.enqueueFileTransfer(
request = ActivityFileTransferRequest(sizeInBytes),
onSuccess = { data -> Log.d("Corsano-SDK", "Got ${data.items.size} records") },
onError = { error -> Log.e("Corsano-SDK", "Failed: $error") },
onProgress = { progress -> Log.d("Corsano-SDK", "Progress: $progress") }
)

If your app uses coroutines, prefer awaitCommandV2 and awaitFileTransferV2 from com.corsano.sdk.data.util. They return a Result<T> rather than throwing, and accept an optional timeout in milliseconds.

import com.corsano.sdk.data.util.awaitCommandV2

val result: Result<BatteryLevel> = bleDevice.awaitCommandV2(
request = GetBatteryLevelRequest(),
timeout = 10_000
)

result
.onSuccess { level -> Log.d("Corsano-SDK", "Battery: $level") }
.onFailure { error -> Log.e("Corsano-SDK", "Failed: $error") }

Warning: The earlier awaitCommand and awaitFileTransfer are deprecated — they can crash if the bracelet disconnects mid-command. Use the V2 variants, which capture the failure in the returned Result instead.

Note that these helpers live in the data module, so they are available only if you depend on com.corsano.sdk:data.

Listening to notifications

The bracelet pushes notifications without being asked. Observe them all, or filter by type:

// everything
bleDevice.observeNotifications { notification ->
Log.d("Corsano-SDK", "Notification: $notification")
}

// just one type
bleDevice.observeNotificationsOfType<Notification.RealTimePing> { ping ->
Log.d("Corsano-SDK", "Live heart rate: ${ping.hrm}")
}

Both return the underlying NotificationSource.NotificationListener, which you pass to bleDevice.notifications.removeNotificationListener(listener) when you are done.

Notification is a sealed class with four cases: RegularPing, RealTimePing, LiveHrm and ChargingEventPing. They are described in Instant data.

Errors

Commands fail through onError (callback style) or a failed Result (coroutine style). The BLE module defines these exceptions in com.corsano.sdk.ble.exceptions:

ExceptionMeaning
PairingRequiredExceptionThe bracelet is not bonded; pair it first. See Pairing
InvalidCommandResponseExceptionThe bracelet returned a response that could not be decoded
CommandResponseValidationExceptionThe response decoded but failed validation