-->

How do I effectively read temperature from two BLE

2019-07-04 18:24发布

问题:

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:

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.



回答2:

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();