Search code examples
javaandroid-bluetoothrxandroidble

RxAndroidBLE already connected and can't send data to IoT device


I have an IoT device with BLE on it and also I have a smartphone which support BLE protocol. I am using RxAndroidBle: com.polidea.rxandroidble2:rxandroidble:1.11.1 The problem is to communicate each other. I have established connection:

    @OnClick(R.id.connectButton)
    void onConnectButton() {

        if (rxBleDevice == null) {
            if (myViewModel.getMacAddress().getValue() != null) {
                if (!myViewModel.getMacAddress().getValue().isEmpty()) {
                    // get BLE device
                    rxBleDevice = SampleApplication.getRxBleClient(this.getActivity())
                            .getBleDevice(myViewModel.getMacAddress().getValue());

                    // establish connection
                    connectionObservable = rxBleDevice.establishConnection(false)
                            .takeUntil(disconnectTriggerSubject);
//                            .compose(ReplayingShare.instance());
                    /*
                    reason: no instance(s) of type variable(s) T exist so that ReplayingShare<T> conforms to
                    ObservableTransformer<? super RxBleConnection, ? extends R
                     */

                    statusTextView.setText(R.string.connected);
                }

            }
        } else {
            triggerDisconnect();
            statusTextView.setText(R.string.disconnected);
        }
    }

and then I just use the connectionObservable to send data like this:

                if (rxBleDevice != null) {
//                    if (isConnected()) {
                    final Disposable disposable = connectionObservable
                            .firstOrError()
                            .flatMap(rxBleConnection -> rxBleConnection.writeCharacteristic(uuid, HexString.hexToBytes(data)))
                            .subscribe(
                                    bytes -> onWriteSuccess(bytes),
                                    throwable -> onWriteFailure(throwable)
                            );
                    compositeDisposable.add(disposable);
//                    }
                }

The error what I always got is: Already connected to device with MAC address EA:A5:34:E6:28:2E, but if i try to isConnected() always says that they are not connected. Is there a way to send data every 300 ms to IoT device? Full stack trace below.

I/VideoFragment: Write error: 
      com.polidea.rxandroidble2.exceptions.BleAlreadyConnectedException: Already connected to device with MAC address EA:A5:34:E6:28:2E
        at com.polidea.rxandroidble2.internal.RxBleDeviceImpl$1.call(RxBleDeviceImpl.java:84)
        at com.polidea.rxandroidble2.internal.RxBleDeviceImpl$1.call(RxBleDeviceImpl.java:72)
        at io.reactivex.internal.operators.observable.ObservableDefer.subscribeActual(ObservableDefer.java:33)
        at io.reactivex.Observable.subscribe(Observable.java:12284)
        at io.reactivex.internal.operators.observable.ObservableTakeUntil.subscribeActual(ObservableTakeUntil.java:38)
        at io.reactivex.Observable.subscribe(Observable.java:12284)
        at io.reactivex.internal.operators.observable.ObservableElementAtSingle.subscribeActual(ObservableElementAtSingle.java:37)
        at io.reactivex.Single.subscribe(Single.java:3666)
        at io.reactivex.internal.operators.single.SingleFlatMap.subscribeActual(SingleFlatMap.java:36)
        at io.reactivex.Single.subscribe(Single.java:3666)
        at io.reactivex.Single.subscribe(Single.java:3652)
        at com.example.automotive.Fragments.VideoFragment$1.onMove(VideoFragment.java:275)
        at io.github.controlwear.virtual.joystick.android.JoystickView$2.run(JoystickView.java:860)
        at android.os.Handler.handleCallback(Handler.java:914)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7560)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

isConnected method:

    private boolean isConnected() {
        return rxBleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
    }

Solution

  • Is there a way to send data every 300 ms to IoT device?

    Of course there is. If there is no external source of the data to send one could use code similar to:

    bleDevice.establishConnection(false)
        .flatMap(rxBleConnection -> 
            Observable.interval(300, TimeUnit.MILLISECONDS)
                .flatMap(ignored -> rxBleConnection.writeCharacteristic(uuid, HexString.hexToBytes(data)))
        )
        .subscribe(
            ignored -> {},
            error -> { /* log or something */ }
        );
    

    The above assumes nothing else is subscribing to bleDevice.establishConnection(false) at the same time.

    I think what you wanted to ask is why you get this exception and how to live with it. This exception was introduced to protect users from calling a stateful BLE transmission from multiple places in the code and messing it up. There is a wiki page about it.

    You can share a Observable<RxBleConnection by using RxReplayingShare for instance. Then you will not get BleAlreadyConnectedException. You have tried that but apparently commented out the line because the compiler couldn't find out what is the type of object it will replay/share. Perhaps specifying it with ReplayingShare.<RxBleConnection>instance() would help?