Integrate Microsoft Band features into a Windows Store App

Introduction

Fitness Bands are one of the big things in technology at the moment, new ones appear to be being released all the time each claiming new or improved features. When Microsoft released the band they also released an impressive SDK to allow developers to integrate the Band with apps across all of the major mobile platforms.

In this post I want to take you through some of the features I have added to an app that I released on the Windows Phone. Hopefully these examples will help others who want to create apps for the band and maybe provide some ideas for devs who haven’t thought about it yet.

BeepFitBand2
The completed app running on a device

The App

Rather than a hello world type app I am going to use code from an app called BeepFit. This app allows users to run a multi-staged fitness test (otherwise known as a beep or bleep test) and to store and share their results. It also uses the Microsoft Band to send notifications to users so they don’t need to worry about listening out for alerts. Additionally at the completion of each level of the test it takes various sensor readings to add to the results. If you are interested you can get the completed app for Windows Phone from the store here.

The User Interface

I have already updated the UI to have a menu for selecting the type of device to connect to. This is to enable future updates to include other fitness devices if I choose. In our tutorial we are going to start the connection process via a command linked to this menu item.

DeviceSelection

 

Connecting to the Band

Our first step is to connect to the band itself. The code example below shows that we use the BandClientManager to get an array of IBandInfo. This array then gives us the available bands, to simplify our code we only allow a connection if a single band is connected. We then use the BandClientManager again to connect to the device by sending the object we obtained from our GetBandsAsync call.

With the connection established, we check if a Tile is available and if not call a method to create the tile (this is covered in the next paragraph) and finally we use our bandClient object that we connected too and use the NotificationManager to send a vibration alert. We will see the NotificationManager again later in this tutorial, but for simple vibrations all we need to do is call the VibrateAsync method with a suitable value from the VibrationType enum. For our project we are going to use VibrationType.ThreeToneHigh to let the user know that the app is connected to the band.

private async void ConnectToBand()
{
    if (testRunning)
        return;

    IBandInfo[] bands = 
        await BandClientManager.Instance.GetBandsAsync();
    if (bands.Length != 1)
    {
        DeviceState = "Unable to connect to device";
    }
    else
    {
        BandName = bands[0].Name;
        bandInfo = bands[0];
        bandClient = 
            await BandClientManager.Instance.ConnectAsync(bandInfo);
        IsBandConnected = true;
        if (!IsTileCreated)
        {
            this.CreateTile();
            IsTileCreated = true;
            this.ConnectToBand();
        }
        else
        {
            await bandClient.NotificationManager.VibrateAsync
                (VibrationType.ThreeToneHigh);
            DeviceState = string.Format("Connected to Microsoft Band");
        }
    }
}

Installing a tile

In the previous section we connected to the band and as part of that task we called the our CreateTile method which is detailed below. This method gets the installed tiles as an IEnumerable by using the GetTilesAsync method of the TileManager. We also need to check that there is capacity on the band to add another tile. After this check is carried out we create the icon for the then use this to create the new BandTile item. Key things to note when creating the tile is that it must have a unique reference (we use a constant that is a string of a GUID) and to determine if IsBadgingEnabled should be set to true. If set to true, the tile will show the number of unread notifications for the tile.

private async void CreateTile()
{
    IEnumerable tiles = await bandClient.TileManager.GetTilesAsync();
    int capacity = 
        await bandClient.TileManager.GetRemainingTileCapacityAsync();
    if (capacity >= 1)
    {
        WriteableBitmap iconBitmap = await this.GetBitmapFromFile(
            "ms-appx:///Images/BandLogoWhite.png");
        BandIcon tileIcon = iconBitmap.ToBandIcon();
        WriteableBitmap smallIconBitmap = await this.GetBitmapFromFile
            ("ms-appx:///Images/BandLogoSmallWhite.png");
        BandIcon smallTileIcon = smallIconBitmap.ToBandIcon();
        tileGuid = Guid.Parse(AppConstants.BandTileGuid);
        BandTile tile = new BandTile(tileGuid)
        {
            IsBadgingEnabled = true,
            Name = "Beep Fit",
            TileIcon = tileIcon,
            SmallIcon = smallTileIcon
        };
        await bandClient.TileManager.AddTileAsync(tile);
    }
}

The following is a helper method used in our CreateTile method for getting a bitmap from a file Uri.

private async Task GetBitmapFromFile(string uri)
{
    var file = 
        await StorageFile.GetFileFromApplicationUriAsync(new Uri(uri));
    using (var fileStream = await file.OpenAsync(FileAccessMode.Read))
    {
        var bitmap = new WriteableBitmap(1, 1);
        await bitmap.SetSourceAsync(fileStream);
        return bitmap;
    }
}

Sending Alerts to the Band

Sending alerts to the band during a test is done in the same way as when we made our initial connection earlier on. As we want to provide users a notification on each lap (in lieu of the audio) we send a single OneToneHigh vibration. We also send a dialog to show the current lap and level, along with the interval time that the user would be aiming for.

