1

I connect to my device and attempt to write to its characteristic:

scanSubscription = rxBleClient.scanBleDevices(
  ScanSettings.Builder()
  // .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // change if needed
  // .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) // change if needed
  .build()
  // add filters if needed
 )
 .filter {
  scanResult -> scanResult.bleDevice.name == "MyDevice"
 } // Filter for devices named MyDevice
 .subscribe({
  scanResult ->
  // Print list of available devices
  println("Scan Result: ${scanResult.bleDevice.bluetoothDevice.name}")
  val charUUID = UUID.fromString("49535343-1e4d-4bd9-ba61-23c647249616")
  println("UUID: $charUUID")

  // Connect to MyDevice
  val macAddress = scanResult.bleDevice.bluetoothDevice.address //34:81:F4:55:04:9A
  println("MAC Address: $macAddress")
  val rxBleDevice = rxBleClient.getBleDevice(macAddress)

  val charset = Charsets.UTF_8
  val bytesToWrite = "cmdl000".toByteArray(charset)
  println("Bytes: $bytesToWrite")

  rxBleDevice.establishConnection(false)
  .flatMapSingle {
   rxBleConnection -> rxBleConnection.writeCharacteristic(charUUID, bytesToWrite)
  }

 }, {
  throwable ->
  // Handle an error here.
  println("Scan Error: $throwable")
 })

Output:

I/System.out: Scan Result: MyDevice
    UUID: 49535343-1e4d-4bd9-ba61-23c647249616
    MAC Address: 34:81:F4:55:04:9A
I/System.out: Bytes: [B@4973078

I'm not sure if the byte array that I'm sending to my characteristic is in the right format. When I print it I get the following and my device does not respond as I intend it to. Is this correct?

Martin Erlic
  • 5,467
  • 22
  • 81
  • 153
  • Does the documentation for the receiving device say anything about the expected encoding? – stkent Nov 23 '19 at 19:03
  • 1
    e.g. https://www.bluetooth.com/specifications/assigned-numbers/format-types/ – stkent Nov 23 '19 at 19:03
  • When I use GATT Browser Android app I see the following: ``49535343-1e4d-4bd9-ba61-23c647249616 Properties: (0x1c) Write Without Response Write Notify``. I can send it a string command such as "cmdl000", for example, and the device responds as expected. – Martin Erlic Nov 23 '19 at 19:05
  • How is your peripheral expected to respond? – Dariusz Seweryn Nov 25 '19 at 12:40
  • @DariuszSeweryn By turning on a light... – Martin Erlic Nov 25 '19 at 15:57
  • It might be an MSB-LSB problem. I'm pretty sure if the blutooth API does not fix this, but most apps like nRFconnect and the like do the conversion for you if you are testing using the same byte array. – axjjienn Nov 26 '19 at 01:52

1 Answers1

2

Judging from the code above the problem you encounter is pretty trivial. All Observable objects need to be subscribed to be actually executed. You have correctly subscribed to the scanning flow but not for connecting.

  rxBleDevice.establishConnection(false)
    .flatMapSingle {
      rxBleConnection -> rxBleConnection.writeCharacteristic(charUUID, bytesToWrite)
    }
    .subscribe(
      { /* done */ },
      { /* encountered error */ }
    )

You could wire-up the whole flow (scanning, connecting, writing characteristic) with a single .subscribe(). It could look like:

val charUUID = UUID.fromString("49535343-1e4d-4bd9-ba61-23c647249616")
val bytesToWrite = "cmdl000".toByteArray(charset)

subscription = rxBleClient.scanBleDevices(
    ScanSettings.Builder().build(),
    ScanFilter.Builder().setDeviceName("MyDevice").build() // Filter for devices named MyDevice
)
    .take(1) // stop the scan when a matching device will be scanned for the first time
    .flatMap {
        val device = it.bleDevice
        println("MAC Address: ${device.macAddress}")
        device.establishConnection(false)
            .flatMapSingle { rxBleConnection -> rxBleConnection.writeCharacteristic(charUUID, bytesToWrite) }
            .take(1) // disconnect after the write
    }
    .subscribe(
        { /* written */ },
        { throwable ->
            // Handle an error here.
            println("Scan Error: $throwable")
        }
    )
Dariusz Seweryn
  • 3,212
  • 2
  • 14
  • 21
  • This really helped. Much appreciated. Any idea how to write to a characteristic without scanning and connecting every single time lol? – Martin Erlic Nov 27 '19 at 09:16
  • Happy to help. How to keep the connection? It all depends on your use case — one (recommended) approach is to change the `Observable` returned from `.flatMap()` in a way that would perform multiple things. – Dariusz Seweryn Nov 27 '19 at 11:15