0

My current code is as shown below. I am wondering how do i unsubscribe (disconnect the ble) after writeCharacteristic? Also, is there a way to reconnect on writeCharacteristic fail?

  Subscription subscription = device.establishConnection(false)
                    .timeout(5000, TimeUnit.MILLISECONDS)
                    .flatMap(rxBleConnection ->
                            rxBleConnection.writeCharacteristic(fromString("00005551-0000-1000-8000-008055555fb"), hexToBytes(mData)))
                   .take(1).retry(2)
                    .subscribe(

                            characteristicValue -> {
                                Log.e(TAG, "write success " + characteristicValue + " " + device.getMacAddress());
                               // subscribeList.remove(key).unsubscribe();
                            },
                            throwable -> {
                                Log.e(TAG, "write error " + throwable);
                              //  subscribeList.remove(key).unsubscribe();
                            }
                    );
ericlee
  • 2,703
  • 11
  • 43
  • 68

2 Answers2

1

I am wondering how do i unsubscribe (disconnect the ble) after connection?

I assume that after connection is after the write because if the connection ended by external factors (like the peripheral being turned off) then the whole flow would end with an error.

If you want to write only a single value and then disconnect then everything you need is to take a single value from the flow after writeCharacteristic() by using .take(1) before the .subscribe().

Also, is there a way to reconnect on writeCharacteristic fail?

First of all, a failure of rxBleConnection.writeCharacteristic() does not automatically close the connection since 1.3.0 version of RxAndroidBle if the error is related to the write itself.

You may be experiencing the connection being closed only because you do not handle errors of the write action. You can make the write to retry two times by using .retry(2) operator.

Be mindful which Observable you try to .retry(). If you are interested in retrying writes only if they fail but the connection is still valid then you should apply .retry() on the RxBleConnection.writeCharacteristic(). On the other hand—if you want to retry the whole flow if any error will occur then you should put the .retry() on the whole flow Observable.

Subscription subscription = device.establishConnection(false)
  .flatMap(rxBleConnection ->
    rxBleConnection.writeCharacteristic(
      fromString("00005551-0000-1000-8000-008055555fb"), 
      hexToBytes(mData)
    )
    .retry(2) // retry here will only retry the write if a write characteristic will fail but the connection will still be intact
  )
  .take(1) // this will unsubscribe the above part of the Observable on the first valid emission from it—so after the write will complete
  // .retry(2) if you will put retry here then for whatever reason the above flow [connecting + writing] will fail then a new connection will be established and write performed
  .subscribe(
    characteristicValue -> {
      Log.e(TAG, "write success " + characteristicValue + " " + device.getMacAddress());
    },
    throwable -> {
      Log.e(TAG, "write error " + throwable);
    }
  );
Dariusz Seweryn
  • 3,212
  • 2
  • 14
  • 21
  • one last question. .timeout after writeCharacteristic vs after establishConnection. What's the difference? – ericlee Mar 11 '18 at 20:13
  • The same as with the `.retry()` placement. It will try to timeout a different `Observable`. – Dariusz Seweryn Mar 11 '18 at 20:20
  • so can i say that timeout after establishConnection is the gatt.connect whereas timeout after writeCharacteristic is the timeout for the writeCharacteristic . – ericlee Mar 11 '18 at 20:24
  • 1
    Precisely. :) Just have in mind that timeout `Returns an Observable that mirrors the source Observable, but notifies observers of a {@code TimeoutException} if either the first item emitted by the source Observable or any subsequent item doesn't arrive within time windows defined by other Observables.` so if you would put the `.timeout()` after `.establishConnection()` then it will fire also after the observable will emit the connection. – Dariusz Seweryn Mar 11 '18 at 20:30
  • hi there. i am having problem with writing to 4 ble devices every 6seconds. Should there be a queue or something? Write success device 1 Write success device 2 Write success device 3 Disconnected from device 1 (error) Already connected to device 2 with MAC address (error) Already connected to device 3 with MAC address (error) and so on , should i start a new thread? – ericlee Mar 12 '18 at 01:38
0

Just: subscription.unsubscribe();

If I understand the process correctly, unsubscribing will "bubble up" through the operator stack to the top, thereby disconnecting.

Robert Lewis
  • 1,847
  • 2
  • 18
  • 43
  • how do i call unsubscribe in the characteristicValue -> function? – ericlee Mar 11 '18 at 19:12
  • It should work if you just insert it after the Log "write success" statement. Maybe better would be to insert it in a new `onCompleted()` handler since `writeCharacteristic()` does complete after emitting its value. – Robert Lewis Mar 11 '18 at 19:19
  • i cant ununsubscribe after the log. It shows that subscription is not initialize – ericlee Mar 11 '18 at 19:21
  • Does it work if after the `throwable` handler you insert: `, () -> subscription.unsubscribe()` – Robert Lewis Mar 11 '18 at 19:23
  • Kind of grasping at straws here but what if you declare `Subscription subscription;` in your class declaration and then use `subscription = device.establishConnection(...`? I'm pretty sure that's worked for me. If that doesn't do it, I'm stumped. – Robert Lewis Mar 11 '18 at 19:30
  • nvm, i'll do it another way. Anyway, do you know how to reconnect on writeCharacteristic failed? – ericlee Mar 11 '18 at 19:32
  • `Subscription.unsubscribe()` is useful mostly if an external source is to dismiss the whole flow of data. If you are interested in only a single value from a flow then you can use `.take(1)` just before the `.subscribe()`. As for the failed write you can use `connection.writeCharacteristic(...).retry()` or `.retryWhen()`. Mind which `Observable` you try to `.retry*()` – Dariusz Seweryn Mar 11 '18 at 19:36
  • @DariuszSeweryn as i am very new in rxjava, would you please check if my new edited code works? it seems to be still not working on my android. Does it disconnect after it have successfully writeCharacteristic? And also does it retry up to a maximum of two times on error when writeCharacteristic – ericlee Mar 11 '18 at 19:44
  • @DariuszSeweryn why does `subscription.unsubscribe()` give an error? – Robert Lewis Mar 11 '18 at 20:53
  • It doesn't. It's the chicken and an egg problem where the ` subscription` is not yet initialized to use it in the `unsubscribe()` callback from what I understood – Dariusz Seweryn Mar 11 '18 at 21:20