UWP BLE device pairing

2020-08-01 08:35发布

问题:

I initiate pairing procedure of ble device via:

DevicePairingResult dpr = await deviceInfo.Pairing.PairAsync()

PairAsync returns in a few moments but after that Windows still installs the paired device. The install procedure completes in approx 3 seconds on my computer. After that the BLE device is ready to be used.

My question is how to catch the event when the paired BLE device is ready to use after pairing?

回答1:

As far as I know, after a sucessfull pairing, you have to monitor the Device add with the DeviceWatcher class. This class has an Add event you can consume to know when a paired device is ready to use.

Here a demo console app which monitor and pair an HeartRate sensor.

It works using Windows SDK 10. To create a desktop app which use WinRT you need to manually add Windows.winmd and System.Runtime.WindowsRuntime.dll refeence.

You can use this same code in a UWP app.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Windows.System;
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration.Pnp;
using Windows.Foundation;
using Windows.Storage.Streams;

namespace ConsoleApplication1
{
    class Program
    {
        BluetoothLEAdvertisementWatcher _advWatcher;

        private DeviceWatcher _deviceWatcher;

        private string _deviceId;
        private GattDeviceService _service;
        private GattCharacteristic _char;


        public void Run()
        {
            int devicesFound = 0;

            _advWatcher = new BluetoothLEAdvertisementWatcher();
            _advWatcher.ScanningMode = BluetoothLEScanningMode.Active;
            _advWatcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
            _advWatcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
            _advWatcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
            _advWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);

            _advWatcher.Received +=
                async (s, e) =>
                {
                    // Tell the user we see an advertisement and print some properties
                    Console.WriteLine();
                    Console.WriteLine(String.Format("Advertisement:"));
                    Console.WriteLine(String.Format("  BT_ADDR: {0}", e.BluetoothAddress));
                    Console.WriteLine(String.Format("  FR_NAME: {0}", e.Advertisement.LocalName));
                    Console.WriteLine();

                    Console.WriteLine("ADV Discovered: " + (!String.IsNullOrWhiteSpace(e.Advertisement.LocalName) ? e.Advertisement.LocalName : "Unknown"));
                    if (e.Advertisement.LocalName != "OrseBT")
                        return;

                    _advWatcher.Stop();

                    Console.WriteLine("ADV Pairing...");
                    var device = await BluetoothLEDevice.FromBluetoothAddressAsync(e.BluetoothAddress);
                    device.DeviceInformation.Pairing.Custom.PairingRequested +=
                        (ss, ev) =>
                        {
                            ev.Accept();
                        };

                    var result = await device.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.ConfirmOnly);
                    Console.WriteLine($"Pairing Result: {result.Status}");
                    Console.WriteLine($"Connected Data: {device.GattServices.Count}");

                    if (result.Status == DevicePairingResultStatus.Failed)
                        _advWatcher.Start();                    

                    if (result.Status == DevicePairingResultStatus.AlreadyPaired)
                        await ConfigureSensorService(device.DeviceId);              
                };

            _deviceWatcher = DeviceInformation.CreateWatcher(
                GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.CyclingSpeedAndCadence)/*, new[] { "System.Devices.ContainerId" }*/);

            _deviceWatcher.Added +=
                async (s, e) =>
                {
                    devicesFound++;
                    var di = e as DeviceInformation;
                    Console.WriteLine("Device Discovered: (" + di.Name + ")" + Environment.NewLine + di.Id);

                    await ConfigureSensorService(di.Id);
                };

            _deviceWatcher.Updated +=
                async (s, e) =>
                {
                    var di = e as DeviceInformationUpdate;
                    Console.WriteLine("Device Updated: " + e.Id);                   

                    await ConfigureSensorService(di.Id);
                };

            _deviceWatcher.Removed +=
                async (s, e) =>
                {
                    Console.WriteLine("Device Removed: " + e.Id);
                    await Task.Delay(1);

                    if (_advWatcher.Status == BluetoothLEAdvertisementWatcherStatus.Stopped)
                        _advWatcher.Start();
                };

            _deviceWatcher.Stopped +=
                async (s, e) =>
                {
                    Console.WriteLine("Device Watcher stopped!");
                    await Task.Delay(1);
                };

            _deviceWatcher.EnumerationCompleted +=
                async (s, e) =>
                {
                    //Console.WriteLine("{0} devices found!", devicesFound);
                    await Task.Delay(1);
                };

            _advWatcher.Start();
            _deviceWatcher.Start();
            Console.WriteLine("Device Watcher started!");
        }

        private async Task ConfigureSensorService(string deviceId)
        {
            try
            {
                if(_deviceId != deviceId
                    && _service != null)
                {
                    _service.Dispose();
                    _service = null;
                }

                _deviceId = deviceId;
                _service = await GattDeviceService.FromIdAsync(deviceId);
                if (_service != null)
                {
                    _char = _service
                        .GetCharacteristics(GattCharacteristicUuids.CscMeasurement)
                        .FirstOrDefault();

                    if (_char != null)
                    {
                        _char.ValueChanged +=
                            (s, e) =>
                            {
                                try
                                {
                                    var data = new byte[e.CharacteristicValue.Length];
                                    DataReader.FromBuffer(e.CharacteristicValue).ReadBytes(data);

                                    Console.WriteLine("Data Received from the sensor!");
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine("Error: " + ex.ToString());
                                }
                            };

                        var cc = await _char.ReadClientCharacteristicConfigurationDescriptorAsync();
                        var st = await _char.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.ToString());
            }
        }

        public void ReleaseAll()
        {
            if (_deviceWatcher != null)
                _deviceWatcher.Stop();

            if (_service != null)
                _service.Dispose();
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.Run();

            Console.ReadKey();

            p.ReleaseAll();
        }
    }