Get access to the new Intel® IoT Developer Kit, a complete hardware and software solution that allows developers to create exciting new solutions with the Intel® Galileo and Intel® Edison boards. Visit the Intel® Developer Zone for IoT.
Overview
This document is a guide for creating Java* IoT applications that can access remote Bluetooth* Low Energy devices on IoT platforms, such as the Intel® Edison development board. Support for developing these applications is provided as part of the Intel® IoT Developer Kit, using the open source TinyB project. TinyB exposes simple C++ and Java APIs for using Bluetooth LE devices. This guide will only cover developing applications using the Java API in TinyB on the Intel® Edison development board.
Compatibility and requirements
The current Bluetooth API in TinyB has been tested with the Java 8 runtime environment (OpenJDK 8). This environment as well as TinyB are provided as part of the official Intel® IoT Developer Kit image builds for Intel® Edison boards.
On other Linux-based systems, TinyB can be used as long as BlueZ* version 5.37 or newer is installed and the bluetoothd
daemon has been started with experimental features enabled (-E
flag). More details can be found in the online README file.
In this guide, the TinyB application uses a Texas Instruments Sensor Tag as a Bluetooth LE device.
Documentation and application examples
The documentation for the Bluetooth LE API exposed by TinyB can be found online at the following locations:
The HelloTinyB (or hellotinyb for C++) example uses a Texas Instruments Sensor Tag, from which it reads the ambient and object temperature. The application requires the MAC address of the Sensor Tag as a first parameter to the program (XX:XX:XX:XX:XX:XX
in the following example).
./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
Writing a Bluetooth LE Java IoT application
We will use the HelloTinyB Java sample found in the TinyB repository as an example showing how to write a program that reads data from a GATT Service over Bluetooth LE. A wiki entry describing the Texas Instruments Sensor Tag device can be found here: http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide.
To start looking at the device, we first must initialize the TinyB library. A BluetoothManager object provides an entry point for using Bluetooth devices. There can be only one BluetoothManager at one time, and the reference to it is obtained through the getBluetoothManager()
method.
BluetoothManager manager = BluetoothManager.getBluetoothManager();
The manager will try to initialize a BluetoothAdapter if any Bluetooth adapter is present in the system. To initialize discovery we can call startDiscovery()
, which will put the default adapter in discovery mode.
boolean discoveryStarted = manager.startDiscovery();
We should expect to see the following output:
The discovery started: true
Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false
After discovery is started, new devices will be detected. We can get a list of all devices through the manager's getDevices()
method. We can look through the list of devices to find the device with the MAC address that we provided as a parameter. We continue looking until we find it, or until we have tried 15 times without success (about 1 minute).
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);
if (device.getAddress().equals(address))
sensor = device;
}
if (sensor != null) {
return sensor;
}
Thread.sleep(4000);
}
return null;
}
Afterwards, we can run the connect method on the returned device. The output should be as follows:
Found device: Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false
Sensor with the provided address connected
Our device should expose a temperature service, which has a UUID we can find out from the data sheet. The service description of the SensorTag can be found here: http://processors.wiki.ti.com/images/a/a8/BLE_SensorTag_GATT_Server.pdf. The service we are looking for has the short UUID AA00, which we insert into the TI Base UUID instead of the 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;
}
The code above should produce the following output:
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
First of all, we should obtain the characteristics of this service. There are three of them: the value (UUID AA01), configuration (AA02), and period (AA03). We can obtain them using the following code:
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");
We need to turn on the Temperature Service by writing 1 in the configuration characteristic, as mentioned in the PDF above. We could also modify the update interval by writing in the period characteristic, but the default value of 1s is good enough for our purposes.
byte[] config = { 0x01 };
tempConfig.writeValue(config);
After this configuration, we should be able to read the temperature from the device. The temperature service returns the data in an encoded format, which can be found in the wiki entry for the Sensor Tag device. Convert the raw temperature format to Celsius and print it. Conversion for object temperature depends on ambient temperature according to the wiki, but we will assume the result without conversion is good enough for our purposes.
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);
}
Running this loop will print the temperature values collected from the Bluetooth LE sensor:
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
Known limitations
The API used in this example is based on TinyB v0.3, which only supports polling, but v0.4 will introduce a simplified API for discovering devices and services.