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

GATT cache behavior #17

Open
travisghansen opened this issue Dec 26, 2024 · 12 comments
Open

GATT cache behavior #17

travisghansen opened this issue Dec 26, 2024 · 12 comments

Comments

@travisghansen
Copy link

Forgive the ignorance. I have done some research and haven't been able to find much. Is it possible to hint to the centrals to not cache the gatt data? I significantly change the info based on a number of criteria and run into issues with caching.

On my linux machine it's easy to disable cache functionality but for others I need a bullet proof approach to ensure the centrals don't fail due to caching (could be any os and/or android/ios).

Any tips?

Thanks!

@Emill
Copy link
Owner

Emill commented Dec 27, 2024

Du you mean caching the structure of the gatt services, characteristics and descriptors?

@travisghansen
Copy link
Author

Yeah. I switch the service/characteristics based on certain state in the device. I have clients (centrals) which I have 0 control over and if they cache the data and I have no way to 'fix' that then I will need to come up with another design.

@Emill
Copy link
Owner

Emill commented Dec 27, 2024

Well, according to the BLE spec, the only cases the GATT client is allowed to cache the structure is when any of the following is true:

  1. The devices are bonded.
  2. The Service Changed Characteristic is not present in the GATT server.

This library exposes the Service Changed Characteristic so only option 1 should be relevant. So, simply make sure to not bond the devices to not make the client cache the GATT structure between connections.

If you want the client to be informed of the changes you have made, you should send a Service Changed Indication on the Service Changed Characteristic, with the affected handle range as value. This is the "correct way" to inform a GATT client that the services have changed. This can be sent during an on-going connection if the services are modified while connected and should also be sent to bonded devices immediately after connection setup, in case the service declarations have changed while the device was disconnected.

Alternatively, you can use a different identity when you use different set of services in your GATT database by changing the Bluetooth Device address of the GATT server. In particular, use a Static Random address when initializing the BleManager as explained in this section: https://github.com/Emill/node-ble-host/blob/master/docs/api/ble-manager.md#creating-a-blemanager-object.

@travisghansen
Copy link
Author

OK great! I don't really change the values on the fly..I wait for the current client to disconnect and re-access the situation before advertising again. Do you happen to have any specific example of leveraging the service changed characteristic? I assume I essentially just need to declare it and that's it (central will no longer cache).

@travisghansen
Copy link
Author

Well, I am simply doing BLE so I assume no bonding is involved (I don't exchange pins or anything of that nature).

@Emill
Copy link
Owner

Emill commented Dec 27, 2024

Just Works bonding is allowed by default. To disallow that, use the code in this section: https://github.com/Emill/node-ble-host?tab=readme-ov-file#example---pairing-should-be-disabled. If the client still caches the GATT db between connections, it is not following the spec.

To send indications for the Service Changed characteristic, you can use this method https://github.com/Emill/node-ble-host/blob/master/docs/api/gatt-server.md#gettdbgetsvcccharacteristic to get access to it, then call the notifyAll method on it with Buffer.from([0, 0, 0xff, 0xff]) if you simply want to indicate that the full range has been changed to all connected devices.

@travisghansen
Copy link
Author

I don't have any pairing handlers so I doubt that's in play but I will put that code in place just to be sure. When I connect with LightBlue I do not see the characteristic however. Are you suggesting I should see that no matter what?

@Emill
Copy link
Owner

Emill commented Dec 27, 2024

That characteristic is automatically added when the library is initialized: https://github.com/Emill/node-ble-host/blob/master/lib/internal/gatt.js#L846. Don't you see that one?

@travisghansen
Copy link
Author

It's not there in Light Blue no.

      function startAdv() {
        manager.gattDb.removeService(services[SERVICE_UUID]);
        manager.gattDb.removeService(services[JOIN_SERVICE_UUID]);

        if (ConfigManager.SIDEKICK_DEVICE_TOKEN) {
          manager.gattDb.addServices([services[SERVICE_UUID]]);
          manager.setAdvertisingData(serviceAdvDataBuffer);
          advertised_service_uuid = SERVICE_UUID;
        } else {
          manager.gattDb.addServices([services[JOIN_SERVICE_UUID]]);
          manager.setAdvertisingData(joinServiceAdvDataBuffer);
          advertised_service_uuid = JOIN_SERVICE_UUID;
        }

        manager.startAdvertising(
          {
            /*options*/
          },
          connectCallback
        );
        console.log(
          `${listener.constructor.name} server advertising: dev=${activeDevice.name}, mac=${activeDevice.bdaddr}, service_uuid=${advertised_service_uuid} (${advertised_service_uuid == SERVICE_UUID ? 'normal' : 'join'}), name=${deviceName}, localName=${deviceLocalName}`
        );
      }

@Emill
Copy link
Owner

Emill commented Dec 27, 2024

Do you use LightBlue on iOS? I don't think iOS exposes that service to apps. If you want to confirm that the characteristic is there you can try on Android.

@travisghansen
Copy link
Author

I am on ios, let me try it on android real quick...

@travisghansen
Copy link
Author

Indeed the characteristic is there. Let me do some digging on other OSes and flesh out the behavior a little better and report back my findings. I can say that for sure on linux the bluez stack is caching unless explicitly turned off globally...which is unfortunate. I will confirm bonding isn't happening. I am only doing LE stuff and all of it is through web bluetooth (chromium) and ionic.

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

2 participants