NimBLE-Arduino icon indicating copy to clipboard operation
NimBLE-Arduino copied to clipboard

How to force a attribute refresh with Service Changed Characteristic

Open ln-12 opened this issue 2 years ago • 14 comments

I am using your library to develop a bluetooth device which should connect to iOS and Android smartphones. When using iOS, I came across the topic attribute caching for which the following is suggested:

If the GAP name changes and you want this to be reflected in the .name property, you should 
employ the Service Changed Characteristic, so iOS will read the GAP name (among other things) 
again and update the .name property.

The name of my device can change, so I need to force any client to update the cached values before a connection is established (the device to connect to is determined by the device name). How would I do this with your library? Would it be enough to call void NimBLEServer::serviceChanged() if it was public? Thanks in advance!

ln-12 avatar Aug 31 '21 10:08 ln-12

Interesting question, I haven't thought about this use case. You want to change the actual device name or just the advertised name? To change the device name what you propose is half way there, you would also need to call ble_svc_gap_device_name_set() first. Perhaps this could be an added member function in NimBLEServer.

h2zero avatar Aug 31 '21 13:08 h2zero

I also never thought of it, until I just learned that attribute caching is a thing in BLE.

Well, I think the best way would be to keep the device advertisement name and the GAP device name in sync and I don't see why they should differ. For me it would also be enough if I could set a new name when NimBLE is intialized.

ln-12 avatar Aug 31 '21 13:08 ln-12

I dont know how your code is designed, but there is 2 ways to set device name:

  • there is characteristic in 0x1800 generic access service,
  • name set in advertising

Service change is only required in first case.

Another thing about caching is the problem during development. It is highly advised to clean cache on smartphone every time you change code on device. If you dont do it you can have many issues related to secure connection, not refreshed services, characteristics UUIDs etc.

chegewara avatar Aug 31 '21 13:08 chegewara

@chegewara For now my code is really simple as I simply use NimBLEDevice::init(). When I reboot the microcontroller with a different name set, it stays the same on the phone as mentioned. How would your suggestions look in example code?

I share your opinion on cleaning the cache, but as stated for example here, the only way to do so on iOS is to completely reset the device (= erase ALL data), which is not practical.

ln-12 avatar Aug 31 '21 14:08 ln-12

There is no need to reset iOS, why would you have to do it.

I dont have iPhone in my hands right now, but there is option is BLE settings to remove ble device. Also you should be able to use nrf connect or similar app (maybe lightblue) to refresh services. Ive been working a bit with iOS, but i never had to do some strange things, even didnt have to restart iPhone. I dont really like iPhones but i dont think it is designed so lame to force user to erase data for such lame reason. Even on windows device name is stored, but it is enough to delete ble device, then search and add it again to see new name.

chegewara avatar Aug 31 '21 14:08 chegewara

Of course, I can also use LightBlue to force a refresh. But out of the box there is no option in the operating system to do so. That's why a hard reset is the only way other than using external apps.

My concern is not how I would do it. I would rather like to have an approach where my bluetooth device forces an update of the cached data on the smartphone (btw, Android does the same thing as it is defined so in the bluetooth spec). The problem is that iOS won't give you the real mac of a bluetooth device but a random UUID. I would need the mac to identify the correct device to connect to. So my first thought was to use the name as unique identifier. I can't tell my customers "Hey, download this app and do that if you want to make it work again." if the name of that device ever changes. For now I use the manufacturer data field as workaround.

ln-12 avatar Aug 31 '21 14:08 ln-12

Like i said, if name is set in advertising then i dont see reason why the name would not be refreshed. You dont have to use any app to see new name, just start new scan.

chegewara avatar Aug 31 '21 14:08 chegewara

No, that's not the case. Even LightBlue shows me the old name until I manually connect to the device.

ln-12 avatar Aug 31 '21 14:08 ln-12

Maybe it's the bonding? I suspect that the behaviour of already paired devices is different from unpaired devices.

sivar2311 avatar Aug 31 '21 14:08 sivar2311

@ln-12 then your case is the one with name in 0x1800 service. I believe you should be able to force ble stack on iOS to refresh data, just lightblue does it, even without sending service changed characteristic. I am not going to tell you what should you do, because your question is correct and i asked espressif to add it in bluedroid, just that service is used for something different. It is usually used, which is rare, when during connection you add/delete characteristics or services.

chegewara avatar Aug 31 '21 14:08 chegewara

No, that's not the case. Even LightBlue shows me the old name until I manually connect to the device.

This is normal behavior, the device name shown on the phone will not change until you connect to the device because it needs to read it from the characteristic. For some reason phones seem to ignore the advertised name once the device has been connected to and instead caches the device name at this time and uses that for future display. Also in this situation the displayed name will still not change until reconnected as it will need to read the characteristic as well as to receive the service changed notification to force the cache clearing.

h2zero avatar Aug 31 '21 14:08 h2zero

@h2zero Ok, that's exactly what I needed to know. Mh... I see why this was done but it's also not the best solution in my opinion. Well, so it seems like I have to stick with my workaround to use the manufacturer field to propagate a unique ID as this seems to be not cached.

Thanks to all for the help and clarification! I think we can close this issue then.

ln-12 avatar Aug 31 '21 14:08 ln-12

It's still a good topic in the way that the device name should be changeable in the library. I will look to add a function for this in the future.

h2zero avatar Aug 31 '21 14:08 h2zero

@h2zero Ok, that's exactly what I needed to know. Mh... I see why this was done but it's also not the best solution in my opinion. Well, so it seems like I have to stick with my workaround to use the manufacturer field to propagate a unique ID as this seems to be not cached.

Thanks to all for the help and clarification! I think we can close this issue then.

Hi, have you solved this issue after 2 years?

amplatzer avatar Dec 08 '23 10:12 amplatzer