Windows UWP在发现后连接到BLE设备

Sve*_*übe 19 c# bluetooth-lowenergy gatt win-universal-app windows-10-universal

我正在BluetoothLEAdvertisementWatcher寻找附近的BLE设备并且它运行良好.找到它们后,我想通过GATT连接和读/写数据.但是在获得BluetoothLEAdvertisement(https://msdn.microsoft.com/de-de/library/windows/apps/windows.devices.bluetooth.genericattributeprofile)后我无法弄清楚如何使用API .

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现使用的样品DeviceInformation.FindAllAsync代替BluetoothLEAdvertisementWatcher但是这些样品不起作用/找不到任何设备.

UPDATE

经过一段时间的挖掘,我找到了以下方法.但不幸的是,配对失败了.该设备只是一个带有BLE屏蔽的Arduino.我绝对可以与Android和iOS连接.因此必须以某种方式与UWP合作.:/

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);
}
Run Code Online (Sandbox Code Playgroud)

更新#2

我现在能够发现并配对(不稳定,但现在还可以),但是

var service = await GattDeviceService.FromIdAsync(args.Id);
Run Code Online (Sandbox Code Playgroud)

抛出以下异常

System.IO.FileNotFoundException:系统找不到指定的文件.(HRESULT异常:0x80070002)

我不知道为什么.

Ger*_*son 17

更新04/17 - 创建者更新

微软刚刚更新了他们的蓝牙API.我们现在有未配对的BLE设备通讯!

他们目前只有很少的文档,但这是一个简化的新结构:

BleWatcher = new BluetoothLEAdvertisementWatcher 
{ 
    ScanningMode = BluetoothLEScanningMode.Active
};
BleWatcher.Start();

BleWatcher.Received += async (w, btAdv) => {
    var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
    Debug.WriteLine($"BLEWATCHER Found: {device.name}");

    // SERVICES!!
    var gatt = await device.GetGattServicesAsync();
    Debug.WriteLine($"{device.Name} Services: {gatt.Services.Count}, {gatt.Status}, {gatt.ProtocolError}");

    // CHARACTERISTICS!!
    var characs = await gatt.Services.Single(s => s.Uuid == SAMPLESERVICEUUID).GetCharacteristicsAsync();
    var charac = characs.Single(c => c.Uuid == SAMPLECHARACUUID);
    await charac.WriteValueAsync(SOMEDATA);
};
Run Code Online (Sandbox Code Playgroud)

现在好多了.正如我所说,目前没有文档,我有一个奇怪的问题,我的ValueChanged回调在30秒左右后停止被调用,尽管这似乎是一个单独的范围问题.

更新2 - 一些不确定性

在更多关于新创建者更新的内容之后,在构建BLE应用程序时还需要考虑更多的事情.

  • 您不再需要在UI线程上运行蓝牙功能.如果没有配对,BLE似乎没有任何权限窗口,因此不再需要在UI线程上运行.
  • 您可能会发现应用程序在一段时间后停止从设备接收更新.这是一个范围问题,其中对象被处理,不应该.在上面,如果您正在收听的代码ValueChangedcharac你可能会碰到这个问题.这是因为GattCharacteristic在它应该被处置之前,将特征设置为全局而不是依赖于它被复制.
  • 断开连接似乎有点破碎.退出应用程序不会终止连接.因此,请确保使用App.xml.cs OnSuspended回调来终止连接.否则你会进入一个奇怪的状态,Windows似乎维护(并继续阅读!!)BLE连接.

它有它的怪癖,但它的工作原理!

老答复

继Jason关于需要配对以便发现其服务的设备的正确答案之后,这里有一些示例代码来解决这个问题:

    private void SetupBluetooth()
    {
        Watcher = new BluetoothLEAdvertisementWatcher { ScanningMode = BluetoothLEScanningMode.Active };
        Watcher.Received += DeviceFound;

        DeviceWatcher = DeviceInformation.CreateWatcher();
        DeviceWatcher.Added += DeviceAdded;
        DeviceWatcher.Updated += DeviceUpdated;

        StartScanning();
    }

    private void StartScanning()
    {
        Watcher.Start();
        DeviceWatcher.Start();
    }

    private void StopScanning()
    {
        Watcher.Stop();
        DeviceWatcher.Stop();
    }

    private async void DeviceFound(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs btAdv)
    {
        if (_devices.Contains(btAdv.Advertisement.LocalName))
        {
            await Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
            {
                Debug.WriteLine($"---------------------- {btAdv.Advertisement.LocalName} ----------------------");
                Debug.WriteLine($"Advertisement Data: {btAdv.Advertisement.ServiceUuids.Count}");
                var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
                var result = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
                Debug.WriteLine($"Pairing Result: {result.Status}");
                Debug.WriteLine($"Connected Data: {device.GattServices.Count}");
            });
        }
    }

    private async void DeviceAdded(DeviceWatcher watcher, DeviceInformation device)
    {
        if (_devices.Contains(device.Name))
        {
            try
            {
                var service = await GattDeviceService.FromIdAsync(device.Id);
                Debug.WriteLine("Opened Service!!");
            }
            catch
            {
                Debug.WriteLine("Failed to open service.");
            }
        }
    }

    private void DeviceUpdated(DeviceWatcher watcher, DeviceInformationUpdate update)
    {
        Debug.WriteLine($"Device updated: {update.Id}");
    }
Run Code Online (Sandbox Code Playgroud)

这里要注意的关键事项是:

  • DeviceWatcher需要添加和更新属性设置才能工作.
  • 您需要捕获尝试询问未配对或尚未准备好的服务时发生的异常FileNotFound.


Jas*_*ary 5

更新(5/5/16):"未找到元素"错误问题似乎只发生在蓝牙设置屏幕未打开/扫描时.我不记得10586.218之前的情况,但我没有检查过.显然,并非每个问题都在更新中得到修复.

更新(2016年4月29日):10586.218 Windows更新似乎修复了与之前从未与机器(或电话)配对的设备配对的问题.我在这里概述的过程和Gerard Wilkinson在他的回答中的示例代码现在应该更加一致.

如果您足够幸运能够使用它,则需要等待相当长的时间才能安装驱动程序.我通过同时运行BluetoothLEAdvertisementWatcher和DeviceWatcher来完成它.

从您从BlueBluetoothAddressAsync()获取的BluetoothLEDevice中保存DeviceInformation,然后在启动配对之前Dispose()BluetoothLEDevice.这个很重要.如果不这样做,配对后就不会看到Gatt服务.

然后等待DeviceWatcher查看配对设备.它可能需要几分钟,但您通常会在设备安装(在蓝牙控制面板中)的进度条达到100%之前得到它.如果FromIdAsync仍然失败,通常意味着存在驱动程序安装错误.您可以取消配对,然后重新进行配对过程.这通常对我有用.

但它非常不稳定,而且似乎取决于机器所具有的蓝牙芯片组和驱动程序.我经常使用FromBluetoothAddress获得Element Not Found错误,但如果它通过那里,配对通常适用于第一次或第二次尝试.

PairAsync和UnpairAsync也需要发布到UI线程.如果无法弹出要求授权的蓝色对话框,您将获得例外.您可以使用已保存的UI SynchronizationContext中的Post()或带有异步委托的Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync()来执行此操作.

我在论坛上看过来自MS员工的多篇帖子说FromBluetoothAddressAsync()仅适用于配对设备.情况并非如此,但如果设备已经过去至少手动配对一次,那么它似乎也是最好的.