Как эффективно одновременно считывать температуру с двух устройств BLE?

Прежде всего, я использую библиотеку RxAndroidBLE для управления подключениями BLE.

У меня есть два устройства SensorTag, и я хочу читать температура от обоих одновременно. Например, я хотел бы считывать температуру с обоих устройств ровно каждые 500 мс и отображать ее пользователю в двух TextView.

Мое приложение в настоящее время успешно подключается к обоим устройствам BLE следующим образом:

@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);
        }
    });
}

Теперь я ищу лучший способ считывать температуру с обоих одновременно каждые 500 мс.

Прямо сейчас я делаю что-то вроде этого:

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

И этот блок кода находится внутри запускаемого объекта, который вызывается каждые 500 мс.

Я чувствую, что это крайне неэффективный способ сделать это. Может кто-нибудь, пожалуйста, дайте мне знать, есть ли лучший способ сделать это?


person Guy    schedule 14.08.2016    source источник
comment
Вероятно, вам следует распараллелить чтение, не так ли? Также обратите внимание, что нет причин иметь два анонимных новых подписчика‹RxBleConnection›( (извлеките это как внутренний класс и передайте statusTextView1/2 конструктором)   -  person    schedule 14.08.2016


Ответы (2)


Прежде всего, вы не можете выполнять действительно параллельные чтения или любые другие операции на BLE, поскольку у вас есть только одно радио, и операции должны быть последовательными. Лучшее, что вы можете сделать, это уволить их как можно скорее одного за другим. Используя RxAndroidBle, вы получаете управление сериализацией для себя.

Способ делать то, что вы хотите, я вижу так:

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

Надеюсь, это поможет вам.

Наилучшие пожелания.

person Dariusz Seweryn    schedule 16.08.2016
comment
Спасибо! Это именно тот ответ, который я искал. Хотя один дополнительный вопрос. Как вы узнали, что RxAndroidBle способен на это? Я прочитал всю доступную документацию по этой библиотеке (а ее немного), и не нашел ни одного примера, который бы показывал что-то подобное. Вы копались в исходном коде, чтобы узнать? Или есть что-то еще, что я пропустил, когда узнал об этой библиотеке? Мне это искренне интересно, потому что я часто натыкаюсь на проблему, которую не могу решить даже после того, как долго копался в документации. - person Guy; 16.08.2016
comment
Я являюсь одним из авторов библиотеки RxAndroidBle. Библиотека пытается соответствовать контракту Observable, а остальное сочетает это со знаниями rxJava. В приведенном выше примере я использую только два библиотечных метода: establishConnection(Context, boolean) и readCharacteristic(UUID) — остальное — чистый rxJava. На самом деле есть пример № 5 github.com/Polidea/RxAndroidBle/blob/master/sample/src/main/, где аналогичный поток используется с readRssi() вместо readCharacteristic(UUID) - person Dariusz Seweryn; 16.08.2016
comment
Позвольте спросить - какой информации вы ожидаете? И где? Я постараюсь обновить имеющуюся документацию. - person Dariusz Seweryn; 16.08.2016
comment
На самом деле я не знал, что это в основном просто RxJava. Я также очень новичок в RxJava (практически никогда не использовал его до этого), так что, вероятно, это причина, по которой я не мог использовать эту библиотеку более продвинутым способом. Я думаю, что я ожидал бы от документации показать и, возможно, объяснить некоторые более сложные примеры использования, такие как тот, что в вашем ответе, потому что многие люди, такие как я, впервые встречают RxJava, когда хотят использовать библиотеку, подобную вашей. Но в любом случае, отличная библиотека, мне нравится! Это сделало BLE чрезвычайно простым в использовании для меня :) - person Guy; 17.08.2016

Я бы посоветовал вам создать две темы. Поток 1 проверяет первое устройство, поток 2 проверяет второе. Это гарантирует, что оба читаются одновременно. Чтобы продолжить работу с кодом только после завершения обоих, я бы сделал блокирующий цикл соединения.

//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();
person meedz    schedule 14.08.2016
comment
Эй, спасибо за ваш ответ. Не могли бы вы подробнее рассказать о цикле for, который вы упомянули? Я не думаю, что полностью понимаю, как это поможет мне узнать, когда оба потока закончатся. - person Guy; 14.08.2016
comment
thread.join позволяет дождаться завершения потока до его завершения. Теперь, если вы переберете все потоки и убедитесь, что они все выполнены, то это именно то, что вам нужно! - person meedz; 16.08.2016
comment
Это имеет смысл, спасибо! Я принял другой ответ, так как он более подходит для моего примера, но ваша информация тоже помогла. - person Guy; 16.08.2016