[Перевод] Работа с Bluetooth LE из Java-приложений
О совместимости и предварительных требованиях
Текущая версия Bluetooth API в TinyB протестирована в среде исполнения Java 8 (OpenJDK 8). Это окружение, как и TinyB, поставляется как часть официальной сборки образа Intel IoT Development Kit для плат Intel Edison.
На Linux-системах TinyB можно использовать при установленном BlueZ (версия 5.37. или выше). При этом демон bluetoothd запускается с включенными экспериментальными функциями (флаг –E
). Подробнее об этом можете почитать в файле README. В нашем примере в роли Bluetooth LE-устройства выступает SensorTag от Texas Instruments. Подробности об устройстве можно найти здесь.
Документация и примеры приложений
Вот два варианта документации для Bluetooth API которое предоставляет TinyB. Здесь — материалы для тех, кто пользуется C++, а здесь — для Java-разработчиков.
В примере HelloTinyB, который написан на Java (или в hellotinyb для C++) используется вышеупомянутый SensorTag. С него осуществляется считывание показателей об окружающей температуре и температуре объекта. Для правильной работы приложению требуется MAC-адрес SensorTag. Его надо передать в качестве первого параметра при запуске программы:
./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
IoT-приложение на Java для работы с Bluetooth LE
Здесь мы воспользуемся примером HelloTinyB, который написан на Java. Его можно найти в репозитории TinyB. Мы покажем, как написать приложение, которое читает данные из службы GATT через Bluetooth LE.
Для того, чтобы начать работать с SensorTag, нужно инициализировать библиотеку TinyB. Объект BluetoothManager предоставляет точку входа для использования Bluetooth-устройств. В программе может быть лишь один экземпляр этого объекта-менеджера. Ссылку на него можно получить с помощью метода getBluetoothManager ():
BluetoothManager manager = BluetoothManager.getBluetoothManager();
Менеджер попытается инициализировать объект BluetoothAdapter если в системе присутствует Bluetooth-адаптер. Для того, чтобы запустить поиск других устройств, нужно вызвать метод startDiscovery (), который переведёт адаптер, используемый по умолчанию, в режим поиска:
boolean discoveryStarted = manager.startDiscovery();
После выполнения этой команды можно ждать следующего отладочного вывода:
The discovery started: true
Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false
После запуска поиска обнаружено новое устройство. Список всех найденных устройств можно получить с помощью метода менеджера getDevices (). Этот список нужно просмотреть для того, чтобы найти устройство с MAC-адресом, заданным в качестве параметра при запуске программы. Поиск продолжается либо до тех пор, пока нужное устройство не будет найдено, либо — пока не будет предпринято 15 попыток его обнаружения (занимает это около минуты).
static BluetoothDevice getDevice(String address) throws InterruptedException {
BluetoothManager manager = BluetoothManager.getBluetoothManager();
BluetoothDevice sensor = null;
for (int i = 0; (i < 15) && running; ++i) {
List 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;
}
После того, как нужное Bluetooth-устройство обнаружено, можно запустить процесс подключения к нему с помощью метода connect объекта, который ему соответствует. Вот как должен выглядеть тестовый вывод на данном этапе работы:
Found device: Address = C4:BE:84:72:2B:09 Name = CC2650 SensorTag Connected = false
Sensor with the provided address connected
Устройство, к которому мы подключаемся, должно давать доступ к службе определения температуры, UUID которой можно найти в документации. Служба, которая нам нужна, имеет короткий UUID AA00. Его нужно вставить в основной UUID TI вместо 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 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 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");
Теперь нужно включить службу определения температуры, записав »1» в характеристику конфигурации. Подробности об этом есть в вышеупомянутой документации. Можно изменить и интервал обновления показателей, записав нужное значение в характеристику периода, но значение по умолчанию,»1», нам подходит.
byte[] config = { 0x01 };
tempConfig.writeValue(config);
После настройки можно приступать к чтению с устройства сведений о температуре. Служба температуры возвращает данные в закодированном формате. Особенности работы с этим форматом данных можно найти в документации к SensorTag. Мы собираемся преобразовать полученные данные в градусы Цельсия и вывести их в консоль. Температура объекта, в соответствии с документацией, зависит от температуры окружающей среды. Здесь мы будем считать, что результаты без дополнительных преобразований нас устраивают.
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);
}
В процессе выполнения этого цикла будут выводиться сведения о температуре, полученные с Bluetooth LE-датчика:
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
Итоги
Мы рассказали о том, как писать на Java приложения, которые умеют работать с Bluetooth LE-устройствами. Надо отметить, что API, использованное в рассмотренном примере, основано на TinyB v0.3. Эта версия библиотеки поддерживает лишь работу в режиме опроса устройств, но в версии 0.4. представлено упрощённое API для обнаружения устройств и служб.
Надеемся, то, что вы сегодня узнали, поможет вам в разработке собственных IoT-проектов.
Комментарии (1)
5 июля 2016 в 16:30
0↑
↓
Здравствуйте, можно ли использовать библиотеку TinyB (java) не только работая с SensorTag, но и с Bluetooth адаптером встроенным в ноутбук или же Bluetooth адаптером подключаемым через usb?