10

My goal is to get the Android device to reconnect to a BLE device that it has previously connected to without user intervention in the same way it does for a classic BT paired device does (even works through power cycles).

One of the ideas of BTLE devices is that one saves service, bonding, and enabling states such that a reconnect is VERY fast and consumes very little power on the peripheral.

What I have done seems to work but it works poorly.

The first step is to connect or pair and connect to a new device setting the 'autoconnect' parameter to 'true'. When the device disconnects, do not call gatt.close(). Everywhere I look I see that one should call gatt.close(). But if I do call gatt.close() the Android central app never reconnects. I have tested this many times.

If I have not called gatt.close() and have not power cycled the Android, the auto-connection usually happens. Sometimes it can take a long time, especially after version 5.0. It is, however, unreliable and it may be unreliable due to a very low-duty scan cycle and the device quitting advertising before a scan cycle actually detects the advertisement. I am not sure because there is no way to detect the scanning operation like there is advertisements! It is also possible the scanning stops after a certain amount of time but there is no documentation on that.

So what I think I need to do is to somehow set the background scan rate used by the Android to a higher duty cycle (only possible in 5.0 and up) when auto-connect has been set but I do not know how to do this. I do not want to start my own scan but somehow set the background scanning rate used by Android for the reconnect. Does anyone know how to do this? Does anyone really know how autoconnect and gatt.close() are to work?

Maybe the auto-connect was NOT meant to re-connect as I indicated above?

Zimano
  • 1,870
  • 2
  • 23
  • 41
Brian Reinhold
  • 2,313
  • 3
  • 27
  • 46
  • For a reconnection, you will always have to advertise or scan. Moreover, did you try and find this in the core specification? A lot of the questions you are asking are in there; such as "set background scan rate to a higher duty cycle", by which you probably meant scan window and interval, which are handled by setting the scanning parameters. The type of advertising is also important (Connectionless, connectable). Please provide a part of your code that handles the scanning/advertising on both your master and peripherals. – Zimano Dec 23 '15 at 09:25
  • @Zimano I am aware of the core specification. I have coded embedded BLE collectors and there one has to specify all those minute details. On the Android platform, however, one has considerably less control (usually makes life easier) and one often does not know what Android is doing under the hood. What I don't know is what Android configures its scan rate to when I set the autoconnect parameter to true. It is probably low duty and it may likely change over time since peripheral disconnect. So what I am seeking to do is to figure out how to configure that scan rate to a higher duty cycle. – Brian Reinhold Dec 23 '15 at 13:20
  • @Zimano I suppose I would even be happy to know what the scanning rates are (without digging through the source code). I have many medical device peripherals and they all advertise at different rates (seldom directed) but those are easy to see with a sniffer. – Brian Reinhold Dec 23 '15 at 13:29
  • I disagree that scan parameters are "minute details", they are elementary, yes. Less control creates problems like you have, as you have experienced, I'm not a fan of android bluetooth though >< However, you can always trace anything to see what is going on though, or dig in the source! But I digress, I believe you are looking for either [this](http://stackoverflow.com/questions/27792670/android-aosp-definition-of-scan-interval-and-scan-window-in-android-source-cod) or [this](http://developer.android.com/reference/android/bluetooth/le/ScanSettings.html). See if that helps you :) ? – Zimano Dec 23 '15 at 13:31
  • @Zimano Okay, that is not what I meant by 'minute details'. What I meant is that one has to specify all those details which in most high level APIs is shielded from the application writer (as in Android). For us using Windows systems it is a lot harder to get the source though I am contemplating the headache. I have heard one can use Android Studio to at least browse the AOSP. – Brian Reinhold Dec 23 '15 at 14:30

2 Answers2

5

Well after many trials and tribulations this is how I best get the Android to auto connect with the only user action being to first select the device (if using the settings menu then first pairing).

You have to trap the paired event in a BroadcastReceiver and do a BluetoothDevice.connectGatt() setting the autoconnect to true. Then when the device disconnects, invoke a gatt.connect().

Update: While the above approach works in general, it is sometimes agonizingly slow probably because the pending connection uses extremely conservative scan rates. The other downside is that for each device you want to auto-reconnect to you have to keep a BluetoothGatt object performing a pending connection. In the embedded world this is insane. Instead what one does is continuously scan and connect to a desired device by inspecting its advertisement. One saves only the minimal amount of data about the device (the services, its paired state and keys, etc.). When an advertisement is captured you see if it is one of your known devices and connect to if it is. I tried the equivalent on Android. Scan all the time (low power rate) and connect to advertisements of interest, and maintain a class representing a known device. There are some annoying details in this approach (like turning off scanning while connecting and restarting after connected) but it basically works without the overhead of maintaining connections. BUT there is one exception I do not understand. One pre-paired device's advertisements are never seen by the scanner. However, if I invoke a pending connection to this device, I re-connect. I do not understand this at all. On my embedded platforms it works as it should. If anyone else has tried this approach for auto-reconnecting, please share your experiences!

