Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

missing serviceUUIDs on android 12 #254

Open
ray007 opened this issue Nov 25, 2022 · 17 comments
Open

missing serviceUUIDs on android 12 #254

ray007 opened this issue Nov 25, 2022 · 17 comments

Comments

@ray007
Copy link

ray007 commented Nov 25, 2022

I was now forced by google to increase my target api level for android to 31 (android 12).

After fixing the permission problems (with help from 2 closed issues, a readme update would be nice), the scan started like before but didn't yield any results.

Removing the filter by serviceUUID from scan options did get me results again, but trying to read the service uuid list gets me an empty array.

All this with the latest versions of nativescript, ble module, ...

@farfromrefug
Copy link
Member

@ray007 you are welcome to create a PR for the doc
as for the rest without more details i cant really help you we are using native apis to get serviceUUIDs from advertisment data https://developer.android.com/reference/android/bluetooth/le/ScanRecord#getServiceUuids().
as we are to set the filter https://developer.android.com/reference/android/bluetooth/le/ScanFilter.Builder#setServiceUuid(android.os.ParcelUuid

You can add console logs to the android file of the ble plugin to see where it is failing

@ray007
Copy link
Author

ray007 commented Nov 29, 2022

Anyone any idea what needs to be done to read serviceUUIDs again or filter by some on android 12+ ?

@farfromrefug
Copy link
Member

@ray007 maybe debug it , add logs to see what s happening and where it fails ;)

@ray007
Copy link
Author

ray007 commented Nov 29, 2022

Hmm, I followed things down to ScanCallBackImpl.prototype.onScanResult (around line 475 in bluetooth.android.js).

The property mServiceUuids of the ScanRecord is null.

Ignoring this and trying to read the characteristic anyway also does not work:

