I have the following code using an. RxAndroidBle Bluetooth Low Energy Connection:
private val connectionDisposable = CompositeDisposable()
private fun writeBle(writeCharacteristicUuid: UUID, command: ByteArray)
if (bleDevice.connectionState == RxBleConnection.RxBleConnectionState.CONNECTED) {
activeConnection
.flatMapSingle {
it.writeCharacteristic(writeCharacteristicUuid, command)
}
.subscribe({
Log.d(
TAG,
"${connectionDisposable.size()} - Command successful: ${it.toHexString()}"
)
})
{ Log.e(TAG, "Error executing command: $it") }
.let { connectionDisposable.add(it) }
} else {
Log.e(TAG, "You are not connected")
}
}
The connectionDisposable is .clear()ed when the connection to the device is closed.
But until then several hundreds, thousands or more disposable will land in the connectionDisposable.
I am not completely clear if this presents a Problem in regard to memory usage, or whether I am missing the right way to execute a lot of write commands (that should not be send simultaneously to the device).
Related
i have an application, and my application can connect to a bluetooth device.
After that, i want to send message (Int) to my Blutooth Low Energy device.
I have this code, but i can't figure it out what is the problem.
If you want i have : Characteristic UUID, Service UUID.
Really, i need your help...
I've edited the question :
My code :
val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
lateinit var bluetoothAdapter: BluetoothAdapter
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothAdapter = bluetoothManager.adapter
settingViewModel.bluetooth(bluetoothAdapter = bluetoothAdapter)
val mReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
if (action == BluetoothAdapter.ACTION_STATE_CHANGED) {
val state = intent.getIntExtra(
BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR
)
when (state) {
BluetoothAdapter.STATE_OFF -> {
settingViewModel.setIsConnected(false)
//settingViewModel.stopScan()
settingViewModel.setListDevices(null)
}
BluetoothAdapter.STATE_ON -> {
settingViewModel.setIsConnected(true)
//scan()
settingViewModel.setListDevices(bluetoothAdapter.bondedDevices)
context!!.unregisterReceiver(this)
}
}
}
}
}
context.registerReceiver(mReceiver, filter)
val SERVICE_UUID = "00000000-0001-11e1-9ab4-0002a5d5c51c"
val ConfigCharacteristic = descriptorOf(
service = SERVICE_UUID,
characteristic = "00E00000-0001-11e1-ac36-0002a5d5c51b",
descriptor = "00000000-0000-0000-0000-000000000000",
)
Button(
onClick = {
if (settingViewModel.isConnected.value == true) {
coroutine.launch(Dispatchers.IO) {
try {
settingViewModel.peripheral.write(ConfigCharacteristic, byteArrayOf(1))
} catch (e: Exception) {
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}
}
}
// try {
// val Service =
// settingViewModel.deviceSocket.value.get .getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"))
// val charac: BluetoothGattCharacteristic =
// Service.getCharacteristic(UUID.fromString("00E00000-0001-11e1-ac36-0002a5d5c51b"))
// settingViewModel.deviceSocket.value!!.outputStream.write("1".toByteArray())
// } catch (e: Exception) {
// Toast.makeText(context, e.message.toString(), Toast.LENGTH_LONG).show()
// }
}
) {
Text(text = "HelloWorld")
}
I Already have the mac adress, the caracteristic and the service UUID of the device i want to connect to.
Again, i really need your help
First of all:
When developing an app for a BLE device it is best to first use a generic BLE scanner app to test the connection and to find out which commands need to be sent. If you confirm that the BLE device works as expected you can continue with your own custom app. I would recommend nRF Connect for this task.
Regarding your problem:
There are still many things missing from your sourcecode. You said you can connect to the device but have problems sending a message. Your code does not contain anything related to a BLE connection so I can only assume that you connected to the device using the Bluetooth settings of your phone. This would be correct for Bluetooth Classic but BLE requires you to connect through your own custom app.
The Ultimate Guide to Android Bluetooth Low Energy explains all steps necessary for a successful BLE connection. These steps are:
Setting the correct permissions
Scan for nearby BLE devices
Connect to a BLE device of your choosing
Scan for Services
Read and Write a characteristic of your choosing
All these steps are explained in the Guide using Kotlin as programming language.
I am working on a small app that connects via bluetooth to an Arduino with a bluetooth shield attached. My bluetooth connection is fine and I'm able to send commands from my app to the Arduino. I'm doing this in Kotlin. I'm learning as I go, so I'm misunderstanding something. Which is where I hope someone can point me in the right direction.
You can assume that all the bluetooth connection stuff is working fine(it is).
This is the part of my code that handles the sending of data to the Arduino.
private fun writeDataSendToMothership(outputToBt: String) {
try {
bluetoothSocket.outputStream.write(outputToBt.toByteArray())
Log.i(LOGTAG, "Button clicked, info sent: $outputToBt")
} catch (e: IOException) {
e.printStackTrace()
}
}
button_led_on.setOnClickListener { writeDataSendToMothership("1")}
button_led_off.setOnClickListener { writeDataSendToMothership("0")}
The part i'm having trouble with is receiving data from the Arduino(Mothership) and doing something with it. I cannot figure out what I need to do.
What I am trying to do is show an image in the app depending on what the Arduino sends after a button on the Arduino is pushed.
What I have so far is:
private fun readDataFromMothership(inputFromBt: String) {
try {
bluetoothSocket.inputStream.read(inputFromBt.toByteArray())
Log.i(LOGTAG, "Incoming data from Mothership recieved: $inputFromBt")
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun View.showOrInvisible(imageShow: Boolean) {
visibility = if (imageShow) {
View.VISIBLE
} else {
View.INVISIBLE
}
}
This is where I fall flat.
if (readDataFromMothership()) {
imageView_mothership_button_pushed.showOrInvisible(true)
} else {
imageView_mothership_button_pushed.showOrInvisible(false)
}
I've left out anything from that function call. I've tried many different things, but I'm just not understanding what parameter I need, or am I way off. Am I even in the right neighborhood?
EDIT Other than my lack of general knowledge about programming, I think my hangup has to do with what to do with the "inputFromBt" String. Do I need to use a buffer of some sort. I'm trying/researching/reading up on everything I can. But stalling out.
Here is the code I have in place and currently working in my app:
private fun readBlueToothDataFromMothership(bluetoothSocket: BluetoothSocket) {
Log.i(LOGTAG, Thread.currentThread().name)
val bluetoothSocketInputStream = bluetoothSocket.inputStream
val buffer = ByteArray(1024)
var bytes: Int
//Loop to listen for received bluetooth messages
while (true) {
try {
bytes = bluetoothSocketInputStream.read(buffer)
val readMessage = String(buffer, 0, bytes)
liveData.postValue(readMessage)
} catch (e: IOException) {
e.printStackTrace()
break
}
}
}
// display or don't star image
private fun View.showOrHideImage(imageShow: Boolean) {
visibility = if (imageShow) View.VISIBLE else View.GONE
}
I mentioned in a comment to user frnnd, My main issue was the data being sent from my arduino. I was using println() instead of print() and that newline was messing things up.
I am trying to test google nearby connections API by writing a simple, single class android program. Unfortunately I am not able to connect to physical devices, after starting discovering and advertising.
All code is located within single class. App is written with Kotlin by almost directly copying the code from API website and translating it from Java to Kotlin.
I don't know where to look for a problem. Logs doesn't seem to show any obvious results.
I kept one phone advertising for more than a couple of minutes and the other one discovering meanwhile. Bluetooth is on, and both devices are in one WiFi network with Internet access. I use Star Strategy.
EndpointDiscoveryCallback is never called.
Here are my implementations of startDiscovery and endpointCallback
private fun startClient() {
connClient.startDiscovery(deviceId, endpointDiscoveryCallback, discOptions)
.addOnSuccessListener {
Toast.makeText(
applicationContext,
"Discovering started",
Toast.LENGTH_SHORT
).show()
currentStateTextView.text = "discovering"
}.addOnFailureListener { exception ->
Toast.makeText(
applicationContext,
"Discovery failed, exception thrown: ${exception.message}.",
Toast.LENGTH_SHORT
).show()
}
}
private val endpointDiscoveryCallback = object : EndpointDiscoveryCallback() {
override fun onEndpointFound(endpointId: String, info: DiscoveredEndpointInfo) {
connClient.requestConnection(deviceId, endpointId, connectionLifecycleCallback)
.addOnSuccessListener {
}
.addOnFailureListener {
}
}
override fun onEndpointLost(endpointId: String) {
Toast.makeText(applicationContext, "Endpoint: $endpointId lost!", Toast.LENGTH_SHORT)
.show()
}
}
I succeeded to connect the same decives using sample app "Rock, Paper, Scissors" which is based on the same API. Unfortunately, till now i cannot find the clue why the devices wont find each other with my code, and where to look for a hint.
I'm trying to read an unsolicited data stream from my Bluetooth device. The data should appear as a byte array. Unfortunately, the UUID I'm supplying doesn't seem to be the correct one. What could be going wrong?
val stringDeviceUUID = rxBleDevice.bluetoothDevice.uuids[0].toString()
val charUUID = UUID.fromString(stringDeviceUUID)
println("$stringDeviceUUID = $charUUID?")
/* If device if it is not already connected... */
if (rxBleDevice.connectionState != RxBleConnection.RxBleConnectionState.CONNECTED) {
/* Establish connection to device */
device !!.establishConnection(false) ?
.doOnNext {
_ -> Log.d("Device: ", "Connection Established")
} ?
.flatMapSingle {
rxBleConnection -> rxBleConnection.readCharacteristic(charUUID)
} ? .subscribe({
count ->
// count should be in bytes
println("OUTPUT: $count")
}, {
throwable ->
Log.d("Device: ", "$throwable")
})
}
I get the following error:
D/Device:: com.polidea.rxandroidble2.exceptions.BleCharacteristicNotFoundException: Characteristic not found with UUID 00001101-0000-1000-8000-00805f9b34fb
What is wrong with this UUID? This is precisely the UUID I retrieve from the device so why won't it let me communicate?
It can't be seen from your code snippet, but are rxBleDevice and device the same RxAndroidBle instance? If not, perhaps replace device !!.establishConnection(false) with rxBleDevice.establishConnection(false)
I'm converting a very complex write/read/write cycle written on the native BLE stack and am wondering if the following pattern is feasible for handling in RxAndroidBLE (code is Kotlin)
fun sendCommandList(connection: RxBleConnection, commands: Array<String>) {
Observable.fromArray(commands)
.flatMapIterable { it.asIterable() } // convert to individual commands
.map { it.toByteArray() }
.map {
connection.writeCharacteristic(TX_CHAR_UUID, it)
.flatMap { bytes -> connection.readCharacteristic((RX_CHAR_UUID)) }
.flatMap { bytes -> val ackNackBytes = processResponse(bytes); connection.writeCharacteristic(TX_CHAR_UUID, ackNackBytes) }
}
.subscribeBy( onError = { }, onComplete = { }, onNext = { })
}
I'm just trying to work out the code before I get access to the hardware so can't test this at the moment and am wondering if it's feasible. I'm more worried about the read portion if the complete response might be not be within one readCharacteristic(). If not would having a long running read pumping into a buffer that can be handled one byte at a time and removing only those bytes that make up a valid response and reading from that instead.
Thoughts? This seems like a common usage pattern, but I've been unable to find anything like it as far as samples.