3

First of all, I am using RxAndroidBLE library to manage my BLE connections.

I have two SensorTag devices and I want to read temperature from both at the same time. For example, I'd like to read the temperature from both devices exactly every 500ms and display it to user in two TextViews.

My app currently successfully connects to both BLE devices like this:

@OnClick(R.id.connectButton1)
public void connectFirstSensorTag(Button b) {
    if (!isDeviceConnected(sensorTag1)) {
        connectionObservable1 = sensorTag1.establishConnection(getApplicationContext(), false).compose(new ConnectionSharingAdapter());
    }

    connectionObservable1.subscribe(new Subscriber<RxBleConnection>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
            updateStatus(statusTextView1, "SensorTag not found");
        }

        @Override
        public void onNext(RxBleConnection rxBleConnection) {
            updateStatus(statusTextView1, "Connected");
            enableSensorTagTemperatureSensor(connectionObservable1);
        }
    });
}

@OnClick(R.id.connectButton2)
public void connectSecondSensorTag(Button b) {
    if (!isDeviceConnected(sensorTag2)) {
        connectionObservable2 = sensorTag2.establishConnection(getApplicationContext(), false).compose(new ConnectionSharingAdapter());
    }

    connectionObservable2.subscribe(new Subscriber<RxBleConnection>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
            updateStatus(statusTextView2, "SensorTag not found");
        }

        @Override
        public void onNext(RxBleConnection rxBleConnection) {
            updateStatus(statusTextView2, "Connected");
            enableSensorTagTemperatureSensor(connectionObservable2);
        }
    });
}

Now I'm looking for the best way to read temperature from both at the same time every 500ms.

Right now, I'm doing something like this:

connectionObservable1
                .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(uuidFromShortCode("AA01")))
                .subscribe(bytes -> {

                    // first temperature was successfully read here

                    connectionObservable2
                            .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(uuidFromShortCode("AA01")))
                            .subscribe(bytes -> {

                                // second temperature was successfully read here

                            }, error -> {
                                updateStatus(error.toString());
                            });
                }, error -> {
                    updateStatus(error.toString());
                });

And this block of code is inside a runnable that gets called every 500ms.

I feel like this an extremely inefficient way to do it. Could someone please let me know if there is a better way to do this?

1
  • You should probably parallelize the read, no? Also note that there's no reason to have two anonymous "new Subscriber<RxBleConnection>(" (extract this as an inner class and pass statusTextView1/2 by the constructor)
    – user180100
    Aug 14, 2016 at 10:00

2 Answers 2

2

First of all you cannot make truly parallel reads or any other operations on the BLE as you have only one radio and operations need to be sequential. The best you can do is to fire them as soon one after another as possible. Using the RxAndroidBle you are getting the serialization managed for you.

The way to doing what you want I see this way:

    RxBleDevice sensorTag0 = // your first SensorTag
    RxBleDevice sensorTag1 = // your second SensorTag
    UUID characteristicUuid = uuidFromShortCode("AA01");

    Subscription flowSubscription = Observable.combineLatest(
            sensorTag0.establishConnection(this, false), // establishing connections
            sensorTag1.establishConnection(this, false),
            Pair::new // merging them together
    )
            .flatMap(connections -> Observable
                    .interval(500, TimeUnit.MILLISECONDS) // every 500 ms
                    .flatMap(aLong -> Observable.combineLatest(
                            connections.first.readCharacteristic(characteristicUuid), // performing reads
                            connections.second.readCharacteristic(characteristicUuid),
                            Pair::new // and merging the results
                    )))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                    readings -> {
                        updateUISensorTag0(readings.first); // updating the UI
                        updateUISensorTag1(readings.second);
                    },
                    throwable -> updateStatus(throwable.toString()) // or showing the error
            );

Hope this helps you.

Best Regards.

4
  • Thanks! This is exactly the kind of answer I was looking for. One additional question though. How did you know that RxAndroidBle is capable of doing this? I've read through all the documentation that is available for this library (and there's not much of it) and there was no example that would show anything like this. Did you dig into the source code to find out? Or is there something else that I missed when learning about this library? I am genuinely interested because I often stumble upon an issue that I can't resolve even after digging through documentation a lot.
    – Guy
    Aug 16, 2016 at 18:59
  • I am one of authors of the RxAndroidBle library. The library tries to conform to Observable contract and the rest is combining that with rxJava knowledge. In the above example I only use two library methods: establishConnection(Context, boolean) and readCharacteristic(UUID) - the rest is pure rxJava. Actually there is the Example #5 github.com/Polidea/RxAndroidBle/blob/master/sample/src/main/… where a similar flow is being used with readRssi() instead of readCharacteristic(UUID) Aug 16, 2016 at 19:36
  • If I may ask - what information would you expect? And where? I will try to update available documentation. Aug 16, 2016 at 20:50
  • Actually I didn't know that this is mostly just RxJava. I am very new to RxJava as well (pretty much never used it before this), so that's probably the reason why I couldn't use this library in a more "advanced" way. I guess what I would expect from documentation is to show and possibly explain some more advanced usage examples like the one in your answer, because a lot of people like me meet RxJava for the first time when they want to use a library like yours. But either way, great library, I love it! It made BLE extremely easy to use for me :)
    – Guy
    Aug 17, 2016 at 6:43
0

I would suggest that you start two threads. Thread 1 checks the first device, thread 2 checks the second. This ensure that both are being read at the same time. In order to proceed with the code only after both have completed, I would do a blocking join loop.

//Threads array has been created, with 0 checking the first 
//device and 1 checking the second
for(i = 0; i < threads.length(); i++)
    threads[i].join();
3
  • Hey, thanks for your answer. Could you elaborate on the for loop you mentioned? I don't think I fully understand how it would help me know when both threads finished.
    – Guy
    Aug 14, 2016 at 13:45
  • thread.join allows you to wait for a thread to end before completion. Now, if you loop over all threads an ensure that they're all done, then that's exactly what you want!
    – meedz
    Aug 16, 2016 at 18:22
  • That makes sense, thanks! I accepted another answer since it is more viable for my example, but your information helped too.
    – Guy
    Aug 16, 2016 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.