I have discovered the reason the pre-paired device is not seen by Android. Android only reports scan results IF the device responds to a scan request. Once paired, this device only emits advertisements and ignores scan requests, so the Android system does not pass up its advertisements in the ScanCallback. Thus in order to work using the scan approach, I have to use the pending connect approach for those specific devices. It just seems like you can't win!

============= UPDATE 2020

Many years have passed and I have a lot more experience with the background scan approach. If one keeps the supported platforms 5 and up, one can use only the newest scanner APIs and use filters, eliminating the need to decode the raw advertisements yourself. I have also found that connection and re-connection is snappier if you DONT turn off scanning while connecting. I know it goes against all documentation, but it works and on some platforms allowed connections to happen that otherwise did not. Also, to date, I have found only one (health) device that needs pending connects. Disclaimer: All I have ever worked with is health devices.

Community
  • 1
  • 1
Brian Reinhold
  • 2,313
  • 3
  • 27
  • 46
  • 2
    @brian could please provide a sample code for this. it will be of huge help to us. – Shahid Sarwar Jul 16 '17 at 16:50
  • Oh gees. Why didnt I get notified of this comment? Its a year old! – Brian Reinhold Jul 21 '17 at 18:33
  • @BrianReinhold .. " Then when the device disconnects, invoke a gatt.connect()." did you mean "gatt.disconnect()" ...? – elcuco Dec 28 '17 at 14:12
  • @elcuco No I mean gatt.connect(); This causes a pending connection which, when the device starts advertising again, will result in reconnection without user intervention. – Brian Reinhold Jan 14 '18 at 20:24
  • @BrianReinhold - on my code, I just did not disconnect gatt. Are you sure its needed? – elcuco Jan 15 '18 at 09:27
  • 1
    @Elcuco In my case the device I am communicating with (a health device) is responsible for sending the disconnect about 95% of the time. In order to reconnect without user intervention, I need to start a pending connection. If I do not, I will not reconnect (automatically) to the device when it comes back on line (exposes advertisements) – Brian Reinhold Jan 15 '18 at 22:41
  • The BluetoothGatt object itself doesn't take any particular amount of RAM. What's more interesting is the number of maximum pending connections which is insanely low (like 10) while most Controllers support 128. Note that 10 is just a constant in the Android source code that could be set much higher without any problems. One benefit of auto connect rather than scan + connect is that the advertising filtering and connection establishment can be done without the need to wake up the main cpu for every advertising packet, which saves battery. Compared to embedded where everything runs on same cpu. – Emil Mar 15 '18 at 20:14
  • @Emil I have implemented both options. Its still a messy mass of code because I have not figured out how to best approach all the problems I have faced across platforms and devices. I don't know which is best. But if the pending connect does filtering avoiding the CPU somehow while the scan + connect invokes the ScanFilter using the main CPU then you are right. However, the scan + connect approach IS snappier and it can make for a very simple user interface. Emil, where did you get this information about the Android implementation? I would love to have access to it! – Brian Reinhold Apr 14 '18 at 11:09
  • Well Android has no particular BLE documentation (except the API documentation) except than the source code: https://android.googlesource.com/platform/system/bt/. – Emil Apr 14 '18 at 15:18
  • @Emil yes I assume so. I found your link in some other post and have downloaded the Bluetooth stuff. I would like to be able to follow it from the Java to the C- code (there are also HDP issues). I have the Java now I have the C. Where is the JNI that links the Java to the C? Do you know where that is? – Brian Reinhold Apr 14 '18 at 18:56
  • https://android.googlesource.com/platform/packages/apps/Bluetooth/+/master/jni/com_android_bluetooth_gatt.cpp – Emil Apr 14 '18 at 21:01
  • I note that people are asking for code examples.Unfortunately that's kind of hard to do as it is pretty messy and scattered across files (needs for remote health monitoring). Also, there are considerable differences between the scan-approach and pending connection approach. Is there a 'special' way to post this information on Stack Overflow for everyone's ability to chime in and discuss? (I don't have a blog site ...) – Brian Reinhold May 19 '18 at 12:52
0

This is how I was able to do it for my application. I first stored the address of the device in a SharedPreference then in gattClientCallback funtion of my BluetoothLeService

else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            intentAction = ACTION_DISCONNECTED;


            DeviceActivity.runOnUI(() -> {

                sharedPreferences  = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

             String  name_dev_1 = sharedPreferences.getString("Dev_1", null) ;

              connectToDevice(name_dev_1);

                disconnectGattServer();
            });
        }
    }

What this does is if your device is disconnected it will keep on trying to connect to it until a connection is established.

Surbhit Rao
  • 625
  • 6
  • 14