1

While establishing connection i used .asObservable() property to stay connected.

bleDevice = rxBleDevice;
rxBleDevice.establishConnection(false)
        .flatMap(RxBleConnection::discoverServices)
        **.asObservable()**
        .subscribe(rxBleDeviceServices -> swapScanResult(rxBleDeviceServices));

After connection established when i tried to read values it show

Already connected to device

 bleDevice.establishConnection(false)
        .flatMap(rxBleConnection -> Observable.combineLatest(
                    rxBleConnection.readCharacteristic(gattCharacteristicList.get(6).getUuid()),
                    rxBleConnection.readCharacteristic(gattCharacteristicList.get(7).getUuid()),
                    ReadValuesOnConnection::new
        ))
        .subscribe(
                readValuesOnConnection -> Log.i("UUid 6 Value: ", readValuesOnConnection.value_1+""),
                throwable -> Log.e("Error", throwable.getMessage())
        );

Logs:

I/Bluetooth Enable: True
I/RxBle#QueueOperation: Scan operation is requested to start.
I/Scan Results:: 6Q:6C:05:8E:F5:5B
I/Scan Results:: 6P:6A:05:8E:F8:2X
I/RxBle#CancellableSubscription: Scan operation is requested to stop.
W/zygote64: Suspending all threads took: 5.645ms
I/Characteristics List size:: 33
E/Error: Already connected to device with MAC address 6Q:6C:05:8E:F5:5B

I go through the sample project but didn't find any solution.

James Z
  • 12,209
  • 10
  • 24
  • 44
Salman Naseem
  • 462
  • 4
  • 17

1 Answers1

2

What do you mean by client is in observable state? .asObservable() is not a property but a function that—in this particular case—changes nothing as the result of .flatMap() is already an Observable.

Already connected to device with MAC address comes from BleAlreadyConnectedException and is indication that one tries to establish a new connection when there is one already opened.

What you probably want is to combine the two independent flows into one that would do both: swapScanResult and read characteristics. You could do this like:

subscription = rxBleDevice.establishConnection(false) // first we want to establish the connection
  .flatMap( // once the connection is established
    RxBleConnection::discoverServices, // we want to explicitly discover the services
    (rxBleConnection, rxBleDeviceServices) -> { // when both the connection and services are available
      swapScanResult(rxBleDeviceServices); // we swap scan result?
      return Observable.combineLatest( // and start reading characteristics
        rxBleConnection.readCharacteristic(gattCharacteristicList.get(6).getUuid(),
        rxBleConnection.readCharacteristic(gattCharacteristicList.get(7).getUuid(),
        ReadValuesOnConnection::new // when both characteristics are read we combine the result
      );
    }
  )
  .flatMap(observable -> observable) // we need to flatMap the result as we returned an Observable from the first flatMap
  .take(1) // after the read has completed we unsubscribe from the upstream to make the connection close
  .subscribe( // we consume the result
    readValuesOnConnection -> Log.i("UUid 6 Value: ", readValuesOnConnection.value_1+""),
    throwable -> Log.e("Error", throwable.getMessage())
  );

Additionally this flow uses some side effects which make it potentially non-deterministic. You call a method swapScanResult(RxBleDeviceServices) and in other place you use gattCharacteristicList.get(int).getUuid() and feed it back to the flow.

It is possible to make the code more easy to follow by doing a change to the above mentioned method and access to the list of characteristics (that is stored as a property). It is as simple as changing it into a pure function that could have a signature like:

static Pair<UUID, UUID> getUuidsOfCharacteristicsToRead(RxBleDeviceServices services);
Dariusz Seweryn
  • 3,212
  • 2
  • 14
  • 21
  • I'd like to read some value from peripheral after every 3 seconds, Any thoughts? – Onkar Nene Mar 27 '18 at 07:15
  • Should be fairly easy. – Dariusz Seweryn Mar 27 '18 at 07:40
  • Could you please provide any examples or tutorial? Because I tried to connect first time - **It connected properly** and then I tried to write characteristic, But it is showing `Already connected to device with MAC address` error. – Onkar Nene Mar 27 '18 at 07:48
  • There are already some examples and questions on [stackoverflow](https://stackoverflow.com/questions/tagged/rxandroidble). You can browse them or ask a new question. – Dariusz Seweryn Mar 27 '18 at 07:59
  • With rxandroidble 1.11.1 this no longer compiles - `RxBleConnection::discoverServices` gives `Bad return type in method reference: cannot convert io.reactivex.Single to io.reactivex.ObservableSource>`. Is that an RxJava2 issue? – warbi Jun 24 '20 at 08:49
  • Yes, `RxAndroidBle` based on RxJava2 has a different API (some `Observable` become `Single`, some `Completable`). General idea is the same but one needs to use `.flatMapSingle()`/`.flatMapCompletable()`, `Single.zip()`... etc. where appropriate. – Dariusz Seweryn Jun 24 '20 at 20:01