Skip to content

Commit

Permalink
do Bluetooth LE scan before connecting to improve connection performance
Browse files Browse the repository at this point in the history
  • Loading branch information
oliexdev committed Feb 2, 2019
1 parent bd021b7 commit acdd63a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 13 deletions.
4 changes: 2 additions & 2 deletions android_app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ android {
testApplicationId "com.health.openscale.test"
minSdkVersion 19
targetSdkVersion 28
versionCode 38
versionName "1.9.1"
versionCode 39
versionName "1.9.2"

javaCompileOptions {
annotationProcessorOptions { arguments = ["room.schemaLocation":"$projectDir/schemas".toString()] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package com.health.openscale.core.bluetooth;

import android.Manifest;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;

import com.health.openscale.core.OpenScale;
Expand All @@ -28,6 +30,7 @@
import com.polidea.rxandroidble2.RxBleDevice;
import com.polidea.rxandroidble2.RxBleDeviceServices;
import com.polidea.rxandroidble2.exceptions.BleException;
import com.polidea.rxandroidble2.scan.ScanSettings;

import java.io.IOException;
import java.net.SocketException;
Expand All @@ -36,6 +39,7 @@
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import androidx.core.content.ContextCompat;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
Expand Down Expand Up @@ -74,6 +78,7 @@ public enum BT_MACHINE_STATE {
private RxBleDevice bleDevice;
private Observable<RxBleConnection> connectionObservable;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
private Disposable scanSubscription;
private PublishSubject<Boolean> disconnectTriggerSubject = PublishSubject.create();

private Handler callbackBtHandler;
Expand All @@ -92,6 +97,7 @@ public BluetoothCommunication(Context context)
this.context = context;
this.bleClient = OpenScale.getInstance().getBleClient();
this.rxBleDeviceServices = null;
this.scanSubscription = null;
this.disconnectHandler = new Handler();

RxJavaPlugins.setErrorHandler(e -> {
Expand Down Expand Up @@ -466,9 +472,40 @@ protected boolean isBitSet(byte value, int bit) {
* @param macAddress the Bluetooth address to connect to
*/
public void connect(String macAddress) {
bleDevice = bleClient.getBleDevice(macAddress);

// Running an LE scan during connect improves connectivity on some phones
// (e.g. Sony Xperia Z5 compact, Android 7.1.1). For some scales (e.g. Medisana BS444)
// it seems to be a requirement that the scale is discovered before connecting to it.
// Otherwise the connection almost never succeeds.
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
Timber.d("Do LE scan before connecting to device");
scanSubscription = bleClient.scanBleDevices(
new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
//.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build()
)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bleScanResult -> {
if (bleScanResult.getBleDevice().getMacAddress().equals(macAddress)) {
connectToDevice(macAddress);
}});
}
else {
Timber.d("No coarse location permission, connecting without LE scan");
connectToDevice(macAddress);
}
}

private void connectToDevice(String macAddress) {
Timber.d("Try to connect to BLE device " + macAddress);

bleDevice = bleClient.getBleDevice(macAddress);
// stop LE scan before connecting to device
if (scanSubscription != null) {
scanSubscription.dispose();
}

connectionObservable = bleDevice
.establishConnection(false)
Expand All @@ -478,9 +515,9 @@ public void connect(String macAddress) {
.observeOn(AndroidSchedulers.mainThread())
.compose(ReplayingShare.instance());

if (isConnected()) {
disconnect();
} else {
if (isConnected()) {
disconnect();
} else {
final Disposable connectionDisposable = connectionObservable
.delay(BT_DELAY, TimeUnit.MILLISECONDS)
.flatMapSingle(RxBleConnection::discoverServices)
Expand Down Expand Up @@ -550,7 +587,7 @@ public void disconnectWithDelay() {
disconnectHandler.postDelayed(new Runnable() {
@Override
public void run() {
Timber.d("Timeout disconnect");
Timber.d("Timeout Bluetooth disconnect");
disconnect();
}
}, 60000); // 60s timeout
Expand All @@ -565,6 +602,9 @@ public void disconnect() {
disconnectHandler.removeCallbacksAndMessages(null);
disconnectTriggerSubject.onNext(true);
compositeDisposable.clear();
if (scanSubscription != null) {
scanSubscription.dispose();
}
}

/**
Expand All @@ -590,6 +630,7 @@ protected void nextMachineStateStep() {
cleanupStepNr++;
Timber.d("CLEANUP STATE: %d", cleanupStepNr);
if (!nextCleanUpCmd(cleanupStepNr)) {
Timber.d("Cleanup Bluetooth disconnect");
disconnect();
}
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,15 @@ protected boolean nextBluetoothCmd(int stateNr) {
switch (stateNr) {
case 0:
// set indication on for feature characteristic
setIndicationOn(FEATURE_MEASUREMENT_CHARACTERISTIC
);
setIndicationOn(FEATURE_MEASUREMENT_CHARACTERISTIC);
break;
case 1:
// set indication on for weight measurement
setIndicationOn(WEIGHT_MEASUREMENT_CHARACTERISTIC
);
setIndicationOn(WEIGHT_MEASUREMENT_CHARACTERISTIC);
break;
case 2:
// set indication on for custom5 measurement
setIndicationOn(CUSTOM5_MEASUREMENT_CHARACTERISTIC
);
setIndicationOn(CUSTOM5_MEASUREMENT_CHARACTERISTIC);
break;
case 3:
// send magic number to receive weight data
Expand Down

0 comments on commit acdd63a

Please sign in to comment.