I had started this BLE project in Python, ran into problems with android permissions, so I had a go at (I'll be honest... vibe) coding a native Kotlin android app. The main part of it is to run a thread that will repeatedly poll a specific characteristic by id and send the data by UDP.
So far, it's finding and connecting to the device:
val device = bluetoothAdapter.getRemoteDevice(targetDeviceAddress)
bluetoothGatt = device.connectGatt(context, false, gattCallback)
That is triggering onConnectionStateChange(). I know this is happening because the Bluetooth device responds at this point.
This calls gatt.discoverServices(), which triggers onServicesDiscovered():
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
val service = gatt.getService(UUID.fromString(targetServiceUuid))
if (service != null) {
targetCharacteristic = service.getCharacteristic(UUID.fromString(targetCharacteristicUuid))
_status.value = BleStatus.Connected
} else {
_status.value = BleStatus.Error("Service not found")
}
} else {
_status.value = BleStatus.Error("Service discovery failed")
}
}
I know it's entering this function because "Service not found" flashes in the app's status box. This is the only place where this string is found -- so it is definitely trying to get the service (based on targetServiceUuid, which I've verified by listing the device's services), and it isn't found.
That is -- as far as I know, I'm requesting a correct service UUID, but nothing is coming back, and I'm out of ideas.
The app is also requesting Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT and Manifest.permission.ACCESS_FINE_LOCATION permissions before this (and I checked the apps permissions in the settings -- it does have "location" and "nearby devices," so I believe the failure isn't due to insufficient permissions).
It's a OnePlus (Oppo) phone with Android 14. The device is a BBC Micro:bit.
What am I missing? Thanks.
FURTHER INFORMATION:
With some more logging, I found that the micro:bit's services are being reported differently on the computer compared to the phone.
Leaving out irrelevant results, a python+bleak script running on the computer reports that e95d0753-251d-470a-a062-fa1922dfa9a8 (Handle: 40): MicroBit Accelerometer Service exists.
But this UUID is absent from the Android environment.
Logging Kotlin code looks like this:
val uuid = UUID.fromString(targetServiceUuid)
val lsb = uuid.getLeastSignificantBits()
val msb = uuid.getMostSignificantBits()
Log.i("mb2o", "targetServiceUuid string = %s".format(targetServiceUuid))
Log.i("mb2o", "lsb hex = %s".format(lsb.toHexString()))
Log.i("mb2o", "msb hex = %s".format(msb.toHexString()))
// this is poorly factored but will delete later
val srvIter = gatt.getServices().iterator()
while (srvIter.hasNext()) {
var srvc = srvIter.next()
Log.i("mb2o", "service = %s".format(srvc.uuid))
}
and prints
targetServiceUuid string = e95d0753-251d-470a-a062-fa1922dfa9a8
lsb hex = a062fa1922dfa9a8
msb hex = e95d0753251d470a
service = 00001800-0000-1000-8000-00805f9b34fb
service = 00001801-0000-1000-8000-00805f9b34fb
service = 0000fe59-0000-1000-8000-00805f9b34fb
service = e97dd91d-251d-470a-a062-fa1922dfa9a8
service = 0000180a-0000-1000-8000-00805f9b34fb
service = e95d93af-251d-470a-a062-fa1922dfa9a8
e95d93af-251d-470a-a062-fa1922dfa9a8 is a near match but corresponds to the micro:bit event service, not the accelerometer.
A puzzling result. Well, maybe the event service will work for this.