Categories
Bluetooth

12 Days of Bluetooth – #8 Bluetooth Low Energy in Code

Following on from the last post, which covered the technology of Bluetooth Low Energy, this post will look at how to use it from code using InTheHand.BluetoothLE. We’re going to look at an example using a simple but widely used service – Battery Service. You can probably guess what it is used for.

Step One – Get your device

In the Web Bluetooth world, you must ask the user to select a device using a picker, you can provide a filter to be specific about what type of devices to present to the user. Another restriction with Web Bluetooth is that you can only connect to services which you have specified during this picking process. 32feet.NET’s implementation eases this restriction by allowing you to connect to any service and also by accessing your device either by a programmatic discovery (so you can build your own custom UI), or by using an identifier you have stored from a previous session.

For the purpose of this example I’ll show you the simplest approach using the picker.

Debug.WriteLine("Requesting Bluetooth Device...");
var device = await Bluetooth.RequestDeviceAsync(new RequestDeviceOptions { AcceptAllDevices = true });

RequestDeviceAsync will return once the user has picked a device, or if they cancel the dialog. Therefore it’s important to check if the return value is null before proceeding. RequestDeviceOptions is a class which provides filters and options to the process, but you can set AcceptAllDevices to true which takes precedence over all other options. The method returns an instance of BluetoothDevice which exposes a unique id (platform specific) and a display name. It also has the ability to connect with the GATT server on the remote device to begin working with services.

Step 2 – Connect to a Service

var gatt = device.Gatt;
Debug.WriteLine("Connecting to GATT Server...");
await gatt.ConnectAsync();

Once you have connected you can either request all of the services from the remote device, or select a specific service from its UUID. In this case we use the UUID of the Battery Service.

Debug.WriteLine("Getting Battery Service");
var service = await gatt.GetPrimaryServiceAsync(GattServiceUuids.Battery);

Again you need to check if the service returned is null, as the device may not support the requested service. Once we have the service we can then proceed to get the characteristic. You may remember these levels from the “tree” diagram in the previous post.

Step 3 – Characteristics

Debug.WriteLine("Getting Battery Level Characteristic...");
var characteristic = await service.GetCharacteristicAsync(BluetoothUuid.GetCharacteristic("battery_level"));

You’ll see in this snippet I’ve shown an alternative way of specifying the UUID for the characteristic. All of the assigned service, characteristic and descriptor ids have a name too, and the BluetoothUuid class can look these up – so you have a choice of passing one of the predefined constants (like GattCharacteristicUuids.BatteryLevel) or the text version – either “battery_level” or, more formally, “org.bluetooth.characteristic.battery_level”.

Debug.WriteLine("Reading Battery Level...");
var value = await characteristic.ReadValueAsync();

Debug.WriteLine($"Battery Level is {value[0]} %");

Reading the value is quite straightforward. The data is returned as a byte array and the length will depending on the specific characteristic. In the case of battery level it is stored as a percentage value (0-100) in a single byte so we can just read the first element from the array.

The battery level, unsurprisingly, doesn’t allow the value to be written to, but you can determine the capabilities of any characteristic using it’s Properties property which is a flagged enumeration. Some capabilities of specific characteristics have optional elements so you can’t assume that all devices will behave exactly the same – you need to read the Properties, and you can also read through the relevant Bluetooth specs to find out more. For example the iPhone I’m running this sample against reports Read and Notify flags in the Properties.

Step 4 – Get Notified

Notify and Indicate are two special flags which support change notifications, one of the reasons why Bluetooth Low Energy is more efficient than opening a connection and polling for particular values. From a developers perspective they are much the same, the difference under the hood is that Indicate requires a response from the subscribing device (but this is something which is hidden from you in the API).

To support notifications there is a special Descriptor value on the Characteristic which is called ClientCharacteristicConfiguration. This must be written to with a value to indicate whether to use Notify, Indicate or None for no notifications. You also need to subscribe to the CharacteristicValueChanged event. However in both Web Bluetooth and 32feet.NET this is handled for you using StartNotificationsAsync and StopNotificationsAsync so you don’t need to worry about which underlying method is used.

characteristic.CharacteristicValueChanged += Characteristic_CharacteristicValueChanged;
await characteristic.StartNotificationsAsync();

...

private void Characteristic_CharacteristicValueChanged(object sender, GattCharacteristicValueChangedEventArgs e)
{
    Debug.WriteLine($"Battery Level has changed to {e.Value[0]} %");
}

Of course you can enumerate the Descriptors or retrieve a specific one via UUID if available. There are standard Bluetooth ones defined for ranges, units and formatting of the characteristic value.

By Peter Foot

Microsoft Windows Development MVP