简体   繁体   中英

Android BLE proximity notifications

I've been working on developing an application that interacts with BLE devices. Everything works great, I can scan, connect, and consume services.

I've been reading through all the docs and I do not see anything that gives the developer the option of listening for BLE devices. Basically I would like to trigger a broadcast receiver when the devices enters the range of a BLE device.

I know I could continually scan for this, but battery use is way too high and I would like this to be invoked even when my application is not being used.

Is this feature not supported or am I missing a section of the docs that discuss this?

I have done a project recently, and from what I read in your question it has some similarity to what I did.

I know I could continually scan for this but battery use is way too high and I would like this to be invoked even when my application is not being used.

Regarding battery problem, having Bluetooth on all the time is power consuming, but at the same time you can not detect BLE with out having Bluetooth on.

What I did is two experiments and both are useful but are different and I can not say which one is best, but you need to test it so it fits your requirement.

  1. Having Thread running that turns Bluetooth on and listen to iBeacon and off (with sleeping time) for while programmatically. It can be done many ways.

  2. Using a package called Altbeacon, has a lot of useful features, one of those features is Auto Battery Saving with example code :

     public class MyApplication extends Application implements BootstrapNotifier { private BackgroundPowerSaver backgroundPowerSaver; public void onCreate() { super.onCreate(); // Simply constructing this class and holding a reference to it // in your custom Application class // enables auto battery saving of about 60% backgroundPowerSaver = new BackgroundPowerSaver(this); } } 

We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach. Maybe now there is a better BLE API available than 2 years ago. The most energy saving and most precise method gets rewarded.

Your other part, it is called triggering actions at a specific distance. I still use the Altbeacon to check beacon range and triggering action. A sample code is something like

@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
    for (Beacon beacon : beacons) {
        if (beacon.getDistance() < 5.0) {
            Log.d(TAG, "I see a beacon that is less than 5 meters away.");
            // Perform distance-specific action here
        }
    }
}

So when that said, you can also get distance of specific UUID I build a method based on Altbeacon, looks like this (Look inside the for loop and if statement):

private void startRangeNotifier() {
    Log.i(TAG, "Starting range notifier...");
    beaconManager.setRangeNotifier(new BeaconRangeListener() {
        @Override
        public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {

            if (beacons.size() > 0) {
                for (Beacon beacon : beacons) {
                    Log.d(TAG, "uuid's: " + beacon);
                    Log.d(TAG, "uuid id1: " + beacon.getId1());
                    if (beacon.getId1().toString()
                            .equals("b9407f30-f5f8-466e-aff9-25556b57fe6d")) {
                        Log.d(TAG, "uuid id1 distance: " + beacon.getDistance());
                    }
                }

            }
        }
    });

    try {
        beaconManager.startRangingBeaconsInRegion(
                new Region(BEACON_MONITORING_ID, null, null, null));
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

My log output:

D/Main activity:: uuid's: id1: b9407f30-f5f8-466e-aff9-25556b57fe6d id2: 31807 id3: 59251
D/Main activity:: uuid id1: b9407f30-f5f8-466e-aff9-25556b57fe6d
D/Main activity:: uuid id1 distance: 0.2108658568686884

In my answer I wanted to present the concept I used, Beacons project need patience in general. As the other answer mentioned it is also possible to combine the solution here with Geofences and ActivityRecognition.

Note: Since the nature of bluetooth beacon, the distance is proximity and not absolute, and some time even the bluetooth beacon is 1 meter a way it might show 2 meter or 0.5 meter, so have that in mind

Link reference:

BLE scanning on Android is pretty battery intensive, and it's definitely not something you want to do in the background all the time. If you are working on a background application with stationary bluetooth devices (à la ibeacons) that you know the location of, you can use Geofences to turn scanning on and off when you think you are in the approximate proximity of a device. If you are not careful geofencing can also drain battery.

If you don't know the location of your bluetooth devices I guess you can also play tricks with ActivityRecognition , ie only scan periodically when the user is walking and stopping it if the user is stationary/running/biking/in vehicle. Again, the activity recognition stuff also takes battery so you are going to have to be judicious.

We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach.

You probably know how to filter scan results by Service UUID so I won't go into that. About the waking up: if your app is scanning, it is awake by definition. It may or may not be on the foreground, but it is awake.

Maybe now there is a better BLE API available than 2 years ago.

Since SDK version 21, there is a new API that you can use for BLE scanning. To my knowledge, the only difference is the way you access the API and the underlying functionality (regarding power consumption etc.) has not changed.


About the scanning:
It's true that scanning is battery-intensive. Even the docs say so.

The intensity is relative though. It is intensive compared to not scanning at all, but it is not intensive enough that it will hopelessly drain your battery. It's called low energy after all.

An other answer suggest monitoring Geofences and only scan when you know you are in range of BLE devices. While this will lower the battery consumption of the ble scan , it will need that battery power for the GPS, otherwise it can't monitor the Geofences (well, it can, with cellular/wifi data, but then it won't be nearly as accurate).


Depending on how time critical your scanning is (eg if there is a device nearby, must you know it right away ? or is it okay if it's delayed a couple seconds?) you can implement a pause inbetween scans.

Say you scan for 5 seconds, pause for 5 seconds, scan for 5 seconds again. That way you will be scanning almost all the time, yet only consume roughly half of the battery power. These intervals can be tweaked to match your situation. Maybe you're okay with scanning 3 seconds and pausing for 10. (note that the maximum time between a device's broadcasts is 10.24 seconds ).

I have an app with about 50 users that scans with pauses like this (scan for 3 seconds, pause for 3, repeat) 24/7 in the background, and have not received any complaints about excessive battery usage.

If you have a specific BLE peripheral you want to detect, then figure out its advertisement period. If you have different devices, find the longest advertisement period. Scan longer than the advertisement period of the device, so you get at least one advertisement message. Repeat this scanning periodically with the frequency that is suitable for your use case. Eg Your peripheral is advertising every second once. You would like to detect the device in 5s when it comes to proximity. Then Scan for 1s (or a bit more). Switch off scanning for 4s. This way you can save battery.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM