Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 4.4: Bluetooth Low Energy; Connect without scanning for a BLE device

my app shall connect to a Bluetooth LE device. Usually you perform a device scan using mBluetoothAdapter.startLeScan(mLeScanCallback);. The callback provides you information about available devices.

If you want to connect to a dedicated device, you do something like

BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

and then

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

To me it looks like the only thing you need to connect to a BLE device, is to know the BLE address and then connect to it with the above two steps. So if I know a BLE address already (e.g. it is written on the label of the BLE device) I don’t need to perform a BLE scan.

But what I have encountered is, that if I have a BLE device which I have never found through a BLE scan before, it is not possible to connect to it directly in using its BLE address. I have to find it through a scan at least one time with my android phone. Afterwards I never need a scan again and I can connect to the BLE device just by using its BLE address.

Is it supposed to be like this or did I oversee something?

Thanks a lot, Stefan

like image 282
Stefan Avatar asked Oct 01 '15 11:10

Stefan


2 Answers

The device address is merely a unique identifier for the bluetooth device, it doesn't contain the information for connection. The scan is necessary to retrieve the information within the broadcast signal from the bluetooth device so that a connection can be made. Once the scan is done, the information is saved somewhere on the device and bound to the device address.

I think if you try to retrieve the value for the bluetooth address it will return null until after it has been scanned once.

like image 86
Hoa Do Avatar answered Nov 15 '22 01:11

Hoa Do


The answer from Hoa Do is not really correct.

Due to some horrible design flaws in Android's BLE API there is no way to tell it if you mean the given address is a Public Address or a Random Address. (You can read more about different address types at https://devzone.nordicsemi.com/question/43670/how-to-distinguish-between-random-and-public-gap-addresses/). The getRemoteDevice method should take an additional parameter "random address/public address" but it doesn't. Without the correct address type, the Bluetooth controller cannot connect to the device.

Android's BLE stack has some internal heuristics to "guess" if the address is public or random, but unfortunately that differs between Android versions and also if you use autoConnect=true or false. However if you have bonded the device (https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()) then it will store in its internal DB whether the given address is public or random. If the peripheral you want to connect to uses a random resolvable address it can handle that as well if you use bonding. Therefore I strongly suggest to use bonding.

If you don't use bonding you will need to scan before you connect to the device, since when you start a scan and a device is detected, Android's BLE stack will temporarily (until next restart of Bluetooth) remember the address type for an address. If you don't scan the device before connecting, it will still try to connect, but there is a possibility it tries to connect with the wrong address type and hence fail.

like image 4
Emil Avatar answered Nov 15 '22 02:11

Emil