How to Create a UWP Application with Bluetooth Developer Studio

In this post I will show you how you can use those tools to create a heart rate monitoring application within minutes.

By using Bluetooth Developer Studio and Windows 10 UWP plugin by Matchbox Mobile one can quickly create a new Windows 10 application to communicate with a particular BLE device. The plugin itself is still under development and there could be some little breaks in the API in the future, but it is already incredibly helpful, so don’t hesitate to start using this.

Project Setup

Prerequisites are:

  • You have installed Visual Studio 2015 Community or higher
  • You have downloaded and installed Bluetooth Developer Studio (you can download it here – you need to register to get download link, but it is free of charge)

The process of creating an application can be split into three sections:

  1. Creating a project and UI for Universal Windows Platform application
  2. Defining proper Device Profile inside Bluetooth Developer Studio and generating proper code – we will be working with this later on
  3. Putting generated code into our VS project and connecting it with the UI

But before we can start writing the app, you need to make sure that you have installed our Windows 10 UWP plugin and it is recognized by your Bluetooth Developer Studio instance. You can get the plugin from here. Put the directory with all the plugin’s files inside the Plugin subdirectory of your Bluetooth Developer Studio root installation folder. In my case I put the plugin here:

C:\Program Files (x86)\Bluetooth SIG\Bluetooth Developer Studio\Plugins\win10-bds-plugin

Now when you run Bluetooth Developer Studio it should find and make the plugin available to you. So let’s start the project.

Section 1

Create an “empty” project for our application, with the UI ready to be filled with proper data that comes from the Bluetooth Smart device.

We want a very simple UI, where we can connect to a device and then start or stop the receiving of actual heart rate data. To meet these requirements we prepare the application with a single Page, where we have:

  • TextBlock for displaying the status of the device (connected/disconnected)
  • TextBlock for displaying the current heart rate measurement (or “—“ if there is no data to display)
  • Three buttons:
    • One to start searching and connecting to the device
    • One to start getting notification from Heart Rate device
    • One to stop getting notifications

When the application is put into the background, or shutdown, the application will close all connection to the device.

  • Start Visual Studio 2015
  • Create new project: Visual C# – Windows – Universal – Blank App (Universal Windows)
  • Open package.appxmanifest to edit it, and select “Bluetooth” option on “Capabilities” tab.
  • Open MainPage.xaml file in design mode, and add all Controls we need. Your final XAML could look like below:

Notice that we have button-click handlers – make sure they are available in the C# source code (MainPage.xaml.cs)

1
2
3
4
5
6
7
8
9
10
11
12
13
public sealed partial class MainPage : Page
 {
 public MainPage()
 {
 this.InitializeComponent();
 }
private void BtnConnect_Click(object sender, RoutedEventArgs e)
 { }
private void BtnStart_Click(object sender, RoutedEventArgs e)
 { }
private void BtnStop_Click(object sender, RoutedEventArgs e)
 { }
 }

There will be also some actions which will have to be triggered for particular events.

When the device is found:

  • Add method: private async Task SearchAndConnect()

When the device is connected:

  • Add method: private void DeviceConnected()When the device connects, at this moment we can only enable Start/Stop buttons (for anything else we need to wait for wrappers around our device):
1
2
3
BtnStart.IsEnabled = true;
 
BtnStop.IsEnabled = true;

When the device is disconnected:

  • Add method: private void DeviceDisconnected()When the device is disconnected we should disable Start/Stop buttons and clear the current state of heart rate text as well as the status text:
1
2
3
4
BtnStart.IsEnabled = false;
BtnStop.IsEnabled = false;
TxtHrValue.Text = "--";
TxtStatus.Text = "disconnected";

When the new heart rate value is retrieved:

  • Add method: private void NewHeartRateMeasurement(short hrValue)
  • When the new value is retrieved, we just need to put it into the UI:
  • TxtHrValue.Text = String.Format(“{0} bpm”, hrValue)

When the application is going to be suspended/closed:

  • Add method: private async Task StopHearRateMonitoring()
  • When we want to disconnect from the device, we should remember to make sure that the notifications are not left enabled. So add one line here (later we will add more) and call DisableHeartRateNotifications()

When the user wants to start retrieving heart rate measurements:

  • Add method: private async Task EnableHeartRateNotifications()

When the user wants to stop getting heart rate notifications:

  • Add method: private async Task DisableHeartRateNotifications()
  • Inside that method we can already “reset” TxtHrValue field by:
  • TxtHrValue.Text = “—“;

As you may notice, some of the above methods are async – those will call Bluetooth functionality which requires to be called from async methods. During the implementation you will find out which methods need to be async and which don’t.
At this moment we cannot implement anything more inside those actions. Let’s go back to our button’s clicks handlers. We can run proper actions for every one of our three buttons:

  • BtnConnect -> call action SearchAndConnect()
  • BtnStart -> call action EnableHeartRateNotifications();
  • BtnStop -> call action DisableHeartRateNotifications();

The last thing we can do now, is to connect to app’s lifecycle and disconnect the device when the application is going into the background

  • In MainPage() constructor, after this.InitializeComponent(); add:
  • Application.Current.Suspending += CurrentOnSuspending;Visual Studio should give you a hint to create a new method for that also:
1
private void CurrentOnSuspending(object sender, SuspendingEventArgs e) {}
  • From that new method, trigger the action StopHearRateMonitoring()
  • As you will see, you should call that action with await keyword, and make our CurrentOnSuspending method asynchronous:
1
private async void CurrentOnSuspending(object s, SuspendingEventArgs e)

Now you have an application ready to be connected and to communicate with the Bluetooth Smart Heart Rate monitor. But instead of going into Windows 10 Bluetooth API we will use Bluetooth Developer Studio.

Section 2

Creating a device profile in Bluetooth Developer Studio and generating/exporting source code for it.

Open Bluetooth Developer Studio and Sign in to get all functionality of the tool. After that follow the steps below:

Start a new project with the name Heart Rate Monitor and your choice of namespace.
Click “New Profile” to edit the basic information about the device profile – the only thing we really want to change here is the name of the profile:

  • Click on “New Profile” text again and change it to “Heart Rate Monitor”.
  • Here you can also decide the device namespace – this value will be used in the generated code as a class’s namespace (with suffix: .ble.wrappers).

As the heart rate profile is an adopted one, we don’t need to create all this on our own. Instead, go into the search bar and enter “heart rate”.
Drag the found profile into your designer area. That will include all services adopted for the heart rate profile (Heart Rate and Device Information).

  • After dragging in the adopted profile, your profile’s name can be changed automatically – make sure that your profile name is what you want (in our case “Heart Rate Monitor”).

Switch to Services and now search for word “battery”.
Drag the found adopted service “Battery Service” to your designer.
Now you should have three services in your device profile. Each of those services has one or more characteristics.

Now you have finished defining the device. That was quick – wasn’t it? You can generate the code for your device. Select: Tools -> Generate Code or press Ctrl+G

  • Change Generate Code for: to Client mode.
  • Select Windows 10 UWP Client.
  • Select the output directory for the generated code – it could be inside your project’s root directory, inside HRMonitor subdirectory.

  • Click Generate.
  • You can get some more help from the last message in the output and you can check “Open output location when finished” before closing the dialog, to check manually what was generated.

  • You can save all your work in the Bluetooth Developer Studio and close it.

Go back to Visual Studio and move on to the next section.

Section 3

Using generated code inside the application.

Now you have an empty UI ready to be filled with data from a Bluetooth Smart device and code which will help you to talk with the device. So, we just need to make use of it and connect that to the UI. Let’s start.

You need to add generated files into your project, so Visual Studio can make use of it:

  • Open Explorer and find the folder where your code was generated.
  • Drag that folder into Visual Studio and into your project – this should include all the files, and keep them in a separate folder of your project, so they are not get mixed with your own code.

Go and read README.txt file inside that folder – it will give you a lot of information about the code you are going to use.
First what we need is a reference for our Bluetooth device:

  • Create a new private property HrMonitor and start typing its type with BleHeart… Visual Studio will give you a hint to use BleHearRateMonitor class name. Use that, and finish adding that property;

Now we can search for the new device inside SearchAndConnect() action.

  • Add there a line: HrMonitor = await BleHeartRateMonitor.FirstOrDefault();
  • If the above returned null it means, there is no device matching our profile – otherwise, we can start communicating with the found device.

After finding the device, we need be sure we are notified about the connection status. We can do that by adding a handler for DeviceConnectionStatusChanged event and connecting that to our device

1
2
3
4
5
6
7
8
9
10
11
12
13
private void HrMonitorOnDeviceConnectionStatusChanged(object sender, BleDeviceConnectionStatusChangedEventArgs arg)
{
bool connected = arg.ConnectionStatus ==
BluetoothConnectionStatus.Connected;
if (connected)
{
DeviceConnected();
}
else
{
DeviceDisconnected();
}
}

