Kotlin Beautiful Low Energy (BLE)

YLabZ
7 min readMar 1, 2020

--

Modern (Kotlin / Flow) Bluetooth Low Energy on Android

BLE 5.0

BLE is the gateway from mobile to the physical world

We can think of the mobile app as the brains and the BLE device as the body.

We use all the features of the mobile phone as the intelligence (CPU, WiFi, GPS, etc …) & I/O (Screen / keyboard) with the BLE device as the body. Today many apps use BLE to control everything from medical devices to vending machines.

BLE is one of the most important features of mobile development. Which makes is hard to believe that BLE is so difficult (exceptionally on the earlier versions of Android) to work with.

Official Android Docs:

Why is BLE so hard?

By all accounts working on the BLE tech stack on Android is a nightmare.

After tons of sleepless hours, I’ve conquered the challenge! I actually got data from the sensor! — Android BLE Engineer :-)

And

Android development is hard, and it’s no thanks to its relatively fragmented ecosystem and having a million OEM’s out there. Throw BLE — which is extremely hardware and Bluetooth spec. dependent! — into the mix and the platform’s behavior becomes unpredictable.

Checkout the section: Android has a lot to learn from iOS !!!

Lets look at some reasons why …

  1. The specs

BLE is very different than any other protocol (HTTP). We have lots of UUIDs and this is new to most people.

Here is a summary of key BLE terms and concepts from the developer guide.

Generic Attribute Profile (GATT) — The GATT profile is a general specification for sending and receiving short pieces of data known as “attributes” over a BLE link. All current Low Energy application profiles are based on GATT.

The Bluetooth SIG defines many profiles for Low Energy devices. A profile is a specification for how a device works in a particular application. Note that a device can implement more than one profile. For example, a device could contain a heart rate monitor and a battery level detector.

Attribute Protocol (ATT) — GATT is built on top of the Attribute Protocol (ATT). This is also referred to as GATT/ATT. ATT is optimized to run on BLE devices. To this end, it uses as few bytes as possible. Each attribute is uniquely identified by a Universally Unique Identifier (UUID), which is a standardized 128-bit format for a string ID used to uniquely identify information. The attributes transported by ATT are formatted as characteristics and services.

Characteristic — A characteristic contains a single value and 0-n descriptors that describe the characteristic’s value. A characteristic can be thought of as a type, analogous to a class.

Descriptor — Descriptors are defined attributes that describe a characteristic value. For example, a descriptor might specify a human-readable description, an acceptable range for a characteristic’s value, or a unit of measure that is specific to a characteristic’s value.

Service — A service is a collection of characteristics. For example, you could have a service called “Heart Rate Monitor” that includes characteristics such as “heart rate measurement.” You can find a list of existing GATT-based profiles and services on bluetooth.org.

Roles

Central vs. peripheral. This applies to the BLE connection itself. The device in the central role scans, looking for advertisement, and the device in the peripheral role makes the advertisement.

GATT server vs. GATT client. This determines how two devices talk to each other once they’ve established the connection.

The GATT server is the peripheral and the GATT client is the phone.

2. Java

We do not have the needed libraries to handle callbacks in a graceful way (ie. Coroutines, Channels and Flow).

3. Android

On Android, a Bluetooth device communicates with us via a BluetoothGattCallback which is hard to use because of the asynchronous timing needed to get it working correctly. These methods need to block the execution until onCharacteristicWrite is called back for the characteristic … yack!

But things have evolved and now much better/easier.

First we have Kotlin with Coroutines & Flow.

a new way of managing background threads that can simplify code by reducing the need for callbacks.

Kotlin makes working with BLE work like magic 🪄🪄🥳

Coroutines are a great tool for dealing with asynchronous calls. Combined with channels, we have here the perfect tools to communicate synchronously with a Bluetooth device.

BLE with Jetpack Arch Comp, Compose & Kotlin Channel / Flow

Modern Android development makes BLE not a complete nightmare 🎉. LOL

hings get even better because we have amazing libraries that use these features to make working with BLE a pleasure. We are no longer in the dark ages.

Amazing BLE (Kotlin / Coroutine) Libraries

These make life better by abstracting away all the complexly for us.

Kable — a new Kotlin multiplatform (Coroutines-powered) library that provides a simple/uniform Bluetooth Low Energy API. — Travis Wyatt

The JUUL Labs BLE framework allows us to work at a much higher abstraction and they even work with the Jetpack Android Architectural Components. (ModelView)

Just checkout this code snippet comparing the old and new ways.

The Java Old Way

This is from the office guide. Only a small code snippet is shown because the whole process would be too long … It’s literally like nine pages of code!

Java code to connect to a GATT server

Step1: Setup Adapter — Create a ListActivity to hold all the devices. For this we need to manage the threading, callback ‘leScanCallback’ and error conditions.

Step2: Find BLE Devices — Yet another callback we must implement, because this is how scan results are returned.

Step2: Connect GATT Server — Setup the ‘gattCallback’ various callback methods defined by the API. Looking at this code will make your head spin.

Step3: Call broadcastUpdate() — The callback has another level of complexity and more thread / error management.

Step4: Read BLE Attributes — Iterate through the server’s services and characteristics

Now lets make an unfair comparison looking at a project using Kable and a BLE SensorTag (CC2650STK SimpleLink™ Bluetooth low energy/Multi-standard SensorTag) using AndroidViewModel.

We launch a coroutine to start scanning. The scanner Flow(L51) provides a stream of Advertisement(L52) objects representing advertisements seen from nearby peripherals. When Flow collection is terminated(L54), scanning will stop. We filter(L55)for the `SensorTag` and collect(L56) the advertisement into the MutableStateFlow(L58) which uses data binding to update UI. (We will also do this example but with Jetpack Compose and Kotlin Flow :-)

https://github.com/JuulLabs/sensortag/blob/14dc04c1aa7eafdbcb6c2bbbc4ec063f9276c42e/app/src/androidMain/kotlin/features/scan/ScanViewModel.kt

How beautiful is this code … 😿(tears of joy)

This example uses our favorite BLE SensorTag.

https://www.ti.com/tool/CC2650STK

I personally like the JUUL Kable library but we have another awesome library.

Basic example makes a connection to a BluetoothDevice, reads a characteristic, then disconnects

As you can see these make working with BLE a pleasant experience.

Happy Beautiful Low Energy (BLE) coding in Kotlin!

Github code using Jetpack Compose and Kotlin Flow and BLE SensorTag is coming …

Here is our example App reading GATT Server with Kotlin Flow.

--

--