简体   繁体   English

Windows UWP 蓝牙应用程序,即使关闭电源,设备也会在扫描时显示

[英]Windows UWP bluetooth app, devices showing up when scanning even when they are powered off

I am developing a UWP app that is using bluetooth to connect to different devices.我正在开发一个使用蓝牙连接到不同设备的 UWP 应用程序。

My problem is that some devices that has been paired or previously discovered is showing up in my device list even though they are turned off or not in range.我的问题是,一些已配对或先前发现的设备显示在我的设备列表中,即使它们已关闭或不在范围内。

As of my understanding the property System.Devices.Aep.IsPresent can be used to filter out cached devices that are not available at the time but I always get "True" for that property even though I know the device is not reachable.据我了解,属性System.Devices.Aep.IsPresent可用于过滤掉当时不可用的缓存设备,但即使我知道该设备无法访问,我也总是为该属性获得“True”。

Any ideas on how this can be solved?关于如何解决这个问题的任何想法?

Setup设置

string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected", "System.Devices.Aep.IsPresent", "System.Devices.Aep.ContainerId", "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.Manufacturer", "System.Devices.Aep.ModelId", "System.Devices.Aep.ProtocolId", "System.Devices.Aep.SignalStrength"};
        _deviceWatcher = DeviceInformation.CreateWatcher("{REMOVED, NOT IMPORTANT}", requestedProperties, DeviceInformationKind.AssociationEndpoint);
        _deviceWatcher.Added += DeviceAdded;
        _deviceWatcher.Updated += DeviceUpdated;
        _deviceWatcher.Removed += DeviceRemoved;
        _deviceWatcher.EnumerationCompleted += DeviceEnumerationCompleted;

Callback for when device is added添加设备时的回调

Here isPresent is always true这里 isPresent 永远是真的

private void DeviceAdded(DeviceWatcher sender, DeviceInformation deviceInfo)
{
    Device device = new Device(deviceInfo);
    bool isPresent = (bool)deviceInfo.Properties.Single(p => p.Key == "System.Devices.Aep.IsPresent").Value;
    Debug.WriteLine("*** Found device " + deviceInfo.Id + " / " + device.Id + ", " + "name: " + deviceInfo.Name + " ***");
    Debug.WriteLine("RSSI = " + deviceInfo.Properties.Single(d => d.Key == "System.Devices.Aep.SignalStrength").Value);
    Debug.WriteLine("Present: " + isPresent);
    var rssi = deviceInfo.Properties.Single(d => d.Key == "System.Devices.Aep.SignalStrength").Value;
    if (rssi != null)
        device.Rssi = int.Parse(rssi.ToString());
    if (DiscoveredDevices.All(x => x.Id != device.Id) && isPresent)
    {
        DiscoveredDevices.Add(device);
        DeviceDiscovered(this, new DeviceDiscoveredEventArgs(device));
    }
}

Look into the Microsoft Bluetooth LE Explorer source code of GattSampleContext .查看GattSampleContextMicrosoft Bluetooth LE Explorer 源代码 You need to get properties: System.Devices.Aep.IsConnected, System.Devices.Aep.Bluetooth.Le.IsConnectable and filter only devices, which are connectable.您需要获取属性: System.Devices.Aep.IsConnected, System.Devices.Aep.Bluetooth.Le.IsConnectable并仅过滤可连接的设备。 Take care, that the device may become connectable after the DeviceWatcher.Updated event is called.请注意,在调用DeviceWatcher.Updated事件后,设备可能会变得可连接。 So you have to keep some track of unusedDevices .所以你必须跟踪一些未使用的unusedDevices

Eg my IsConnactable filter method is:例如,我的 IsConnactable 过滤器方法是:

