首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >发现后Windows UWP连接到BLE设备

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

Stack Overflow用户
提问于 2016-02-15 23:21:49
回答 4查看 33.2K关注 0票数 21

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

代码语言:javascript
运行
复制
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();
    }
}

我已经找到了使用DeviceInformation.FindAllAsync而不是BluetoothLEAdvertisementWatcher的示例,但是这些都不能工作/找到任何设备。

更新

在挖了一段时间之后,我发现了下面的方法。但不幸的是,配对失败了。这个装置只是一个带有BLE护盾的Arduino。我绝对可以连接到安卓和iOS。所以用UWP一定是有可能的。:/

代码语言:javascript
运行
复制
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);
}

更新#2

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

代码语言:javascript
运行
复制
var service = await GattDeviceService.FromIdAsync(args.Id);

引发以下异常

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

我不知道为什么。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-03-19 19:26:49

更新04/17 -创建者更新

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

目前,他们的文档很少,但下面是一个非常简化的新结构:

代码语言:javascript
运行
复制
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);
};

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

更新2-一些奇怪的

在更多地玩了新的创建者更新之后,在构建BLE应用程序时还有一些需要考虑的事情。

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

嗯,它有它的怪癖,但它有效!

旧答案

以下是Jason关于设备需要配对才能发现其服务的正确答案,下面是一些解决此问题的示例代码:

代码语言:javascript
运行
复制
    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}");
    }

这里要注意的关键是:

  • DeviceWatcher需要添加和更新属性才能正常工作。
  • 您需要捕获异常FileNotFound,该异常在试图询问未配对或尚未准备好的服务时发生。
票数 21
EN

Stack Overflow用户

发布于 2016-03-02 18:32:02

更新(5/5/16):“元素未找到”错误问题似乎只有在蓝牙设置屏幕未打开/扫描时才会发生。我不记得在10586.218之前的情况,但我还没查过。显然,更新中并不是所有的问题都是固定的。

更新(4/29/16):10586.218 windows更新似乎解决了与以前从未与机器(或电话)配对的设备配对的问题。我在这里描述的过程和Gerard在他的答案中的示例代码现在应该更加一致地工作了。

如果您足够幸运地使这个工作,它需要等待相当长的时间为驱动程序安装。我是通过同时运行BluetoothLEAdvertisementWatcher和DeviceWatcher来做到这一点的。

将DeviceInformation保存在从FromBluetoothAddressAsync()获得的BluetoothLEDevice中,然后在启动配对之前释放() BluetoothLEDevice。这事很重要。如果你不这样做,它就不会在配对后看到关贸总协定。

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

但是,它非常不稳定,而且它似乎依赖于蓝牙芯片组和驱动程序。我经常在FromBluetoothAddress中得到一个没有找到错误的元素,但是如果它过去了,配对通常在第一次或第二次尝试中起作用。

PairAsync和UnpairAsync也需要发布到UI线程。如果无法弹出请求授权的蓝色对话框,则会出现异常。您可以使用保存的UI、Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync()或SynchronizationContext中的Post()和异步委托来完成此操作。

我在论坛上看到多个MS员工的帖子说,FromBluetoothAddressAsync()只适用于配对设备。情况不是这样,但它是错误的,似乎是最好的,如果设备是手动配对,至少在过去一次。

票数 6
EN

Stack Overflow用户

发布于 2016-08-19 13:53:10

杰拉德·威尔金森的答案是正确的。为了让生活变得更简单,我使用反应性扩展()将其转化为一种可使用的方法。欢迎任何意见。

因此,一旦您找到使用BluetoothLEAdvertisementWatcher的设备并与其配对,您就可以使用它来启用GATTServices。

代码语言:javascript
运行
复制
private async Task<GattDeviceService> GetGATTServiceAsync(string deviceName)
{
  //devicewatcher is abused to trigger connection
  var deviceWatcher = DeviceInformation.CreateWatcher(); //trick to enable GATT

  var addedSource = Observable.FromEventPattern(deviceWatcher, nameof(deviceWatcher.Added))
                              .Select(pattern => ((DeviceInformation)pattern.EventArgs));

  var updatedSource = Observable.FromEventPattern(deviceWatcher, nameof(deviceWatcher.Updated))
                                .Select(pattern =>
                                {
                                  var update = ((DeviceInformationUpdate)pattern.EventArgs);
                                  return Observable.FromAsync(() => DeviceInformation.CreateFromIdAsync(update.Id).AsTask());
                                }).Concat();

  var source = addedSource.Merge(updatedSource);
  source.Publish().Connect(); //make sure the event handlers are attached before starting the device watcher

  deviceWatcher.Start();

  var result = await source.Where(di =>  di.Name == deviceName)                                       //find the relevant device
                           .Select(di => Observable.FromAsync(() => GattDeviceService.FromIdAsync(di.Id).AsTask()))       //get all services from the device
                           .Concat()                                                                                      //necessary because of the async method in the previous statement
                           .Where(service => service.Uuid == SERVICE_UUID)                                                //get the service with the right UUID
                           .Retry()                                                                                       //GattDeviceService.FromIdAsync can throw exceptions
                           .FirstAsync();

  deviceWatcher.Stop();

  return result;
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35420940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档