Search code examples
iosswiftbluetoothrx-swift

Extend Bluetooth connection timeout only when connection was successful using RxBluetoothKit


What I want to do are:

  1. Write value to a characteristic
  2. If connection fails within a certain time, handle as a timeout error
  3. If connection succeeds, extend or ignore timeout and keep connection

I realized 1 and 2, but how can I realize 3? Thank you very much for your help.

My source:

manager = CentralManager(queue: .main, options: options)
manager!.observeState()
    .startWith(self.manager!.state)
    .filter { $0 == .poweredOn }
    .timeout(3.0, scheduler: MainScheduler.instance)
    .take(1)
    .flatMap { _ in self.manager!.retrievePeripherals(withIdentifiers: [peripheralUUID])[0].establishConnection() }
    .timeout(5.0, scheduler: MainScheduler.instance) // (A) Set connection timeout here
    .flatMap{ $0.writeValue(data, for: BLECharacteristic.char, type: .withResponse)}
    .subscribe(onNext: { char in
        // (B) I want to extend timeout here
        // Handle success
    }, onError: { (error) in
        // Handle error
    }, onCompleted: nil, onDisposed: nil)

Solution

  • You want the observable for the connection to timeout, as opposed to imposing a timeout on the whole chain

    // ...
    .take(1)
    .flatMap { _ in 
      self.manager!.retrievePeripherals(withIdentifiers: [peripheralUUID])[0]
        .establishConnection()
        .timeout(5.0, scheduler: MainScheduler.instance)
        .take(1)
    }
    .flatMap{ $0.writeValue(data, for: BLECharacteristic.char, type: .withResponse) }
    // ...
    

    The addition of .take(1) makes sure the observable completes after the connection is established (though in an ideal world, establishConnection() should be the one responsible for this behavior).