I've been a big fan of Estimote (and beacons in general) for awhile now, but only just recently had a chance to finally play around with their nearables, dubbed Estimote Stickers. These stickers are similar to beacons, except that their primary purpose is to be attached to physical objects, and in addition to proximity also broadcast more contextual information about the object. This extra information contains a bunch of interesting details such as temperature, orientation, and motion in three dimensions.
Getting Started
With these stickers in my possession, the first step was seeing what was involved in getting set up with Estimote's SDK for interacting with the stickers. Thankfully this is as trivial as it gets. Simply head over to the Xamarin Component Store, grab the components for iOS and Android, and you're good to go!
iOS
With that installed, it's just as easy to start detecting nearables:
var manager = new NearableManager();
manager.RangedNearables += (sender, e) =>
{
foreach (var nearable in e.Nearables ?? Enumerable.Empty<Nearable>())
Console.WriteLine(nearable);
};
manager.StartRangingForType(NearableType.All);
On iOS8+ you also need to specify a value for NSLocationAlwaysUsageDescription
or NSLocationWhenInUseUsageDescription
in your Info.plist
file in order to get access to the iOS location APIs, which Estimote sits on top of.
If you're only looking for a specific nearable type you can alternatively specify that in the call to StartRangingForType()
, instead of always scanning for all types. Other types available as of right now include Dog
, Fridge
, Door
, Generic
, and more. That's all you need to initiate basic scanning for nearables, and you will get access to all the discovered nearables in the RangedNearables
callback.
Android
The Android SDK is also easy to get up and running with, though I do find it a bit lacking compared to the iOS one (more on that later). Here is an activity that starts scanning for nearables when it loads up:
[Activity(Label = "Nearables!", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity, BeaconManager.IServiceReadyCallback
{
private BeaconManager _beaconManager;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_beaconManager = new BeaconManager(this);
_beaconManager.Nearable += (sender, e) =>
{
foreach (var nearable in e.Nearables ?? Enumerable.Empty<Nearable>())
Console.WriteLine(nearable);
};
_beaconManager.Connect(this);
}
public void OnServiceReady()
{
_beaconManager.StartNearableDiscovery();
}
}
Easy enough. Where on iOS we were able to limit scanning by nearable type, that doesn't seem to be exposed in the Android SDK. In Fact, despite there being a NearableType
enum in the SDK, that doesn't even seem to be exposed as a property on a Nearable
object.
Triggers
One of the other nice things about the iOS SDK that is not currently available in the Android SDK is the ability to specify rules and triggers for when you get a callback from a nearable. While it's not the end of the world to have to compose these things by hand, this makes it trivial to define the scenarios you care about in your apps.
For example, let's say you attached the Dog
sticker to your dog and wanted to detect when the dog rolled over. All you need to do is define an orientation rule for that nearable type and create a trigger based on it:
var triggerManager = new TriggerManager();
var dogRollsOverRule = OrientationRule.OrientationEquals(NearableOrientation.HorizontalUpsideDown, NearableType.Dog);
var dogRollsOverTrigger = new Trigger(new [] { dogRollsOverRule }, "dog rolls over");
triggerManager.ChangedState += (sender, e) =>
{
if (!e.Trigger.State)
return;
if (e.Trigger.Identifier == dogRollsOverTrigger.Identifier)
new UIAlertView(null, "dog rolled over", null, "Ok", null).Show();
};
triggerManager.StartMonitoringForTrigger(dogRollsOverTrigger);
In the ChangedState
callback, e.Trigger.State
indicates whether the trigger is currently active.
In addition to OrientationRule
there are several other built-in rules you can use, such as DateRule
, ProximityRule
, TemperatureRule
, and MotionRule
. You can also define your own rule classes that create any scenarios you'd like.
Composing Rules
You're also not limited to a single rule for a trigger, so you can compose multiple rules together to form a more interesting scenario. Let's say that you attached a sticker to your refrigerator and want to detect when it opens late at night to cut back on late night snacking. With Estimote's trigger API this is trivial:
var fridgeDoorMovesRule = MotionRule.MotionStateEquals(true, NearableType.Fridge);
var afterMidnightRule = DateRule.HourBetween(0, 5);
var lateNightSnackingTrigger = new Trigger(new Rule[] { fridgeDoorMovesRule, afterMidnightRule }, "fridge door moves after midnight");
triggerManager.ChangedState += (sender, e) =>
{
if (!e.Trigger.State)
return;
if (e.Trigger.Identifier == lateNightSnackingTrigger.Identifier)
new UIAlertView(null, "late night snacking!", null, "Ok", null).Show();
};
triggerManager.StartMonitoringForTrigger(lateNightSnackingTrigger);
Simply compose a DateRule
with a MotionRule
and you're done!
Summary
Obviously this just scratches the surface of what you can do with nearables, but the exciting part to me is how easy it is to build smart, contextual experiences. Estimote is an awesome company as well, so I suspect they will close the SDK gaps between iOS in Android over time to make things easy across the board.