Search code examples
androidibeaconeddystoneandroid-ibeacon

How Catch separate Eddystone Frames


I'm developing an Eddystone Library Parser. The nodal point I didn't understand is this:

I use this callback to get the data from the beacon:

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
        new BluetoothAdapter.LeScanCallback() {

    @Override
    public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
        runOnUiThread(new Runnable() {
               @Override
               public void run() {
                  ...

I get in byte[] scanRecords the bytes from the beacon. What I didn't understand is how Eddystone beacons behaves. Do they call onLeScan callback every time for every frame the beacon transmits or do they call the callback only once with all the frames inside the scanrecord ? If onLeScan is called multiple times how can I make the difference and separate the frames that was sent from the same beacon from the frames from other beacons in the same field ?


Solution

  • Each Eddystone frame will be in its own scan record and will get its own callback to onLeScan. For the case of multiple frames (e.g. combining Eddystone-TLM to Eddystone-UID), you need some way of knowing the two are from the same physical beacon.

    The typical way of doing this is using the bluetooth MAC address, which is unique for each hardware transmitter. You can find this address using the BluetoothDevice object, with device.getAddress(), which will return a String of the form: aa:bb:cc:00:11:22, where each segment is a one byte hex component of the 6 byte bluetooth MAC address.

    OPTIONAL You can also decide if you want to combine frames like Eddystone-TLM with non-Eddystone beacon frames like iBeacon or AltBeacon. If you do not wish to do this, then you also wan to make sure the frame has an Eddystone Service UUID before combining them.

    This is the technique that I used to combine Eddystone frames using the open-source Android Beacon Library. You can see the source code of the implementation in the ExtraBeaconDataTracker class here: https://github.com/AltBeacon/android-beacon-library/blob/master/src/main/java/org/altbeacon/beacon/service/ExtraDataBeaconTracker.java This class also implements the optional part described above using the matchBeaconsByServiceUUID variable.

    When using the Android Beacon Library, this is all automatic. an you can simply access the extra frames (like Eddystone-TLM) from a given beacon with beacon.getExtraDataFields(). Here is an example of how that works:

        if (beacon.getExtraDataFields().size() > 0) {
                    long telemetryVersion = beacon.getExtraDataFields().get(0);
                    long batteryMilliVolts = beacon.getExtraDataFields().get(1);
                    long pduCount = beacon.getExtraDataFields().get(3);
                    long uptime = beacon.getExtraDataFields().get(4);
    
                    Log.d(TAG, "The above beacon is sending telemetry version "+telemetryVersion+
                            ", has been up for : "+uptime+" seconds"+
                            ", has a battery level of "+batteryMilliVolts+" mV"+
                            ", and has transmitted "+pduCount+" advertisements.");
    
         }
    

    I realize you are trying to roll your own, so I offer the above implementation as a reference. The above is all open source, so you are free to copy and modify it at will.