Advertising custom UUID from Puck.js

Posted on
  • It says by default, Puck.js has a Nordic UART service (UUID 6e400001-b5a3-f393-e0a9-e50e24dcca9e) that allows us to communicate with the JS interpreter, as well as a TX and RX characteristic of this service.

    Is there any way to advertise a custom UUID from the Puck.js, or will we only ever be able to advertise that default Nordic UART service? Would advertising a different service break the Web Bluetooth, and ability to program wirelessly?

    If we can advertise a custom one, how would I go about doing so? I've been playing around with NRF.setAdvertising but haven't been getting anywhere. Should I be using NRF.setServices instead?

    I'm trying to advertise a UUID in the form "ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD". http://www.espruino.com/Reference#t_l_NRF_setServices says a UUID can be of that form, but says unless I disable the UART UUID, I can't advertise due to a size limitation. But that breaks the web bluetooth, so how would I program the Puck?

    Code examples would be appreciated!

  • Ther are quite a few Bluetooth LE tutorials listed at https://www.espruino.com/Tutorials

    As for basics check this one
    https://www.espruino.com/About+Bluetooth+LE

    You don't need to advertise the service at all. You only need to implement it via setServices.
    As I understand it the contents of advertisement packet and what services are provided after connection is not directly related.

    Not sure but I guess nordic uart could be removed from advertisement but you could still connect to it if setServices has 'uart : true'

  • Would advertising a different service break the Web Bluetooth, and ability to program wirelessly?

    Not at all. However the Espruino tools tend to look for devices with a certain name or an advertised Nordic UART service. If you change the name and remove the UART service then they will no longer be able to find the device to connect.

    I've been playing around with NRF.setAdvertising but haven't been getting anywhere. Should I be using NRF.setServices instead?

    As @fanoush says you shouldn't really need to advertise a custom service UUID unless you've got some other thing you're trying to fool/connect to. All they're for is as a way to 'find' a device but if you have the device name then that'd be enough.

    Once connected you can use the first argument of setServices to define 128 bit UUIDs and you're fine.

    To advertise a 128 bit service UUID (without data) you can use the second argument of setServices - but as you note if you want to do it easily you'll have to disable the UART. Perhaps that's not such a big deal for you though - develop without the service being advertised, then when you're done you can add the line, remove the UART and advertise your custom service.

    However: Espruino advertises service UUIDs in the scan response packet by default. If you want to have UART and your service UUID you can just overwrite the scan response packet with setScanResponse: http://www.espruino.com/Reference#l_NRF_setScanResponse

    You'll need to specify the actual binary data for the 128 bit UUID but it's not that bad:

    https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2017/02/10/bluetooth_advertisin-hGsf

    NRF.setScanResponse([17,  // Length of Data
      0x07,  // Param: Complete List of 128-bit Service Class UUIDs
      0xAB,0xCD,0xAB,0xCD,0xAB,0xCD,0xAB,0xCD,0xAB,0xCD,0xAB,0xCD,0xAB,0xCD,0xAB,0xCD]);
    

    Not tested, but should work...

  • There are quite a few Bluetooth LE tutorials listed at https://www.espruino.com/Tutorials
    As for basics check this one: https://www.espruino.com/About+Bluetooth­+LE

    @fanoush I looked through a couple of these but didn't find anything exactly like what I'm trying to do.

    Not at all. However the Espruino tools tend to look for devices with a certain name or an advertised Nordic UART service. If you change the name and remove the UART service then they will no longer be able to find the device to connect.

    As @fanoush says you shouldn't really need to advertise a custom service UUID unless you've got some other thing you're trying to fool/connect to. All they're for is as a way to 'find' a device but if you have the device name then that'd be enough

    @Gordon Got it. I do have something I'm trying to fool/connect to. I have a mobile app that broadcasts a specific BLE UUID and I'm trying to mimic that with the puck. Both the Advertised Service and the Name need to be something different than the default Nordic UART service the puck advertises.

    I'm thinking of using the push button to alternate between programming mode and service advertising mode. So for programming, I would have this code:

    NRF.setServices(undefined, {
          uart : true
        });
    

    but then when I want to advertise my custom service UUID I could run this code, disabling the Nordic UART service, and advertise my own:

    NRF.setServices(undefined, {
          uart : false
        });
    //run function that advertises my custom service UUID
    

    Would that work, so I don't have to completely reset the Puck every time I want to test advertising this custom service UUID?

    To advertise a 128 bit service UUID (without data) you can use the second argument of setServices - but as you note if you want to do it easily you'll have to disable the UART. Perhaps that's not such a big deal for you though - develop without the service being advertised, then when you're done you can add the line, remove the UART and advertise your custom service.

    So for the second argument in setServices, do you mean something like this?

    NRF.setServices(undefined, {
      uart : false, // optional, default is true. Enable BLE UART support
      advertise: [ 'ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD' ] // optional, list of service UUIDs to advertise
    });
    

    As NRF.setServices(data, options)
    data - The service (and characteristics) to advertise
    options - Optional object containing options

    So I don't need to add the UUID in data, only the options portion under advertise?

  • Would that work, so I don't have to completely reset the Puck every time I want to test advertising this custom service UUID?

    Yes, totally - seems fine to me. It'll only update once it's disconnected from the device in question, but that should be fine I imagine.

    So for the second argument in setServices, do you mean something like this?

    Yes, that looks spot on. Espruino will advertise that in the Scan Response packet, but that should be totally fine for most things.

  • Yes, that looks spot on. Espruino will advertise that in the Scan Response packet, but that should be totally fine for most things.

    So I feel like I'm very close, but not quite there. I've been successful in switching between UART being set true and false, so I can test my custom advertisement, and then switch back to the default Nordic UART service to reprogram wirelessly, without having to reset the Puck.

    I don't know if my service UUID is being "advertised" correctly though. I've been using the iOS versions of nRF Connect (by Nordic Semiconductor) and BlueSee BLE Debugger (by Synapse), and I see both the custom Name and the custom Service UUID advertised from the Puck, and appearing exactly like the thing I'm trying to mimic (the phone advertisement). Meaning from both of those apps, the name and UUID appear to be advertised identically between the Puck and what I'm trying to mimic, using the code snippet below:

    NRF.setServices(undefined, {
          uart : false, 
          advertise: [ 'ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD' ]  
    });
    NRF.setAdvertising({}, {name:"Puck.js"}); 
    

    However, on the custom hardware I'm trying to communicate to, the Puck isn't being picked up at all. Let's say the custom name I'm advertising is "Puck.js" and the service UUID is "ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD"

    Looking into the RAW BLE packet from NRF Connect, the Puck looks like it's advertising this:

    0x02010608095075636b2e6a73
    

    Which looks like 2 advertisements in 1 BLE packet.

    Adv 1:
    Length: 0x02
    Type: 0x01 (Flag)
    Value: 0x06

    Adv 2:
    Length: 0x08
    Type: 0x09 (Complete Local Name)
    Value: 0x5075636b2e6a73 ("Puck.js" in hex, using ASCII table)

    However what I'm wanting to see, is 3 advertisements in the packet, the missing one being the service UUID. Something like

    Adv 3:
    Length: 0x11 (17 in hex, 1 for the type, 16 for the UUID itself)
    Type: 0x07 (Complete List of 128-bit Service Class UUIDs)
    Value: 0xabcdabcdabcdabcdabcdabcdabcdabcd (the service UUID)

    So the overall RAW BLE packet looking something like this:

    0x0201061107abcdabcdabcdabcdabcdabcdabcdabcd08095075636b2e6a73
    

    What am I potentially doing wrong to where the service UUID isn't being brodcast in the RAW BLE packet?

  • Ahh, ok. So it's what I'd mentioned above about the scan response packet (which is an extra advertising packet that can be requested in a 'active' scan). Espruino sticks advertised service UUIDs in there because usually there's not enough space in the main packet.

    So to work around it, I'm afraid you'll have to manually specify the advertising data:

    NRF.setAdvertising([
      [
    0x02,0x01,0x06,
    0x11,0x07,0xab,0xcd,0xab,0xcd,0xab,0xcd,0xab,0xcd,0xab,0xcd,0xab,0xcd,0xab,0xcd,0xab,0xcd,
    0x08,0x09,0x50,0x75,0x63,0x6b,0x2e,0x6a,0x73,
    ]]); 
    

    But that will likely work perfectly for you. In fact you wouldn't even have to stop the UART.

  • So to work around it, I'm afraid you'll have to manually specify the advertising data:

    Thank you, that was the missing piece I needed to figure out the rest, and I got it working now!

    Thanks for all your help so far! I'm learning a lot!

    If I have any other questions on this I'll follow up here.

  • @Gordon
    Hi I'm sorry for reviving this post, I can create a new one if required. I'm trying to do a similar thing by using a UUID as a way of distinguishing between two pucks to use as presence detection for home automation. I understand I could setup up something like the ibeacon service but all I need is a UUID that doesnt change for each puck. I tried creating a 128 bit UUID using

    date | md5sum
    

    and then seperating the result like you suggested above

    NRF.setAdvertising([
      [
    0x13,0x19,0x00,0x01,0x07,0x6e,0xe3,0xac,0xd3,0xc5,0x1b,0xbd,0xf7,0x28,0x83,0x6c,
    ]]);
    

    , but this didnt work and I had to hard reset to get it back programmable , did I need to add a service similar to above ?

    NRF.setServices(undefined, {
          uart : false, 
          advertise: [ 'ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD' ]  
    });
    

    I'm very new to this it been a bit of a learning curve today to understand how it all works.

    is this the best way to achieve what I want ?

    thanks in advance

  • well, you can also distinguish by device mac address or even advertised device name out of box, no code needed for that on puck

  • MAC address would be great , but doesn't it randomly change from time to time ? If not then I can definitely use the MAC address. I will be using ESPHome with a Bluetooth esp as a base station device that sends the presence back to Home assistant .

    https://esphome.io/components/binary_sensor/ble_presence.html

    You can see MAC address as one of the 3 options

  • By default it does not change, it is taken from nrf52 ROM area FICR where unique serial id and MAC is.

  • And I take it each puck has a unique one ? In which case this is great, I can use that without any addition to the code. Thanks for your help

  • Very well explained article thank you , much appreciated

  • Glad you sorted this! Just a note on the initial code in https://forum.espruino.com/comments/16814776/

    The issue is by specifying: NRF.setAdvertising([ [ .... ]]) you're telling Espruino to advertise exactly that raw data (which probably isn't a valid Bluetooth advertising packet). Using NRF.setServices would work, or you can do:

    NRF.setAdvertising({ "ABCDABCD-ABCD-ABCD-ABCD-ABCDABCDABCD" : "" })
    

    Which would advertise 'service data' with that UUID, which might have been what you were after?

    but if you just want to tell the devices apart, MAC address is definitely the best!

  • but if you just want to tell the devices apart, MAC address is definitely the best!

    It was thank you so much for the reply , however as you said I managed with the MAC address which is even easier, now I just need to work out how to get Esphome to understand the advertised battery percentage from the pucks , but that's a topic for another thread .

    Thanks again

  • now I just need to work out how to get Esphome to understand the advertised battery percentage from the pucks

    This might be handy for that: https://forum.espruino.com/conversations/382301/#comment16798335

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

Advertising custom UUID from Puck.js

Posted by Avatar for user113948 @user113948

Actions