Android 蓝牙 LE 通知的问题

Posted

技术标签:

【中文标题】Android 蓝牙 LE 通知的问题【英文标题】:Problems with Android Bluetooth LE Notifications 【发布时间】:2014-10-13 14:40:40 【问题描述】:

我正在尝试编写访问 Zephyr HxM 智能心脏监视器的蓝牙 LE 应用程序。该显示器有多个蓝牙服务,但我对电池服务、心率服务和具有活动和峰值加速的自定义服务感兴趣。每个都有一个特性,电池电量 (BAT)、心率测量 (HR) 和自定义测量 (CUS)。 HxM 大约每秒更新一次。

我正在使用搭载 android 4.4 的 Galaxy S4 进行此操作。

它没有按文档中的预期工作。

我最初的做法是:

Read BAT
Set notification for HR 
Set notification for CUS.

然后等待回调。设置通知就是调用

BluetoothGatt.setCharacteristicNotification(Characteristic char , boolean enabled)

(也可以为 BAT 做通知,但是规范并不要求支持这一点。然而,HxM 确实支持它。)

这不起作用。我收到了 BAT 和 HR 的通知,但没有收到 CUS。如果我消除了第二步,我会收到 CUS 的通知。我无法同时获得两者。 (这表明我正在正确读取特征,所以这[可能]不是问题。)

我发现一些迹象表明 Android 的蓝牙堆栈同步存在问题,但没有硬性文档。然后我尝试了以下方法:

Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then disable notification for HR, and start notification for CUS.
Get CUS, then disable notification for CUS, and start notification for HR.
And continue to loop.

我有 BAT,仅此而已。

通过反复试验,我发现了以下作品:

Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then start notification for CUS.
Get CUS, then start notification for HR.
And continue to loop.

(与上面相同,但没有禁用通知。)通常,我会在 200 毫秒内获得 HR 读数,然后是 CUS 读数。可以假设它们来自同一个更新。 (数据中没有时间戳,必须保持简短才能成为 LE。)实际上,逻辑更复杂,因为在没有预期读数的情况下需要计时器。这个逻辑要复杂得多(并且比我第一次尝试更容易出错),这就是文档似乎所说的合适。

我已经联系了 Zephyr,他们说 HxM Smart 已经在 Windows 上进行了广泛的测试,并且会同时发出通知。也有迹象表明它可以在 ios 上正常工作。

还有一个我不明白的问题。为了获得通知,您必须在本地启用特性以进行通知,例如:

BluetoothGattDescriptor descriptor = characteristic
        .getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG);
resSet = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
resWrite = mBluetoothGatt.writeDescriptor(descriptor);

这是针对每个特性的设置,并且只需要在首次接收到特性时进行一次。相反,我发现每次设置通知时都必须这样做。这可能会导致足够的时间延迟以使事情正常进行。我不知道。这种反复试验占用了我很多时间。最好能对其工作原理有一个明确的说明。

我应该注意,对于所有返回结果的调用,结果都是 true(成功)。

对于冗长的声明,我深表歉意。我的问题是:

我没有发现我必须做所描述的事情的文档。所有迹象表明您设置了通知并等待回调。 是否有文档,或者这是一个错误,还是只是一个糟糕的实现?(或者是我的错误?)我特别想知道我必须做的文档在哪里。

其次,还有一个更复杂的问题。我试图调试例程以查看代码实际在做什么。当我到达 BluetoothGatt.class 时,源代码行与调试堆栈所说的不匹配。因此,我假设 S4 没有使用标准的 Android。我不知道从那里去哪里。这令人沮丧,虽然我有一些似乎可以工作的东西,但它很笨拙,几乎可以肯定不那么健壮。

感谢您的帮助。

【问题讨论】:

好问题。我有一个类似的问题,我必须通过通知收听两个特征并写给第三个特征。无法让它在 android 上正常工作,但它在 ios 上运行良好。如果有机会,我建议您在不同的(品牌)Android 设备上尝试。 BLE 即使在 4.4.4 上仍然不稳定,很多事情都无法按预期工作,缺乏文档,并且在不同的移动设备上仍然给出不同的结果。 您应该能够启用通知并直接接收它们,而无需继续做任何进一步的事情。要意识到的是,您一次只能执行一个后端操作,例如 writeDescriptor。如果一个仍在进行中,而您尝试做另一个,它只会忽略新的请求。这一点都没有很好的记录和痛苦。你必须设置某种形式的排队方法见***.com/questions/21278993/… Ifor,谢谢。我认为我的问题不在于等待 writeDescriptor。 ***.com/questions/17910322/… 也有一篇关于此的文章,但它不考虑通知。根据您的说法,我不必担心它们(在使用 writeDescriptor 正确启用它们之后)。我离开了我的电脑,但我一回来就会试试这个。再次感谢。 我确实为 writeDescriptor 和 readCharacteristic 实现了队列,如 miznick 在***.com/questions/17910322/… 中所述。我删除了所有排队通知的逻辑,它似乎工作得很好。我只需要启用一次通知。这与Ifor所说的一致。如果将其作为答案提交,我会将其标记为答案。使用 bluevoid 回答的 sleep 也应该有效,但我认为队列是一种更好的方法。不幸的是,这没有记录。这也可能是一个错误。 【参考方案1】:

我在按顺序写入多个值时遇到了同样的问题,在它们之间放置一个 Thread.sleep(200) 解决了这个问题(唉,我应该说)。也许这也有助于获得通知。 在 Nexus 5 上的 android 4.4.2 上对此进行了测试。不,4.4 并不能解决所有问题......

【讨论】:

【参考方案2】:

我可能已经很晚了,但是您应该实现一个队列架构来设置您的特征以发送通知。我在https://***.com/a/18207869/3314615 的帖子中使用了与 miznick 类似的技术,最后只为本地 BLE 堆栈编写了包装器代码,因为我使用了几个应用程序。从那以后,我在接收通知方面没有任何问题。我同意你的观点,Android BLE 文档应该有一些关于 BLE Stack 不同步的信息或警告。坦率地说,我认为应该重写它以处理同步写入调用并将它们排队。

【讨论】:

早在 2014 年,我确实为 writeDescriptor 和 readCharacteristic 实现了队列,如 miznick 在 ***.com/questions/17910322/... 中所述。请参阅原始帖子的评论。它继续工作。如果这项工作有任何功劳,应该归功于 Ifor。【参考方案3】:

首先,您为第一个特征设置通知(即 setCharacteristicNotification 和设置描述符)。

并且,在 onDescriptorWrite 回调函数中设置第二个特征的通知。

【讨论】:

以上是关于Android 蓝牙 LE 通知的问题的主要内容,如果未能解决你的问题,请参考以下文章

低功耗蓝牙通知间隔

如何从 iPhone 向蓝牙 LE 设备发送电子邮件、短信通知?

如何在 iOS 应用程序中从蓝牙 LE 设备获取通知

iOS 蓝牙 LE 无法以编程方式获取通知,但可以在其他应用程序中

使用蓝牙 LE“Proximity”配置文件 Android 检测接近度

iOS 中的蓝牙 LE 和 ANCS