Battery friendly indoor positioning with iBeacon
This post is the first of the series on working with beacons and mobile devices and was written by our CTO, Arvid E. Picciani (aep). Arvid is an ex-Nokia engineer, IoT pioneer, and self-proclaimed embedded devices hacker.
Indoor positioning and proximity tracking have become universally available thanks to apples iBeacon profile. It allows any compatible mobile device track its location indoor, using tiny battery powered “beacons”. All much much less battery hungry than GPS.
If you remember the painful pairing process of classical Bluetooth, iBeacons are not like that. In fact, iBeacons don’t connect to devices at all. The communication is one way, in that the iBeacon only continuously broadcasts its unique device id together with the strength of its own signal. The device then calculates the distance by matching its own perceived signal strength to the one advertised by the device. All that the mobile phone really knows is that:
“There is an iBeacon with id X at Y meters distance”
It is up to the individual application developer to figure out what to do with that information. Common use cases include showing the user location based advertising, such as “You are near our special offer, if you actually put down your phone for a second, you would see it”. Another cool use case is location based gamified rewards. “Get a free coffee if you visit all or 3 stores in the city”. For that, you will a way to match the devices major and minor numbers to something that has meaning in your application. “Number 06:03 is Tanja’s corner shop”
Bluetooth 4.0 Low Energy, also called Bluetooth Smart, is not backwards compatible with classic Bluetooth and requires Android 4.3 or iOS7 and later, as well as hardware support in the mobile phone, available in e.g. the iPhone 5s, iPhone 6, or the Google Nexus 4 and 5.
In the first part of my series on iBeacons, I will cover the basics of getting started with iOS.
If you don’t have an iOS, don’t despair, there will be love for Android later on!
Getting started #
Since you are working on iOS, you will need, well, an iPhone, and a Mac.
If you don’t have a beacon hardware yet (my company is launching one soon!), that is fine, since your Mac can emulate one using this handy tool
Because beacons are tiny location guides, iOS7 restricts availability to the geolocation classes. It requires 3 essential components:
CLLocationManager, the iOS core api for geolocation
CLBeaconRegion, declaring a physical region using iBeacons
CLLocationManagerDelegate, receiving location updates in your application
Telling the iOS core geolocation API to use beacons for location monitoring is as easy as declaring a ClBeaconRegion, which has to be restricted to one specific iBeacon vendor uuid. For this example, we’ll just use something funny. Note that you’ll have to enter the same uuid in OSXBeacon, or it won’t work.
NSString * const kBeaconUUID = @”beefbeef-beef-beef-beef-beefdeadf00d” NSString * const identifier = @”com.myapp.example1" NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kBeaconUUID]; CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:proximityUUID identifier:identifier];
There are two different methods available for getting changes to a
Monitoring and Ranging #
Monitoring is more battery friendly, giving you events when a user has exited or entered a region, it is supposed to work while your app is in the background. As of iOS7, it does not. The other interface is ranging, giving you periodic updates about all the beacons in a region. For maximum responsiveness, enable both.
locationManager = [CLLocationManager new]; locationManager.delegate = self; locationManager startMonitoringForRegion: beaconRegion locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers; self.locationManager startMonitoringForRegion:self.region locationManager startRangingBeaconsInRegion:beaconRegion locationManager startUpdatingLocation
Note the counter-intuitive use of
startUpdatingLocation, which is actually intended to receive GPS coordinates. We set desiredAccuracy to the lowest and most battery friendly resolution, which disables GPS and uses cell towers to locate the device instead. Your delegate will now receive periodic updates of beacons in range:
When a beacon is within a region (i.e. visible) iOS knows 3 different proximity ranges:
CLProximityFar. It does calculate these ranges for you, and smoothes out transitions. For maximum responsiveness in for example smart home applications, we find that that
CLProximityImmediate works best, but your use case might be different.
CLProximityUnknown is a side effect on a caveat you should be aware of when using beacons in location applications: Bluetooth Low Energy and WiFi share the same frequency band, and sometimes even the same antenna. While transmitting data through WiFi, beacon signals are unavailable, and iOS may mark the proximity of the beacon as “unknown”.
When your application is in the background, beacon ranging may be unavailable as well, unless you have
UiBackgroundModes = location capabilities. Even then, iOS may decide to lower the update frequency dramatically after the user appears to be not using the phone any longer.
When they power the device again, you can receive an instantaneous update when setting
region.notifyEntryStateOnDisplay = YES;
Occasionally, iOS decides the user is no longer moving, and stops location updates anyway, which can be countered with
locationManager.pausesLocationUpdatesAutomatically = NO;
iOS makes it real simple to get kickin’ with iBeacons by providing us the necessary low level tools to deal with them in their geo API. Unfortunately they also built in some caveats when it comes to using them in responsive applications, like actual indoor location guidance. Apple appears to be committed to making it work seamlessly throughout the next updates.
In our next post of the series, we will go in deeper and cover how to build stuff with beacons on Android, which is a much different experience.