Scanning Bluetooth Low Energy beacons with Gluon Charm Down


amber_devices_2Charm Down is a Gluon open source project with the purpose of creating a common API for accessing native services on mobile devices when developing JavaFX projects.

We have recently blogged about it, and you can find the code here, and the documentation here.

Now we are adding a new service: a Bluetooth Low Energy API to scan for beacons. For now it is available in the latest snapshot.

BLE and beacons

Bluetooth Low Energy (BLE), a wireless personal area network technology, while providing the same range of communications as classic bluetooth, considerably reduces the power consumption and cost.

Based on this principle, beacons are small wireless devices designed to transmit a simple radio signal continuously, which can be received by nearby smartphones. They transmit only their ID and their signal power, and the smartphone can read those values and estimate the distance to that device.

Among other uses, one of the possible applications for it is for proximity sensing: physical proximity to certain devices equipped with this technology can be estimated based on their radio receiver’s rssi value. This allows for indoor positioning, indoor behavior tracking, in-store interaction between customers and retailers, indoor navigation, and so on.

iBeacons and other beacon protocols

iBeacon is a brand name created by Apple in 2014, a new location technology that lets any phone using iOS7 or newer constantly scan the environment for BLE devices such as beacons. It is a proprietary, closed standard. Other standards like AltBeacon are open. Google launched Eddystone, its open source beacon, in 2015.

Hardware

If you want to use this technology in production, you will need real beacons equipped with BLE, and implementing one of the mentioned protocols. Those are small devices that can be purchased online from different vendors like Estimote, Kontakt or Gimbal. You can find an extensive list of vendors here.

For development, you can simulate a beacon with different apps on Android and iOS.

How to use the Charm Down BLE services

The Charm-Down-Common API provided for beacon detection in Charm Down consists of two classes: `Configuration` and `ScanDetection` and, and one service `BleService`.

Use `Configuration` to set the UUID of the group of devices with that same ID that will be scanned.

When a beacon is detected, an instance of `ScanDetection` is created that provides the UUID, major and minor id, rssi, and proximity (unknown, far, near, immediate).

To use the service, you only need to provide a callback to process the `ScanDetection` object that will be returned from the scan implementation.
The following code snippet does everything that is required to be notified of the presence of beacons with the provided UUID.

BleService bleService = PlatformFactory.getPlatform().getBleService();
Configuration conf = new Configuration("74278BDA-B644-4520-8F0C-720EAF059935");
Consumer callback = (ScanDetection t) -> {
    Platform.runLater(() -> {
        System.out.println("Got result: " + t + " with major = " + t.getMajor() + " and minor = " + t.getMinor());
        // do some UI operations
    });
};

// run
bleService.startScanning(conf, callback);

// stop
bleService.stopScanning();                        

Note that the callback handler is called on a non-JavaFX Thread. Hence, if you want to update user interface components, you have to call `Platform.runLater()` as shown in the code snippet.

Requirements

It is mandatory that Android apps leveraging the `BleService` add these permissions to the AndroidManifest file:



It is mandatory that iOS apps making use of the `BleService` add these keys to the property list file:

NSLocationUsageDescription
This app needs location services
NSLocationWhenInUseUsageDescription
This app needs location services

Beacons Sample

In the Gluon repository you will find Beacons, a new sample implementing a JavaFX application with Gluon Mobile for the UI and BleService functionality. We have a few screenshots further below in this blog post.

The BleService will be included in the next release of Charm-Down. For now, you can use the snapshot version that is available as well.

In the `build.gradle` file, we declare a dependency on the snapshot version of charm-down:

repositories {
    jcenter()
    mavenLocal()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases/'
    }
}

dependencies {
    compile 'com.airhacks:afterburner.mfx:1.6.2'
    
    compile 'com.gluonhq:charm-down-common:1.0.1-SNAPSHOT'
    androidRuntime 'com.gluonhq:charm-down-android:1.0.1-SNAPSHOT'
    desktopRuntime 'com.gluonhq:charm-down-desktop:1.0.1-SNAPSHOT'
    iosRuntime 'com.gluonhq:charm-down-ios:1.0.1-SNAPSHOT'
    
    compile "com.gluonhq:charm-glisten:1.0.0"
    androidRuntime "com.gluonhq:charm-glisten-android:1.0.0"
    iosRuntime "com.gluonhq:charm-glisten-ios:1.0.0"
    desktopRuntime "com.gluonhq:charm-glisten-desktop:1.0.0"
}

We created a single home view, with a start and stop button, and some labels to show the beacon values. Also three circles will inform about its proximity (unknown, far, near or immediate).

By default, the app will be scanning for this UUID: “74278BDA-B644-4520-8F0C-720EAF059935”.

The AndroidManifest.xml file in the sample already includes the bluetooth required permissions.
The Default-Info.plist file in the iOS directory in the sample, includes the key `NSLocationWhenInUseUsageDescription` to require location services. You can change its description.

Beacons App

Beacons App

Testing the app

Clone, build and install the app on your device, and if you don’t have a real beacon, install Locate on a different device (Locate for Android, Locate for iOS), set the same UUID this app, and start transmitting. As you can see in the picture below, you can modify the major, minor and power settings, and you will see these new values on the Beacons app.

Locate app

Locate app

Notice that if bluetooth is not enabled, a popup will ask you to enable it (both in iOS and Android), and for iOS, the first time you click on the start scanning button, a popup will ask you to enable location services. This can be changed in Settings -> Security -> Location.

Implementation Details

Under the hood, Charm Down creates the implementation for accessing native bluetooth services on Android and iOS, so developers don’t need to worry about this.

Beacon Protocol

Beacons transmit small amounts of data. Beacon IDs consists of a maximum of three values: A universally unique identifier (UUID), a major value and a minor value. Every beacon also transmits information about its signal power.

According to the Bluetooth core specification, a beacon advertises a data package called the Scan Response Data. The scan response is divided into what are called AD structures.

Usually, these will be the 31 bytes sent by the beacon on every transmission, corresponding to two AD structures:

Scan Response Data. Source: https://www.pubnub.com/blog/2015-04-14-building-android-beacon-android-ibeacon-tutorial-overview/

Android

Android API provides a Bluetooth adapter, and a BLE scanner:

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeScanner scanner = adapter.getBluetoothLeScanner();
scanner.startScan(new ScanCallback() {
    @Override public void onScanResult(int callbackType, ScanResult result) {
        ScanRecord scanRecord = result.getScanRecord();
        // process scanRecord
    }
});

The resulting `ScanRecord` object can be processed following the mentioned bytes structure to obtain a `ScanDetection` instance that can be passed finally to the service callback.

ScanDetection detection = processAD(scanRecord.getBytes());
callback.accept(detection);

iOS

iBeacon is closed protocol, but iOS7+ provides a Location framework for dealing with different location services like GPS and beacons. A `CLBeaconRegion` object defines a type of region that is based on the device’s proximity to a Bluetooth beacon.

While a beacon is in range, the `startRangingBeaconsInRegion` method is used to begin receiving notifications when the relative distance to the beacon changes.

These notifications will be received through the `locationManager:didRangeBeacons:inRegion` method, returning an array of `CLBeacon` with the beacons in range, sorted by proximity. Selecting the first one on that array allows generating a `ScanDetection` instance that can be passed to the service callback.

Conclusions

The functionality we provided in Charm-Down is currently very basic, but it allows you to see how easy it is to use Bluetooth Low Energy devices and detections in a Java Client Application.
There are more usecases for BLE applications, and we encourage developers to create pull requests if you want to contribute to Charm-Down development.

If you have a commercial use case, you can get in touch with us as well.