private async void LapBeep()
{
    if (IsBandConnected)
    {
        await bandClient.NotificationManager.VibrateAsync
            (VibrationType.OneToneHigh);
        await bandClient.NotificationManager.ShowDialogAsync(tileGuid,
            string.Format("Level: {0} Lap: {1}/{2}", CurrentLevel,
            CurrentLap, Laps), string.Format("Lap Time: {0}", PerLap));
    }
    individualTestView.PlaySound();
}

Getting sensor data from the Band

We get sensor data by listening for changes to the readings. Each sensor has a set of supported reporting intervals that can be used. As we need to get the reading closest to the lap/level beep of our test, we are going to get the first interval available as this will give us the most regular updates. In the code below we setup to get the readings for both the HeartRate and SkinTemperature sensors. These are the only ones relevant to our tests, but the principle is the same if you want to get the readings from other sensors.

var x = bandClient.SensorManager.HeartRate.SupportedReportingIntervals;
bandClient.SensorManager.HeartRate.ReportingInterval = 
    x.FirstOrDefault();
bandClient.SensorManager.HeartRate.ReadingChanged += 
    HeartRate_ReadingChanged;
await bandClient.SensorManager.HeartRate.StartReadingsAsync();
var y =
  bandClient.SensorManager.SkinTemperature.SupportedReportingIntervals;
bandClient.SensorManager.SkinTemperature.ReportingInterval =
    y.FirstOrDefault();
bandClient.SensorManager.SkinTemperature.ReadingChanged += 
    SkinTemperature_ReadingChanged;
await bandClient.SensorManager.SkinTemperature.StartReadingsAsync();

When the SkinTemperature calls its ReadingChanged event we want to store the temperature value from the sensor. We are doing it this way for our app as the timings that we need the sensor data from will be continually changing based on the current level of the test. We then do the same again but for the HeartRate sensor.

void SkinTemperature_ReadingChanged(object sender, 
    Microsoft.Band.Sensors.BandSensorReadingEventArgs e)
{
    lastTempReading = e.SensorReading.Temperature;
}

void HeartRate_ReadingChanged(object sender, 
    Microsoft.Band.Sensors.BandSensorReadingEventArgs e)
{
    lastReading = e.SensorReading.HeartRate;
}

When our test reaches a new level we take the latest sensor readings and add them to the overall test data and display a notification to the user that they are on a new level. As the standard beep test would have a triple beep to indicate this, we use the ThreeToneHigh vibration alert.

private async void LevelBeep(int levelNumber)
{
    if (IsBandConnected)
    {
        if (levelHeartRates == null)
            levelHeartRates = new Dictionary<int, int>();
        levelHeartRates.Add(levelNumber, lastReading);
        if (levelTempReadings == null)
            levelTempReadings = new Dictionary<int, double>();
        levelTempReadings.Add(levelNumber, lastTempReading);
        await bandClient.NotificationManager.VibrateAsync
           (VibrationType.ThreeToneHigh);
        await bandClient.NotificationManager.ShowDialogAsync(tileGuid,
            string.Format("Level: {0} Lap: {1}/{2}", CurrentLevel, 
            CurrentLap, Laps), string.Format("Lap Time: {0}", PerLap));
        }
        individualTestView.PlayTripple();
    }

Ending a test

Our test is ended via a command on the Windows Phone. When this is called a number of actions are carried out:

  1. A message is sent to the band to notify the test is completed.
  2. The sensor manger is told to stop taking readings for HeartRate and SkinTemperature.
  3. The application navigates to a results page.

The difference between the SendMessageAsync method used here and the SendDialogAsync message we have been using in other parts of the app, is that this message will remain on the band and can be viewed by tapping the tile at a later date. The provides the user with an easy way to see recent test results.

private async void StopTestCommandHandler(IUICommand command)
{
  if (command.Label.Equals("Yes"))
  {
      testRunning = false;
      beepTest.Lap -= bt_Lap;
      totalTimer.Tick -= dispatcherTimer_Tick;
      beepTest.StopTest();
      StartStopBtnText = "Start";
      displayRequest.RequestRelease();
      if (IsBandConnected)
      {
          await bandClient.NotificationManager.SendMessageAsync(
              tileGuid, "Test Completed", string.Format("You reached
              level {0}.{1}", CurrentLevel, CurrentLap),
              DateTimeOffset.Now, MessageFlags.ShowDialog);
          await
              bandClient.SensorManager.HeartRate.StopReadingsAsync();
          await 
          bandClient.SensorManager.SkinTemperature.StopReadingsAsync();
            //Navigate to results frame
        }
        else
        {
            //Navigate to results frame.
        }
    }
}

After the test has ended we would navigate to a page with to display the results (this has been omitted from the example above). In the case of our app, the results page shows a graph with the collected results if a band was used during the test.

wp_ss_20151007_0001

 

Conclusion

I have tried to cover a lot in this blog post. What I hope to get across is that it is quite simple to add functionality to connect your Windows Store apps to a Microsoft Band. The official developer site at developer.microsoftband.com has up to date documentation for the SDK and includes examples for integrating with Android and iOS.