Before developing an android application using an external device, a detailed knowledge of the device is essential. In this case, it is important to know what an iBeacon actually does, how reliable it is, and how to properly incorporate its functionality within an android application.

Identifying iBeacons

iBeacons are Bluetooth Low Energy (BLE) devices that transmit advertising packets. Each advertising packet contains 3 main parameters:

  1. Universally Unique Identifier (UUID)
  2. Major
  3. Minor

UUID contains 32 hexadecimal digits and is used to distinguish a group of iBeacons from other beacons or BLE devices that are within range. Major is used to identify a subgroup of beacons and Minor identifies a specific beacon. To find out these parameters in android, download an android BLE scanner application and look for an id similar to e2c56db5-dffb-48d2-b060-d0f5a71096e0. This is the UUID of the iBeacon which will be used in this example.

iBeacon Calibration

In order to scan for iBeacons in an android app, the Android Beacon Library will be used. This library provides the means to output Received Signal Strength Indicator (RSSI) levels as well as the distance between the iBeacon and the android device. The lower the transmitter power of the iBeacon is, the error in distance calculation will be greater. Therefore, it is recommended that the transmitter power is set to strongest if possible.

Why is calibration necessary

The iBeacon was physically placed at different distances from the device, then for every distance, average RSSI values were measured and then plotted for analysis. Ideally, the result would be a linear function. However, Bluetooth is susceptible to interference, so it is not surprising that the result is actually not an ideal one. The function extrema are also noticeably far from the trendline. If the transmitting power of the iBeacon were greater, the result would have been closer to the ideal linear function with better distance accuracy.

Distance axis does not show correct distances. For example, the sixth measurement shows that the beacon was 102cm away from the device when in fact it was 240cm away.

Calibrating the Beacon

The results from measuring only the RSSI values and plotting them with actual distances of the iBeacon from the device are shown below.

Much closer to the ideal linear function.

Considering average RSSI values greater than -69.2 becomes impractical because the function above would produce two distance values. Since there is no means of determining which of the two distance values to take as the final result, RSSI values greater than -69.2 will be omitted. Therefore, the final function used when calculating the distance between the android device and the beacon is shown below.

The function used to calculate distance from given RSSI value.

The distance is calculated by finding two points whose RSSI is less than and greater than the RSSI value received by the iBeacon. Next, find the equation between two points and input the received RSSI value. The result can still be affected by interference, so it is recommended to take several RSSI values before making distance calculations.

Service Implementation

Firstly, create a function to return distance. This function creates an equation between two points.

private String calculateDistance(double averageRSSI, double x1, double y1, double x2, double y2) {
    double slope = (y2 - y1) / (x2 - x1);
    double b = y2 - slope * x2;
    Double distance = slope * averageRSSI + b;
    return distance.toString();
}

Next, define beaconManager in onStartCommand(…) and implement BeaconConsumer methods.

public class BeaconService extends Service implements BeaconConsumer{

    /*	 
    …
    …
    …
    */

    //Points from the final chart
    //Notice: axes here are inverted
    private final int numPoints = 6;
    private final double[] beaconRSSI = {-35, -48.4, -55.8, -61.12, -62.56, -69};
    private final double[] beaconDistance = {0, 65, 99, 149, 209, 238};

    /*	
    …
    … 
    …
    */

    @Override
    public void onBeaconServiceConnect() {
        beaconManager.addRangeNotifier(new RangeNotifier() { @Override
            public void didRangeBeaconsInRegion(Collection collection, Region region) {

                if (collection.size() > 0) {
                    currCalculation++;
                    sumRSSI += collection.iterator().next().getRssi();
                    if(maxCalculations == currCalculation){ 
                        Log.d("Tag", "Distance: " + e(sumRSSI/maxCalculations));
                        currCalculation = 0;
                        sumRSSI = 0;
                     }
                 }
             }
        });
        try {
            beaconManager.startRangingBeaconsInRegion(beaconRegion);
        } catch (RemoteException e) { 
            e.printStackTrace();
        }
    }

    private String getDistance(double averageRSSI) { 
        if(averageRSSI > beaconRSSI[0]) return "0"; 
        for(int i = 0; i < numPoints - 1; i++) {
            if(averageRSSI <= beaconRSSI[i] && averageRSSI >= beaconRSSI[i + 1])
                return calculateDistance(averageRSSI, beaconRSSI[i], beaconDistance[i], beaconRSSI[i + 1], beaconDistance[i + 1]);
        }
        //if averageRSSI is less than -69
        return "Too far";
    }
}

This service constantly scans for iBeacons with given UUID in range. Doing this is not viable for actual applications since it significantly impacts the battery on an android device. In order to overcome this problem, it is recommended that you increase the scan period or start the service only when absolutely required and then stop it when done.

Decorator pattern
Software DevelopmentTech Bites
January 23, 2023

Decorator pattern

Design patterns are typical solutions to common problems in software design. Each pattern is like a blueprint that you can customize to solve a particular design problem in your code. A decorator pattern allows users to add new functionality to an existing object without altering its structure. This design pattern comes under…
JPA annotations in Hibernate
Software DevelopmentTech Bites
January 5, 2023

JPA annotations in Hibernate

Suppose you have wondered how we interact with relational databases without (directly) using SQL queries. In that case, the answer usually lies in Object-Relational Mapping (ORM), which will do the job of converting Java objects and statements to database tables and related queries. Hibernate comes into this story as the…
Dynamic programming
Software DevelopmentTech Bites
December 9, 2022

Dynamic Programming

Dynamic programming is both a mathematical optimization method and a computer programming method. By definition, it is a technique in computer programming that helps to efficiently solve a class of problems with overlapping subproblems and optimal substructure properties. It refers to simplifying a complicated problem by breaking it into simpler…

Leave a Reply