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



我正在开发一个使用蓝牙连接到不同设备的 UWP 应用程序。

我的问题是某些已配对或以前发现的设备显示在我的设备列表中,即使它们已关闭或不在范围内。

据我了解,属性System.Devices.Aep.IsPresent可用于过滤掉当时不可用的缓存设备,但即使我知道该设备无法访问,我也总是为该属性获得"True"。

关于如何解决这个问题的任何想法?

设置

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;

添加设备时的回调

这里是现在永远是真的

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));
}
}

查看GattSampleContext的Microsoft蓝牙 LE 资源管理器源代码。您需要获取属性:仅System.Devices.Aep.IsConnected, System.Devices.Aep.Bluetooth.Le.IsConnectable和筛选可连接的设备。请注意,在调用DeviceWatcher.Updated事件后,设备可能会变得可连接。所以你必须保持一些跟踪unusedDevices.

例如,我的 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;
}

对我有用的是让设备观察程序枚举 AssociationEndpointContainers,这与文档建议的相反。

具体来说,我使用,

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)

我通过记录发现期间提供的每个 DeviceInformation 和 DeviceInformationUpdate 的所有属性来解决这个问题,并发现 AssociationEndpointContainer,与 AssociationEndpoint 和 Device (Device!) 相比,System.Devices.Aep.Bluetooth.Le.IsConnectable 属性始终出现并直接对应于设备是否已通电。

顺便说一句,回想起来,这是有道理的。 在文档中,我们看到 关联端点容器

表示可能具有多个物理设备的单个物理设备关联与其关联的终结点对象。例如,如果电视支持两种不同的网络协议,则AssociationEndpointContainer将是电视。它还将有两个AssociationEndpoint对象来表示每个协议。

因此,这是 Windows 为跟踪与设备的连接而构造的中心结构。 它能够告诉我们设备是否可以连接是有道理的。

我必须说,令人困惑的是,相比之下,DeviceInformationKind.Device不提供此功能,而且,它甚至不代表设备,而是设备的组件:

这些设备是表示设备的一部分的对象 功能,并选择性地在其上加载驱动程序。当一个 物理设备与窗口配对,多个设备对象是 为它而生。设备包含 0 个或多个设备接口对象, 是一个设备容器对象的子对象,并且与 0 或 1 相关关联终结点对象。

关于这个主题的官方文件是残暴的。Microsoft,这里有一个提示,如果你不希望人们在你的API上绊倒。 我知道时间是宝贵的,那些有钱包的人很难在他们冰冷的心中找到体面来支付开发人员正确记录他们的东西,但为了对所有神圣事物的热爱,如果你只提供如何使用你的东西的例子,那么提供解决初学者最常见问题的例子

举个例子,对于初学者BLE开发人员来说,哪个目标更有可能? 你希望发现设备,即使它们无法连接到,或者你希望仅发现可以连接到的设备。

嘭!

顺便说一下,在我想通这一点之前,我走上了使用AdvertisementWatcher的路线。 具体来说,我会检测广告,从广告连接到设备以获取其名称,然后处理它。 这非常慢,并且可能会占用大量内存来启动(间接地,通过设备关联服务)。

根据我的经验,这种方法在各个方面都更胜一筹;它更快、更可靠,对系统资源的要求更低。

具体回答您的问题有点困难,因为您可以通过多种方式使用蓝牙连接到设备。 例如,某些设备需要配对才能使用。 除非蓝牙堆栈发出查询,否则无法发现某些设备。

不过,要使它指向正确的方向,还是要做一些事情。

  1. 您要做的第一件事是使用 AQS 选择器字符串来约束您正在发现的内容。 选择器还应约束协议,因为您不希望电脑发现 WiFiDirect 设备和网络设备。 后过滤对性能不利。
  2. 接下来看一下蓝牙示例。 它们有许多用于不同方案的 get 选择器类型方法,可用于传递到创建观察程序。 其中一个将执行您想要的操作,或者您可以查看它们的 AQS 字符串以了解您的过滤器应该是什么样子。

就可用于 AQS 选择器的属性而言,我不确定存在是否有效,但这里有一些您可以考虑用于构建选择器/过滤器的其他属性。 就像我说的,场景有很大的不同;就像耳机必须配对一样,而某些 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

选择器可能如下所示,以枚举配对的蓝牙 BR 设备:

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

如果您有更具体的设备方案,我可以详细说明更具体的答案。

最新更新