[BluetoothError]:error_function_call, readCharacteristic, [B@e4a57a1, {"peripheralUUID":"EB:38:0B:BE:FD:D7","serviceUUID":"78a90000-26ce-4367-bfeb-7e3c1d217561","characteristicUUID":"78a90001-26ce-4367-bfeb-7e3c1d217561","timeout":1000}

@farfromrefug
Copy link
Member

@ray007 there is no mServiceUuids variable in the plugin. on post lollipop Service uuids are directly recovered from a native object

get serviceUUIDs() {
.

@ray007
Copy link
Author

ray007 commented Nov 29, 2022

Yes, but when dumping a ScanRecord with console.log, you can see the mServiceUuids property.

The funny things also is, I can see a serviceUUID there from one garmin device.

Talking to our sensor developer, it seems there's the advertisement and then a second 'scan response' message?
And since the serviceUuids of our sensors are in the second message they seem to be missing after setting the target api level to 31...

@farfromrefug
Copy link
Member

@ray007 something bugs me in what you are saying.ScanRecord is a native object (android.bluetooth.le.ScanRecord) so the mServiceUuids should not be printed. even if it shows you a mServiceUuids you should (to debug) try to console log using native methods https://developer.android.com/reference/android/bluetooth/le/ScanRecord#getServiceUuids()

Now about your double message thing i didnt know it was possible. Now the thing is the ble plugin does not send duplicate events for discovery. which might be your issue

if (!stateObject) {

You can try to remove the if test. If it works you are welcome to create a PR for a scanning parameter to allow duplicate events (default to false to be retro compatible).

@ray007
Copy link
Author

ray007 commented Nov 29, 2022

Looking at https://docs.particle.io/reference/device-os/api/bluetooth-le-ble/blepeerdevice/#blescanresult, there seems to be a scanResponse separate from the advertisingData, which needs an extra request but no connect.

And starting with api level 31 on android, this extra data apparently does not get retrieved anymore.

It's much harder to read in the Bluetooth Core Specification 5.2, but
Volume 3, Part C, Chapter 11 Advertising and Scan Response Data Format (page 1392)
and
Volume 4, Part E, Chapter 7.8.8 LE Set Scan Response Data command (page 2489)
should hold the relevant information.

@farfromrefug
Copy link
Member

farfromrefug commented Nov 29, 2022

@ray007 good catch! Have you tried to remove the if i talked about to see if there was not a second "event" with the extra data?
Edit : we can continue that discussion on discord until we find the solution

@ray007
Copy link
Author

ray007 commented Nov 30, 2022

Unfortunately no.
But on my test device, the code path does not seem to go through this onLeScan function, but through a similar method ScanCallBackImpl#onScanResult.
The stateObject check there is only a get or create.

Since the problem only happened upon increasing the targetApi level with the same ble module code, I suspect, that the problem is somewhere on a lower level in the java api.
I had hoped that it might just need an extra flag/option/... to be set somewhere, but looking at android docs I have found nothing so far.

@farfromrefug
Copy link
Member

@ray007 yes it depends on the OS version. It uses one or the user if os version is pre or post lolippop

Yes it is an issue in android itself but we might be able to fix it. You need to be able to test on android 31 or more though

@ray007
Copy link
Author

ray007 commented Dec 5, 2022

My question on stackoverflow hasn't got any responses so far.
Maybe we need to file a bugreport somewhere with the android project...

@erik777
Copy link

erik777 commented Dec 23, 2022

This might help

#261

I'm reading without a problem on Android 12 (API 31) now. I'm using nativescript-vue, and to debug, I output the JSON with:

      <TextView class="theDevice" editable="false" maxLines="3">
        {{ currentDevice.json }}
      </TextView>

Where I populate the json property with "json: JSON.stringify(perip)". So, I can see all the service UUIDs on the device after populating perip.services from a call to discoverServices. Note that I do not get them on connect, per my original issue.

@ray007
Copy link
Author

ray007 commented Dec 29, 2022

@erik777 Thanks for trying, but no luck so far.

But I tried to call discoverServices({peripheralUUID:peripheral.UUID}) in my onDiscovered callback during the scan, not in onConnected like you did.

Calling discoverServices like this on the bluetooth instance I'm also using to call startScanning(args) on results in an error:

[BluetoothError]:Cannot read property 'discoverServices' of undefined, discoverServices, undefined, {"peripheralUUID":"F2:D7:ED:2E:D9:80"}

Note: I also checked with nRF Connect, and there I also can only see the services when I do a connect, not before.
Did something get broken in Android with newer API levels?

Update: trying to ignore the problem at scan-time and just trying to connect and read the characteristic does not work either:

[BluetoothError]:error_function_call, readCharacteristic, [B@9abe29b, {"peripheralUUID":"EB:38:0B:BE:FD:D7","serviceUUID":"78a90000-26ce-4367-bfeb-7e3c1d217561","characteristicUUID":"78a90001-26ce-4367-bfeb-7e3c1d217561","timeout":1000}

@erik777
Copy link

erik777 commented Jan 12, 2023

@ray007 if you want to check it out, I got it all working in this app

https://github.com/erik777/fun/tree/main/nativescript/osBT-ts

Runs on Android 12 and 11. Note I had to do things with permissions in the beginning, which can be your issue. There were definitely major permission changes in BLE in Android 12. I've seen a lot of app devs struggle with this in other discussions. But, I did finally get it where you just have to accept the popups on first run and no longer have to navigate to settings to explicitly give it permission. I think other devs had a hard time figuring that one out so they throw up an upset dialog then send the user to the system settings lol.

You can run the app, but the part where it reads/writes it is specific to my RoboSmart lightbulbs. I debug by appending to text boxes. That's how I reverse engineer what it returns as I develop, and how I got services working.

Note that I never discover characteristics because I knew them in advance. So, can't verify if that query works. But, have no trouble reading/writing to them.

Here's where I defined characteristic IDs for my light bulbs.

https://github.com/erik777/fun/blob/main/nativescript/osBT-ts/app/shared/RoboSmart.ts

I did have to discover services, though, even though I had them in advance, as well. That does work.

@ray007
Copy link
Author

ray007 commented Jan 12, 2023

@erik777 thanks for trying to help.
I don't think permissions are the problem. I know those have changed but updating for that was quite easy.
I also do find our sensors and other devices during a scan, but not if I try to filter by serviceUUID.

Question: does your hardware send the serviceUUIDs in the advertisingData, or in an extra scanResponse?

@erik777
Copy link

erik777 commented Jan 12, 2023

@ray007 so far I have only seen in the discoverServices response. I have yet to see advertisingData populated, but also haven't considered it, so not sure when it is supposed to populate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants