Categories
Bluetooth Windows

Read iBeacons from UWP

I recently got some estimate beacons and have been trying out various things with them. By default they are configured to support Apple’s iBeacon format and could be used in an iOS app to provide location awareness in a close environment. You can read the same data from UWP and can add some location/context awareness in this way. In this post I’ll just discuss the iBeacon approach.

In UWP development there is a BluetoothLEAdvertisementWatcher which is used to read advertisement data from nearby Bluetooth Low Energy devices. The watcher fires the Received event for each advertisement found and you can read the data as required. The key to using iBeacon is to understand how the data is encoded. Advertisement sizes are limited so they need to be designed to be as compact as possible while providing enough information to uniquely identify each device. The iBeacon format consists of a UUID (Guid) and two unsigned short integers. These should be thought of as a hierarchical format:-

UUID > Major > Minor

A location aware app would use a unique UUID for its own use, for example a chain of stores. The Major id would then represent an individual store and the Minor id a location within that store. In iOS the raw iBeacon advertisements are “hidden” from the CoreBluetooth API and instead exposed by CoreLocation. In UWP we use the BluetoothLEAdvertisementWatcher and reconstruct the elements of the beacon. These are stored in a ManufacturerData section with Apple’s manufacturer id (0x4C) used. Within this we access the raw data as an iBuffer (WinRT/UWP equivalent of a byte[] array). The DataReader class is used to sequentially read through the data. The data is:-

Byte 0 – type – 2 for iBeacon

Byte 1 – data length: 21 bytes for iBeacon

Bytes 2-17: UUID

Bytes 18-19: Major ID

Bytes 20-21: Minor ID

We must be careful to respect the byte ordering of the Guid element, the following Gist wraps up the operation:-


public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
_watcher = new BluetoothLEAdvertisementWatcher();
_watcher.Received += _watcher_Received;
_watcher.Start();
}
private void _watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
foreach(BluetoothLEManufacturerData md in args.Advertisement.ManufacturerData)
{
if(md.CompanyId == 0x4C) // Apple
{
DataReader reader = DataReader.FromBuffer(md.Data);
byte advertismentType = reader.ReadByte(); // 0x02 – iBeacon
byte len = reader.ReadByte(); // 0x15 (21) – iBeacon
int a = reader.ReadInt32();
short b = reader.ReadInt16();
short c = reader.ReadInt16();
byte[] d = new byte[8];
reader.ReadBytes(d);
Guid uuid = new Guid(a, b, c, d);
ushort major = reader.ReadUInt16();
ushort minor = reader.ReadUInt16();
Debug.WriteLine(uuid + " " + major + " " + minor + " " + args.RawSignalStrengthInDBm);
}
}
}

view raw

App.xaml.cs

hosted with ❤ by GitHub

The event also gives you the Rssi, you can use this to make a general assumption about the relative distance of multiple beacons but should not assume a direct measurement of distance from it.

By Peter Foot

Microsoft Windows Development MVP

One reply on “Read iBeacons from UWP”

Comments are closed.