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

Connecting the Bean: the bumpy road of BLE on A...

Connecting the Bean: the bumpy road of BLE on Android

Slides for the presentation given at mdevcon 2015

Hugo Visser

March 06, 2015
Tweet

More Decks by Hugo Visser

Other Decks in Technology

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 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 SDK for OS X and iOS 5
  8. The bumpy road of BLE on Android LightBlue Bean Unofficial

    Android SDK bitbucket.org/littlerobots/beanlib 6
  9. The bumpy road of BLE on Android LightBlue Bean Unofficial

    Android SDK bitbucket.org/littlerobots/beanlib 6
  10. The bumpy road of BLE on Android 8 Bluetooth Low

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

    Protocol Peripheral is advertising it’s presence Observer scans for peripherals
  12. The bumpy road of BLE on Android 10 Generic Attribute

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

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

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

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

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

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

    Platform API since Android 4.3 (API 18) Part of bluedroid
  19. The bumpy road of BLE on Android 14 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"/> Optionally require Bluetooth BLE
  20. The bumpy road of BLE on Android 15 First steps

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

    Get the Bluetooth Adapter BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); (but…this also works) mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  22. The bumpy road of BLE on Android 17 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
  23. The bumpy road of BLE on Android Find me a

    device BluetoothAdapter. startLeScan() and LeScanCallback 18 public boolean startLeScan (BluetoothAdapter.LeScanCallback callback)
  24. 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) 19
  25. The bumpy road of BLE on Android Small bump #2

    How many callbacks per device? a) One b) Many c) It depends 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 Find me type

    of device public boolean startLeScan (UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) 22
  28. 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 23
  29. 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 25
  30. 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! } }); 26
  31. The bumpy road of BLE on Android *one more thing

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

    connection to the peripheral Don’t forget to close() when done, manage reference carefully! 29
  33. 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 30
  34. 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 31
  35. 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(); } } }); 32
  36. 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+ 33
  37. 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(); } } 34
  38. 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(); } } 35
  39. The bumpy road of BLE on Android Profit! @Override public

    void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // handle updated value } 36
  40. 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 37
  41. 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! } 38
  42. 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 39
  43. 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 40
  44. 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 41
  45. The bumpy road of BLE on Android Learn more bitbucket.org/littlerobots/beanlib

    d.android.com/guide/topics/connectivity/bluetooth-le.html DutchAUG Bluetooth workshop - 17th of “Appril" www.dutchaug.org 42