I'm using BluetoothLEAdvertisementWatcher
to find nearby BLE devices and it's working well. After finding them I want to connect and read/write data via GATT. But I can't figure out how to use the API after getting the BluetoothLEAdvertisement
(https://msdn.microsoft.com/de-de/library/windows/apps/windows.devices.bluetooth.genericattributeprofile).
public class Adapter
{
private readonly BluetoothLEAdvertisementWatcher _bleWatcher = new BluetoothLEAdvertisementWatcher();
public Adapter()
{
_bleWatcher.Received += BleWatcherOnReceived;
}
private void BleWatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
// how to connect?
// I know, it's the wrong place to to this, but this is just an example
}
public void StartScanningForDevices(Guid[] serviceUuids)
{
_blewatcher.advertisementfilter.advertisement.serviceuuids.clear();
foreach (var uuid in serviceuuids)
{
_blewatcher.advertisementfilter.advertisement.serviceuuids.add(uuid);
}
_blewatcher.start();
}
}
I've found Samples that are using DeviceInformation.FindAllAsync
instead of BluetoothLEAdvertisementWatcher
but these are not working / finding any device.
UPDATE
After digging around some time, I found the following way. But unfortunately, the pairing fails. The device is just an Arduino with a BLE shield. I can definitely connect with Android and iOS. So it must be possible with UWP somehow. :/
private void BleWatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
// dev.DeviceInformation.Pairing.CanPair is true
// dpr.Status is Failed
DevicePairingResult dpr = await dev.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
var service = await GattDeviceService.FromIdAsync(dev.DeviceInformation.Id);
}
UPDATE #2
I'm now able to discover and pair (unstable, but ok for now), but
var service = await GattDeviceService.FromIdAsync(args.Id);
throws the following Exception
System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
I have no clue why.
Basically you have the answer partly included in the questions. In essence you use the BluetoothLEAdvertisementWatcher for finding the devices only, basically they work just as beacons.
And you are not suppose to connect these devices by only using this API. To connect the devices you must use DeviceInformation.FindAllAsync(), and to get it to show you any devices, you do need to pair them first.
Anyway, if you are interested on getting data from some specific BLE characteristics, you could try using GattCharacteristicNotificationTrigger, for full example & a bit of additional explanations see my blog.
UPDATE (5/5/16): The "Element Not Found" error issue seems to only happen when the bluetooth settings screen isn't open/scanning. I don't remember that being the case before 10586.218 but I haven't checked. Obviously, not every issue is fixed in the update.
UPDATE (4/29/16): The 10586.218 windows update appears to have fixed the problem of pairing with a device that has never been paired to the machine (or phone) before. The process I've outlined here and Gerard Wilkinson's sample code in his answer should work more consistently now.
If you are lucky enough to get this to work, it requires waiting a considerable amount of time for the driver to install. I've done it by having both BluetoothLEAdvertisementWatcher and a DeviceWatcher running simultaneously.
Save the DeviceInformation from the BluetoothLEDevice that you get from FromBluetoothAddressAsync() then Dispose() the BluetoothLEDevice before initiating pairing. This is important. If you don't, it won't see the Gatt Services after pairing.
Then wait for the DeviceWatcher to see the paired device. It can take minutes but you'll usually get it before the progress bar for device installation (in the Bluetooth control panel) gets to 100%. If FromIdAsync still fails, it usually means there was a driver installation error. You can unpair and then do the pairing process over again. That usually works for me.
It's very unstable, though, and it seems to be dependent on which Bluetooth chipset and driver the machine has. I often get an Element Not Found error with FromBluetoothAddress but if it gets past there, pairing usually works on the first or second try.
PairAsync and UnpairAsync also need to be posted to the UI thread. If it isn't able to pop up a blue dialog asking for authorization, you'll get exceptions. You can use Post() from a saved UI SynchronizationContext or Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync() with an async delegate to do this.
I've seen multiple posts from MS employees on the forums saying FromBluetoothAddressAsync() only works for paired devices. This isn't the case but it is buggy and seems to work best if the device has been paired manually at least once in the past.
Gerard Wilkinson's answer is correct. To make life easier, I turned it into an awaitable method using Reactive Extensions (). Any comments are welcome.
So once you found the device using the BluetoothLEAdvertisementWatcher and paired with it, you can use this to enable GATTServices.
UPDATE 04/17 - CREATORS UPDATE
Microsoft have just updated their Bluetooth APIs. We now have unpaired BLE device communication!
They have very little documentation up at the moment but here is the much simplified new structure:
Much better now. As I said there is next to no documentation at the moment, I have a weird issue where my ValueChanged callback stops being called after 30 seconds or so, though that seems to be a separate scoping issue.
UPDATE 2 - SOME WEIRDNESS
After some more playing around with the new creators update there are a few more things to consider when building BLE apps.
ValueChanged
on thecharac
you may hit this issue. This is because theGattCharacteristic
is disposed of before it should be, set the characteristic as a global rather than relying on it being copied in.App.xml.cs
OnSuspended
callback to terminate your connections. Otherwise you get in a bit of a weird state where Windows seems to maintain (and keep reading!!) the BLE connection.Well it has its quirks but it works!
OLD ANSWER
Following on from Jason's correct answer about devices needing to be paired to have their services be discovered, here is some sample code to address this:
The key things to note here are: