import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.tinyb.BluetoothDevice; import org.tinyb.BluetoothException; import org.tinyb.BluetoothFactory; import org.tinyb.BluetoothGattCharacteristic; import org.tinyb.BluetoothGattService; import org.tinyb.BluetoothManager; import org.tinyb.HCIStatusCode; public class HelloTinyB { static boolean running = true; static void printDevice(final BluetoothDevice device) { System.out.print("Address = " + device.getAddress()); System.out.print(" Name = " + device.getName()); System.out.print(" Connected = " + device.getConnected()); System.out.println(); } static float convertCelsius(final int raw) { return raw / 128f; } /* * 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 the look through the list of devices to find the device with the MAC which we provided * as a parameter. We continue looking until we find it, or we try 15 times (1 minutes). */ static BluetoothDevice getDevice(final BluetoothManager manager, final String address) throws InterruptedException { BluetoothDevice sensor = null; for (int i = 0; (i < 15) && running; ++i) { final List list = manager.getDevices(); if (list == null) return null; for (final 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; } /* * 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: f000XXXX-0451-4000-b000-000000000000 */ static BluetoothGattService getService(final BluetoothDevice device, final String UUID) throws InterruptedException { System.out.println("Services exposed by device:"); BluetoothGattService tempService = null; List bluetoothServices = null; do { bluetoothServices = device.getServices(); if (bluetoothServices == null) return null; for (final BluetoothGattService service : bluetoothServices) { System.out.println("UUID: " + service.getUUID()); if (service.getUUID().equals(UUID)) tempService = service; } Thread.sleep(4000); } while (bluetoothServices.isEmpty() && running); return tempService; } static BluetoothGattCharacteristic getCharacteristic(final BluetoothGattService service, final String UUID) { final List characteristics = service.getCharacteristics(); if (characteristics == null) return null; for (final BluetoothGattCharacteristic characteristic : characteristics) { if (characteristic.getUUID().equals(UUID)) return characteristic; } return null; } /* * This program connects to a TI SensorTag 2.0 and reads the temperature characteristic exposed by the device over * Bluetooth Low Energy. The parameter provided to the program should be the MAC address of the device. * * A wiki describing the sensor is found here: http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide * * The API used in this example is based on TinyB v0.3, which only supports polling, but v0.4 will introduce a * simplied API for discovering devices and services. */ public static void main(final String[] args) throws InterruptedException { if (args.length < 1) { System.err.println("Run with argument"); System.exit(-1); } /* * To start looking of the device, we first must initialize the TinyB library. The way of interacting with the * library is through the BluetoothManager. There can be only one BluetoothManager at one time, and the * reference to it is obtained through the getBluetoothManager method. */ final BluetoothManager manager; try { manager = BluetoothFactory.getDBusBluetoothManager(); } catch (BluetoothException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) { System.err.println("Failed to initialized "+BluetoothFactory.DBusImplementationID); throw new RuntimeException(e); } /* * The manager will try to initialize a BluetoothAdapter if any adapter is present in the system. To initialize * discovery we can call startDiscovery, which will put the default adapter in discovery mode. */ @SuppressWarnings("deprecation") final boolean discoveryStarted = manager.startDiscovery(); System.out.println("The discovery started: " + (discoveryStarted ? "true" : "false")); final BluetoothDevice sensor = getDevice(manager, args[0]); /* * After we find the device we can stop looking for other devices. */ try { manager.stopDiscovery(); } catch (final BluetoothException e) { System.err.println("Discovery could not be stopped."); } if (sensor == null) { System.err.println("No sensor found with the provided address."); System.exit(-1); } System.out.print("Found device: "); printDevice(sensor); if ( HCIStatusCode.SUCCESS == sensor.connect() ) System.out.println("Sensor with the provided address connected"); else { System.out.println("Could not connect device."); System.exit(-1); } final Lock lock = new ReentrantLock(); final Condition cv = lock.newCondition(); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { running = false; lock.lock(); try { cv.signalAll(); } finally { lock.unlock(); } } }); final BluetoothGattService tempService = getService(sensor, "f000aa00-0451-4000-b000-000000000000"); if (tempService == null) { System.err.println("This device does not have the temperature service we are looking for."); sensor.disconnect(); System.exit(-1); } System.out.println("Found service " + tempService.getUUID()); final BluetoothGattCharacteristic tempValue = getCharacteristic(tempService, "f000aa01-0451-4000-b000-000000000000"); final BluetoothGattCharacteristic tempConfig = getCharacteristic(tempService, "f000aa02-0451-4000-b000-000000000000"); final BluetoothGattCharacteristic tempPeriod = getCharacteristic(tempService, "f000aa03-0451-4000-b000-000000000000"); if (tempValue == null || tempConfig == null || tempPeriod == null) { System.err.println("Could not find the correct characteristics."); sensor.disconnect(); System.exit(-1); } System.out.println("Found the temperature characteristics"); /* * Turn on the Temperature Service by writing 1 in the configuration characteristic, as mentioned in the PDF * mentioned above. We could also modify the update interval, by writing in the period characteristic, but the * default 1s is good enough for our purposes. */ final byte[] config = { 0x01 }; tempConfig.writeValue(config, false /* withResponse */); /* * Each second read the value characteristic and display it in a human readable format. */ while (running) { final byte[] tempRaw = tempValue.readValue(); System.out.print("Temp raw = {"); for (final byte b : tempRaw) { System.out.print(String.format("%02x,", b)); } System.out.print("}"); /* * The temperature service returns the data in an encoded format which can be found in the wiki. Convert the * raw temperature format to celsius and print it. Conversion for object temperature depends on ambient * according to wiki, but assume result is good enough for our purposes without conversion. */ final int objectTempRaw = (tempRaw[0] & 0xff) | (tempRaw[1] << 8); final int ambientTempRaw = (tempRaw[2] & 0xff) | (tempRaw[3] << 8); final float objectTempCelsius = convertCelsius(objectTempRaw); final float ambientTempCelsius = convertCelsius(ambientTempRaw); System.out.println( String.format(" Temp: Object = %fC, Ambient = %fC", objectTempCelsius, ambientTempCelsius)); lock.lock(); try { cv.await(1, TimeUnit.SECONDS); } finally { lock.unlock(); } } sensor.disconnect(); } }