5

I'm developing an app which connects and disconnects several times to different bluetooth low energy peripherals. After a lot of research on the internet, I didn't have found a way to store already discovered services and characteristics, so that I can reconnect faster. At the moment I'm discovering the required services and characteristics after each reconnection, which costs me between 1.5 and 2 seconds.

Does someone have experience or a solution to store/cache a CBService or a CBCharacteristic or does someone know a way to reconnect faster?

Thanks for any help

Linard Arquint
  • 574
  • 3
  • 12
  • 32
  • Are you asking how to cache something in your application ? – Dennis Mathews Feb 14 '13 at 23:49
  • 1
    That would be a solution to cache services and characteristics, but I have already tried to make a copy of a services. But unfortunately CBPeripheral, CBService and CBCharacteristic do not have adopted NSCopying. Is there another way to store them? – Linard Arquint Feb 15 '13 at 07:49
  • You can put the Pripheral in an array. This array you can 'save' as user defaults with the NSUserDefaults Class – Areal-17 Feb 19 '13 at 12:23
  • Thank you @Areal-17 for your input. I've tried to save a CBPeripheral in the NSUserDefaults Class, but unfortunately only property values can be stored. Here's the error output: [NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '( { peripheral = " A8BB2F03-A42D-CC4E-9206-B936AA2AB663, Name = \"LightControl Device\", IsConnected = NO>"; } )' of class '__NSArrayM'. Note that dictionaries and arrays in property lists must also contain only property values. – Linard Arquint Feb 20 '13 at 08:17
  • In the `didDiscoverPeripheral:` peripheral delegate method you add the discovered peripheral to an array. for example: `id peripheralUUID = (id)peripheral.UUID; if (![self.discoveredPeripherals containsObject:peripheralUUID]) { [self.discoveredPeripherals addObject:peripheralUUID]; }` self.discoveredPeripherals is a NSMutableArray property. The next step is setting the userDefault with setObjectForKey:. Important is to cast the CBUUID object into id. – Areal-17 Feb 20 '13 at 12:50
  • @Areal-17: I understand what you mean, but I already store the UUID. What I want is to store the entire CBPeripheral object and not just his UUID. – Linard Arquint Feb 20 '13 at 14:12

2 Answers2

7

I've tried caching peripheral, service and characteristic objects in memory and manual caching does not work. Once you have disconnected from the peripheral, the service and characteristic objects are no longer valid for use. In fact, even the CBPeripheral can change out from under you – CoreBluetooth has an internal behavior where the device UDID will change every few minutes (if the CBPeripheral is another iOS device).

However, if you are running developing for iOS 6, there is a way to speed things up. If you watch the Advanced Bluetooth talk at WWDC 2012, you'll see a slide towards the end about caching services and characteristics. Essentially, the OS can cache them all for you but only for paired devices. To pair, you need to respond to a write request with an insufficient authentication error. For example, for an iOS peripheral you would write something like:

- (void)peripheralManager:(CBPeripheralManager *)peripheralManager didReceiveWriteRequests:(NSArray *)requests {
      ...

      [peripheralManager respondToRequest:request withResult:CBATTErrorInsufficientAuthentication];

      ...
}

That will pop up a pairing dialog on the iOS peripheral, after which point you will be paired. Other than that you don't have to change your code – just call discoverServices etc as normal and they will respond more quickly (ie instantly).

I have also tested this behavior on 10.8.3 and it does not appear to work. So, I don't know of a way to speed things up on OS X (other than staying connected to the peripheral).

  • thank you for your answer. I've already filled out a bug report and Apple told me, that they are caching the services and characteristics. But I have tested that with my peripheral and I saw the same slow connection interval. Is this caching only available with 2 iOS Devices or also with an 3rd party peripheral? – Linard Arquint Apr 18 '13 at 15:13
  • 1
    It should work with a 3rd party peripheral if you establish an encrypted link with it. Have not tested this myself. – William henderson Apr 23 '13 at 18:33
  • has it to be an encrypted connection? Because at the moment I connect to my peripheral without any encryption at all – Linard Arquint Apr 25 '13 at 20:45
  • 1
    Right. Only encrypted connections get the caching behavior. – William henderson May 01 '13 at 21:23
  • how can I establish an encrypted connection? Does the peripheral ask for encryption? And are not only the characteristics encrypted or password protected? – Linard Arquint May 02 '13 at 05:01
  • 1
    I believe the pairing process establishes an encrypted link. When you try to connect, iOS will pop up an alert asking the user to pair or cancel. On the manager side you don't need to do anything for pairing. I don't know how it works on the peripheral side. – mezulu May 04 '13 at 14:55
  • I have paired my two devices (iPad and custom BLE accessory), I see the pairing in my bluetooth settings as well, yet when I try to call `retrievePeripherals:` with the stored UUID I get no objects back in the callback – Dan F Aug 27 '13 at 19:51
  • 1
    @Williamhenderson You wrote "CoreBluetooth has an internal behavior where the device UDID will change every few minutes (if the CBPeripheral is another iOS device)." I would love to read more on that, can you link me to where you got this information? – bsarrazin Jul 28 '14 at 15:42
3

iOS 7 adds additional caching (iOS 7: What's New in Bluetooth LE). I'm seeing times less than 100ms (~80ms average) total to reconnect to a peripheral, discover services, discover characteristics, and read the value of a single characteristic.

My test configuration was an iPad Air connecting to an iPad 3.

darrinm
  • 9,117
  • 5
  • 34
  • 34
  • Darrinm, can you specify exactly where the caching explanation is in the article? I could be daft, I just can't seem to find it. – Maximilian Jan 08 '14 at 19:49
  • @Max There isn't much of an explanation, only "The peripheral data caching [...] is enhanced with even more data from each characteristic and service, including the last-known value of each characteristic." So I timed the whole connect/discover services/discover characteristics/read value process to see how much of an improvement the new caching made. – darrinm Jan 09 '14 at 02:02