Sergiy Baydachnyy

Blog about technologies

Archive for May 8th, 2017

UWP: Working with Bluetooth (part 3: Advertisement)

leave a comment »

Bluetooth Low Energy can be used to implement beacons. Usually beacons are not designed for pairing and simply broadcast data making them available for everybody. You can use beacons in a mall to notify shoppers about some deals, or in quests, notifying players about some treasures in the area, or even for people with disabilities notifying them about surrounding environment. Today, almost all mobile devices support Bluetooth Low Energy and advertisement feature there and you even can find some SDKs for Android and iOS that implement own data payload specifications (Eddystone and iBeacon) based on Bluetooth Low Energy Advertisement. Thanks to the specifications you can understand what kind of data is broadcasting and use them in your applications even if a beacon was implemented by somebody else.

In the case of Universal Windows Platform you have access to a special namespace Windows.Devices.Bluetooth.Advertisement that can help you receive and send data using BLE Advertisement. Using this namespace you can implement classes that will use existing payload specifications or simply broadcast data in your own way.

To implement advertisement example, I am not going to use any microcontroller. Instead, I would recommend to use just Windows 10 computers. In general, any Windows 10 computer can send and receive advertisement, but in some cases, it’s not true and some Bluetooth radio adapters don’t support broadcasting advertisement data.

To understand if your adapter supports broadcasting, you can simply execute the following line of code:

BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync();

And just check adapter’s property using Debugger:

clip_image002

You can see that there is a property IsAdvertisementOffloadSupported that shows if your adapter can broadcast advertisement. In my case this property is true.

Ok, let’s start with code that broadcast some data:

BluetoothLEAdvertisementPublisher publisher;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    var manufacturerData =
        new BluetoothLEManufacturerData();
    var writer = new DataWriter();
    writer.WriteString("Buy our socks for a dollar");
    manufacturerData.CompanyId = 0xFFFE;
    manufacturerData.Data = writer.DetachBuffer();
    publisher =
        new BluetoothLEAdvertisementPublisher();
    publisher.Advertisement.ManufacturerData.Add(manufacturerData);
    publisher.StatusChanged += Publisher_StatusChanged;
    publisher.Start();
    base.OnNavigatedTo(e);
    }
private void Publisher_StatusChanged(BluetoothLEAdvertisementPublisher sender,
    BluetoothLEAdvertisementPublisherStatusChangedEventArgs args)
{
    Debug.WriteLine(args.Status.ToString());
}

In our case we made all preparation work using the BluetoothLEManufacturerData class. We used this class just in order to simplify our work, because we are not going to broadcast anything special, but in the most cases you will use the DataSections property rather than the ManufacturerData property. Exactly DataSections contains all payloads and filling ManufacturerData you automatically add a section to DataSections collection. But working with the BluetoothLEAdvertisementDataSection class to fill DataSections is a little bit more complicated, because you need to know different data types from BLE specification, form a header that will include special flags and size of the buffer and so on. In the case of the BluetoothLEManufacturerData class you can write your data directly and all what you need is just provide a company id. Using this link (https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers), you can find some hardcoded company ids for companies like Apple and Microsoft. Therefore, I selected the first available ID from the end. Additionally, I implemented the StatusChanged event handler to make sure that my application starts broadcasting data.

Therefore, we have a publisher that broadcasts a text message. Now, we can create a watcher that will receive our advertisement. Let’s look at the following code:

private BluetoothLEAdvertisementWatcher watcher;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    watcher = new BluetoothLEAdvertisementWatcher();
    watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
    var manufacturerData =
        new BluetoothLEManufacturerData();
    manufacturerData.CompanyId = 0xFFFE;
    watcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(
        manufacturerData);
    watcher.Stopped += Watcher_Stopped;
    watcher.Received += Watcher_Received;
    watcher.Start();
    base.OnNavigatedTo(e);
}
private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{ }
private void Watcher_Received(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementReceivedEventArgs args)
{
    Debug.WriteLine(args.Advertisement.LocalName);
    Debug.Write(args.RawSignalStrengthInDBm);
    if ((args.Advertisement.ManufacturerData.Count>0))
    {
        DataReader data =
            DataReader.FromBuffer(args.Advertisement.ManufacturerData[0].Data);
        Debug.Write(data.ReadString(
            args.Advertisement.ManufacturerData[0].Data.Length));
    }
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    watcher.Stop();
    base.OnNavigatedFrom(e);
}

In fact, it’s not a complex task to create a watcher, but implementing your own application, you should not always watch all advertisements around. It’s better to watch exactly beacons that were designed for your application. That’s why the BluetoothLEAdvertisementWatcher class allows us to setup filters. In our case we have two filters: signal strength and company id. It can help us understand that we are too close to the beacon and that it’s exactly our service.

Working with beacons we have to note several things:

  • In most cases you will work with the DataSections property. So, if you want to develop something cool, you have to learn Bluetooth LE Advertisement specification. Additionally, you may need to implement Eddystone and iBeacon specifications;
  • You can see that beacon broadcasts the same data all time and if you run our application in the Debug mode, you will be able to see that the application prints advertisement message all time. So, it’s important to check if you already received the message to avoid duplicate actions;
  • Above we implemented just foreground applications, but it’s not wisely. Probably, our application will not stay open all time even in the case of watcher. In the case of publisher, there is no sense to implement interface at all. That’s why it’s important to know how to work with Bluetooth in background. We will discuss background approach later;
Advertisements

Written by Sergiy Baydachnyy

05/08/2017 at 10:27 PM