private static bool IsConnectable(DeviceInformation deviceInformation)
{
    if (string.IsNullOrEmpty(deviceInformation.Name))
        return false;
    // Let's make it connectable by default, we have error handles in case it doesn't work
    bool isConnectable = (bool?)deviceInformation.Properties["System.Devices.Aep.Bluetooth.Le.IsConnectable"] == true;
    bool isConnected = (bool?)deviceInformation.Properties["System.Devices.Aep.IsConnected"] == true;
    return isConnectable || isConnected;
}

What worked for me was to have device watcher enumerate AssociationEndpointContainers, contrary to what the documentation suggests.对我有用的是让设备观察者枚举 AssociationEndpointContainers,这与文档建议的相反。

Specifically, I use,具体来说,我使用,

string[] RequestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected", "System.Devices.Aep.Bluetooth.Le.IsConnectable"};
 DeviceInformation.CreateWatcher(BluetoothLEDevice.GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus.Disconnected), RequestedProperties, DeviceInformationKind.AssociationEndpointContainer)

I figured this out by logging all properties of each DeviceInformation and DeviceInformationUpdate provided during discovery, and found that AssociationEndpointContainer, in contrast to AssociationEndpoint, and Device (Device!), the System.Devices.Aep.Bluetooth.Le.IsConnectable property always appears and directly corresponds to whether the device is powered on, or not.我通过记录发现期间提供的每个 DeviceInformation 和 DeviceInformationUpdate 的所有属性来解决这个问题,发现 AssociationEndpointContainer 与 AssociationEndpoint 和 Device (Device!) 相反,System.Devices.Aep.Bluetooth.Le.IsConnectable 属性总是出现并且直接对应设备是否开机。

By the way, in retrospect, this makes sense.顺便说一句,回想起来,这是有道理的。 In the documentation, we see that the AssociationEndpointContainer在文档中,我们看到 AssociationEndpointContainer

represents a single physical device that might have more than one AssociationEndpoint objects associated with it.表示可能具有多个关联的AssociationEndpoint对象的单个物理设备。 For example, if a television supports two different network protocols, the AssociationEndpointContainer would be the television.例如,如果电视支持两种不同的网络协议,则AssociationEndpointContainer就是电视。 It would also have two AssociationEndpoint objects to represent each protocol.它还有两个AssociationEndpoint对象来表示每个协议。

So, this is the central structure that Windows constructs for tracking connections to a device.因此,这是 Windows 构建的用于跟踪设备连接的中心结构。 It makes sense that it would be able to tell us whether the device can be connected to, or not.它能够告诉我们设备是否可以连接,这是有道理的。

I must say that it is confusing as heck that, in contrast, DeviceInformationKind.Device does not provide this functionality, and further, that it doesn't even represent a device, but a component of a device:我必须说令人困惑的是,相比之下,DeviceInformationKind.Device 不提供此功能,而且,它甚至不代表设备,而是设备的组件:

These devices are objects that represent a piece of the device functionality and optionally have drivers loaded on them.这些设备是代表一部分设备功能的对象,并且可以选择在其上加载驱动程序。 When a physical device is paired with windows, multiple Device objects are created for it.当一个物理设备与 windows 配对时,会为其创建多个Device对象。 A device contains 0 or more DeviceInterface objects, is a child to one DeviceContainer object, and is related to 0 or 1 AssociationEndpoint objects.一个设备包含 0 个或多个DeviceInterface对象,是一个DeviceContainer对象的子对象,并且与 0 个或 1 个AssociationEndpoint对象相关。

The official documentation on this subject is atrocious.关于这个主题的官方文档非常糟糕。 Microsoft, here is a tip, if you don't want people tripping all over your API.微软,这是一个提示,如果你不希望人们在你的 API 上绊倒。 I know that time is precious, and people with purse-strings have difficulty finding the decency in their stone-cold hearts to pay developers to properly document their stuff, but for the love of all that is holy, if you're going to provide only examples on how to use your stuff, then provide examples that address the most common issue for beginners.我知道时间是宝贵的,有财力的人很难在他们冰冷的心中找到体面来支付开发人员来正确记录他们的东西,但是为了所有神圣的东西,如果你要提供仅提供有关如何使用您的东西的示例,然后提供解决初学者最常见问题的示例

