I'm developing an app to keep scanning certain smart bluetooth LE tags to check when a tag is out of range.
I'm getting one signal from each tag per second when I'm running my code in foreground. But in background (like scanning in a service) this rate keeps decreasing down to 1 signal per 10 seconds!
I'm almost sure that the frequency of the smart tag is the same in both cases, but maybe the Android operating system slows down discovering bluetooth devices due to battery issues when the scan happens in the background.
I'm afraid that this will be not satisfying, especially when you need to detect a bag is being stolen or something critical that forces me to keep the rate at 1 signal per 3 seconds or so.
UPDATE:
For the code I used, first:
private BluetoothAdapter bluetoothLeAdapter;
this for starting scanning:
bluetoothLeAdapter.startLeScan(LeScanCallback);
and this is the callback:
private BluetoothAdapter.LeScanCallback LeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Log.i("Found: ", device.getName() + " - " + device.getAddress());
}
};
Android 4.3 and 4.4 do not slow down discovery in the background. In the Android Beacon Library, I had to put in extra code to slow down scans to save battery when apps are in the background.
I cannot explain what you say you are seeing. Perhaps you should try the library mentioned above and see if you see the same behavior. It is open source, so you can look at the code, too. It scans the same way as in your snippets in your question.
Related
With Android 4.3, Android implemented the idea of always-on WiFi where, even if you had Wi-Fi toggled off, the device and apps could still scan for WiFi networks to improve the location's accuracy. Along with using network triangulation, it's another way of getting your current position as quickly as possible without having to rely too much on GPS signals.
Android M is taking the idea further, adding Bluetooth scanning to the equation. Under the Location settings on M, you'll find a Scanning option in the menu, where both Wifi and Bluetooth scanning can be toggled on and off. When enabled, Bluetooth scanning will presumably look for BLE devices like beacons to get a quicker location fix.
Image resized. Click to view in full size
This may be very useful in the future inside malls, airports, and various indoor or underground locations where the reach and dispersion of Bluetooth beacons can outweigh a slow or impossible GPS signal lock. And the fact that it's always on, accessible whenever apps need a location fix, will make it even handier than if you had to remember to manually turn on Bluetooth.
Can anyone help in providing some insights or sample code for scanning for beacons with BLE without the main Bluetooth settings turned on?
I figured it out.
We have to write a system application and use the
BluetoothAdapter.enableBLE()
method.
This method is for special/system apps which use Bluetooth Low energy to scan for nearby devices which is mostly used for location accuracy.Even if the Bluetooth is turned off in the device settings.
Then we can use
BluetoothAdapter.LeScanCallback
callback to get the device details.
Sample:
for calling the method:
mBluetoothAdapter.enableBLE())
for callback:
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if( device == null ){
System.out.println("-------onLeScan "+device);
}
runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
Thanks
I am using android beacon library to detect beacons.I have created a service which implements Bootstrap Notifier and It got two methods :
#Override
public void didEnterRegion(Region arg0) {
Log.i(TAG, "A beacon has enter the region .........");
}
#Override
public void didExitRegion(Region arg0) {
Log.i(TAG, "A beacon has exit the region .........");
}
and also :
mAllBeaconsRegion = new Region("all beacons", Identifier.parse(UUID),null, null);
mBeaconManager = BeaconManager.getInstanceForApplication(this);
new BackgroundPowerSaver(this);
bootstrap = new RegionBootstrap(this, mAllBeaconsRegion);
mBeaconManager.setBackgroundScanPeriod(1000l);
mBeaconManager.setBackgroundBetweenScanPeriod(1000l);
My problem is that in some devices beacon exits the region automatically and didExitRegion called and then re-enters in region and didEnterRegion called.It again disconnects automatically.
This is happening in loop. I am testing it with Lollipop.
How can i get rid of this?
Please help.
It is important to understand what causes a Region exit. A region exit fires when no advertising packets from a beacon matching a Region object are detected in a 10 second period. There are a number of things that can cause this:
Hardware beacons that do not advertise frequently enough. For best performance, beacons should advertise at a rate of 10 Hz or more. Some manufacturers slow down the advertising rate to save battery, making beacons advertise only every 5 seconds or so. This can cause region exits if some of the packets are missed by the receiver due to radio noise or other issues. To solve this problem, configure your beacon to advertise at least once per second (1 Hz.)
Beacons being on the edge of the radio range of the mobile device. Bluetooth beacons have a varying range of 2-50 meters, depending on the manufacturer, settings, placement and the antenna on the receiving mobile device. If the signal is very weak, detections an be intermittent, causing exits if no packets have been seen in 10 seconds. To fix this, increase the transmitter power of your beacon, or add a software filter to ignore intermittent exit events.
Some mobile devices (e.g. Moto X, Moto G, Nexus 4, Nexus 7) have a hardware flaw where bluetooth and WiFi do not work simultaneously. This can cause the symptoms you describe because it makes beacon detections intermittent. To solve this problem, disable WiFi when looking for beacons on one of these devices.
I am developing an Android app that scans for BLE devices periodically, and use the beacon information for further processes. I need to catch the Beacon which is closest.
// Scan for bluetooth devices and parse results
private void scanLeDevice() {
// Stops scanning after a pre-defined scan period.
if(!mScanning){
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d(TAG, "stop scanning");
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
Log.v(TAG, "closing scan. beacon found:" + beaconFound);
broadcastLocalUpdate();
beaconFound = false;
stopSelf();
}
}, SCAN_PERIOD);
proximity=null;
totalDevices=0;
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
Log.d(TAG, "start scanning");
}
}
The beacons I use:
Emit an advertisement 3x each second
Emit over 3 different channels
I have over 5 in a room
On one of my test devices, the Sony Xperia z2, this works. I get a long list of devices with Beacon information and RSSI values. each Beacon is discovered multiple times each scan.
On my other test device, the Motorolla Moto G(2nd generation), this scanning behaves WILDLY UNPREDICTABLE. On most scans only 2 or 3 devices are discovered. Other occasions it discovers about 10 devices (includes duplicates). It does not matter whether these devices are close or far.
Is this a software issue or a hardware issue?
How can I improve the results of a BLE scan?
Your beacons are not advertising frequently enough, creating a very real chance that no transmission occurs while the receiver is monitoring on its frequency. Try for at least 10 transmissions a second, but preferably more if you have an external power source.
Of course it is not all in the transmitter - Android phones vary drastically in how much they receive to detect BLE advertisements, and may report drastically different signal levels under the same conditions.
You may want to collect results over several scans in a short period, and look at the aggregate data, not just that of a single scan.
The scan result is for each received adv. No matter what rssi.
The antenna is a shared resource on most phones.
Wifi, bt classic, ble. So the phone only listens for adv in windows. Only if the adv falls into this window will get callback. The phone must listen on 3 channels.
So try playing with your adv interval and adv package size. If you have many in the same room you should not use too fast adv interval as the adv channels will be filled and collisions will occur.
Try turning off wifi and retest.
Avoid having classic bt connection.
Put name in scanresponse if you can to keep adv package short.
What I need is to get a list of every devices in my range so I can call a certain method on them one after another.
What I have tried so far is to use the startDiscovery() method of the BluetoothAdapter and while it returns a list of devices it takes about 12 seconds to complete which is a lot for my task to complete.
I also managed to user the LeScanCallback succesfully every 2-3 seconds and I do discover devices, but on every scan it returns only one device at a time.
I'm trying to search for Beacons so this type of method could return every call a single other device that uses BlutoothLE when it's found ,while not returning my Beacon's info at all.
So, is there a way to discover a list of all devices in a range without waiting for the startDiscovery() to finish after 12 seconds ?
A few points:
startDiscovery is intended for bluetooth classic devices, not Bluetooth LE.
Android does not contain any APIs specific to parsing beacons, only for dealing with raw Bluetooth LE devices.
You can use the free and open source Android Beacon Library add-on to detect and parse beacons. It does not have a 12 second delay and wraps the LeScanCallback method and combines the results so you can get callbacks every second like:
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon beacon : beacons) {
Log.i(TAG, "I see a beacon:"+beacon+" that is "+beacon.getDistance()+" meters away.");
}
}
You need to call startScan(ScanCallback) api of BluetoothLeScanner to start scanning, this has support on Android 21(5.0).
Also look below question, it has sample code you can use to start/stop Le Scanning.
How to restart BluetoothLeScanner?
I'm trying to implement the application which will communicate with BLE findme device. I have the one of these devices, but have some problem with it. Using iPhone I have tested this device with bleTools application and this app works correctly, i.e. I have managed to read all device's characterictics and send the characteristics to make the device beep. But using Android (Nexus 5) I could only read the device's characteristics, but cannot make the device beep.
My code is:
private static final UUID IMMEDIATE_ALERT_SERVICE =
UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID IMMEDIATE_ALERT_LEVEL =
UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
...
public void beep(DeviceData device) {
BluetoothGatt gatt = mConnectedDevices.get(device.getDeviceAddress());
BluetoothGattService bluetoothGattService = gatt.getService(IMMEDIATE_ALERT_SERVICE);
if (bluetoothGattService == null) {
return;
}
BluetoothGattCharacteristic characteristic =
bluetoothGattService.getCharacteristic(IMMEDIATE_ALERT_LEVEL);
if (characteristic == null) {
return;
}
byte[] arrayOfByte = new byte[1];
arrayOfByte[0] = (byte) 0x01;
characteristic.setValue(arrayOfByte);
gatt.writeCharacteristic(characteristic);
}
The callback method returns Ok:
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (characteristic.getUuid().toString().equals(IMMEDIATE_ALERT_LEVEL.toString())) {
//TODO: use device address to identify the device-receiver
Message msg = new Message();
msg.what = MSG_PARAM_WRITTEN;
msg.obj = (status == BluetoothGatt.GATT_SUCCESS);
mHandler.sendMessage(msg);
}
}
but nothing happens on the device side.
Can anyone explain me what I'm doing wrong or maybe give some advice what should I do?
And again, I can read the device characteristics, but cannot write them to the device.
Unlike iOS, Android has quite a few undocumented tricks with Bluetooth. I'm assuming you are using the standard Bluetooth library included in Android 4.3 and later. If you using other libraries like Samsung or Broadcom, the results could be different.
Because I do not have a findeme device I cannot confirm anything. But I have worked with both classic and low energy Bluetooth energy on Android for a while now. My advice is to go through the complete process of scan, discover services and read/write characteristics.
startLeScan
onLeScanCallBack connect to the device
onConnect discoverServices
onServicesDiscovered get all characteristics
check the properties on each characteristic
if you can read it, go ahead and do that
after that is done, you can then write the characteristic and listen for the onCharacteristicWrite event. You may get the beep then. If not, you'll need to go back to the iOS project and trace every bit that is sent to and received from the findme device. That sounds difficult but it's really just a matter of reading bytes inside of the right delegates. Document that. Then go back and recreate the bit sequence on the Android side. Again, capture all the traffic to and from the findme device. If you can get the bit sequence to match, you'll have success.
There's one more very important thing to know about Android BLE. The writes must be sequential. By that I mean, if you write a characteristic, you must wait for the onCharacteristic event to fire before you can write another one. This is not documented on the Android developer site. The best way to implement this functionality is to use a LinkedList as a work queue.
Good luck and ping me if you have questions.