I am sorry that it took me a while to get the second part ready, but better late than ever.
This second part will be actually about discovering services and characteristics using the new API's available in Windows Phone 8.1 release. As you probably remember this was not possible using the Windows 8.1 BLE API as it is not directly exposed for the store applications. The good news is that things started to move in the right direction with Windows Phone 8.1: possibility to query the services and the characteristics available in a device, support for background tasks and triggers for Bluetooth events, possibility to open the Bluetooth pairing window from inside of our applications (this feature was already available in Windows Phone 8.0 and, luckily, it is still there in 8.1) . There are still some missing features like:
- no support real beacon scenario as the user have to manually pair the BLE device before it is accessible to the application
- no support for server mode. Windows Phone 8.1 supports only client mode
Hopefully we will see better API in the next release of Windows and at some point the two API's will aliogn. In this moment Windows Phone has better support for BLE devices than it's bigger brother.
To better illustrate the new API I have created and published an Windows Phone XAML application that is already available in the Store and I've uploaded the source code on Github.
In order to be able to develop/test for BLE devices you will need and LE device (see the devices from my previous post and since then my collection just got bigger as I've got an Polar H7 heart rate monitor, and the Nokia Treasure Tag) and you will need an Windows Phone 8.1 device that supports the new LE stack. Regarding the device there are good news and a bad news. The good news is that all the Windows Phone 8 devices have hardware that support LE and will support the feature once they will receive the official update. The bad news is that with the Developer Preview this feature is not supported (on the Nokia devices there is an stack conflict between the GDR3 Nokia LE driver and the Microsoft one, Samsung Ativ S it needs a firmware upgrade, and maybe, from what I've heard, it works on the HTC 8x devices but I don't have one and I cannot confirm). So if you have an Windows Phone 8 device you will need to wait for the official release. On the other hand if you have a new Windows Phone 8.1 device like the Lumia 930 or 630 these feature is already supported along with all the other cool features available in the new release . The Lumia 630 and 930 are awesome as they have support for Nokia Sensor Core a technology similar to the one present in the iPhone 5S. The easiest way to see if your device supports LE is to buy an LE device, open the system Bluetooth pairing window and see if you are able to see the device in the list of devices you can pair with.
In this post I will use the Nokia Treasure Tag. Our goal is to find out as much as we can about the services and characteristics exposed by this device. We will use the new Windows Phone XAML projects available in Visual Studio 2013 Update 2.
Just like Windows 8 in order to be able to list LE devices from inside of our application we will have to specify in the Package.appxmanifest the type of Device we would like to connect to. As we don't know the services a priory we would choose the a generic service that is implemented in most of the devices and, from my tests, I think Generic Access is a good choice. The lines we will have to manually add inside the Package.appxmanifest are:
<Capabilities>
<Capability Name="internetClientServer" />
<m2:DeviceCapability Name="bluetooth.genericAttributeProfile">
<m2:Device Id="any">
<m2:Function Type="name:genericAccess" />
</m2:Device>
</m2:DeviceCapability>
</Capabilities>
Then just like in Windows 8.1 we can enumerate the paired devices using DeviceInformation.FindAllAsync and use the predefined GenericAccess UUID:
bleDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.GenericAccess));
The output of this method is a DeviceInformationCollection of paired devices that expose the Generic Access service.
If no devices were found that exposes this service it means that no device was paired with our phone or the Bluetooth is disabled on the device. In this case we can easily open the Bluetooth settings window:
Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-bluetooth:", UriKind.RelativeOrAbsolute));
Once we have the devices we can select one of them and create a new instance of the newly added class in Windows Phone 8.1 SDK BluetoothLEDevice. This class can be usedto enumerate all the services available on the device. If you look at the description of the class you will see that it is only supported on Windows Phone (no support for Windows Store applications). We will use the Id property available inside the DeviceInformation to instantiate the class. BluetoothLEDevice _device = await BluetoothLEDevice.FromIdAsync(((DeviceInformation)e.Parameter).Id);
The BluetoothLEDevice exposes a property called GatServices of type IReadOnlyList<GattDeviceService> that will give us the list of all the services available on the device. GetDeviceService is a class that is already implemented in Windows 8.1 but it was extended on Windows Phone 8.1. To get a friendly name of the device service (not only the Guid) you could use reflection, but I have created a helper class BLEHelper.cs (see the github project) that can be easily extended to cover more known services. Remember that all the LE services that have an id that start
with 000018 and end with -0000-1000-8000-00805f9b34fb are probably standard LE services and you can find further details about them here.Once we've identified the service we are interested in (we have an instance of the class) we will use the newly added method GetAllCharacteristics() (another method available only for Windows Phone) to get the list of all the characteristics the services exposes and for each characteristic we can get its properties, values, type,....
Each characteristic have an unique id and, int his case, for mapping the Guid to a known name on the UI I have created a simple converter that uses reflection to search and map the Guid to a GattCharacteristicUuids name:
public class CharacteristicName : DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value != null && (value.GetType() == typeof(GattCharacteristic)))
{
var c = (GattCharacteristic)value;
if (c.UserDescription != "")
return c.UserDescription;
foreach (var prop in typeof(GattCharacteristicUuids).GetRuntimeProperties())
{
object v = prop.GetValue(null);
if (v != null && v.GetType() == typeof(Guid) && ((Guid)v) == c.Uuid)
return prop.Name;
}
}
return "Unknown";
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
If you download the BLEExplorer app you can also use share to export all the data (services+characteristics) to any application that support text sharing (like email).
In the next post I will explain how to create background tasks that subscribe notifications from an BLE device, manage connection lost and reconnect in the backgroun.
P.S. If you have questions please do contact me by email and I will be glad to help. I have disabled the comments on the blog because there was a huge amount of Spam.
NAMASTE!