Eddystone UID scanning?

Posted on
  • Trying to understand how I could use Espruino to scan for Eddystone UID beacons. Specifically, I want to find all UID beacons within a certain namespace and get their instances.

    Note this is as a central, not as a peripheral as outlined in the documentation.

    @Gordon?

    Thanks!
    Bill

  • NRF.findDevices should be what you need: http://www.espruino.com/Reference#l_NRF_­findDevices

    NRF.findDevices(function(devices) {
      devices.forEach(function(device) {
        console.log(device);
        // I believe you'll find a device.servicedata field that'll contain the raw information for any Eddystone beacons
      });
    }, 1000);
    
  • Thanks @Gordon -- yes, that will work just fine, but I was hoping for a bit more support. Certainly an 'enhancement request' if you decide to provide specific support for iBeacon and Eddystone scanning. What would be great would be:

    NRF.requestDevice({ filters: [{ eddystoneNamepace: '1234567890' }] }).then(function(device) { ... });
    

    Support for iBeacon might be something like:

    NRF.requestDevice({ filters: [{ ibeaconUuid: 'B9407F30F5F8466EAFF925556B57FE6D' }] }).then(function(device) { ... });
    
  • I probably wouldn't change NRF.requestDevice since that's meant to work the same as the standard 'Web Bluetooth' one, but something like that could easily be a library.

    I don't have any Eddystone UUID beacons here so can't be a huge amount of help, but can you post up what you're getting from NRF.findDevices(print) for some Eddystone beacons that you know the UUID of so I can see exactly what we're getting and how to extract it?

    Once I know what bit of data needs to be extracted I imagine what you're after will look a lot like:

    NRF.findDevices(function(devices) {
      var yourDevices = devices.filter(d=>d.servicedata && d.servicedata["..."]==something);
      // ...
    }, 1000);
    

    So it shouldn't be too hard to work with. If you want to connect I believe you can just do yourDevices[0].connect - only difference is you get to be able to deal with >1 beacon if you found them.

  • Thanks @Gordon. Beacons are by definition non-connectable advertisers, so no need for the .connect :-} Both Eddystone and iBeacon use Manufacturer Specific advertisements, with different Company ID's and, of course, define the advertising payload differently. There are several 'competing' for the beacon standards, but IMHO, iBeacon and Eddystone are the current front-runners by far. Eddystone allows several different types of beacons, ranging from URL to data. I'm using the UID format.

    Note that beacons become quite a bit more powerful in Bluetooth 5 with enhanced and extended advertising. I'm hoping you'll be considering potential updates for that support in Nordic's updated Softdevices?

    iBeacon info
    Eddystone info

  • Yes, there will eventually be Bluetooth 5 support with a new softdevice, but realistically I'm waiting for a stable nRF52840 SDK release before I target a completely new Nordic SDK.

    And yes, I know how the beacons work. I just wanted to see what data you actually received so I can give you some code that I know works - given so far I have only used Eddystone URL advertising. There's a big difference between writing you some code that's based on data from Google and giving you something that's tested on real data.

  • edited: never mind!! @Gordon - the first device in the list (with services: feaa) is the Eddystone UID beacon. Please ignore the rest of the blather and remind me to pull out my HP16 more often to convert decimal to hex...

    Hi @Gordon -- Sorry, didn't mean to lecture, but I hadn't understood the question. So I tried looking for my Eddystone UID tag and couldn't see it with the following. Is espruino doing some sort of filtering on manufacturer specific data types?

    NRF.findDevices(function(devices) {
      console.log(devices);
    }, 5000);
    

    Below is the output from this code with the puck.js positioned on top of the Eddystone UID beacon (should have RSSI ~ -25 or so). Attached is a screenshot from the nRF Connect app on iOS showing the beacon.

    [
      BluetoothDevice {
        "id": "ac:23:3f:22:fe:0e public",
        "rssi": -45,
        "services": [
          "feaa"
         ],
        "data": new Uint8Array([2, 1, 6, 3, 3, 170, 254, 21, 22, 170, 254, 0, 0, 18, 52, 86, 120, 144, 18, 52, 86, 120, 144, 18, 52, 86, 18, 52, 86]).buffer
       },
      BluetoothDevice {
        "id": "40:cb:c0:af:24:b9 public",
        "rssi": -83,
        "services": [  ],
        "data": new Uint8Array([2, 1, 26, 7, 255, 76, 0, 16, 2, 1, 0]).buffer
       },
      BluetoothDevice {
        "id": "27:64:ef:27:26:04",
        "rssi": -81,
        "services": [  ],
        "data": new Uint8Array([2, 1, 27, 11, 255, 76, 0, 9, 6, 3, 9, 10, 0, 1, 11]).buffer
       },
      BluetoothDevice {
        "id": "60:03:08:9b:60:d3 public",
        "rssi": -85,
        "services": [  ],
        "data": new Uint8Array([2, 1, 6, 7, 255, 76, 0, 16, 2, 11, 0]).buffer
       },
      BluetoothDevice {
        "id": "7f:20:81:4f:14:52",
        "rssi": -86,
        "services": [  ],
        "data": new Uint8Array([2, 1, 6, 19, 255, 76, 0, 12, 14, 8, 173, 216, 194, 36, 35, 248, 17, 45, 128, 119, 142, 198, 153]).buffer
       }
     ]
    

    1 Attachment

    • IMG_7730.PNG
  • Is it somthing like this.
    I made this on my Puck to get ruuvi tags and display the results.
    The ruuvi tags are emitting raw values in "Manufacturer specific data".

    // pucktest05
    
    setBusyIndicator(LED1);
    var darray = {};
    var tg = 0x2F; // 0x2F ^ 0x73 = 0x5C
    var count = 0;
    
    
    function getDewpoint(temp, humi) {
    
      var C = {
        a1 : 8.1332,
        b1 : 1762.39,
        c1 : 235.66
      };
    
      PP = Math.pow(10,C.a1 - C.b1 / (this.temp + C.c1));
      this.dewp = -((C.b1 / (Math.log(this.humi * PP / 100) / Math.log(10) - C.a1)) + C.c1);
      return this.dewp.toFixed(2);
    }
    
    function bprint(dada, navn) {
      humi = dada.data[8] / 2;
      temp = dada.data[9] + dada.data[10] / 100;
      if(temp >128) {temp = 128 - temp;}
      bati = (dada.data[19] * 256 + dada.data[20]);
      dewi = getDewpoint(temp, humi);
      console.log(navn +
                  dada.rssi +
                 '  ' + temp.toFixed(2) +
                 '  ' + humi.toFixed(1) +
                 '  ' + dewi +
                 '  ' + bati);
    }
    
    function cprint(didi) {
      tg ^= 0x73;
      console.log('count: ' + count++);
      console.log(String.fromCharCode(tg) +
                     ' ' + NRF.getBattery().toFixed(3));
      console.log('   Sted  Rssi  Temp  Humi   Dewi  Bati');
      bprint(didi[0], '    Ude: ');
      bprint(didi[1], 'Drivhus: ');
      bprint(didi[2], '    Bad: ');
      bprint(didi[3], 'Udestue: ');
      console.log(' ');
    }
    
    function find() {
      NRF.findDevices(function(devices) {
        console.log(devices.length);
        for(i=0;i<devices.length;i++) {
          if(devices[i].id == 'ce:5c:55:08:22:5a random') {
            darray[0] = devices[i];
          }
          if(devices[i].id == 'da:dc:f2:19:d4:e3 random') {
            darray[1] = devices[i];
          }
          if(devices[i].id == 'fa:2e:7b:6d:97:e0 random') {
            darray[2] = devices[i];
          }
          if(devices[i].id == 'fc:62:2d:b7:96:30 random') {
            darray[3] = devices[i];
          }
        }
        cprint(darray);
      }, 3000);
    }
    
    find();
    setInterval(function () {
      find();
    }, 60000);
    
    
    
  • @billsalt thanks! Actually I think if you use one of the 'cutting edge' builds from http://www.espruino.com/binaries/travis/­master/ you'll find there'll be a servicedata field that you can check with device.servicedata["feaa"]. Sorry, I'd assumed it was in 1v94 but it seems it wasn't.

    However even as-is, something like this should work to check the device's UID:

    NRF.findDevices(function(devices) {
      devices.forEach(function(device) {
        var uid = (new Uint8Array(device.buffer)).slice(23,30).­map(x=>
    ((256+x).toString(16)).substr(-2)).join(­"");
        if (uid=="123456123456") ...
      });
    });
    

    @Frida thanks! As above, I think with new builds you might find the data is exposed a little more cleanly (so you don't have to go diving as deep into the data field). When you say 'Manufacturer Specific Data' do you mean the 0xFF AD type from https://www.bluetooth.com/specifications­/assigned-numbers/generic-access-profile­ ?

    If so, I should ensure Espruino parses that out (and can easily specify it) as well. Any thoughts as to how to specify it? Maybe just:

    NRF.setAdvertising({
      "" : [12,34,56]
    });
    

    or

    NRF.setAdvertising({
      "manufacturer" : [12,34,56]
    });
    
  • Thanks! just sidetracking this thread a bit: it looks like it's free to get a Company identifier from the Bluetooth SIG to use with the 'manufacturer specific data' - as sadly it looks like one still has to be specified. I just applied, so hopefully we'll have an Espruino ID to use soon (much like Ruuvitag has their own ID)

  • Thanks @Gordon! I applied for my Company Identifier a few days ago; it is in process as well. Note that the specifications state that it is OK to use 0xFFFF while in development.

    Is there a good way that I can keep up on improvements/features as they are released, or do I need to lurk on the git repo?

    Thanks for all of the help and support and great work, now and going forward! I keep coming across new, fun, and just plain practical use cases for Espruino.

    Bill

  • Note that the specifications state that it is OK to use 0xFFFF while in development.

    Thanks - I didn't spot that - that's handy!

    Is there a good way that I can keep up on improvements/features as they are released

    I announce any big stuff on the news section of the forum, and new releases on Twitter... But on a finer level it'll be a matter of either watching the GitHub Repo (which will spam you a lot!) or just keeping an eye on https://github.com/espruino/Espruino/blo­b/master/ChangeLog

  • @Gordon:

    FYI, from this link:

    65535 0xFFFF This value has special meaning depending on the context in which it used. Link Manager Protocol (LMP): This value may be used in the internal and interoperability tests before a Company ID has been assigned. This value shall not be used in shipping end products. Device ID Profile: This value is reserved as the default vendor ID when no Device ID service record is present in a remote device.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Eddystone UID scanning?

Posted by Avatar for billsalt @billsalt

Actions