Everything is better with(out) Bluetooth - Droidcon 2018
Presentation at Droidcon 2018 by Ronaldo Pace and Falko Richter
Everything is better with(out) Bluetooth
Tells the story of struggle to connect to a bluetooth GATT peripheral, discover services, write a message and disconnect under 1 second.
and buildings interact ◦ Getting into a space is the first interaction ◦ Of course with your phone! ◦ Bluetooth LE really is the only common denominator for a reliable connection ▪ offline capable, fast, reliable* • Interactions currently: ◦ book a meeting room ◦ open a locker ◦ open the entrance ◦ open a garage * let´s talk later about reliablity
Attributes (GATT) define a hierarchical data structure that is exposed to connected Bluetooth Low Energy (LE) devices) ◦ Service ▪ Group of Characteristics ◦ Characteristic ▪ Write/ Read /Subscribe ▪ has a UUID • Descriptions availble on bluetooth.com ◦ https://www.bluetooth.com/specifications/gatt ◦ you can also make up your own!
BLE • open source / standard by nordic • https://learn.adafruit.com/introducing-adafruit-bl e-bluetooth-low-energy-friend/uart-service ◦ find (by Service) ◦ connect ◦ discover ◦ subscribe to Rx ◦ write to Tx Request ◦ wait for answer on Rx Response ◦ disconnect https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v14.0.0%2Fble_sdk_app_nus_eval. html
Some devices doesn’t support certain scan settings parameters • Some devices doesn’t support scan filters ◦ Some devices say they support scan filters, but result on callback never called • Workaround: ◦ Use Nordic Scanner compat https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library ◦ // disable hardware filtering .setUseHardwareFilteringIfSupported(false)
fun onScanResult(callbackType: Int, result: ScanResult) { • On some devices is called for every scan • on others, only on the first time a BLE device is scanned • Workaround is to startScan/stopScan every second • Starting on Android Nougat Developer Preview 4 > We’ve changed the BLE Scanning behavior starting in DP4. We’ll prevent applications from starting and stopping scans more than 5 times in 30 seconds. For long running scans, we’ll convert them into opportunistic scans. ◦ Sources: ▪ https://web.archive.org/web/20160820074825/https://developer.android.com/preview/support.html#dp4 ▪ https://android-review.googlesource.com/c/platform/packages/apps/Bluetooth/+/215844/15/src/com/android/bluet ooth/gatt/AppScanStats.java#144
val scanCallback = object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { scanResults[result.device.address] = result private fun openClosest() { val scanList = scanResults.values.filter { it.rssi >= threshold }.sortedBy { it.rssi } open(scanList[0]) } • rssi variance ◦ time dependent weighted moving average https://github.com/sensorberg-dev/motionless-average • on device learning of threshold variance ◦ start with a permissive default ◦ adjust with a moving average of the rssi during successful connection ◦ offset a few decibels for actual filtering
only works if called from UI-thread ◦ on some devices • override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (newState != BluetoothGatt.STATE_CONNECTED) // connect again • override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { ◦ if(status != GATT_SUCCESS) // retry ◦ if (status == 133) ▪ Source code: #define GATT_ERROR 0x0085
Scanning: ◦ NordicScannerCompat ◦ ScannerStartStop ◦ ScannerNougat ◦ Averaging algorithms ◦ Did you try turn off and on again? • Communicating: ◦ Synchronous API ◦ Retry on random fail ◦ Retry on random disconnection ◦ Did you try turn off and on again?
no filtering ◦ aggregations are to limited • Elasticsearch to the rescue ◦ account: 2 minutes https://www.elastic.co/cloud/elasticsearch-service/signup ◦ post JSON to your [...].aws.cloud.es.io:9243/{index}/mobile_statistics ◦ simple rules for data integrity ▪ never change a type (String becomes Number, String becomes Object) ▪ lower case all strings / remove spaces ▪ add UUIDs/hashes so you can count devices / users ▪ one index per deployment (production / staging) ◦ leave out personal data ◦ delete indexes (buckets) regularly @POST("/") @Headers("Content-Type: application/json") Call<String> pushStatistics(@Body Stats stats);
BTLE device is so close, I should connect to it”) ▪ NFC (nfc://connect/to/DF:96:C3:46:84:3A) ▪ Optical?! ▪ (magnetic) tap detection ◦ communication (try all, winner takes it all) ▪ Bluetooth ▪ HTTPS via wifi/cellular ▪ NFC (in the next generation of the hardware) ▪ synchronize with a request ID in backend or on access hub … how to avoid bluetooth
anymore) powered tracks (no battery) ◦ use two power modules for reliability - it will make the train go reliably slow! ▪ Schwerlastzug 60098 is great • You need to physically test it! ◦ real devices ◦ actual Bluetooth hardware ◦ use your statistics to verify the performance ◦ Long term testing • Parameters ◦ speed ◦ distance to device ◦ additional sensor to detect phone position ◦ power the train from the access hub => full control
https://github.com/sensorberg-dev/EasyIPC • https://github.com/sensorberg-dev/gradle-scripts • https://github.com/sensorberg-dev/android-sdk • soon: https://github.com/sensorberg-dev/synchronous-gatt We will of course make an SDK from this as well https://www.youtube.com/watch?v=rLuBxsLot5U Another Bluetooth related GDG talkby Falko https://www.youtube.com/watch?v=OSJ8gIPnvDw