65.9K
CodeProject 正在变化。 阅读更多。
Home

用于蓝牙 LE 应用程序的 Java

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2016年3月18日

CPOL

4分钟阅读

viewsIcon

34856

本文档是关于如何为物联网平台(例如 Intel® Edison 开发板)创建可以访问远程低功耗蓝牙设备的 Java 物联网应用程序的指南。

获取新的 Intel® IoT Developer Kit,这是一个完整的硬件和软件解决方案,让开发人员能够使用 Intel® Galileo 和 Intel® Edison 板创建令人兴奋的新解决方案。请访问 Intel® 物联网开发者中心

概述

本文档是关于如何为物联网平台(例如 Intel® Edison 开发板)创建可以访问远程低功耗蓝牙*设备的 Java* 物联网应用程序的指南。Intel® IoT Developer Kit 提供了开发这些应用程序的支持,使用了开源的 TinyB 项目。TinyB 公开了简单的 C++ 和 Java API 来使用低功耗蓝牙设备。本指南仅涵盖在 Intel® Edison 开发板上使用 TinyB 中的 Java API 开发应用程序。

兼容性和要求

TinyB 中当前的低功耗蓝牙 API 已在 Java 8 运行时环境 (OpenJDK 8) 中进行了测试。该环境以及 TinyB 都包含在 Intel® Edison 板的官方 Intel® IoT Developer Kit 映像构建中。

在其他基于 Linux 的系统上,只要安装了 BlueZ* 5.37 或更高版本,并且 bluetoothd 守护进程已通过启用实验性功能(-E 标志)启动,就可以使用 TinyB。有关更多详细信息,请参阅在线 README 文件。

在本指南中,TinyB 应用程序使用 德州仪器传感器标签 作为低功耗蓝牙设备。

文档和应用程序示例

TinyB 公开的低功耗蓝牙 API 的文档可在以下在线位置找到:

HelloTinyB(或 C++ 版的 hellotinyb)示例使用 德州仪器传感器标签,从中读取环境温度和对象温度。该应用程序需要传感器标签的 MAC 地址作为程序的第一个参数(以下示例中的 XX:XX:XX:XX:XX:XX)。

./examples/hellotinyb XX:XX:XX:XX:XX:XX

java -cp examples/java/HelloTinyB.jar:/usr/lib/java/tinyb.jar HelloTinyB XX:XX:XX:XX:XX:XX

编写低功耗蓝牙 Java 物联网应用程序

我们将使用 TinyB 存储库中的 HelloTinyB Java 示例 作为示例,展示如何编写一个程序,该程序可以通过低功耗蓝牙读取 GATT 服务的数据。有关德州仪器传感器标签设备的维基页面可以在此处找到:http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide

要开始查看设备,我们首先必须初始化 TinyB 库。BluetoothManager 对象提供了使用蓝牙设备的一个入口点。一次只能有一个 BluetoothManager,并通过 getBluetoothManager() 方法获取其引用。

BluetoothManager manager = BluetoothManager.getBluetoothManager();

如果系统中存在蓝牙适配器,管理器将尝试初始化一个 BluetoothAdapter。要初始化发现,我们可以调用 startDiscovery(),这将把默认适配器置于发现模式。

boolean discoveryStarted = manager.startDiscovery();

我们应该会看到以下输出

The discovery started: true
Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false 

发现开始后,将检测到新设备。我们可以通过管理器的 getDevices() 方法获取所有设备列表。我们可以浏览设备列表以查找具有我们作为参数提供的 MAC 地址的设备。我们会一直查找,直到找到它,或者在尝试 15 次(约 1 分钟)后仍未成功。

static BluetoothDevice getDevice(String address) throws InterruptedException  {
    BluetoothManager manager = BluetoothManager.getBluetoothManager();
    BluetoothDevice sensor = null;
    for (int i = 0; (i < 15) && running; ++i) {
        List<BluetoothDevice> list = manager.getDevices();
         for (BluetoothDevice device : list) {
            printDevice(device);
            /*
             * Here we check if the address matches.
             */
            if (device.getAddress().equals(address))
                sensor = device;
        }
        if (sensor != null) {
            return sensor;
        }
        Thread.sleep(4000);
    }
    return null;
}

之后,我们可以在返回的设备上调用 connect 方法。输出应如下所示:

