Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Connecting the Bean: the bumpy road of BLE on Android

Connecting the Bean: the bumpy road of BLE on Android

Slides from my talk at the Android Developer Days in Ankara

Hugo Visser

May 09, 2015
Tweet

More Decks by Hugo Visser

Other Decks in Programming

Transcript

  1. Connecting the bean: The bumpy road of BLE on Android

    Hugo Visser Little Robots source: https://www.flickr.com/photos/klaasjan/6295632164
  2. The bumpy road of BLE on Android LightBlue Bean 3

    Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean
  3. The bumpy road of BLE on Android LightBlue Bean 3

    Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean
  4. The bumpy road of BLE on Android LightBlue Bean 3

    Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean
  5. The bumpy road of BLE on Android LightBlue Bean BLE

    “serial” protocol Control LED & Arduino Read sensors & configuration 4
  6. The bumpy road of BLE on Android LightBlue Bean BeanLoader

    for OS X LightBlue for iOS BeanLoader of iOS BeanLoader for Windows (2015) SDK for OS X and iOS 5
  7. The bumpy road of BLE on Android LightBlue Bean BeanLoader

    for OS X LightBlue for iOS BeanLoader of iOS BeanLoader for Windows (2015) SDK for OS X and iOS 5
  8. The bumpy road of BLE on Android LightBlue Bean Unofficial

    Android SDK est. July 2014 bitbucket.org/littlerobots/beanlib MIT License 6
  9. The bumpy road of BLE on Android LightBlue Bean Unofficial

    Android SDK est. July 2014 bitbucket.org/littlerobots/beanlib MIT License 6
  10. The bumpy road of BLE on Android Beanloader! Official Android

    app by Punch Through Released end of April 2015 7
  11. The bumpy road of BLE on Android 9 Bluetooth Low

    Energy Branded: Bluetooth Smart Low power, low transmission rate (1 Mbps) Sports & fitness, health care, keyboards and mice, beacons, wearables, …
  12. The bumpy road of BLE on Android 10 Generic Access

    Profile Peripheral is advertising it’s presence Observer scans for peripherals
  13. The bumpy road of BLE on Android 11 Generic Attribute

    Profile Profiles Services Characteristics
  14. The bumpy road of BLE on Android Profile Service Characteristic

    Characteristic Service Characteristic 11 Profiles Services Characteristics GATT
  15. The bumpy road of BLE on Android 12 UUIDs Unique

    identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de 0000180F-0000-1000-8000-00805F9B34FB Reserved base UUID 00002A19-0000-1000-8000-00805F9B34FB
  16. The bumpy road of BLE on Android 12 UUIDs Unique

    identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de Reserved base UUID 0000180F-0000-1000-8000-00805F9B34FB 00002A19-0000-1000-8000-00805F9B34FB
  17. The bumpy road of BLE on Android 12 UUIDs Unique

    identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de Reserved base UUID 180F 2A19
  18. The bumpy road of BLE on Android 13 What about

    beacons? Formatted advertisement packets iBeacon, UriBeacon, proprietary Use rssi to determine distance
  19. The bumpy road of BLE on Android 14 Android BLE

    Platform API since Android 4.3 (API 18) Part of bluedroid
  20. The bumpy road of BLE on Android 15 First steps

    Declare permissions in AndroidManifest.xml <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> Require Bluetooth BLE if essential to the app
  21. The bumpy road of BLE on Android 16 First steps

    Check for BLE support if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { // awww snap :( No LE support }
  22. The bumpy road of BLE on Android 17 First steps

    Get the Bluetooth Adapter BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); (but…this also works) mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  23. The bumpy road of BLE on Android 18 First steps

    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } Check that bluetooth is enabled
  24. The bumpy road of BLE on Android Find me a

    device BluetoothAdapter. startLeScan() and LeScanCallback 19 public boolean startLeScan (BluetoothAdapter.LeScanCallback callback)
  25. The bumpy road of BLE on Android Small bump #1

    What does false mean? Most likely: Bluetooth is disabled (but you checked) Or…infamous bugs (check logcat) 20
  26. The bumpy road of BLE on Android Small bump #2

    How many callbacks per device? a) One b) Many c) It depends 21
  27. The bumpy road of BLE on Android Small bump #2

    How many callbacks per device? a) One b) Many c) It depends 22
  28. The bumpy road of BLE on Android Find me type

    of device public boolean startLeScan (UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) 23
  29. The bumpy road of BLE on Android Find me type

    of device public boolean startLeScan (UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) Does not work with 128 bit UUIDs Solution: DIY filtering stackoverflow.com/questions/18019161/startlescan-with-128-bit- uuids-doesnt-work-on-native-android-ble-implementation 24
  30. The bumpy road of BLE on Android BluetoothLeScanner Filtering Batching

    of results* Power modes* ParcelUuid uuid = ParcelUuid.fromString("a495ff10-c5b1-4b44-b512-1370f02d74de"); BluetoothManager bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); BluetoothAdapter adapter = bm.getAdapter(); ScanFilter scanFilter = new Builder().setServiceUuid(uuid).build(); ScanSettings settings = new ScanSettings.Builder().build(); * this asterix might spoil the party 26
  31. The bumpy road of BLE on Android BluetoothLeScanner adapter.getBluetoothLeScanner().startScan(singletonList(scanFilter), settings,

    new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { // process the result, there's currently only one callbackType defined } @Override public void onBatchScanResults(List<ScanResult> results) { // terms and conditions apply } @Override public void onScanFailed(int errorCode) { // handle error based on the errorCode! } }); 27
  32. The bumpy road of BLE on Android *one more thing

    Power modes & batching require hardware support 28
  33. The bumpy road of BLE on Android BluetoothGatt Manages the

    connection to the peripheral Don’t forget to close() when done, manage reference carefully! 30
  34. The bumpy road of BLE on Android Auto connect? Advice

    against using autoConnect = true Behaviour is unclear Disconnect to cancel does not work on 4.3 Recommendation: manage (re)connection in your app 31
  35. The bumpy road of BLE on Android BluetoothGattCallback Typical sequence:

    1. onConnectionStateChange() 2. call discoverServices() 3. onServicesDiscovered() 4. read / write characteristics and / or subscribe to updates 5. close() when done 32
  36. The bumpy road of BLE on Android Connection & discovery

    BluetoothDevice device = ... // obtained from scanning device.connectGatt(this, false, new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothGatt.STATE_CONNECTED) { if (!gatt.discoverServices()) { // requesting service failed, make sure we clean up gatt.close(); } } } else { // connection failed, clean up gatt.close(); } } public void onServicesDiscovered(BluetoothGatt gatt, int status) { // find the service we like to use mSerialService = gatt.getService(BEAN_SERIAL_CHARACTERISTIC_UUID); if (mSerialService == null) { // service is not found, close the client gatt.close(); } } }); 33
  37. The bumpy road of BLE on Android Not in the

    docs Limited amount of LE connections (total!) 4 connections on 4.3 7 on 4.4+ 34
  38. The bumpy road of BLE on Android Characteristics public void

    onServicesDiscovered(BluetoothGatt gatt, int status) { BluetoothGattCharacteristic characteristic = service.getCharacteristic(BEAN_SERIAL_CHARACTERISTIC_UUID); if (!gatt.readCharacteristic(characteristic)) { gatt.close(); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { byte[] value = characteristic.getValue(); String stringValue = characteristic.getStringValue(0); } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { boolean bonding = gatt.getDevice().createBond(); // note: API 19 gatt.close(); } else { gatt.close(); } } 35
  39. The bumpy road of BLE on Android Notifications public void

    onServicesDiscovered(BluetoothGatt gatt, int status) { BluetoothGattService service = gatt.getService(UUID.fromString("a495ff10-c5b1-4b44-b512-1370f02d74de")); BluetoothGattCharacteristic characteristic = service.getCharacteristic(BEAN_SERIAL_CHARACTERISTIC_UUID); if (characteristic == null) { gatt.close(); return; } if (gatt.setCharacteristicNotification(characteristic, true)) { UUID descriptorUuid = UUID.fromString("2902-0000-1000-8000-00805f9b34fb"); // remember? BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descriptorUuid); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); if (!gatt.writeDescriptor(descriptor)) { gatt.close(); } } } public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if (status != BluetoothGatt.GATT_SUCCESS) { gatt.close(); } } 36
  40. The bumpy road of BLE on Android Profit! @Override public

    void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // handle updated value } 37
  41. The bumpy road of BLE on Android Notification limits There’s

    a hard limit on the number of notifications you can have: 4 on Android 4.3 7 on Android 4.4 15 on Android 5 38
  42. The bumpy road of BLE on Android Writing characteristics public

    void write(byte[] data) { mCharacteristic.setValue(data); if (!mGatt.writeCharacteristic(mCharacteristic)) { mGatt.close(); } // important: wait for onCharacteristicWrite callback before attempting the next write! } 39
  43. The bumpy road of BLE on Android Juggling writes By

    design the Bean SDK does a lot of writing Split data in 20 byte packets, write to characteristic Assemble packets from notifications Single characteristic for read/write makes it harder 40
  44. The bumpy road of BLE on Android Conclusions Android has

    full support for BLE, maturing in Lollipop The BLE related API’s are is a really low level Error checking all over the place Documentation could use some work 41
  45. The bumpy road of BLE on Android Observations Complexity managing

    multiple characteristics in a single callback. Low level interface seems straightforward, but is difficult to get right. Bean SDK has GattClient to solve some of those problems 42
  46. The bumpy road of BLE on Android Learn more bitbucket.org/littlerobots/beanlib

    d.android.com/guide/topics/connectivity/bluetooth-le.html punchthrough.com/bean 43
  47. The bumpy road of BLE on Android Thank you @botteaap

    google.com/+hugovisser www.littlerobots.nl 44