jordanebelanger / SwiftyBluetooth

Closures based APIs for CoreBluetooth
MIT License
209 stars 66 forks source link

discoverCharacteristics 1 failure -operationTimedOut(operation: SwiftyBluetooth.SBError.SBOperation.discoverServices) #39

Open kshrikant opened 5 years ago

kshrikant commented 5 years ago

Hello @jakerockland ,

First of all thanks for such wonderful library which I'm using in my project currently i.e. SwiftyBluetooth. Theres one issue i'm facing in it, please kindly help me or you can suggest solution for it.

I'm scanning for below CBUUIDs using SwiftyBluetooth.scanForPeripherals

let serviceId3 = CBUUID(string:"FFF0") let serviceId4 = CBUUID(string:"FFB0")

these service ids are used for detecting temperature devices.

Ill get scanned devices successfully, after that I do successful connection with those peripheral using selectedPeripheral!.connect(withTimeout: 10)

I'm calling func discoverServices for serviceId = CBUUID(string:"FFE0")

After that the issue I'm getting in your library is

discoverCharacteristics 1 failure -operationTimedOut(operation: SwiftyBluetooth.SBError.SBOperation.discoverServices)

I did deep debugging in your library so I got to know that here in below code

extension PeripheralProxy  {

func discoverServices(_ serviceUUIDs: [CBUUID]?, completion: @escaping ServiceRequestCallback)  {

    self.connect { (result) in
        if let error = result.error {
            completion(.failure(error))
            return
        }

        if let serviceUUIDs = serviceUUIDs {
            let servicesTuple = self.cbPeripheral.servicesWithUUIDs(serviceUUIDs)

            if servicesTuple.missingServicesUUIDs.count == 0 {
                completion(.success(servicesTuple.foundServices))
                return
            }
        }

        let request = ServiceRequest(serviceUUIDs: serviceUUIDs) { result in
            completion(result)
        }

        self.serviceRequests.append(request)

        if self.serviceRequests.count == 1 {
            self.runServiceRequest()
        }
    }
}

In file PeripheralProxy.swift on line number 183 or in above code

let servicesTuple = self.cbPeripheral.servicesWithUUIDs(serviceUUIDs)

 if servicesTuple.missingServicesUUIDs.count == 0 {
          completion(.success(servicesTuple.foundServices))
          return
 }

Whenever I'm getting above timeout error at that time serviceTuple.missingServicesUUIDs.count is one.

So whatever serviceId I've requested i.e serviceId = CBUUID(string:"FFE0") is missing. Kindly please let me know how can I resolve this, I'm trying to resolve this issue since last 3-4 days. Please help me. Thanks in advance.

NOTE :- This is issue is not getting generated always its happening few times and sometimes serviceTuple.missingServicesUUIDs.count is zero and I'm getting success

jordanebelanger commented 5 years ago

Are you sure service "FFE0" exists on the peripheral you are working with? Basically the library is timing out trying to discover that service on the peripheral.

Tip, try to use one of the bluetooth utility app on the appstore to check, for example: https://itunes.apple.com/us/app/ble-nearby/id1069714373

Use that and you should be able to see all public services on your peripheral.

If the service is really there and your issue only happens from time to time, like you say, it's probably because there is a problem on the peripheral you are trying to access making it unreliable.

In that case you should either try to fix the peripheral (if you can) or implement some-kind of auto-retry logic in your app to try to discover your "FFE0" service a couple times before giving up.

So in your example, it looks like you are trying to discover and or read a characteristic of the "FFE0" service, so the library is trying to automatically discover that service for you when you do that, but is timing out while trying to automatically discover that service.

So since the discovery of that FFE0 service seems to be the problem, your auto retry logic should try to call discoverServices(["FFEO"] a couple times. Once a service has been successfully discovered for a peripheral, it wont have to be rediscovered again so you will have a good guarantee that your calls to characteristics of that service will at least not timeout trying to discover that service.

Good luck :)

kshrikant commented 5 years ago

@jordanebelanger Thanks! for quick reply. As you said I've downloaded sample and tested the services are fine. The actual issue is whenever app killing and launching again app (or first time) at that time only its receiving characteristics. When within app I'm doing disconnect and cancelPeripheral connection still its not receiving characteristics. Any idea with this problem ? Or what can I do with Peripheral class objects ? Please help me thanks. Is there any issue with strong and weak references. ?

I went through state preservation code too in library that is I'm writing it in didFinishLaunchingWithOptions

SwiftyBluetooth.setSharedCentralInstanceWith(restoreIdentifier:Central.CentralManagerWillRestoreState.rawValue) Is there anything with it which I'm missing.

In addition to it I didn't added this observer NotificationCenter.default.addObserver(forName:Central.CentralManagerWillRestoreStateNotification which is already in library. Is there something related to it which I'm missing due to that its happening ?

In short I am also facing same issue which previous developers faced already. Issue thread #37