When a former colleague - who is now working in the beacon industry - pointed me to Eddystone beacons, I was directly hooked. The reason being that the Eddystone specification is completely open and (relatively) easy to understand. For the tinkerer in me this was important, as now I could (cheaply) build my own.

Beacons

So what are beacons ? Beacons are simply put devices that transmits information (its location, unique id, an URL, sensor data, …) which then can be picked up by other devices. One application (of the many) could be distributing information at a specification point of interests e.g. aisle, room, venue, bus stop, … .

beacons.jpg

BLE (Bluetooth Low Energy)

The majority of beacons that are available today, are build around the Bluetooth Low Energy (BLE or sometimes also called Bluetooth Smart) specification.

The BLE specification targets devices that doesn’t need to constantly send big amounts of data, this results in lower power requirements. Some BLE devices can run for weeks, months or even years and that on a single battery.

BLE also has a particular feature called advertising mode. In advertising mode a BLE device repeatedly sends data packets (frames) at certain intervals. These packets can then be picked up and read by BLE compatible devices, for example smart phones, tablets, ….

Most beacons are using this mode to send out packets which contains a signature and some data. It’s based on that signature the receiving device can determine the packets came from a beacon or actively look (scan) for this kind of packets.

scanning.jpg

As a bonus it’s then possible to use the strength of the signal to determine the relative distance between the beacon and the receiver. And in the situation of having more than 2 beacons, you can even use triangulation to get a rough indication of your position.

From a pure technical low-level hardware point of view, a lot of beacons operate more or less in the same way. The only difference is the structure (and information) of the packets in question. That is why a lot of those systems can be an Eddystone beacon at one time and an Estimote at another time.

Eddystone

There are multiple beacon systems out there: iBeacon, Estimote, Harald,… just to name a few. But the one that I personally find the most interesting is Google’s Eddystone as it is completely open and (relatively) easy to understand.

One thing where Eddystone is different from iBeacons, is that it defines 3 types of frames (packets) it can send:

This is something that can easily be expanded in the future. As a matter of fact, if you look at the official specification you will see that 2 bytes (0x30 and 0x40) are reserved for (possible) future use.

It is also perfectly possible to extend Eddystone so you can implement your own type of frames with information that is relevant for your particular case.

Being completely open also means that from the hardware side we can build an Eddystone beacon ourselves. Something I personally did by using an Arduino and a BLE shield :-)

Eddy the arduino

My Arduino setup (see picture below) consists of an Arduino Uno in combination with the RedBearLab BLE shield and nothing more. The reason that I’ve chosen this particular shield is easy of use, documentation and good support from third party libraries.

But in principle every shield or breakout board that has a Nordic Semiconductor nRF8001 chip should - in theory - work.

arduino_redbearlab.jpg

The total cost of my setup is around 25 euro’s and mostly because I made the choice to use an Arduino clone instead of an official board, it is open hardware after all. You could go a bit cheaper if you use an Arduino Micro in combination with an Olimex MOD-nRF8001 breakout board.

The Arduino IDE doesn’t include libraries that support for the nRF8001 chip set, but fortunately there is an open source library that we can use: the arduino-BLEPeripheral library.

It also comes with some functions that makes it embarrassingly easy to transform our setup into a beacon that is able to send UUID or URL frames. Support for TLM frames is missing.

// Import libraries
#include <SPI.h>
#include <EddystoneBeacon.h>

// You need to change this if you use something
// other then the RedBearlab BLE shield
#define EDDYSTONE_BEACON_REQ   9
#define EDDYSTONE_BEACON_RDY   8
#define EDDYSTONE_BEACON_RST   UNUSED

EddystoneBeacon eddystoneBeacon = EddystoneBeacon(
    EDDYSTONE_BEACON_REQ,
    EDDYSTONE_BEACON_RDY,
    EDDYSTONE_BEACON_RST
);

void setup() {
  Serial.begin(9600);
  delay(1000);
  eddystoneBeacon.begin(-18, "http://www.simplicity.be");   
}


void loop() {
  eddystoneBeacon.loop();
}

I certainly didn’t lie if I said it was easy, feels a bit like cheating to be completely honest.

The only “difficulty” lays in determine the values for the REQ, RDY and RST parameters. You may need to refer to the documentation and use other values if you are using something other than the RedbearLab BLE shield.

Of course having a working Eddystone beacon is not enough. We will need a mobile app who can interact with our beacon. I even went a bit farther than usual and developed 3 mobile demo apps: one for android, one for iOS and one for Windows.

An Android app

As Eddystone has been developed by Google, it is an easy choice to start of with Android. It is also a mobile platform where I have some experience with.

Google has a proximity API available, but it involves registering my app with the Google Developer Console and that is something I don’t want at this point. I made the choice to use the Android Beacon Library instead.

This library includes support for different beacon systems including Eddystone and is used by some big brands like Coca Cola, McDonalds, Air france, …. At retrospect it was also an easy library to implement and work with. At max the build time of my android app took 1 hour.

The code isn’t as clean as its iOS or Windows counterparts, but it is comprehensible.