Found device: Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false 
Sensor with the provided address connected

我们的设备应该公开一个温度服务,该服务具有我们可以从数据表中找到的 UUID。传感器标签的服务描述可以在这里找到:http://processors.wiki.ti.com/images/a/a8/BLE_SensorTag_GATT_Server.pdf。我们要查找的服务具有短 UUID AA00,我们将其插入 TI Base UUID 的 XXXX 位置:f000XXXX-0451-4000-b000-000000000000。

static BluetoothGattService getService(BluetoothDevice device, String 
 UUID) throws InterruptedException {
    System.out.println("Services exposed by device:");
    BluetoothGattService tempService = null;
    List<BluetoothGattService> bluetoothServices = null;
    do {
        bluetoothServices = device.getServices();
        for (BluetoothGattService service : bluetoothServices) {
            System.out.println("UUID: " + service.getUuid());
            if (service.getUuid().equals(UUID))
                tempService = service;
        }
        Thread.sleep(4000);
    } while (bluetoothServices != null && bluetoothServices.isEmpty() && running);
    return tempService;
}

上述代码应产生以下输出:

Services exposed by device:
UUID: f000aa64-0451-4000-b000-000000000000
UUID: 0000180a-0000-1000-8000-00805f9b34fb
UUID: f000ccc0-0451-4000-b000-000000000000
UUID: f000ac00-0451-4000-b000-000000000000
...
Found service f000aa00-0451-4000-b000-000000000000

首先,我们应该获取此服务的特性。有三个:值(UUID AA01)、配置(AA02)和周期(AA03)。我们可以使用以下代码获取它们:

static BluetoothGattCharacteristic getCharacteristic(BluetoothGattService service, String UUID) {
    List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
    for (BluetoothGattCharacteristic characteristic : characteristics) {
        if (characteristic.getUuid().equals(UUID))
            return characteristic;
    }
    return null;
}
BluetoothGattCharacteristic tempValue = getCharacteristic(tempService, "f000aa01-0451-4000-b000-000000000000");
BluetoothGattCharacteristic tempConfig = getCharacteristic(tempService, "f000aa02-0451-4000-b000-000000000000");
BluetoothGattCharacteristic tempPeriod = getCharacteristic(tempService, "f000aa03-0451-4000-b000-000000000000");

如上所述的 PDF 文件所提到的,我们需要通过向配置特性写入 1 来开启温度服务。我们也可以通过向周期特性写入值来修改更新间隔,但 1 秒的默认值对我们来说已经足够了。

byte[] config = { 0x01  };
tempConfig.writeValue(config);

在此配置之后,我们应该能够从设备读取温度。温度服务以编码格式返回数据,可在传感器标签设备的维基页面中找到。将原始温度格式转换为摄氏度并打印。对象温度的转换取决于维基中提到的环境温度,但我们假设未经转换的结果对我们来说已足够。

while (running) {
    byte[] tempRaw = tempValue.readValue();
    System.out.print("Temp raw = {");
    for (byte b : tempRaw) {
        System.out.print(String.format("%02x,", b));
    }
    System.out.print("}");
        int objectTempRaw = tempRaw[0] + (tempRaw[1] << 8);
    int ambientTempRaw = tempRaw[2] + (tempRaw[3] << 8);
        float objectTempCelsius = convertCelsius(objectTempRaw);
    float ambientTempCelsius = convertCelsius(ambientTempRaw);

    System.out.println(String.format(" Temp: Object = %fC, Ambient = %fC", objectTempCelsius, ambientTempCelsius));
    Thread.sleep(1000);
}

运行此循环将打印从低功耗蓝牙传感器收集的温度值。

Temp raw = {10,0b,c8,0d,} Temp: Object = 22.125000C, Ambient = 25.562500C
Temp raw = {10,0b,c8,0d,} Temp: Object = 22.125000C, Ambient = 25.562500C
Temp raw = {04,0b,cc,0d,} Temp: Object = 22.031250C, Ambient = 25.593750C
...
Temp raw = {34,0b,cc,0d,} Temp: Object = 22.406250C, Ambient = 25.593750C

已知限制

本示例中使用的 API 基于 TinyB v0.3,它只支持轮询,但 v0.4 将引入一个简化的 API 来发现设备和服务。

© . All rights reserved.