Persistent BLE connection/bonding

Posted on
  • I'm currently working on a small app that allows to control a ... marital aid of the satisfyer variety via BLE. After learning that the connection needs to be bonded (I'm not really experienced in BLE yet) I also managed to control the device quite well. However, everytime I restart the app or go back to clock, the device is disconnected and I need to re-bond it, which takes alot of time. Is there a way to have a persistent connection in the background that stays active (and send a keepalive every ~100ms) or at least be able to skip the bonding procedure to save time?
    Thanks!

    Also, if I get the app to work more consistently, it shouldn't be that hard to change it to also work with sextoys from different brands and add features like control via accelerometer etc. I'd love to upload it once finished but due to the nature of the app I'm not sure if Gordon/the team would like something like this in the official store.

  • You could always change it to a different PG rated device for demo purposes maybe?

    I'm not part of the team but I think there is a lot of appeal for programmable smart watches for schools so your concerns may be valid.

  • That should be possible, yeah. Though I'm not sure which kind of device has similar control mechanics. Most of the BLE devices I know are sensors rather than motors/actuators with single or double channels of intensity.

  • However, everytime I restart the app or go back to clock, the device is disconnected and I need to re-bond it

    oh, this may be caused by design decision of doing reset() when exiting each app to prevent memory leaks, only the console connection (from WebIDE or gadgdetbridge) survives.
    However bonding should have persistent storage (managed by PeerManager component of Nordic SDK) and Espruino uses it so it should not be needed to do it again when connection drops (or even after reset/reboot). After all connection drop can happen anytime.

    Can you test in your app that you can disconnect and reconnect without doing it all again while your app still runs? And perhaps create issue for this https://github.com/espruino/Espruino/iss­ues linking this thread.

    BTW some of those devices run nrf52, there was quite interesting (or funny, or scary) video on youtube from DEFCON talk about reflashing firmware remotely in those devices while chatting with person using it, check https://github.com/smealum/butthax
    So one could even run Espruino on both sides of the connection :-)

  • Hey fanoush,
    thanks for the reply! I now tried to remove the startBonding step but if I omit that, nothing happens on the Device despite all other actions succeding.

    Here is the complete code I use to control the device. Maybe there are some steps that I could remove or speed up to save time, I'd be very grateful for any hints (or also JS best practice remarks, I haven't worked with JS before). Also, does console.log take up alot of time?

    NRF.connect(ST_ADDRESS).then(function connectComplete(connection){
    	st = connection;
      console.log("Connected to", connection);
      return st.device.gatt.connect();
    }).then(function(gatt) {
      st_gatt = gatt;
      console.log("connected");
      return st_gatt.startBonding(false);
    }).then(function() {
      console.log("bonded", st_gatt.getSecurityStatus());
      return st.getPrimaryService("51361500-c5e7-47c7­-8a6e-47ebc99d80e8");
    }).then(function serviceComplete(service){
      st_service = service;
      console.log("Got Service", service);
      return service.getCharacteristic("51361501-c5e7­-47c7-8a6e-47ebc99d80e8");
    }).then(function statusComplete(data) {
      st_status = data; 
      console.log("Status Success", st_status);
      return st_service.getCharacteristic("51361502-c­5e7-47c7-8a6e-47ebc99d80e8");
    }).then(function statusComplete(data) {
      st_motor = data; 
      console.log("Motor Success", st_motor);
    ).then(function start() {
      return st_status.writeValue([1]); //Send enable byte
    }).then(vibrate, console.log);
    
    

    I've heard about the security risks associated with these devices if nrf dfu remains possible, however this particular device (plug-ilicous 2) seems to use a realtek ic. Although I love the idea of a buttplug running js (the most direct way to tell someone to shove JS up their ass...) :D

  • OK, the false parameter (or nothing) in startBonding should not do it again so it could be faster second time as per http://www.espruino.com/Reference#l_Blue­toothRemoteGATTServer_startBonding
    so keep it in if it doesn't work without it.
    console.log should be fast, there is also print which should be the same.
    You can also log time in each step (console.log(Date().toISOString(),....), maybe the service and chacteristics discovery takes most of the time, not the startBonding step (except first time)?

    EDIT:
    Also one random idea, maybe the startBonding can be done later so the service/characteristics discovery runs without encryption, maybe it can be faster that way(?)

  • I timed every step as you said, the service discovery takes most of the time, up to 4 seconds.
    Bonding does make a difference but below one second and since it's apparently necessary to do before doing anything else, I'll leave that in for now (when I moved it to later in the code, it didn't work anymore).

    When I have the primaryService, the characteristics take about 300ms each, and maybe I can even shorten that by just using getCharacteristics and directly assinging both instead of looking for both indivitually. But this is also small compared to the time it takes for the primaryService.

    Is there any way to "cache" the primaryService for later use (and store it in a JSON or something like that)?

  • Is there any way to "cache" the primaryService for later use (and store it in a JSON or something like that)?

    There is, yes! Although normally you'd cache them in the app, not between apps.

    I believe all you really need to do is do:

    st_status = new BluetoothRemoteGATTCharacteristic();
    st_status.handle = ...; // i think - it may be called something slightly different
    

    ... and get the handle from the number in your existing code. The handle number won't actually ever change on that device - it basically only changes with different firmwares/device types.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Persistent BLE connection/bonding

Posted by Avatar for Jonathan @Jonathan

Actions