5
votes

I'm developing an app with iBeacon support. Basically, I have a single view that updates its content according to the nearest beacon, and to scan beacons, I use no framework (just the CoreLocation from Apple), even though I use Estimote Beacons.

The problem is that my application doesn't detect the beacons instantaneously, I have to wait about 5 seconds in front of a beacon in order to get the content updated, while the Estimote app detects the beacons within 1-2 seconds. My Estimote beacons are configured to advertise every 960 ms.

How is that possible ? Can I set a time interval to scan for beacons ? How to improve my app to update the view faster ?

Here is the code I use to initialize the location manager and to update the view :

// ViewController.h =================
@property (strong, nonatomic) CLLocationManager *locationManager;

// ViewController.m =================
-(void)initBeaconMonitor {
    NSUUID *estimoteUUID = [[NSUUID alloc] initWithUUIDString:estimoteBeaconUUID];
    _region = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID major:estimoteBeaconMajor identifier:beaconRegionIdentifier];

    self.locationManager = [[CLLocationManager alloc] init];
    // For iOS 8
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationManager requestAlwaysAuthorization];
    }

    self.locationManager.delegate = self;
    self.locationManager.pausesLocationUpdatesAutomatically = NO;

    [self.locationManager startMonitoringForRegion:_region];
    [self.locationManager startRangingBeaconsInRegion:_region];
    [self.locationManager startUpdatingLocation];
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:
(NSArray *)beacons inRegion:(CLBeaconRegion *)region {

    if(beacons.count > 0) {
        CLBeacon *nearestBeacon = beacons.firstObject;

        if(nearestBeacon == _lastBeacon) {
            return;
        }

        _lastBeacon = [nearestBeacon copy];

        switch(nearestBeacon.proximity) {
            case CLProximityFar:
                break;
            case CLProximityNear:
                [self updateViewWithBeacon:nearestBeacon];
                break;
            case CLProximityImmediate:
                [self updateViewWithBeacon:nearestBeacon];
                break;
            case CLProximityUnknown:
                return;
        }
    }
}
3

3 Answers

13
votes

You cannot change the beacon scanning interval on iOS. When ranging in the foreground, iOS will constantly scan for beacons so this is not what is causing delays.

The problem is that the app logic will only update the UI once CoreLocation determines the beacon is in Near/Immediate proximity and the beacon is closest according to the sorted position in the beacons array. Both the sorting and the value of the proximity field are based on CoreLocation's distance estimate to the beacon (the accuracy field), and this is based on a 20 second running average of the signal strength between the mobile device and the beacon. It is this 20 second running average that is causing the delays you mention, because the distance estimate updates slowly and does not reach a steady state until the mobile device has been in the same place relative to all beacons for 20 seconds. Unfortunately, this 20 seconds is fixed and not configurable.

For faster responsiveness, you can stop using the accuracy field and sorted order of the beacon within the array. A few alternatives:

  1. Change your logic to not be based on distance at all, perhaps based on timing and what beacons have been seen before.

  2. Switch to using the rssi field as a proxy for distance. This field is averaged over only 1s, but be aware that it has as lot if variability due to radio noise. Less negative values for this field indicate closer beacons. Increasing the beacon transmission frequency as @heypiotr suggests in his answer will help give more stable RSSI numbers.

  3. Manually calculate your own running average of RSSI over a shorter time interval (2-5 secs) for a better tradeoff between rapid updates in distance estimation and stability.

You can read more about how iBeacon ranging works here:

http://developer.radiusnetworks.com/2014/12/04/fundamentals-of-beacon-ranging.html

2
votes

Decreasing the advertising interval of your beacon should improve the responsiveness, just keep in mind it comes at the expense of the battery life. Something around 300–400 ms is usually a good trade-off between the former and the latter. You can use the Estimote's iOS app to configure your beacon.

iOS uses the beacon's advertising packets to estimate the distance to the beacon, and thus figure out the proximity zone (far/near/immediate). It usually needs to gather at least a few packets to make sure that the estimate is more-or-less correct. This is why advertising with a higher frequency should help.

0
votes

You can also enable CoreBluetooth and scan for your beacon as for normal BLE device. When doing that, you could force refresh your bluetooth scan using for example timer. Note, that this solution won't work in background and is not very energy efficient.