Even Quicker Development with Xamarin Forms Using Telerik UI for Xamarin
Location Based Development Using Xamarin
-
Upload
kym-phillpotts -
Category
Technology
-
view
344 -
download
1
Transcript of Location Based Development Using Xamarin
Contents
• An example app • Using Beacons for loca3on detec3on
• What are Beacons? • Which provider should I choose? • Which protocol should I use? • GeoLoca3on vs Beacons • Configuring beacons
• Development Code • The reality of how they work
The AudioPuppy App
• Both beacon and GPS loca3on detec3on
• Plays audio files based on physical loca3on
Contents
• An example app • Using Beacons for loca3on detec3on
• What are Beacons? • Which provider should I choose? • Which protocol should I use? • GeoLoca3on vs Beacons • Configuring beacons
• Development Code • The reality of how they work
What is a Beacon?
Es*mote specifica*ons as an example It is: • A small computer 32 bit ARM Cortex MO CPU • With other components Es*mote has an acceleromiter
and temperature sensor. • A Radio 2.4 Ghz using Bluetooth 4.0 SMART
• A baJery CR2477 -‐ 3 years on default seLngs.
• A cover Sealed plas*c.
• Expect a signal range of 40-‐50 meters • No ‘pairing’ required • Smartphones can listen to many at the same 3me
A Beacon is a Bluetooth Low Energy (BLE) devices.
Choosing a beacon manufacturer They must: • support the beacon protocol you with to use.
• have appropriate baJery life • baJery life 3 months or 3 years? • do they have baJery conserva3on op3ons
• no3fica3on of impending baJery expiry • have an appropriate form factor. Consider:
• physical size • weather resistant • can be physically secured (to prevent theY)
• blend with intended environment
• be configurable: • Most have base signal configura3on (frequency and strength of message)
• are they server configurable • -‐ are they wirelessly configurable (or physically take baJery out to configure)
• have an easily replacable baJery. • be cost effec3ve:
• once off purchase • charge per transac3on use
• support other features you need: • Temperature detec3on • mo3on sensor • Holding user data (e.g. url)
For a full evalua3on go to : hJp://www.aislelabs.com/reports/beacon-‐guide/
Beacon Protocols • There are different protocols. This defines the data you get from the beacon into your app:
• iBeacon (introduced by Apple in 2013) (see slide) • Eddystone (introduced by Google in 2015) • Nearable (introduced by Es3mote in 2014 aimed at the wearable market) • Manufacturer proprietary (e.g. Gimbal beacons support both their own & iBeacon)
• Poten3al uses: • Retails store product informa3on, aJach to retail products, auc3on item informa3on, turn on the TV, loyalty program detec3on, mapping a conferences and exhibi3ons, direc3on while indoors.
• My choices: • Ini3ally: Qualcom and Qualcom protocol • I now use: Es3mote and iBeacon
iBeacon Protocol Property Description
proximityUUID Your businesses UUID that the beacon is assigned to. When you listen for beacon signals you specify this value and you will only get these beacon message back.
major A random number assigned to identify a beacon which you can change. For example rather than register beacons for different project to different UUID’s you could assign them to a common major code. The names ‘major’ and ‘minor’ have no signiDicance – any differentiation between this is within your app.
minor A random number assigned to identify a beacon.
proximity Values: Immediate, Near, Far, Unknown. With the Estimote beacons I have found that ‘Immediate’ is within 0.5m, ‘Near’ is within 2.0m and ‘Far’ could be anything greater than 2.0m and up to 50m. You will receive ‘Unknown’ values regularly. This means that for some reason the Bluetooth signal was temporarily interrupted. (No signal is receive if a beacon is out of range).
accuracy (i.e. distance) Is intended to represent the distance in meters, but we advised not to use it in this manner as it will usually be wrong. You can use this to determine the relative closeness between two beacons.
rssi (in dB) Is the decibel reading of the signal strength, the root data that the above items are derived from.
GeoLocation vs Beacons • When using GPS for loca3on detec3on you define the central
point then a radius. The circumference is called a GeoFence – you are either inside or outside the ‘fence’.
• For beacons you place the beacon at the central point, measure the radius using signal strength, and op3onally record the La3tude and Longitude of where you placed the beacon.
• GPS characteris3cs: • Satellite based hence it doesn’t work well indoors. • Can be very accurate, but not on a standard smartphone …
they are dumbed down to conserve phone baJery life.
• Beacon characteris3cs: • Low energy radio device – beacon baJery life restricted. • Ideal for indoors.
Configuring beacons
• Can change: • Frequency messages are sent • The power of the message …. impac3ng baJery life (more on this later)
• Dynamic configura3on: • Does your beacon have the ability to be able to configure the above remotely?
Contents
• An example app • Using Beacons for loca3on detec3on
• What are Beacons? • Which provider should I choose? • Which protocol should I use? • GeoLoca3on vs Beacons
• Development Code • The reality of how they work
Xamarin Coding • Two op3ons:
• ‘Ranging’ -‐ scan for beacons in range and read their values, • ‘GeoFencing’ -‐ not supported by Es3mote (and I’m not sure it
would work anyway due to beacon limita3ons)
• Coding snippets are available at: • Android: hJps://blog.xamarin.com/use-‐ibeacons-‐in-‐android-‐with-‐c/ • iOS: hJps://blog.xamarin.com/play-‐find-‐the-‐monkey-‐with-‐ios-‐7-‐ibeacons/
• Use the Xamarin.Mobile package
using System;"using Foundation;"using CoreBluetooth;"using CoreLocation;"using CoreFoundation; "
namespace iBeacon"{ " public class NavigationManager : NSObject" { " static readonly string uuid = "########-####-####-####-############"; "
static readonly string appId = "AudioPuppy"; "
private CLLocationManager beaconLocationMgr; " private CLBeaconRegion beaconRegion; " private Boolean monitoring = false; "
public void Initialise() " { " beaconRegion = new CLBeaconRegion (new NSUuid (uuid), appId); "
beaconRegion.NotifyEntryStateOnDisplay = true; " beaconRegion.NotifyOnEntry = true; " beaconRegion.NotifyOnExit = true; "
beaconLocationMgr = new CLLocationManager (); " beaconLocationMgr.RequestAlwaysAuthorization (); "
beaconLocationMgr.DidRangeBeacons " += (object sender, CLRegionBeaconsRangedEventArgs e) => " { ProcessBeaconUpdates( e ); }; "
StartLocationTracking (); " } "
public void StopLocationTracking() " { " if (monitoring) { " if (beaconLocationMgr != null) { " beaconLocationMgr.StopMonitoring (beaconRegion); " } " monitoring = false; " } " } "
public void StartLocationTracking() " { " if (!monitoring) { " if ( beaconLocationMgr != null " && SharedValues.SharedObject.TrackingBeacons) { " beaconLocationMgr.StartMonitoring (beaconRegion); " } " monitoring = true; " } " } "
private async void ProcessBeaconUpdates(CLRegionBeaconsRangedEventArgs e) " { " if (e.Beacons.Length == 0) " return; "
// Record all beacons in range" BeaconService.SharedManager.BeaconSightings (e.Beacons); " // Business logic when beacons detected" EventService.ProcessForCurrentLocation (); " } " } "} "
Coding considerations
• Make sure you check that Bluetooth is turned on and consider what to do both when the user has:
• forgoJen to turn it on, and • purposely turned it off.
• Background mode: • iOS has the ability to start your app when it detects a beacon. • Beacon signals arrive less frequently in background mode.
Contents
• An example app • Using Beacons for loca3on detec3on
• What are Beacons? • Which provider should I choose? • Which protocol should I use? • GeoLoca3on vs Beacons • Configuring Beacons
• Development Code • The reality of how they work
Limitation
Bluetooth: • penetrates most materials, and • is most absorbed by water.
Beacon limita3on: • BaJery life
• High power and frequency means lower baJery life • Power fluctua3ons
Smartphone limita3ons • BaJery life compromises
Beacon lab test results We tested: • 5 Es3mote beacons set with normal power sekngs, and • 5 with a high power and high frequency sekng. • At 0.2, 1.5, 2.5 and 4 meters. • Each with 50 message (total of 2000 readings).
Lab test results:
Higher power sekngs had: • An increase in accuracy up to 2.5m, • A marked increase in standard
devia3on at 4m (less accuracy), • BaJery life reduced from 3-‐4 years to
6 months.
Challenges • Inundated with beacon messages: messages from all beacons with 50m every second.
• Too much Bluetooth absorp3on • Absorbed by water. • 60% of human are water.
• Not enough Bluetooth absorp3on • The floor above may be closer than your current
floor.
• ‘Unknown’ message • 1 in 10 is a message “Unknown” meaning in range
but signal is unknown.
• Message synchronisa3on • (See next slide)
• Signal strength irregulari3es • (see lab test results)
• Out of range detec3on • If no messages?
• If messages in and out of power range?
• “Significant change” problem • Fluctua3ons in signal strength could mean many
things.
• User behavior irregulari3es • Moves forwards, back, away, comes back, …
• Incoming phone calls • How do you handle incoming messages when user is
talking on the phone?
• Fast moving users • Exaggera3ng message synchronisa3on problem.
• Beacons are imperfect and have their own characteris3cs.
• Thread processing • Make sure beacon message are processed on a
background thread.
Suggested coding Create: • A Beacon class:
• Handing characteris3cs of an individual beacon • calibra3on, • averaging of messages, • managing when goes out of range
• A BeaconsInRange class: • A dic3onary of all beacons in range
• Comparison of one beacon to another to determine highest Rssi
• A BeaconService class • Singleton to manage mul3ple beacon ac3vity:
• Current beacon • Process beacon sigh3ngs (adding and removing beacons from BeaconsInRange)
using System;"
namespace iBeacon"{ " public class Beacon " { " #region Local variables" private int AverageDenominator{ get; set;} " private double CalibrationFactor { get; set;} "
// previous 4 values stored as the raw uncalibrated value" private int Rssi_1 { get; set;} " private int Rssi_2 { get; set;} " private int Rssi_3 { get; set;} " private int Rssi_4 { get; set;} "
#endregion"
#region Properties" public string Uuid { get; set;} " public int Minor { get; set;} " public int Major { get; set;} "
private int _averageRssi; " public int AverageRssi { " set { _averageRssi = value; } " get { return (int) Math.Round(_averageRssi * CalibrationFactor); } " } "
public double LastUpdate { get; set; } " public double Accuracy { get; set;} "
private int _rssi; // Stored as the uncalibrated value" public int Rssi { " get { " if (this.Expired) " return -999; " " return (int) (Math.Round (_rssi * CalibrationFactor)); " } " set { " LastUpdate = DateTime.Now.ToOADate(); "
Rssi_4 = Rssi_3; " Rssi_3 = Rssi_2; " Rssi_2 = Rssi_1; " Rssi_1 = _rssi; "
_rssi = value; "
double aveRssi; "
if (AverageDenominator == 1 || (Rssi_1 == 0 && Rssi_2 == 0)) " aveRssi = _rssi; " else if (AverageDenominator == 2 || (Rssi_2 == 0 && Rssi_3 == 0)) " aveRssi = (_rssi + Rssi_1)/2; " else if (AverageDenominator == 3 || (Rssi_3 == 0 && Rssi_4 == 0)) " aveRssi = (_rssi + Rssi_1 + Rssi_2)/3; " else if (AverageDenominator == 4 || (Rssi_4 == 0)) " aveRssi = (_rssi + Rssi_1 + Rssi_2 + Rssi_3)/4; " else " aveRssi = (_rssi + Rssi_1 + Rssi_2 + Rssi_3 + Rssi_4)/5; "
AverageRssi = (int)Math.Round (aveRssi); "
} " } "
#endregion"
#region Public Methods" public bool IsInRange() " { "
if (this.AverageRssi < Settings.MinRssi || this.AverageRssi > Settings.MaxRssi) " return false; " else" return !this.Expired (); " } "
public static Beacon ForKey(int major, int minor) " { " return BeaconService.SharedManager.BeaconsInRange.ForKey (major, minor); " } " #endregion"
#region Constructors"
public Beacon (string uuid, int major, int minor, int rssi, double accuracy) " { " this.CalibrationFactor = 1; "
// HARD CODED FOR PURPOSES OF DEMO" switch (minor) { " case 12295: " this.CalibrationFactor = 0.944661095636026; " break; " case 29160: " this.CalibrationFactor = 1.01113098787517; " break; " case 45308: " this.CalibrationFactor = 1.0499484004128; " break; " } "
AverageDenominator = Settings.BeaconAverageCount; "
this.Rssi_1 = 0; " this.Rssi_2 = 0; " this.Rssi_3 = 0; " this.Rssi_4 = 0; " this.AverageRssi = 0; "
this.Uuid = uuid; " this.Minor = minor; " this.Major = major; " this.Accuracy = accuracy; " this.Rssi = rssi; " } " #endregion"
#region Private methods" private bool Expired() " { " double now = (int)DateTime.Now.ToOADate(); " if ((this.LastUpdate + Settings.OutOfRangeSeconds * 1000) < now) { " return true; " } " return false; " } " #endregion" } "} "
Beacon class
using System;"using System.Collections.Generic;"
namespace iBeacon"{ " public class BeaconsInRange : Dictionary<int, Beacon> " { " public Beacon ForKey(int major, int minor) " { " foreach(KeyValuePair<int, Beacon> entry in this) " { " if (entry.Value.InRange ()) { " if (entry.Value.Major == major && entry.Value.Minor == minor) { " return entry.Value; " } " } " } " return null; " } "
public Beacon GetHighestRssiBeacon(){ " int highestRssi = -999; " Beacon highest = null; "
foreach(KeyValuePair<int, Beacon> entry in this) " { " if (entry.Value.InRange ()) { " if (entry.Value.AverageRssi > highestRssi) { " highestRssi = entry.Value.AverageRssi; " highest = entry.Value; " } " } " } " return highest; " } " } "} "
BeaconsInRange class
using System;"using Foundation;"using CoreLocation;"
namespace iBeacon"{ " public class BeaconService" { " #region Properties" private BeaconsInRange _beaconsInRange = new BeaconsInRange(); " public BeaconsInRange BeaconsInRange { " get { return _beaconsInRange; } " set { _beaconsInRange = value; } " } "
public Beacon CurrentBeacon { set; get; } " #endregion"
#region Constructors" private BeaconService () " { " this.CurrentBeacon = null; " } " #endregion"
#region Public methods" public void BeaconSightings (CLBeacon[] beacons) " { " foreach (CLBeacon clBeacon in beacons) { " Beacon beacon = new Beacon ( " clBeacon.ProximityUuid.ToString (), " Int32.Parse (clBeacon.Major.ToString ()), " Int32.Parse (clBeacon.Minor.ToString ()), " clBeacon.Rssi, " clBeacon.Accuracy); "
if (clBeacon.Proximity != CLProximity.Unknown) { " if (!beacon.InRange () && beacon.Expired ()) { " RemoveFromBeaconList (beacon); " } else { " AddToBeaconList (beacon); " } "
} else { // Proximity not known" if (beacon.Expired ()) " RemoveFromBeaconList (beacon); " } " } " } " #endregion"
#region Private methods" private void AddToBeaconList (Beacon beacon) " { " Beacon myBeacon = null; "
// If a beacon is already in range, update it's rssi value" if (BeaconsInRange.ContainsKey ( beacon.Minor )) { " myBeacon = BeaconsInRange [ beacon.Minor ]; " myBeacon.Accuracy = beacon.Accuracy; " myBeacon.Rssi = beacon.Rssi; " BeaconsInRange [beacon.Minor] = myBeacon; "
} else { " BeaconsInRange.Add (beacon.Minor , beacon); " myBeacon = beacon; " } " } "
private void RemoveFromBeaconList (Beacon beacon) " { " if (BeaconsInRange.ContainsKey ( beacon.Minor )) { " BeaconsInRange.Remove (beacon.Minor); " } " } " #endregion" } "} "
BeaconService class
Summary
• Beacons are used to detect loca3on indoors • From the simple to the complex:
• A user has entered a coffee shop and has been there more than 15 minutes. • To the complex:
• To mapping 100 stalls within an exhibi3on and which person was interested in which stall.
• There are technology limita3ons, some relevant to your situa3on, some not.
Solving the problems is easy … but only aYer you know what they are.
Questions?
And feel free to contact me later.