Bluetooth LE Beacons in a UWP

One of the new Bluetooth LE features of Windows 10 is being able to watch for Bluetooth LE advertisements, otherwise known as Bluetooth beacons. Not only can you watch for advertisements but you can also publish them too enabling your Windows 10 device to act as a beacon.

What are beacons? Well they are devices that use the Bluetooth Low Energy protocol to send out advertisements with information. Unlike most Bluetooth scenarios, what makes the beacon scenario more intuitive is that it doesn’t require any pairing. The advertisement of the beacon is a set of hex values from which your application derives meaning from. To help explain this better let me use a scenario. Imagine you are in a shopping center where you have multiple beacons placed everywhere, each one broadcasting its unique id. Applications on your mobile device can listen for beacons nearby and when in range they can notify you of things like special offers. The cool part is that many applications can use the same beacon as it only transmits identification data – like a primary key in a database. It is the application which determines if the beacon is useful and what meaning it has to that app – generally done by looking up the id in its application database.

In this blog post I want to walk you through how you can implement a UWP application that acts as both a publisher and a watcher.

There are 3 screens, the first one is the screen which the user has to make a decision if it wants to publish or watch.

 

If the user selects publish, the device starts publishing Bluetooth LE advertisements – it becomes the beacon.

 

If the user selects watch, the device then listens for Bluetooth LE advertisements.


Here you can see that it has a decibel number, that is because the application is specifying the Relative Signal Strength Indicator which is abbreviated to RSSI. The closer you are to 0 the closer you are to the beacon, negative 127 means you are out range. Note that this is not relative to meters or inches and should only be used as an indicator, not accurate measurement.

So let’s dive into the code.


PUBLISHING

 I think first we’ll start with the publish screen – I’ll omit anything that’s not relevant like properties the XAML binds to and general navigation between screens.

The first thing I do is create a private variable

private BluetoothLEAdvertisementPublisher publisher;

Then in the OnNavtigatedTo method I instantiate the publisher and setup the details of my advertisement.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.publisher = new BluetoothLEAdvertisementPublisher();
    ushort id = 0x1234;
    var manufacturerDataWriter = new DataWriter();
    manufacturerDataWriter.WriteUInt16(id);
    var manufacturerData = new BluetoothLEManufacturerData
    {
        CompanyId = 0xFFFE,
        Data = manufacturerDataWriter.DetachBuffer()
    };

    publisher.Advertisement.ManufacturerData.Add(manufacturerData);
    publisher.Start();
}

The payload of the advertisement is basically hex values which is encapsulated in the type BluetoothLEManfacturerData. BluetoothLEManfacturerData consists of the CompanyID, in this case the hex value of 0xFFFE, and Data of type IBuffer - I use a DataWriter to write the hex value 0x1234. Once I have the payload created I then add it to the advertisement and then call the start method on the publisher to start broadcasting advertisements.

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    publisher.Stop();
}

When the user navigates away I call the stop method.

That’s all there is to publishing


WATCHING

Now onto watching:

private BluetoothLEAdvertisementWatcher watcher;

Notice that the type is very similar to publishing, so be careful you use the right one.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.watcher = new BluetoothLEAdvertisementWatcher();
    var manufacturerDataWriter = new DataWriter();
    manufacturerDataWriter.WriteUInt16(0x1234);

    var manufacturerData = new BluetoothLEManufacturerData
    {
        CompanyId = 0xFFFE,
        Data = manufacturerDataWriter.DetachBuffer()
    };

    this.watcher.AdvertisementFilter.Advertisem.ManufacturerData         .Add(manufacturerData);

    watcher.Received += Watcher_Received;
    watcher.Start();
}

Hopefully this looks familiar :)

We create an instance of the watcher, but wait… why am I creating another BluetoothLEManufacturer? Well in my scenario I don’t want the noise of any other beacons around me, my application only cares about a particular beacon, in this case ones with the company id 0xFFFE and Data of 0x1234. I then add this manufacturer data to the advertisement filters. Remember, if I decided not add the manufacturer data in the filters then I would get all the advertisements that are being broadcasted around me, this could be quite overwhelming for my app and drain my battery.

I then wire up the event for when an advertisement is received and start listening.

private async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
    var manufacturerData = args.Advertisement.ManufacturerData;
    if (manufacturerData.Any())
    {
        var manufacturerDataSection = manufacturerData[0];
        var data = new byte[manufacturerDataSection.Data.Length];

        using (var reader = DataReader.FromBuffer(manufacturerDataSection.Data))
        {
            reader.ReadBytes(data);
        }

        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            this.Rssi = (int)args.RawSignalStrengthInDBm;
            this.BeaconData = BitConverter.ToString(data);
        });
    }
}

When I receive an advertisement I simply extract the manufacturer data and then set the property of the BeaconData which is data bound to my UI. I also set the Rssi property which is also data bound to my UI – the Rssi simply comes as part of the args as it’s not payload information.

When I leave the page I simply stop the watcher, unwire the event and I’m good to go.

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    watcher.Received -= this.Watcher_Received;
    watcher.Stop();
}

That’s all there is to it, don't forget that to see the watcher work you need to have something publishing advertisements. Thankfully this is a UWP so I deploy the app to both my laptop and phone, I start the app on my laptop and click publish and then on phone I select the watch.

I hope you enjoyed the post and I wish you all happy coding!

All code can be found at:
https://github.com/shenchauhan/blog/tree/master/Beacons