Does espruino support bonding with a pin?

Posted on
Page
of 2
/ 2
Next
  • I'm using an official Espruino MDBT42Q breakout board to try to connect to a BLE enabled video camera. When pairing with a phone a pin is displayed on the screen to bond with the camera.

    When I try to connect from the Espruino (running 2v00.120) I get disconnect with code 19 (0x13 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTIO­N) when I execute gatt.startBonding().

    I completely understand if this just is not implemented. Just wanted to check if I was missing something.

  • Hi! It's something that could be added in future firmwares, but I'm afraid it's not in there at the moment...

  • Ok, I thought that was the case. I'm not familiar with the nRF52 libs but if I find some time I'll see if I can't figure it out and submit a PR.

  • Won’t this need to be done interactively?
    E.g start the pairing and then enter the pin - probably via the console directly into a (new) function call?

  • I would think so yes. The camera does not show a pin until the bonding is started.

  • Digging into the docs I found I can change the Peer Manager config io_caps to BLE_GAP_IO_CAPS_KEYBOARD_ONLY and I get a pin to display on the camera when binding.

    Then when binding I'm receiving a BLE_GAP_EVT_AUTH_KEY_REQUEST and replying with sd_ble_gap_auth_key_reply to supply the passkey, but so far no love.

    This API is new to me so I'll keep digging.

  • I was using the wrong connection handle. Dumb mistake. It works great now. The additions to the code base are quite minor.

    Looks like the device is saving the keys as expected so future connections are secured and the connection is seamless.

    So would you guys be interested in me cleaning this up and sending a PR? Is it something you would like to be implemented? If so I think we should decide on how exactly it should work. I would image we would just have the Gatt emit an event on BLE_GAP_EVT_AUTH_KEY_REQUEST and then it would be up to the user to acquire the passkey from the user somehow and submit it back. Right now I just added a gatt.submitPasskey method to the jswrap_bluetooth.c that calls sd_ble_gap_auth_key_reply in bluetooth.c.

    Edit: Looks like the encrypted characteristics are working and notifications are working! But now I see that there is no indication implementation and the main characteristic value I need to watch is only readable via indication.

  • Yes, I'd definitely be interested in adding this - as long as there was a way to do it in such a way that it didn't suddenly start requiring a passkey on normal devices! That could probably be done by enabling the BLE_GAP_IO_CAPS_KEYBOARD_ONLY with a bleStatus flag though.

    Hopefully you should be able to do the normal method of queueing a BLEP_ enum which would then emit a NRF.on('passkey_request'...) event.

    I guess while we're at it, it might be possible to allow the DISPLAY caps as well... It'd just be another event with a passkey in it.

    Real shame about the indications though. They shouldn't be too hard to add in the same way as notifications - there just hasn't been much call for them as there are very few devices that use them. It looks like your camera is particularly strange!

  • I would definitely second this request as I suspect we are both attempting (and failing miserably in my case) to connect to the same brand of video camera !

  • Sorry to be a pain but noticed its been added as an open issue on GitHub and wondering if there is an ETA ?
    Many thanks

  • There's no ETA at the moment, I just put it in there so I didn't forget. If this is actually the same camera then you'll probably be disappointed - as above it appears to use indications which aren't in Espruino yet either.

    Which camera is it? It's very difficult for me to develop if I have no way to test.

    Specifically what do you want to do?

    • The camera displays a PIN which you have to enter
    • or: Espruino should display a PIN that you have to enter on the camera

    It looks like the latter one is easier (or at least more obvious) to do.

    @user63214 could you share the code you used with sd_ble_gap_auth_key_reply?

  • Thanks for the response.

    The camera is the Blackmagic Pocket 4K Cinema Camera (though it is also used with other cameras from the same manufacturer).

    Camera control spec is here :
    https://documents.blackmagicdesign.com/D­eveloperManuals/BlackmagicCameraControl/­20181019-740d71/BlackmagicCameraControl.­pdf

    The camera displays a PIN on its setup screen which I would then want to respond to.

    I have created an Android app that controls all of the camera parameters and now I'm wanting to create a small hardware controller based around the Pixl but I'm floundering at this first step.

  • The camera control service is UUID: 291D567A-6D75-11E6-8B77-86F30CA893D3

    The commands to the camera are sent on characteristic UUID: 5DD3465F-1AEE-4299-8493-D2ECA2F8E1BB

    And we request notifications on characteristic UUID: B864E140-76A0-416A-BF30-5876504537D9

    If you connect a phone to the camera with the nRF app then sending anything to the command characteristic UUID then it immediately invokes the PIN display on the camera screen.

  • Ok, thanks. Wow, that's a nice bit of kit - not the kind of thing I can afford to buy and test out though!

    You're sure it uses nofitications on B864E140-76A0-416A-BF30-5876504537D9 and not indications? If so I can definitely look at adding something but no promises - we'll just have to see if it works or not.

  • Mmm...the spec says notifications but, yes, when attached to nRF as you can see here it is indications.

    I made the Android app with AppInventor and the BLE extension just has a generic register for bytes function so that subtlety is hidden (though it does work as I need it to obviously).


    1 Attachment

    • Screenshot_20190131-142421.png
  • Hmm, ok - looks like you are both trying to use the same device then!

    So... I've just tried to add the security, but I have no way to actually test. You should be able to do:

    NRF.setSecurity({keyboard:1});
    // find device with NRF.requestDevice/etc
    dev.on('passkeyRequest', function() {
      // then you need to call the following after you've had a chance to get it
      dev.sendPasskey("123456")
    });
    

    I have also added support for Indications (I hope!) - startNotifications will just use indicate if notify isn't there (as the Web Bluetooth spec seems to imply it should).

    Builds are available at http://www.espruino.com/binaries/travis/­master/

    Please let me know how you get on!

  • Cheers

    I'm probably (very likely) being a bit dim but I'm getting an uncaught reference error as "dev" is not defined when I try this.

    The Pixl definitely took the 2v01.16 build.

  • Sorry, the find device with NRF.requestDevice/etc comment was a 'you should do this' comment - so I guess you have some code to connect to the device already - stick the code in that, after you found the device, but before you call connect

  • Thanks for your help with this and again I have to apologise for being less than switched on in trying to make it work.

    I've made two versions of a function to write a value to the camera which I trigger with two of the buttons on the Pixl.

    This is the first one

    function WriteToCamera_V1(){
    var gatt;
    NRF.requestDevice({ filters: [{ id: "90:fd:9f:b8:ca:37 public" }] }).then(function(device) {
    NRF.setSecurity({keyboard:1});
    console.log("Connecting");
    return device.gatt.connect();
    }).then(function(g) {
    gatt = g;
    return gatt.getPrimaryService("291d567a-6d75-11­e6-8b77-86f30ca893d3");
    }).then(function(service) {
    return service.getCharacteristic("5dd3465f-1aee­-4299-8493-d2eca2f8e1bb");
    }).then(function(characteristic) {
    console.log("Writing To Characteristic");
    return characteristic.writeValue([0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00] );
    }).then(function() {
    gatt.disconnect();
    console.log("Done!");
    });
    }
    

    This version triggers all of the console log stages and doesn't return any errors, although it neither invokes the PIN pop up on the camera screen or executes the function.

    The second version of the function looks like this

    function WriteToCamera_V2() {
    var gatt;
    NRF.setSecurity({keyboard:1});
    NRF.connect("90:fd:9f:b8:ca:37").then(fu­nction(g) {
    gatt = g;
    console.log("Connecting");
    return gatt.getPrimaryService("291d567a-6d75-11­e6-8b77-86f30ca893d3");
    }).then(function(service) {
    return service.getCharacteristic("5dd3465f-1aee­-4299-8493-d2eca2f8e1bb");
    }).then(function(characteristic) {
    console.log("Writing To Characteristic");
    characteristic.writeValue([0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00] );
    }).then(function() {
    gatt.disconnect();
    console.log("Done!");
    });
    }
    

    Again, this one does not invoke the PIN pop up on the camera but it does produce the following errors in the console at the "Writing To Characteristic" point

    Writing To Characteristic
    Uncaught Error: Unhandled promise rejection: Error: BLE task 6 is already in progress
    Uncaught InternalError: BLE task completed that wasn't scheduled (3/0)
    

    I haven't included the additional passkeyRequest function (I was just trying to get the PIN pop-up to invoke on the camera for now) but I'm guessing that the second variation of the function is possibly the one that is more likely to be in the right direction for adding it?

    Again, I've got to apologise for my lack of understanding of how and where to put the passkeyRequest function example that you gave me but any example within one of my functions would be greatly appreciated.

  • The first version looks pretty promising to me... What were you doing previously that caused the pin popup to appear when you tried to connect though?

    Can you try this? It's the same, but will tell you when the camera is requesting a passkey.

    function WriteToCamera_V1(){
    var gatt;
    NRF.requestDevice({ filters: [{ id: "90:fd:9f:b8:ca:37 public" }] }).then(function(device) {
    NRF.setSecurity({keyboard:1});
    device.on('passkeyRequest', function() {
      console.log("passkey requested");
    });
    console.log("Connecting");
    return device.gatt.connect();
    }).then(function(g) {
    gatt = g;
    return gatt.getPrimaryService("291d567a-6d75-11­e6-8b77-86f30ca893d3");
    }).then(function(service) {
    return service.getCharacteristic("5dd3465f-1aee­-4299-8493-d2eca2f8e1bb");
    }).then(function(characteristic) {
    console.log("Writing To Characteristic");
    return characteristic.writeValue([0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00] );
    }).then(function() {
    gatt.disconnect();
    console.log("Done!");
    });
    }
    

    Another possibility is that the camera allows non-bonded connections, but will only respond to commands over a secure, bonded connection.

    In that case you could try:

    var gatt;
    NRF.requestDevice({ filters: [{ id: "90:fd:9f:b8:ca:37 public" }] }).then(function(device) {
      NRF.setSecurity({keyboard:1});
      console.log("Connecting"); 
      return device.gatt.connect();
    }).then(function(g) {
      gatt = g;
      console.log("Connected");
      return gatt.startBonding(); //<---- use startBonding(true) here to force re-pairing - might be handy for debug
    }).then(function() {
      console.log("bonded", gatt.getSecurityStatus());
    return gatt.getPrimaryService("291d567a-6d75-11­e6-8b77-86f30ca893d3");
    }).then(function(service) {
    return service.getCharacteristic("5dd3465f-1aee­-4299-8493-d2eca2f8e1bb");
    }).then(function(characteristic) {
    console.log("Writing To Characteristic");
    return characteristic.writeValue([0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00] );
    }).then(function() {
    gatt.disconnect();
    console.log("Done!");
    });
    

    Just to add that when I wrote:

    dev.on('passkeyRequest', function() {
      // then you need to call the following after you've had a chance to get it
      dev.sendPasskey("123456")
    });
    

    I didn't really mean that exact code - more like you get the passkeyRequest event and then at some point in the future you do sendPasskey - it doesn't have to be immediate obviously - and assuming you had saved device as a global variable you could just do it manually at the repl for now

  • Many thanks for that.

    We now have some real progress of sorts.

    The second option you provided worked in terms of invoking the PIN on the camera screen.

    The first option just went straight through as per the original version and did not invoke the PIN or fire the passkeyRequest.

    I inserted that part into the second one just to confirm that it does fire and it does.

    So, this is the version I have been working with

    function WriteToCamera_V1(){
    var gatt;
    NRF.requestDevice({ filters: [{ id: "90:fd:9f:b8:ca:37 public" }] }).then(function(device) {
    dev=device;
    NRF.setSecurity({keyboard:1});
    console.log("Connecting"); 
    device.on('passkeyRequest', function() {
    console.log("passkey requested");
    //dev.sendPasskey("123456");
    });
    return device.gatt.connect();
    }).then(function(g) {
    gatt = g;
    console.log("Connected");
    return gatt.startBonding(true); //<---- use startBonding(true) here to force re-pairing - might be handy for debug
    }).then(function() {
    console.log("bonded", gatt.getSecurityStatus());
    return gatt.getPrimaryService("291d567a-6d75-11­e6-8b77-86f30ca893d3");
    }).then(function(service) {
    return service.getCharacteristic("5dd3465f-1aee­-4299-8493-d2eca2f8e1bb");
    }).then(function(characteristic) {
    console.log("Writing To Characteristic");
    return characteristic.writeValue([0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00] );
    }).then(function() {
    gatt.disconnect();
    console.log("Done!");
    });
    }
    
    

    When I trigger it from the Button, it produces the following in the console

    >
    WRITE TO CAMERA_V1
    Connecting
    Connected
    bonded { "connected": true, "encrypted": false, "mitm_protected": false, "bonded": true }
    passkey requested
    Writing To Characteristic
    Done!
    >
    

    The problem is that it executes the write characteristic and disconnects before I've had any sort of opportunity to pass the PIN to it.

    I put in a dummy PIN that I've commented out to test that it would send it to the camera and it does send it and the camera invokes a failed connect message as expected with it being the wrong PIN.

    What I've done to give myself a chance to send the correct PIN is to split the bond function out without the write characteristic part which I activate off one button, then change the PIN value in the console (using the variable 'p' ) and then fire a separate function to do the sendPasskey off another button.

    As soon as I fire the sendPasskey function the camera (Line 6) does the immediate disconnect in the same way as if I'd sent it the wrong PIN in the main function and produces the following :

    Connecting
    Connected
    bonded { "connected": true, "encrypted": false, "mitm_protected": false, "bonded": true }
    >p="314390"
    ="314390"
    SENDING PIN
    Uncaught InternalError: BLE task completed that wasn't scheduled (3/0)
    > 
    

    My guess at the moment (with a dummy and a correct PIN producing the same outcome) is that I'm doing something wrong that is somehow related to Comments 6 & 7 from User63214 when he was attempting to do the same?

  • Thanks - that looks so promising... @user63214 did you have any thoughts on this?

    Are you sure it's actually disconnecting? Or is it just that it's giving the error.

    The BLE task completed that wasn't scheduled bit is probably ok - looking at the code it's just a 'connect' event that I guess happens when that bonding completes successfully. Espruino complains because it wasn't expecting the event.

  • What happens is the PIN prompt appears on the camera and stays there until I sent it the value, it then shows a connection failed message for about 10 seconds and then shows a message saying no device is attached .

    I have attached some (blurry!) pictures of the camera during this process.

    Not sure if the no device connected is a bit of a red herring though as the camera shows this when you connect to it via nRF for example but aren't bonded yet.

    For reference, here is an nRF log of performing the same process manually from an unbonded phone (so its essentially in the same state as the Pixl) to the camera and writing the same value to the characteristic UUID 5dd3465f-1aee-4299-8493-d2eca2f8e1bb

    It is at the point of sending the value to that characteristic that the PIN screen is invoked on the camera and in this log I have obviously entered the PIN on the phone to complete the process and then am able to send to the characteristic and then register and receive notifications on the other characteristic.

    nRF Connect, 2019-02-04
    Pocket Cinema Camera 4K A:1C2 (90:FD:9F:B8:CA:37)
    V    11:08:00.011    Connecting to 90:FD:9F:B8:CA:37...
    D    11:08:00.011    gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE)
    D    11:08:00.274    [Server callback] Connection state changed with status: 0 and new state: CONNECTED (2)
    I    11:08:00.274    [Server] Device with address 90:FD:9F:B8:CA:37 connected
    I    11:08:00.275    [Server] MTU changed to 64
    D    11:08:00.384    [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
    D    11:08:00.384    [Broadcast] Action received: android.bluetooth.device.action.ACL_CONN­ECTED
    I    11:08:00.384    Connected to 90:FD:9F:B8:CA:37
    D    11:08:00.392    wait(1600ms)
    V    11:08:02.007    Discovering services...
    D    11:08:02.007    gatt.discoverServices()
    D    11:08:02.023    [Callback] Services discovered with status: 0
    I    11:08:02.023    Services discovered
    V    11:08:02.051    Generic Access (0x1800)
    - Device Name [R] (0x2A00)
    - Appearance [R] (0x2A01)
    Device Information (0x180A)
    - Manufacturer Name String [R] (0x2A29)
    - Model Number String [R] (0x2A24)
    Unknown Service (291d567a-6d75-11e6-8b77-86f30ca893d3)
    - Unknown Characteristic [W] (5dd3465f-1aee-4299-8493-d2eca2f8e1bb)
    - Unknown Characteristic [I] (b864e140-76a0-416a-bf30-5876504537d9)
     Client Characteristic Configuration (0x2902)
    - Unknown Characteristic [N] (6d8f2110-86f1-41bf-9afb-451d87e976c8)
     Client Characteristic Configuration (0x2902)
    - Unknown Characteristic [N R W] (7fe8691d-95dc-4fc5-8abd-ca74339b51b9)
     Client Characteristic Configuration (0x2902)
    - Unknown Characteristic [W] (ffac0c52-c9fb-41a0-b063-cc76282eb89c)
    - Unknown Characteristic [R] (8f1fd018-b508-456f-8f82-3d392bee2706)
    D    11:08:02.052    gatt.setCharacteristicNotification(b864e­140-76a0-416a-bf30-5876504537d9, true)
    D    11:08:02.054    gatt.setCharacteristicNotification(6d8f2­110-86f1-41bf-9afb-451d87e976c8, true)
    D    11:08:02.058    gatt.setCharacteristicNotification(7fe86­91d-95dc-4fc5-8abd-ca74339b51b9, true)
    V    11:08:15.364    Writing request to characteristic 5dd3465f-1aee-4299-8493-d2eca2f8e1bb
    D    11:08:15.364    gatt.writeCharacteristic(5dd3465f-1aee-4­299-8493-d2eca2f8e1bb, value=0xFF04000000010000)
    D    11:08:15.819    [Broadcast] Action received: android.bluetooth.device.action.BOND_STA­TE_CHANGED, bond state changed to: BOND_BONDING (11)
    D    11:08:15.837    [Broadcast] Action received: android.bluetooth.device.action.PAIRING_­REQUEST, pairing variant: PAIRING_VARIANT_PIN (0)
    D    11:08:24.100    [Broadcast] Action received: android.bluetooth.device.action.BOND_STA­TE_CHANGED, bond state changed to: BOND_BONDED (12)
    I    11:08:24.100    Device bonded
    I    11:08:24.125    Data written to 5dd3465f-1aee-4299-8493-d2eca2f8e1bb, value: (0x) FF-04-00-00-00-01-00-00
    A    11:08:24.126    "(0x) FF-04-00-00-00-01-00-00" sent
    V    11:08:36.136    Writing request to characteristic 5dd3465f-1aee-4299-8493-d2eca2f8e1bb
    D    11:08:36.136    gatt.writeCharacteristic(5dd3465f-1aee-4­299-8493-d2eca2f8e1bb, value=0xFF04000000010000)
    I    11:08:36.196    Data written to 5dd3465f-1aee-4299-8493-d2eca2f8e1bb, value: (0x) FF-04-00-00-00-01-00-00
    A    11:08:36.196    "(0x) FF-04-00-00-00-01-00-00" sent
    V    11:08:47.245    Disabling notifications for 7fe8691d-95dc-4fc5-8abd-ca74339b51b9
    D    11:08:47.245    gatt.setCharacteristicNotification(7fe86­91d-95dc-4fc5-8abd-ca74339b51b9, false)
    D    11:08:47.246    gatt.writeDescriptor(00002902-0000-1000-­8000-00805f9b34fb, value=0x0000)
    I    11:08:47.311    Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
    A    11:08:47.311    "Notifications and indications disabled" sent
    V    11:08:47.313    Notifications and indications disabled for 7fe8691d-95dc-4fc5-8abd-ca74339b51b9
    V    11:08:50.416    Enabling notifications for 7fe8691d-95dc-4fc5-8abd-ca74339b51b9
    D    11:08:50.416    gatt.setCharacteristicNotification(7fe86­91d-95dc-4fc5-8abd-ca74339b51b9, true)
    D    11:08:50.417    gatt.writeDescriptor(00002902-0000-1000-­8000-00805f9b34fb, value=0x0100)
    I    11:08:50.479    Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
    A    11:08:50.479    "Notifications enabled" sent
    V    11:08:50.481    Notifications enabled for 7fe8691d-95dc-4fc5-8abd-ca74339b51b9
    V    11:08:58.285    Disabling indications for b864e140-76a0-416a-bf30-5876504537d9
    D    11:08:58.285    gatt.setCharacteristicNotification(b864e­140-76a0-416a-bf30-5876504537d9, false)
    D    11:08:58.286    gatt.writeDescriptor(00002902-0000-1000-­8000-00805f9b34fb, value=0x0000)
    I    11:08:58.377    Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
    A    11:08:58.377    "Notifications and indications disabled" sent
    V    11:08:58.378    Notifications and indications disabled for b864e140-76a0-416a-bf30-5876504537d9
    V    11:08:59.207    Enabling indications for b864e140-76a0-416a-bf30-5876504537d9
    D    11:08:59.208    gatt.setCharacteristicNotification(b864e­140-76a0-416a-bf30-5876504537d9, true)
    D    11:08:59.209    gatt.writeDescriptor(00002902-0000-1000-­8000-00805f9b34fb, value=0x0200)
    I    11:08:59.303    Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 02-00
    A    11:08:59.303    "Indications enabled" sent
    V    11:08:59.304    Indications enabled for b864e140-76a0-416a-bf30-5876504537d9
    I    11:08:59.352    Indication received from b864e140-76a0-416a-bf30-5876504537d9, value: (0x) FF-05-00-00-01-07-01-02-00
    A    11:08:59.352    "(0x) FF-05-00-00-01-07-01-02-00" received
    
    
  • Files wouldn't attach to original post.

  • PIN prompt


    1 Attachment

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

Does espruino support bonding with a pin?

Posted by Avatar for user63214 @user63214

Actions