Configure Puck.js as an iBeacon

Posted on
  • Has anyone already managed to turn Puck.js into an Apple iBeacon?

    So far, I used these information from Stackoverflow:
    http://stackoverflow.com/questions/18906988/what-is-the-ibeacon-bluetooth-profile
    and the NRF.setAdvertising function to test with the following code:

    var g = [0xd6, 0xbe, 0x89, 0x8e, 0x40, 0x24, 0x05, 0xa2, 0x17, 0x6e, 0x3d, 0x71, 0x02, 0x01, 0x1a, 0x1a, 0xff, 0x4c, 0x00, 0x02, 0x15, 0xe2, 0xc5, 0x6d, 0xb5, 0xdf, 0xfb, 0x48, 0xd2, 0xb0, 0x60, 0xd0, 0xf5, 0xa7, 0x10, 0x96, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x52, 0xab, 0x8d, 0x38, 0xa5];
    NRF.setAdvertising(g);
    

    When sending the code to Puck.js, I get the following error message:

    Uncaught Error: Got BLE error code 9
     at line 1 col 21
    NRF.setAdvertising(g);
                        ^
    =undefined
    

    Any ideas? Thanks in advance!

  • As I understand it, the maximum data you can send in a Bluetooth advertising packet is something like 31 bytes - that's 47.

    However you're on the right track. Copying the middle bit of the data (with a change to the flags as we don't support normal Bluetooth modes) should work:

    var d = [0x02, // Number of bytes that follow in first AD structure
    0x01, // Flags AD type
    0x04, // Flags value 0x1A = 000011010  
    //   bit 0 (OFF) LE Limited Discoverable Mode
    //   bit 1 (OFF) LE General Discoverable Mode
    //   bit 2 (ON) BR/EDR Not Supported
    //   bit 3 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (controller)
    //   bit 4 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (Host)
    0x1A, // Number of bytes that follow in second (and last) AD structure
    0xFF, // Manufacturer specific data AD type
    0x4C, 0x00, // Company identifier code (0x004C == Apple)
    0x02, // Byte 0 of iBeacon advertisement indicator
    0x15, // Byte 1 of iBeacon advertisement indicator
    0xe2, 0xc5, 0x6d, 0xb5, 0xdf, 0xfb, 0x48, 0xd2,
    0xb0, 0x60, 0xd0, 0xf5, 0xa7, 0x10, 0x96, 0xe0,// iBeacon proximity uuid
    0x00, 0x00, // major 
    0x00, 0x00, // minor 
    0xc5]; // The 2's complement of the calibrated Tx Power
    NRF.setAdvertising(d, {interval:100});
    

    However I don't have an BLE-capable iDevice here to test this with.

  • Thanks Gordon, for your fast reply.

    I also tried to just use the middle part of the example, but didn't realize that I have to change the flags. Your code above works perfectly!

    Thanks again, for your help.

  • Great! Thanks for letting me know! Is it just the iBeacon proximity uuid that you have to change for your own devices? It would probably make sense for me to turn it into a module, like has been done for the eddystone one

  • An own iBeacon module would be great and definitely add value also for other users.

    Changeable input parameters for an iBeacon module would be:

    1. UUID => Bytes 9 - 24
    2. Major: integer value between 0 and 65535 => Bytes 25 - 26
    3. Minor: integer value between 0 and 65535 => Bytes 27- 28
    4. Calibrated TX Power: integer value between 0 and 255 => Byte 29
  • Please can you try this then?

    var advertise = function(options) {
      var d = new Uint8Array([
        0x02, // Number of bytes after first AD structure
        0x01, // BLE_GAP_AD_TYPE_FLAGS
        0x04, // BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED
        0x1A, // Length
        0xFF, // BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA
        0x4C, 0x00, // 0x004C == Apple
        0x02, 0x15, // iBeacon type + length
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// iBeacon proximity uuid
        0, 0, // major
        0, 0, // minor
        0xc5]); // 2'c complement RSSI at 1 meter distance in dBm
      d.set(9,options.uuid);
      if (options.major!==undefined) d.set(25,[options.major>>8,options.major]);
      if (options.minor!==undefined) d.set(27,[options.minor>>8,options.minor]);
      if (options.rssi!==undefined) d.set(29,[(options.rssi<0)?(options.rssi+256):options.rssi]);
      NRF.setAdvertising(d, {interval:100});
    };
    
    
    advertise({
      uuid : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // ibeacon uuid
      major : 0x0102, // optional
      minor : 0x0304, // optional
      rssi : -59, // optional RSSI at 1 meter distance in dBm
    });
    

    If so I'll make that into a module

  • I had two issues during testing:

    1. I think the parameters in the set methods were in a wrong order: typedarr.set(array [,offset])
    2. NRF.setAdvertising has not accepted the Uint8Array as object: Error message "Uncaught TypeError: Expecting object or undefined, got Uint8Array"

    But, with some small adjustments below, I got your code running. The device is then successfully recognized as an iBeacon.

    var advertise = function(options) {
      var d = new Uint8Array([
        0x02, // Number of bytes after first AD structure
        0x01, // BLE_GAP_AD_TYPE_FLAGS
        0x04, // BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED
        0x1A, // Length
        0xFF, // BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA
        0x4C, 0x00, // 0x004C == Apple
        0x02, 0x15, // iBeacon type + length
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// iBeacon proximity uuid
        0, 0, // major
        0, 0, // minor
        0xc5]); // 2'c complement RSSI at 1 meter distance in dBm
      
      d.set(options.uuid,9);
      if (options.major!==undefined) d.set([options.major>>8,options.major],25);
      if (options.minor!==undefined) d.set([options.minor>>8,options.minor],27);
      if (options.rssi!==undefined) d.set([(options.rssi<0)?(options.rssi+256):options.rssi],29);
      
      var e = [].slice.call(d);
      NRF.setAdvertising(e, {interval:100});
    };
    
    advertise({
      uuid : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // ibeacon uuid
      major : 0x0001, // optional
      minor : 0x0001, // optional
      rssi : -59 // optional RSSI at 1 meter distance in dBm
    });
    

    Perhaps you have a better idea how to pass the Uint8Array to the NRF.setAdvertising function.

  • Thanks - sorry, should have tested!

    I'll tweak setAdvertising to take uint8array in 1v91, but what you've done there looks fine.

  • Just to add, this is now a module: http://www.espruino.com/Puck.js+iBeacon

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

Configure Puck.js as an iBeacon

Posted by Avatar for LongJogger @LongJogger

Actions