Improving detecting the nearest beacon

I ran into this issue as well. I was having a beacon from across the room flickering into domination over a beacon that was 3 inches away and this was a new set of beacons.

And here is why…

[CLBeacon (uuid:<__NSConcreteUUID 0x14c69e490> B9407F30-F5F8-466E-AFF9-25556B57FE6D, major:13719, minor:65410, proximity:3 +/- 2.59m, rssi:-83), 
CLBeacon (uuid:<__NSConcreteUUID 0x14c6399b0> B9407F30-F5F8-466E-AFF9-25556B57FE6D, major:3720, minor:63371, proximity:3 +/- 5.80m, rssi:-90), 
CLBeacon (uuid:<__NSConcreteUUID 0x14c69db20> B9407F30-F5F8-466E-AFF9-25556B57FE6D, major:25615, minor:47301, proximity:0 +/- -1.00m, rssi:0)]

You might have to scroll right but the closest beacon went to 0 rssi which put it on the bottom of the pile.

I was using the prefab “proximity content” app to see how this all worked and while there is a “firstEventSent” check that forces it to happen twice in a row, these events it would occasionally last for a couple iterations which would take it beyond its “firstEvenSent” check. And it seemed to be even worse as I walked around.

So for iOS Swift in “NearestBeaconManager.swift” I replaced the “firstEventSent” check with a check on a counter. So the number 1 closest, if it changed, would have to persist more than 3 times in a row to change the app. Of course the sacrifice is having to wait a few seconds for it to figure this out because iOS only seems to refresh its delegate every second or so.

func beaconManager(manager: AnyObject, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion) { print("NearestBeaconManager : beaconManager")
    let nearestBeacon = beacons.first

    // These just check to see what is being passed in.
    print("PASSED BEACONS")
    print(beacons)
       
    if nearestBeacon?.beaconID != self.nearestBeaconID{
        
        if self.countEventSent > 3  {
            
            //If it has changed for more than 3 itterations, send that change up the stack!
            self.nearestBeaconID = nearestBeacon?.beaconID
            self.delegate?.nearestBeaconManager(self, didUpdateNearestBeaconID: self.nearestBeaconID)
            
            // Reset that count now that we have a new king beacon!
            self.countEventSent = 1
            
            print("NEW LOCATION")
            print(nearestBeacon?.beaconID)
            
        } else {
            
            //Increment the count to hold off and make sure it is a true change.
            self.countEventSent++
            print("LOCATION CHANGED??")
        }
        //self.firstEventSent = true
    } else {
        
        // we don't want countEventSent to increment just because it had a previous hickup, so reset if the old and new are identical.
        self.countEventSent = 1
    }
}

While there is a little bit of lag, you can reduce the number of checks from 3 to 2 if you notice it doesn’t happen often.

Hope this helps.

2 Likes

Thanks for sharing! (I moved your post to a new topic outside the “Archive”, to better surface it to the rest of the community.)

One extra idea from me: with those intermittent “RSSI = 0” issues, decreasing the advertising interval sometimes helps.

Decreasing the advertising interval? As in, changing it from 300ms to 900ms?

That seems counter intuitive since iOS aggregates data (by some of the sources i have searched on this - apply grain of salt) that the data returned by iOS would be more accurate since there is more sampled data available.

I am new to much of this so any info as to why that is the case would help fine-tune my expectations and adjustments.

Much thanks,
~C. Wade Cantley

By decreasing, I actually meant going the other way (: For example, from 300 ms to 100 ms. 300 ms => 900 ms, that’d be increasing (;

Great, that makes sense.
Thank you!