Unless you live under a rock, you’ve probably heard I’m developing a location-aware automation app called Beacon Action. If not, you can read about it here. In a nutshell, it uses your proximity to Bluetooth beacons to trigger automation events (actions) within your home. Want to be a beta tester? Join our newsletter to get on the invite list.
[pullquote align=”right” color=”#52bac3″]One thing I’ve noticed: beacons can be very noisy.[/pullquote]
Anyway, along the way I’ve learned a lot about beacon hardware and protocols. There are two big players in the beacon protocol world: Apple’s iBeacon and Google’s Eddystone. A physical beacon could implement one or both protocols. Although I’m fascinated by Eddystone and it’s flexibility, I’m building the first version of Beacon Action with iBeacon. I’ll cover the details of both protocols sometime soon, but that definitely deserves its own post.
One thing I’ve noticed: beacons can be very noisy. I don’t mean audibly noisy. They don’t squeak or hum or buzz. I mean the fluctuations in Bluetooth signals and constant broadcasts make it difficult to accurately identify beacons within the app.
Let me explain.
Beacon hardware is simple. It constantly broadcasts a Bluetooth Low Energy (BLE) signal that includes a few identifiers. Apps and other devices can pick up these signals and use them to identify each beacon and approximately how far away they are. Typical beacons have a range of 75+meters. In the case of iBeacon, the device listens to all of the beacons within range.
If there’s only a single beacon within 75 meters, it’s no problem. If you have a dozen beacons within your home, that’s where things get noisy.
The iBeacon API handles some of this by requiring you to define a region that is specific to your beacons. To understand regions, let’s quickly cover the anatomy of an iBeacon advertisement frame. An advertisement frame is simply the message the beacon broadcasts. Every advertisement frame contains 3 identifiers:
Universally Unique ID (UUID)
The UUID is used to identify a “batch” of beacons and is also used to define regions. The major and minor IDs are arbitrary values used to identify beacons within the same region.
For example, a retail store may be placing 10 beacons throughout their space. When they purchase the beacons, they can request all 10 of them to have the same UUID. This allows them to define a region based on that UUID. Within that region, they can uniquely identify each beacon using a combination of their major and minor IDs.
Most beacons allow you to modify the UUID. Here’s how to do it with Estimote beacons.
Once the region is defined, apps can listen to that specific region. This means no filtering out other people’s beacons. However, the app is still responsible for identifying and reacting to all of the beacons within that region.
Here comes the fun part. The region is defined, your app is only reacting to your beacons and it’s smooth sailing from here.
Well, not quite.
When in “range” mode, the iBeacon API scans for beacons every second. It then passes all of the beacons it detected along to your app. This includes the identifiers we talked about earlier as well as a rough proximity. Proximities are grouped into three distinct values:
Immediate: Within a few centimeters.
Near: Within a few meters.
Far: More than 10 meters away.
When you’re dealing with multiple beacons within the same region you start to see the weaknesses of Bluetooth. Physical obstructions, battery power, how you’re holding your phone and a million other variables affect how beacons are detected.
For example, let’s say you’re holding your phone in front of you. There’s a beacon 20 feet in front of you and another one 2 feet behind you. Because your body is between your phone and the beacon behind you, the iBeacon API might think it’s farther away. Or, if there are two beacons equal distance away but one has a weak battery, the one with a strong battery will always appear closer.
The problem gets amplified as you add more beacons to the region. Here’s a sample output from the API with fluctuating proximities that can be difficult to deal with.
By glancing at this table you can quickly and easily tell that Beacon 1 is the closest of the three available beacons. But, you’ll also notice the slight inconsistencies in proximity. Although we intuitively know that Beacon 1 is closest, the detected proximity is fluctuating between Near and Immediate. This is what I mean by noisy beacons.
If your goal is to identify the nearest beacon you can’t simply sort by proximity. The fluctuations may cause the wrong beacon to end up at the top of the list. So how can you deal with this?
Disclaimer: this is not a one size fits all solution. Depending on what you are trying to accomplish this may or may not be useful. Hopefully, though, somebody is trying to accomplish the same thing as me and benefits from this approach.
To get a more accurate output of the nearest beacon, I created a queue containing the last X number of beacons detected. When the queue is created, I specify a maximum number of items allowed in the queue. Let’s say the maximum number is 5. After the queue contains 5 items, every subsequent item that is added forces the oldest member of the queue to be removed. This ensures the queue never exceeds 5 items.
Every second, sort the available beacons by proximity. The iBeacon API doesn’t sort them for you, so you’ll have to order them by the 3 proximity values mentioned earlier. Take the beacon with the closest proximity value (even though it may not actually be the closest) and add it to the queue. Repeat this every second.
Now, when you need to know what the closest beacon is, you can query the queue. If every item in the queue represents the same beacon you can be confident that is the closest beacon. If 4/5 items in the queue are the same, you have 80% confidence that is the closest beacon. Depending on how you’re using this data, you can increase the size of the queue, adjust your queries to require more confidence, etc.
I created this structure in Swift. If you’re interested in the actual code I wrote, shoot me an email and I’d be glad to share it.
Have you ran into this issue before? How did you solve it? Let me know in the comments!
And finally, if you’d rather not bang your head against the wall for hours on end, you can just use my app. Not for everything, of course, but if you’re into home automation I’d love to hear from you. The Beacon Action app will be needing beta testers soon, so join our newsletter below to get on the invite list!