Skip to content

Add onPassKeyEntry to NimBLEServerCallbacks and onPassKeyDisplay to NimBLEClientCallbacks - #1115

Merged
h2zero merged 1 commit into
masterfrom
copilot/fix-nimble-callback-parity
Mar 17, 2026
Merged

h2zero merged 1 commit into
masterfrom
copilot/fix-nimble-callback-parity

Conversation

Copilot AI commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

The BLE pairing IO capability matrix requires both display and entry callbacks on both roles. NimBLEServerCallbacks lacked onPassKeyEntry (needed when the server has Keyboard-Only IO capability and the client displays the passkey), and NimBLEClientCallbacks lacked onPassKeyDisplay (needed when the client has display capability and the server must input).

Changes

  • NimBLEServerCallbacks — adds onPassKeyEntry(NimBLEConnInfo&):

    • Server handleGapEvent now handles BLE_SM_IOACT_INPUT, calling this callback
    • Default implementation injects 123456 via NimBLEDevice::injectPassKey
  • NimBLEClientCallbacks — adds onPassKeyDisplay(NimBLEConnInfo&) -> uint32_t:

    • Client handleGapEvent now handles BLE_SM_IOACT_DISP, calling this callback and injecting the returned passkey via ble_sm_inject_io
    • Default implementation returns NimBLEDevice::getSecurityPasskey()
    • Mirrors the same fallback logic as the server's existing onPassKeyDisplay handler
// Server: Keyboard Only IO cap — peer (client) displays, server must input
class ServerCallbacks : public NimBLEServerCallbacks {
    void onPassKeyEntry(NimBLEConnInfo& connInfo) override {
        // Prompt user to enter passkey shown on the client device
        NimBLEDevice::injectPassKey(connInfo, 123456);
    }
};

// Client: Display IO cap — client displays, peer (server) must input
class ClientCallbacks : public NimBLEClientCallbacks {
    uint32_t onPassKeyDisplay(NimBLEConnInfo& connInfo) override {
        // Return passkey to display; server must enter this value
        return 123456;
    }
};
Original prompt

This section details on the original issue you should resolve

<issue_title>Server/Client callback completeness and parity</issue_title>
<issue_description>Im just getting started with migrating some very old esp32 Bluetooth peripheral code to NimBLE Arduino v2.x. But I'm confused on what appears to be a new limitation during bonding.

Why is it that the NimBLEServerCallbacks do not at least share the same callbacks regarding pair/bond/security?
For as can been seen in this reference from Nordic chart attached, the initiator/central, and responder/peripheral, could have any combination of capabilities. So, for example in the case where a peripheral is set to only keyboard, and the remote central has a Just Display, or even Keyboard and Display, or even LE Secure Connections enabled, the negotiated method should require the peripheral to enter the displayed passkey by the initiator, and get some sort of notification on what it needs to do.

In this lib implementation, presumably that is the onPassKeyEntry callback, which is what's missing on NimBLEServerCallbacks. And inversely the onPassKeyDisplay callback missing from the Client object for the same reasoning.

Also, from what i recall this chart mirrors what the Bluetooth specification indicates, so regardless, it appears to me that both 'Display' and 'Entry' callbacks should be present (and functional) for both the Server and client i suppose.

Image</issue_description>

<agent_instructions>Create a PR to add the missing callbacks to the server/client classes.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@h2zero The initiator/client normally would be the one to input the key, while the peripheral/server displays it. I have not seen any case where the initiator/client would display the key, so that is not in the callback set for the client class and vice versa for the peripheral/server.

In this library the security/pairing process is either initiated manually in the application after a connection is made if desired or when the client tries to read/write a characteristic which requires security in which case the process starts automatically.</comment_new>
<comment_new>@h2zero

Yes, but the problem with not implementing the specification correctly is that it leaves no possibility for the application to control whether securing the connection or not. Again, this might not be the popular implementation, but absolutely within the specification and something done before.

That's what my comment implied In this library the security/pairing process is either initiated manually in the application. The specification is being followed, security is optional on a per-attribute basis by setting a flag on it's properties. If you want connections to be secure at all times just call NimBLEDevice::startSecurity when a peer connects.

If really necessary for your application you can just install your own gap handler to handle the security cases that you require with NimBLEDevice::setCustomGapHandler and handle the BLE_GAP_EVENT_PASSKEY_ACTION event yourself for the cases that are not implemented in the C++ API. The stack will generate the events as per the chart as they occur.


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI changed the title [WIP] Fix server/client callback completeness in NimBLE Add onPassKeyEntry to NimBLEServerCallbacks and onPassKeyDisplay to NimBLEClientCallbacks Mar 17, 2026
Copilot AI requested a review from h2zero March 17, 2026 12:27

@h2zero h2zero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change the examples, these are unlikely to get much use.

Copilot AI commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

Don't change the examples, these are unlikely to get much use.

Done — reverted both example files in 7e6e131.

Copilot AI requested a review from h2zero March 17, 2026 12:54

@h2zero h2zero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@h2zero
h2zero marked this pull request as ready for review March 17, 2026 12:56
…imBLEClientCallbacks

Co-authored-by: h2zero <32826625+h2zero@users.noreply.github.com>
@h2zero
h2zero force-pushed the copilot/fix-nimble-callback-parity branch from 7e6e131 to d3658f4 Compare March 17, 2026 12:59
@h2zero
h2zero merged commit 66522ce into master Mar 17, 2026
41 checks passed
@h2zero
h2zero deleted the copilot/fix-nimble-callback-parity branch March 17, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Not all GAP events appear to be propagated to a custom GAP handler. Server/Client callback completeness and parity

2 participants