public class MainActivity extends AppCompatActivity
implements BeaconConsumer, RangeNotifier {

private BeaconManager beaconManager;


    /**
     * Search beacon
     */
    private void searchBeacon()
    {
        // init beacon manager
        beaconManager = BeaconManager.getInstanceForApplication(
            this.getApplicationContext()
        );

        // Detect the Eddystone URL frame:
        beaconManager.getBeaconParsers().add(
            new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v")
        );

        beaconManager.bind(this);
    }

    @Override
    public void onBeaconServiceConnect() {
        Region region = new Region("all-beacons-region", null, null, null);
        try {
            beaconManager.startRangingBeaconsInRegion(region);
        } catch (Exception e) {
            e.printStackTrace();
        }
        beaconManager.setRangeNotifier(this);
    }

    @Override
    public void didRangeBeaconsInRegion(Collection<Beacon> beacons,
    Region region) {
        for (Beacon beacon: beacons) {
            if (beacon.getServiceUuid() == 0xfeaa
            && beacon.getBeaconTypeCode() == 0x10) {

                // get id
                id = beacon.getBluetoothAddress();

                // update url
                url = UrlBeaconUrlCompressor.uncompress(
                    beacon.getId1().toByteArray()
                );

                // update string
                distance = beacon.getDistance();

                // update UI
                runOnUiThread(new Runnable() {
                    ...
                }
            }
        }
    }
}

Lets be swift and build and iOS app

Next up was Apple’s iOS, which was a bit of a challenge as I never done any serious iOS programming. Despite being an iOS user for some years now, I never really liked programming in Objective-C.

That is the main reason why I made the choice to write the app in Swift. It took me no time to get started and come up with something that worked. Off course an iOS library called eddystone-ios also helped me a bit.

This is the eddystone related iOS code:

import Eddystone

class ViewController: UIViewController,
                      Eddystone.ScannerDelegate {
...
var urls = Eddystone.Scanner.nearbyUrls
    ...
    /**
     * process eddystone info
     **/
    func processEddystoneInfo()
    {
        // check if urls has been found
        if(urls.count > 0){
            // update identifier
            lblEddystoneUUID.text = urls[0].identifier

            // update url
            lblEddystoneUrl.text =  urls[0].url.absoluteString

            // update strength //urls[0].signalStrength
            lblEddystoneStrength.text = String( urls[0].signalStrength)
        }

        // start scanning
        Eddystone.Scanner.start(self)
    }

    /**
     * Search button clicked
     **/
    @IBAction func searchButtonClicked(sender: AnyObject) {
        // start scanning
        Eddystone.Scanner.start(self)
    }

    /**
     * Executed when we detected changes
     **/
    func eddystoneNearbyDidChange() {
        // store scanned urls
        self.urls = Eddystone.Scanner.nearbyUrls

        // process urls
        self.processEddystoneInfo()
    }


}

Lets be a bit more universal and build a Windows App

Windows smartphones or tablets aren’t the most popular devices at this time, but as I have a Windows tablet (HP Stream 7) laying around I couldn’t resist it.

I made the choice to build a Universal Windows App, something I have never done before. I also opted to write it in C# as it is a language that I have programmed in one numerous occasions.

I also found a .NET beacon (Universal Beacon Library for Windows 10) which made the whole process rather painless. It took me one hour to build a basic working app that could find my Eddystone beacon.

The beacon related code is rather compact and self-explanatory:

/**
 * Default constructor
 **/
public MainPage()
{
    // init beacon manager
    beaconManager = new BeaconManager();

    // create and start the (W10 UWP) BLE watcher
    watcher = new BluetoothLEAdvertisementWatcher {
        ScanningMode = BluetoothLEScanningMode.Active
    };

    // trigger following method when we receive data
    watcher.Received += WatcherOnReceived;

    // start watching
    watcher.Start();
}

/**
 * Triggered when we receive data
 **/
private async void WatcherOnReceived(
    BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementReceivedEventArgs eventArgs
)
{
    // Let the library manager handle the advertisement to analyse
    // and store the advertisement
    beaconManager.ReceivedAdvertisement(eventArgs);
}

...

// iterate over beacons we have found
foreach (var bluetoothBeacon in beaconManager.BluetoothBeacons.ToList())
{
    // if the beacon is type eddystone
    if (bluetoothBeacon.BeaconType == Beacon.BeaconTypeEnum.Eddystone)
    {
        // update labels
        txtEddystoneID.Text = bluetoothBeacon.BluetoothAddressAsString;
        txtEddystoneRSSI.Text = bluetoothBeacon.Rssi.ToString();

        // iterate over frames
        foreach (var beaconFrame in bluetoothBeacon.BeaconFrames.ToList())
        {
            // be sure we are receiving an URL frame
            if (beaconFrame is UrlEddystoneFrame)
            {
                txtEddystoneURL.Text = ((UrlEddystoneFrame)beaconFrame).CompleteUrl;
            }
        }
    }
}

Other platforms

There is a cordova package called cordova-eddystone available, but in the last couple of months I have really developed a personal dislike for hybrid mobile platforms. So it may work… you need to test it yourself.

This is something I say under reservations as I’m not at the position to test it at this moment, but a raspberry pi (zero, if you ever find one) and a USB Bluetooth dongle with a CSR8510A10 chip could also be transformed in an Eddystone beacon. This is something that is definitely on my TODO.

Giving back

I have made the decision to give something back to the community and release everything as open source. The code (Arduino, Android, iOS and Windows) can be found on my github account.

Keep in mind that everything is released AS IS!