Windows 10 蓝牙低功耗连接 c#

6

我需要从一台蓝牙设备中获取数据,使用C#在Windows 10上进行操作。我对蓝牙API不太熟悉,无法弄清楚以下内容为什么不能工作:

使用BluetoothLEAdvertisementWatcher搜索广告,这部分可以正常工作。我收到了来自设备的广告(本地名称匹配),以及它的ServiceUuids。接下来,我尝试使用与广告一起收到的BluetoothAddress连接到设备:

private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, 
                    BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
    ulong blAdress = eventArgs.BluetoothAddress;
    BluetoothLEDevice blDevice = await 
         Windows.Devices.Bluetooth.BluetoothLEDevice.FromBluetoothAddressAsync(blAdress);
}

然而,这样做会导致异常:

未找到元素。(HRESULT 异常:0x80070490)。

这是从设备读取数据的正确方法吗?还有其他选项可以从服务中读取数据吗?在 windows 中手动配对设备并不是一个真正的选择,也似乎失败了。
/编辑 1:我检查设备的本地名称,以确保只尝试连接到正确的设备。所以我想这个特定设备的连接存在问题,但我仍然不知道如何解决它。iOS 上已成功读取服务数据,因此应该是可行的。
6个回答

3
直到微软修复这个问题,我找到的唯一可靠的解决方法是要求注册表列出已配对的BLE设备列表,并将广告中的蓝牙地址与已配对的设备列表进行比较,以连接到BLE设备。我的经验是,当在未配对的设备上调用FromBluetoothAddressAsync时,Windows会抛出异常并杀死观察器线程。我有一些C++代码可以分享,它读取注册表并创建已配对BLE设备列表。
希望微软能像苹果一样充分支持BLE技术。

你好,你能分享一下这段代码吗?谢谢。 - daniel metlitski

2

1
当我直接使用BluetoothLEAdvertisementWatcher时,遇到了同样的问题。然后我测试了观察器列出的不同地址。我发现这与蓝牙设备有关。在添加以下过滤器后,我成功连接到GATT设备(TI Sensor Tag)。
public sealed partial class MainPage : Page
{
    private BluetoothLEAdvertisementWatcher watcher;

    public MainPage()
    {
        this.InitializeComponent();

        // Create and initialize a new watcher instance.
        watcher = new BluetoothLEAdvertisementWatcher();

        // Part 1B: Configuring the signal strength filter for proximity scenarios

        // Configure the signal strength filter to only propagate events when in-range
        // Please adjust these values if you cannot receive any advertisement 
        // Set the in-range threshold to -70dBm. This means advertisements with RSSI >= -70dBm 
        // will start to be considered "in-range".
        watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;

        // Set the out-of-range threshold to -75dBm (give some buffer). Used in conjunction with OutOfRangeTimeout
        // to determine when an advertisement is no longer considered "in-range"
        watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -75;

        // Set the out-of-range timeout to be 2 seconds. Used in conjunction with OutOfRangeThresholdInDBm
        // to determine when an advertisement is no longer considered "in-range"
        watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);

        // By default, the sampling interval is set to zero, which means there is no sampling and all
        // the advertisement received is returned in the Received event

        // End of watcher configuration. There is no need to comment out any code beyond this point.
    }


    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        watcher.Received += OnAdvertisementReceived;

        watcher.Stopped += OnAdvertisementWatcherStopped;

        App.Current.Suspending += App_Suspending;

        App.Current.Resuming += App_Resuming;
    }


    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        App.Current.Suspending -= App_Suspending;
        App.Current.Resuming -= App_Resuming;

        watcher.Stop();

        watcher.Received -= OnAdvertisementReceived;
        watcher.Stopped -= OnAdvertisementWatcherStopped;

        base.OnNavigatingFrom(e);
    }


    private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
    {
        // Make sure to stop the watcher on suspend.
        watcher.Stop();
        // Always unregister the handlers to release the resources to prevent leaks.
        watcher.Received -= OnAdvertisementReceived;
        watcher.Stopped -= OnAdvertisementWatcherStopped;

    }

    private void App_Resuming(object sender, object e)
    {
        watcher.Received += OnAdvertisementReceived;
        watcher.Stopped += OnAdvertisementWatcherStopped;
    }

    private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
    {
        var address = eventArgs.BluetoothAddress;

        BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);

        var cnt =device.GattServices.Count;

        watcher.Stop();
    }

    /// <summary>
    /// Invoked as an event handler when the watcher is stopped or aborted.
    /// </summary>
    /// <param name="watcher">Instance of watcher that triggered the event.</param>
    /// <param name="eventArgs">Event data containing information about why the watcher stopped or aborted.</param>
    private void OnAdvertisementWatcherStopped(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementWatcherStoppedEventArgs eventArgs)
    {

    }

    private void start_Click(object sender, RoutedEventArgs e)
    {
        watcher.Start();
    }
}

2
你的代码非常相似,但我尝试了一下。不幸的是,只要我调用“BluetoothLEDevice device = ...”,就会抛出相同的异常 :( 那么这是设备特定的问题吗?你知道有什么解决方法吗? - Stoffel

0

只是猜测,也许你需要这个:

watcher.ScanningMode = BluetoothLEScanningMode.Active;

并且在OnAdvertisementReceived事件中

if (e.AdvertisementType == BluetoothLEAdvertisementType.ScanResponse)
{
  BluetoothLEDevice blDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(e.BluetoothAddress);
}

0
如果这是一个UWP项目,请确保启用蓝牙功能。
在Visual Studio解决方案资源管理器中,双击*.appxmanifest,选择“功能”选项卡,并确保选中“蓝牙”。
它将添加一些类似于以下的xml代码;

<Capabilities>
    <Capability Name="internetClientServer" />
    <DeviceCapability Name="bluetooth" />
</Capabilities>


0

这个问题已经超过3年了,但因为它有超过13000次的浏览量,我会回答。 元素未找到的原因是Windows.Devices在蓝牙设备广告未配对或连接之前不知道它们的存在。 相反,在OnAdvertisementReceived中只需使用:

 var device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);

我在Github上还有一个非常简单的UWP示例,它没有任何控件,以保持尽可能简单。所有结果都显示在调试输出窗口中。 最有用的信息在MainPage.xaml.cs文件中。

请查看:https://github.com/GrooverFromHolland/SimpleBleExample_by_Devicename


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接