Usage of createBond() with Bluetooth Low Energy - android

I am creating an app that communicates through Bluetooth Low Energy with a device, mostly to have the phone display the data from the device. I need to implement functionality where if the device and phone are moved into range, they will automatically identify as a pair and will connect without user interaction. I have been looking into Bonding to accomplish this.
I am currently trying to take the currently connected device and create a bond with it when the user clicks a ListItem. I call BluetoothDevice.createBond() on a reference to the connected BluetoothDevice variable. The Android Developer site says that for BluetoothDevice.createBond(), false will be returned if there is an error, and that I should register for ACTION_BOND_STATE_CHANGED to be informed when Bonding has started and is completed.
I have a few problems with createBond(), which is where my questions lie:
Most of the time createBond() returns false, indicating that it has failed to start bonding. What are some possible reasons for this? (My phone runs Android 4.4.2, API19 which is where createBond() is introduced - so it isn't that.)
Sometimes, bonding apparently succeeds because the code inside the ACTION_BOND_STATE_CHANGED receiver will be called. I may misunderstand what is involved in maintaining and using a bond, but the BLE device does not automatically connect to the phone when it is in range, so I am probably missing some code. After establishing a bond, what else do I need to do?
In the event that createBond() is no good for whatever reason (e.g. I have to make the app work for API18 when createBond() is introduced in API19), what alternatives are there?
Examples would be incredibly helpful. Finding information about bonding with BLE has been frustrating. Self-teaching this stuff has been difficult, especially with no tutorials lying around. On top of that, some people say it's impossible due to being "Just Works" when others say it's certainly possible. BLE is still a big cloud of confusion for me, so for now, some clarity with createBond() would be much appreciated.

Related

Android BLE automatic reconnections after pairing

We want Android to automatically connect to our custom made BLE peripheral.
Our peripheral should regularly (but infrequently) advertise and attempt to Indicate some time-sensitive sensor data to the phone. Thus we want the phone to be ready to connect at any time.
Generally, you can pair a smart watch with an Android, and Android will then automatically connect to the smart watch whenever it is in range. So we believe our use case should be feasible.
I read a lot of answers that advise to set the "autoconnect" parameter to true when connecting. I have tried that and the reconnections don't persist through a reboot or even after disabling and re-enabling Bluetooth on Android. This answer by Brian says I should scan in the background, but Android made this unrealistic. If I use a foreground service, my users will hate the app. If I use a background service, I may miss the peripheral's attempts to connect during Android's Doze and the code becomes error prone.
Ideally, I want to do something like what Emil said in his answer here. Please read the follow up question and response.
However, we can't see our app through Android's Bluetooth settings. We can only connect to the peripheral and pair with it using our app (or nrf Connect). In desperation, I tried modifying the peripheral's advertising flags. Then I could see it in Android's Bluetooth settings. But when I try to pair using Android's settings, the attempt fails because the peripheral is not in "pairing mode".
We are building both the app and the peripheral, so we can change both. I want to know if our use case is possible and what we need to do to get it working. We are using the STM32WB for our peripheral.
Use a combination of these techniques:
Bond the device. This might be needed due to the crappy Android Bluetooth LE API design that doesn't take the "address type" as an extra parameter when connecting to a device. When you connect using the Bluetooth device address, it looks up a device with this address in the bonding info, and uses the corresponding address type (random or public).
Use connectGatt with autoConnect set to true. This means no timeout, as well as auto-reconnect if the connection drops. Even if it takes days or weeks until the peripheral starts advertising, it will still work.
Listen to https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#ACTION_STATE_CHANGED and restart your connections when Bluetooth is re-started.
Use a Foreground Service in your application's process to prevent the OS from killing the process. Users can nowadays hide the annoying notification in Android settings if they want to.
Listen to https://developer.android.com/reference/android/content/Intent#ACTION_BOOT_COMPLETED to start your app after boot, including your Foreground Service.
Listen to https://developer.android.com/reference/android/content/Intent#ACTION_PACKAGE_REPLACED to automatically restart your app after an app update. See https://stackoverflow.com/a/2134443/556495 for some instructions.
The best approach is to make sure your peripheral can be bonded. Once you have bonded with it you can ALWAYS use autoconnect because Android stores info about bonded devices and you don't have to scan for it anymore. Hence you avoid the issues with scanning in the background.
Although that resolves the need for scanning, you still need to deal with your app being killed once it is in the background. Using a Foreground Service is still the best solution to my knowledge. I don't think you users will hate your app for it...

HM-10 as BLE Listener: setting up a brief connection from it

I need to estabilish a brief communication between a BLE master and a BLE peripherical device.
Until I have to use the mobile phone I have no problems, since I select the bluetooth device from Android, I can connect to it and then I can receive data simply writing them to HM-10.
BUT, this approach is battery expensive, since the BLE scanning is more battery expensive than the BLE advertising (right?). So I want that the mobile becames an advertisor and the HM-10 takes the ROLE of Slave.
BUT, I still don't understand if it is possible to connect to other devices: I tried AT+CONN and it always fails (AT+CONF). Is there any way to send brief data from the HM-10 to the advertisor, even without connecting?
Even my firmware looks slightly different from the readme! For example,AT+LN is present in the documentation but it appears to not exist. Does a better version of the firmware for this device exist, or, are sources available somewhere? I installed the HM-Soft V705 (lastest).
Thanks
UPDATE 1:
#ChrisStratton Ok, I have some intresting news: I was already following your idea (phone advertise sometimes, while HM-10 always scan and tries to connect to the service if it sees it, then HM-10 send some data, phone answer). I managed to make the phone visible from HM-10 (don't ask me how!). I am using the BLE Tool Android app to test everything. Now, the central problem now is that HM-10 won't connect to the android service even if the advertisor is connectable (see attached images).
I am sospicious that the AT+CO (that I discovered is a kind a replacement of AT+LN, but I am not sure) can help, but i don't know how.

Android: Auto-reconnect BLE devices

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?
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.
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.

Android Bluetooth Low Energy (BLE) API Not Ready for Prime Time

I am working on a fitness app that is to supports two BLE sensors (heart rate, stride). I ended up with two bounded services (one for each sensor) called and bounded by my main activity. This is running on Nexus 7 II, with KitKat. I have spent days trying to get the app to stable state. The Gatt connections, and notifications work perfectly right after a clean reboot. The problem I am having is getting things back to a working state after one or both of the devices get disconnected and needs to be reconnected. Since similar issues have been reported by others, I have developed and tested various scenarios which included keeping the service and the connections going when the activity is restarted, closing the connections and the server and then starting fresh, closing only and not disconnecting, waiting before reconnecting, etc. Currently, with one sensor, I can get the app to reconnect most of the time. With two sensors, the connections do not get re-established most of the time. It is such a shame that android BLE API is so fragile considering that there are many new BLE devices every week. I am wondering if anyone else has had much luck with multiple BLE sensors and if they would share their approach to get it working.
This isn't a very question-y question but your comment indicates knowing what 0x85 means would help. The Android BLE API was taken from Samsung's second BLE API, but not all of the constants Samsung had defined made it over.
0x85 = 133 (which you also see in the logs) is GATT_ERROR. Basically this means that something went wrong, it could be the peripheral went out of range of the device, or the Bluetooth chip just messed up. I've found calling connect() on the BluetoothGatt in onConnectionStateChange is a decent solution since that will wait for things to get sorted out and connect when it can.
0x8D = 141 GATT_ALREADY_OPEN This one is pretty self-explanatory.
The other thing to watch out for is making sure anything happening to Bluetooth happens sequentially. Multiple threads sending commands to a BluetoothGatt before the result of the previous action happens tends to not be a good thing.

Android: wifi & bluetooth searching together

Currently I have a question about using Android Wifi, Bluetooth APIs together.
(Please be noted that it's a problem on app development, not for a normal user guide)
I have a trouble when search device' services via Wifi at the same time with searching device via Bluetooth.
For more info:
On wifi search, I use Bonjour protocol (an Apple's implement of Zeroconf which can help locating services that local network devices offer). The Java implement that I use is jmdns. During the search session, I create a MulticastLock in order to receive multicast packages of Bonjour.
On bluetooth search, I just use BluetoothAdapter together with BroadcastReceiver to get bluetooth device info.
Problem happens to the search result, whenever two search sessions above are executed at the same time, mysearch result on Bonjour (Wifi) search has never get enough like it does when only it is executed.
Ex: Bonjour search just gets 1 instead of 2 device' services when search together with Bluetooth. Bluetooth search result is always enough, however.
This is tried many times and I surely confirm that there is nothing related to network' strength problems.
Has anyone met this problem yet?
Even if your situation is about using Wifi together with Bluetooth, any experiences or guests are very helpful to me!
Khoi.
I am doing pretty much the same stuff you are doing.
My experience differs in that:
I do not use Bluetooth discovery, as I know what device I want to connect to. I just initiate a client connection.
I use Asynctasks for background operations. What are you using?
Two possible issues:
Multiple Asynctasks not executing in parallel due to Android faulty implementation. I have had a similar bug after setting my Android API target to the latest SDK (as it is best practice). Now, after API13, Android Asynctask implementation changed and tasks are NO LONGER executed in parallel (so my wifi thread never started for example, if bluetooth thread was running!!!). The fix is to put a couple of lines of code to make the default executor parallel again, or to just use API11 or lower as target version. See this thread for details.
OverTheAir interference between the 2. Bluetooth discovery is, to my knowledge, the most expensive operation you could do on Bluetooth. So that 2.4GHz multi-purpose chip may be swamped over the air. Internally it has coexistence between WiFi and BT. Remember the WiFi and Bluetooth channels over the 2.4GHz overlap. So what I am saying doing discovery over the same main frequency at the same time might not work that great. You should investigate that...

Categories

Resources