You can now start your application and check the result

Best case scenario – nothing has happened, worst case – your application crashed. Let’s fix that – there are a couple of things you need to remember when working with Bluetooth Smart on Windows 10.

Firstly, and this is very important, you need to have your device already paired with your smartphone/computer before your application can even see it. Go to the system setting for Bluetooth, enable it, and search for all nearby devices. After finding the device you are interested in tap/click to pair it with your machine. Only after that manual step (every user needs to run this on his own computer) your machine can then see your heart rate monitor from inside your application.

It is Heart Rate monitor specific, but be aware that your monitor could be “turned off” unless you have it on and it can read your heart rate. Otherwise it could be, again, invisible for other devices around (or always in a disconnected state). I am sorry… you have to put it on and try to keep your heart rate at peace.

When your application tries to connect to the device for the first time, you will get another confirmation window if you want to allow that application to use the device. Just click “Yes”.

Lastly, but also very important: most of the callbacks and events you will be getting from background threads, so you cannot call any UI code directly inside those handlers, just like in the previous step: calling DeviceConnected directly from DeviceConnectionStatusChanged event. To make this work you need to push that code into the UI thread. We will do that by adding a simple helper method to our MainPage class:

1
2
3
4
5
6
7
8
private async void RunOnUiThread(Action a)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
a();
});
}

Now we can call DeviceConnected/DeviceDisconnected methods by wrapping them with our RunOnUiThread method:

1
RunOnUiThread(DeviceConnected); and RunOnUiThread(DeviceDisconnected);

Now when you start your application, it should work fine, and you should see that Start/Stop button have been enabled after some time. Let’s update the status text as well to make the change more visible.

  • Go to the implementation of DeviceConnected method and update the status with the device name by adding one line at the end of the method
  • TxtStatus.Text = String.Format(“{0}: connected”, HrMonitor.Name);

Your application should now work properly, connect to the device, and be able to react for connection status changes. Now we need to get the heart rate measurements. We have two options here:

  • Enabling a notification for a particular characteristic and listen for new values – the value we will get in handlers are raw values used on the OS level of the Bluetooth API. You would need to parse those bytes on your own inside the handler.
  • You can make everything easier by using BleValueParsers. They are a helper class which makes it easier to work with particular characteristics. Generally every characteristic could have their own format and the method for parsing the value, so you would need to implement a proper parser for any characteristic you want to work with. Right now we are providing you with three examples, a parser for a Heart Rate Measurement characteristic, a String characteristic, and a Battery Level characteristic. You can go and check how they look. Every BleValueParser subclass is quite a simple type providing only two methods ParseReadValue and ParseWriteValue. You can only implement the one you really want. As you will see, our parser for heart rate doesn’t implement ParseWriteValue, as that characteristic doesn’t support writing at all.
  • We will add more parsers for the most widely used adopted characteristics in the future. Now we can focus on the heart rate and use that parser for our needs.

Add new property to your MainPage class to keep reference to the parser:

  • private HeartRateMeasurementParser HrParser { get; set; }

You should initialize that property after the device is found, and connect this parser with a proper characteristic:

1
2
3
HrParser = new HeartRateMeasurementParser();
 
HrParser.ConnectWithCharacteristic(HrMonitor.HeartRate.HeartRateMeasurement);

 

After the device is successfully connected, we need to add a handler for new values retrieved from the device. Inside DeviceConnected method, at the end add that line:
HrParser.ValueChanged += HrParserOnValueChanged;
Visual Studio will help you to add proper event handler. This will make your life easier if you use that help. Inside that handler, we just need to get the value from custom event args, and pass it to our action NewHeartRateMeasurement(), remembering to put that call inside our helper method RunOnUiThread:

1
2
3
4
private void HrParserOnValueChanged(object s, ValueChangedEventArgs<short> arg)
{
RunOnUiThread(() => { NewHeartRateMeasurement(arg.Value); });
}

What we have left, is to enable and disable the notification for our characteristic. Because we are using ValueParser, we are doing that via our HrParser property:

  • Enable: await HrParser.EnableNotifications();
  • Disable: await HrParser.DisableNotifications();

The above calls should be added to our actions EnableHeartRateNotifications() and DisableHeartRateNotifications().
Run your application and check that your heart is beating!