Case in point, which is a likelier goal for a beginner BLE developer?举个例子,对于初级 BLE 开发人员来说,哪个是更可能的目标? That you'd want to discover devices, even when they can't be connected to, or that you'd want to discover only devices that can be connected to.您想要发现设备,即使它们无法连接,或者您只想发现可以连接的设备。

Sheesh!嘘!

By the way, before I figured this out, I went down the route of using the AdvertisementWatcher.顺便说一句,在我弄明白这一点之前,我走上了使用 AdvertisementWatcher 的路线。 Specifically, I would detect advertisements, connect to the device from the advertisement to obtain its name, and then dispose of it.具体来说,我会检测广告,从广告连接到设备以获取其名称,然后对其进行处理。 This is horribly slow and can take up a ton of memory to boot (indirectly, through the Device Association Service).这非常慢,并且可能会占用大量内存来启动(间接地,通过设备关联服务)。

This method, in my experience is superior in every way;这种方法,以我的经验,各方面都优越; it is faster, more reliable, and less demanding on system resources.它更快、更可靠,对系统资源的要求更低。

It is a little hard to specifically answer your question because you can use Bluetooth in several ways to connect to a device.具体回答您的问题有点困难,因为您可以通过多种方式使用蓝牙连接到设备。 For instance, some devices need to be paired to be usable.例如,某些设备需要配对才能使用。 Some devices can't be discovered unless the Bluetooth stack is issuing an enquiry.除非蓝牙堆栈发出查询,否则无法发现某些设备。

There are a few things to do though to get this pointed in the right direction.不过,要使这指向正确的方向,还需要做一些事情。

  1. The first thing you want to do is use an AQS selector string to constrain what you are discovering.您要做的第一件事是使用 AQS 选择器字符串来限制您发现的内容。 The selector should also constrain the protocol because you don't want the PC discovering WiFiDirect devices and network devices.选择器还应约束协议,因为您不希望 PC 发现 WiFiDirect 设备和网络设备。 Post filtering is not good for performance.后过滤不利于性能。
  2. Next look at the Bluetooth samples.接下来看看蓝牙示例。 They have many get selector type methods for different scenarios that you can use to pass into create watcher.他们有许多用于不同场景的 get 选择器类型方法,您可以使用它们传递给创建观察者。 Either one of those will do what you want, or you can look at their AQS string to get an idea of what your filter should look like.其中任何一个都可以满足您的需求,或者您可以查看它们的 AQS 字符串以了解您的过滤器应该是什么样子。

In terms of properties you can use for your AQS selector, I am not sure if is present will be effective, but here are some other properties you might consider for constructing your selector/filter.就您可以用于 AQS 选择器的属性而言,我不确定是否存在,但这里有一些其他属性,您可能会考虑构建您的选择器/过滤器。 Like I said, the scenario makes a big difference;就像我说的,场景有很大的不同。 like a headset must be paired, whereas some LE device can't be paired and are just connectable.就像耳机必须配对,而某些 LE 设备无法配对,只能连接。

System.Devices.Aep.Bluetooth.IssueInquiry
System.Devices.Aep.Bluetooth.LastSeenTime
System.Devices.Aep.Bluetooth.Le.IsConnectable
System.Devices.Aep.IsPaired
System.Devices.Aep.CanPair
System.Devices.Aep.IsConnected
System.Devices.Aep.IsPresent
System.Devices.Aep.ProtocolId

A selector could look like this to enumerate Bluetooth BR devices that are paired:选择器可能如下所示以枚举配对的蓝牙 BR 设备:

System.Devices.Aep.ProtocolId:="{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}" AND System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True";

If you have a more specific device scenario, I can elaborate with a more specific answer.如果您有更具体的设备场景,我可以详细说明更具体的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM