Android Things 支持蓝牙和蓝牙低功耗 API。在这篇博文中,我们将使用 Bluetooth LE API 在服务器(Android Things 开发板)和客户端(手机/手表上的 Android 应用程序)之间进行通信。
我们将为我们的真棒(awesomeness)建立一个计数器:每当你感觉真棒(awesomeness,无论什么原因),按一下你的移动设备上的按钮。 一只幸运的猫会移动它的爪子,并增加你的真棒(awesomeness)计数器。
理解低功耗蓝牙 BLE
BLE基于一个名为 “通用属性概要文件”(General ATTribute profile,GATT)的规范,该规范定义了如何在服务器和客户端之间传输和接收被称为 “属性” (attributes)的短小数据。
它提到了“概况”(profiles),“服务”(services),“特征” (characteristics) 和 “描述” (descriptors)等概念。
一个配置文件是(一或多个)服务的集合。每个服务(可以被认为是一个行为)可以包含一个或多个封装数据的特征(characteristics)。
GATT 结构图
为了确保互操作性,Bluetooth SIG(特殊兴趣小组)已经预定义了多个配置文件和服务。想象一下,我们要创建我们自己的键盘设备。 为确保兼容性,我们将不得不通过 GATT 配置文件遵循 HID(人机界面设备):
HID 设备
配置文件主要是一个规范,告诉我们我们将不得不实施哪些服务。要创建我们的自定义键盘,我们将必须实施 3 个强制性服务(HID、电池、设备信息)以及可选的扫描参数服务。
如果我们看过电池服务,它暴露了设备内的电池状态,我们可以看到它嵌入了一个名为电池电量的单一的强制只读特性。这个特性封装了一个介于 0 和 100 之间的 int 值,代表了设备电池的百分比。它也有一个可选的 “通知” (Notify)属性,这意味着客户可以订阅它,当值改变时自动通知。
电池级别在 Android 上开始使用 BLE
官方文档 是在 Android 上开始使用蓝牙低功耗的最佳方式。
Google 还提供了 2 个示例项目:
android-BluetoothLeGatt:扫描设备暴露服务并列出其特征的 Android 客户端。
sample-bluetooth-le-gattserver:实现当前时间服务的 Android Things 服务器。
部署这两个项目之后,您将能够扫描 Android Things GATT 服务:
示例 BLE
服务和特征由 UUID 唯一标识。这里,Raspberry Pi 3 公开了 3 个服务:通用属性(0x1801),通用访问(0x1800)和当前时间服务(0x1805)。后者有两个特征:当前时间(0x2A2B)和本地时间信息(0x2A0F)
关于自定义GATT服务/特性, 虽然按照蓝牙技术联盟的定义实施服务是推荐的方式,但也可以创建自己的专有服务(我们将在今天这样做)。在某些情况下,这可能是首选的解决方案,但是您将不具有互操作性的好处。
您应该为您的非标准服务和特性使用 128 位随机 UUID。短的 16 位 UUID 仅用于由蓝牙标准定义的服务/特性。
创建服务器
现在我们已经熟悉 BLE 关键概念,我们可以开始实施我们的 GATT 服务器。
我们的 Android Things 项目将公开一个具有两个特征的服务:
:一个只读的,可通知的属性,表示你到目前为止真棒(Awesomeness)的次数
:当一个客户端为这个特性写一个值时,该设备应该移动猫的爪子并且增加真棒(Awesomeness)计数器。
下面的代码受到 sample-bluetooth-le-gattserver 的启发。如果你需要创建一个 GATT 服务器,你可以使用这个项目作为参考,或者按照官方文档。
常量
我们将定义以下常量
如前所述,服务和特征由 UUID 唯一标识。由于我们没有实施标准服务,我们使用随机生成的值。
另外请注意 常量:每个特征都有价。如果我们以“电池电量”特性为例,它保持从 0 到 100 的值。特性也可以包含一些描述符。描述符定义元数据,如描述和展示信息。
GATT 描述符的一些示例:
特征用户描述 (0x2901):提供特征值的文本用户描述。
有效范围 (0x2906):定义特征的范围。
客户端特性配置 (0x2902):定义特性如何由特定客户端配置。
如果一个客户想订阅一个特性,所以当一个值发生变化的时候它可以被自动地通知,它应该在 “客户特性配置” (Client Characteristic Configuration)描述符上执行一个写操作来通知它的意图。
在这里,我们定义一个 ,以便客户端可以订阅 的值。
AndroidManifest.xml
首先,我们声明 和 权限。 需要启动发现,或自动启用设备上的蓝牙。
我们还指定我们的应用程序需要使用 功能。如果低功耗蓝牙是您的应用程序的可选功能,请将此功能设置为 。
开始广播(advertising)
当 Android Things 程序启动时,它应该开始广播(advertising),以便其他设备可以看到它公开哪些 BLE 服务,并可以连接到它。
广播是电池密集型的。在这里,我们的设备总是连接到交流电源,所以它会连续广播。如果它使用电池供电,一个好主意是添加一个超时和一个物理按钮来开始广播过程。 此外,您需要在客户端连接后停止广播。
方法需要一个 实例,定义如下:
创建 GATT 服务
我们必须以编程的方式定义我们的 GATT 服务。请记住,我们的服务应该包含两个特点:
计数器(只读,通过配置描述符支持订阅)
交互器(只写)
启动服务器
然后,我们用 方法启动低功耗蓝牙服务器。
此方法采用 实例,该实例包含在读取或写入特征/描述符时实现的回调。
返回计数器值
当 GATT 客户端读取 时,我们应该返回计数器的值。为此,我们重写我们的 的 方法,如果在计数器特性上有读取请求,则返回 :
添加计数器
当 GATT 客户端写入 时,我们应该增加计数器的值。为此,我们可以覆写 方法:
请注意 被调用了。
由于计数器值已经改变,我们应该通知设备。 稍后我们将看到实现,但首先,我们来处理订阅。
处理通知
如果客户想要得到计数器特征值的任何变化的通知,就应该把它的意图写在一个配置描述符上。
我们重写 ,并在名为 的私有列表中保留蓝牙设备的引用:
现在,我们可以创建我们的 方法,为每个订阅的设备简单地调用 :
测试 GATT 服务器
我们已经完成了我们的 GATT 服务器的编写。在开始创建客户端之前,我们将首先测试服务器,以确保我们已经正确实施了所有功能。
要测试低功耗蓝牙设备,您可以使用 nRF Connect for Mobile 应用程序。此应用程序允许您扫描蓝牙低功耗设备,并让您读取、写入、订阅特征。
启动应用程序后,我们可以看到 RPI3 是广播。 一旦我们连接到它,我们可以看到我们的自定义服务(UUID = 7950 ...)
测试 RPI 广播
使用这个应用程序,我们可以浏览给定服务的所有特征。
领取专属 10元无门槛券
私享最新 技术干货