I have an Android application running with RxAndroidBle library and I want to change it to Nordic-Ble-Android library. I'm not that good with Bluetooth and the actual version of the app is not developed by me so I'm in trouble trying to make it work.
Our connection with the wireless bluetooth sensor is following a few steps:
- The APP establishes a connection with the wireless sensor
- The APP send a request connection command frame to wireless sensor
- The APP send a command to the wireless sensor to start blinking
- User tap on a button on the app to confirm that the APP is blinking
- The APP send one more command to confirm the connection and now it's done
If the user does not confirm that the sensor is blinking, the wireless sensor will automatically timeout within 10 seconds.
I'm successfully establishing a connection with the sensor using this method:
val man = MyBleManager(this@BluetoothService) man.setGattCallbacks(this@BluetoothService) bleManagers?.put(device, man) man.connect(device) .done { Log.d("BLESERVICE", "success") //not working man.sendRequestConnectionCommand(DeviceType.SENSOR) //not working startBlinkingDeviceLed(man, DeviceType.SENSOR) connectionFlowListeners.forEach { it.onConnectionEstablished(device) } } .fail { d, status -> Log.d("BLESERVICE", "fail") devicesList?.remove(device) bleManagers?.remove(device) } .timeout(10000) .enqueue()
The issue is writing characteristcs after that, It seems that I'm doing something wrong.
The current version of the connection with RxAndroidBle is written below:
fun connectToDevice(device: BraincareDevice, pairColor: Int) { BleLogHelper.writeLog("Connecting to ${device.name}") val deviceType = if (device is Sensor) DeviceType.SENSOR else DeviceType.DONGLE if (deviceType == DeviceType.SENSOR) { sensorConnectionSubscription?.dispose() } else { dongleConnectionSubscription?.dispose() } val connectionSubscription = device.device.establishConnection(false) .flatMapSingle { connection -> if (device is Sensor) { sensorConnection = connection connectedSensor = device } else if (device is Dongle) { dongleConnection = connection connectedDongle = device } BleLogHelper.writeLog("Send Request Connection Command $deviceType") val command = BraincareBluetoothCommandProtocol.createRequestConnectionCommandFrame(deviceType) connection.writeCharacteristic(BraincareBluetoothProtocol.rxCharacteristicUUID, command) } .delay(300, TimeUnit.MILLISECONDS) .subscribe({ BleLogHelper.writeLog("Connection Established ${device.type}") if (device.device.connectionState == RxBleConnection.RxBleConnectionState.CONNECTED) { startBlinkingDeviceLed(deviceType, pairColor) connectionFlowListeners.forEach { it.onConnectionEstablished(device) } } }
You can see that it's using the connection to write the characteristic that sends the request command frame within .flatMapSingle
Also, the command to startBlinking is inside the .subscribe method. You can see as well that it's not using any service at all to use the characteristic rxCharacteristicUUID, and looking on Blinky and Toolbox examples given, it seems that I have to initialize the characteristic using gatt.getService, and I got confused because there is no need to use a service for these commands on actual application.
I tried to do exactly like this snippet, but using Android-Ble-Nordic library, but I could not really understand how I have to do that.
Below is my entire version of my BleManager following the examples given on Android-nRF-Blinky and Android-nRF-Toolbox.
package io.b4c.brain4care.modules.ble import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import android.content.Context import android.graphics.Color import android.support.annotation.NonNull import android.support.annotation.Nullable import android.util.Log import io.b4c.brain4care.BraincareApplication import io.b4c.brain4care.modules.monitoringservice.BraincareBluetoothManager import io.b4c.brain4care.modules.monitoringservice.protocol.BraincareBluetoothCommandProtocol import io.b4c.brain4care.modules.monitoringservice.protocol.BraincareBluetoothProtocol import io.b4c.brain4care.util.constants.AppConstants import io.b4c.brain4care.util.enums.DeviceType import io.b4c.brain4care.util.extensions.toByteStringRepresentation import io.b4c.brain4care.util.helpers.BleLogHelper import io.reactivex.schedulers.Schedulers import no.nordicsemi.android.ble.BleManager import no.nordicsemi.android.ble.BleManagerCallbacks import no.nordicsemi.android.ble.data.Data import no.nordicsemi.android.log.ILogSession import no.nordicsemi.android.log.LogContract import no.nordicsemi.android.log.Logger class MyBleManager(context: Context): BleManager<BleManagerCallbacks>(context) { override fun getGattCallback(): BleManagerGattCallback { return mGattCallback } private var mLogSession: ILogSession? = null private var rxCharacteristic: BluetoothGattCharacteristic? = null private val mGattCallback = object : BleManagerGattCallback() { override fun onDeviceDisconnected() { } override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean { //?? i don't need this i guess val service = gatt.getService(BraincareBluetoothProtocol.serviceDeviceInformationUUID) return true } protected override fun initialize() { super.initialize() Log.d("BLESERVICE","initializing") //I not so sure if I need this setNotificationCallback(rxCharacteristic).with(mLedCallback) enableNotifications(rxCharacteristic).with(commandCallback) enableIndications(rxCharacteristic).with(commandCallback) } } private val commandCallback = object : CommandSentCallback { override fun onDataSent(device: BluetoothDevice, data: Data) { super.onDataSent(device, data) Log.d("BLESERVICE", "sent something") } } private val mLedCallback = object : ManufectureDataCallback() { override fun onReceived(device: BluetoothDevice, value: Int) { Log.d("BLESERVICE", "received something") } } fun sendRequestConnectionCommand(deviceType: DeviceType){ Log.d("BLESERVICE","sending request command") val command = BraincareBluetoothCommandProtocol.createRequestConnectionCommandFrame(deviceType) writeCharacteristic(rxCharacteristic, command).enqueue() } private fun getRandomPairColor(): Int { val colorOptions = AppConstants.lighsyncColorOptions val colorIndex = (0 until colorOptions.size).shuffled().first() return context.getColor(colorOptions[colorIndex]) } fun sendSetLedProfileCommand(deviceType: DeviceType, color: Int) { BleLogHelper.writeLog("Device Blinked $deviceType") Log.d("BLESERVICE","sending blink command") val command = BraincareBluetoothCommandProtocol.createBlinkLedCommandFrame(Color.red(color), Color.green(color), Color.blue(color), 2) writeCharacteristic(rxCharacteristic, command).with(commandCallback).enqueue() /*val connection = if (deviceType == DeviceType.SENSOR) BraincareBluetoothManager.sensorConnection else BraincareBluetoothManager.dongleConnection BraincareBluetoothManager.connectionFlowListeners.forEach { it.onDeviceBlinkSuccess(color) } val disposable = connection?.writeCharacteristic(BraincareBluetoothProtocol.rxCharacteristicUUID, command) ?.subscribeOn(Schedulers.io()) ?.subscribe({ }, { BleLogHelper.writeError("Error on sendSetLedProfileCommand", it) }) BraincareBluetoothManager.sensorCompositeDisposable.add(disposable ?: return)*/ } /** * Sets the log session to log into. * * @param session nRF Logger log session to log inti, or null, if nRF Logger is not installed. */ fun setLogger(@Nullable session: ILogSession) { mLogSession = session } override fun log(priority: Int, @NonNull message: String) { Logger.log(mLogSession, LogContract.Log.Level.fromPriority(priority), message) Log.println(priority, "BleManager", message) } }