Skip to main content

Keyboard Dongle

warning

This implementation is experimental and subject to change.

The information below is for keyboards consisting of a board and a shield. The setup for keyboards consisting exclusively of a board is not yet documented.

A bluetooth dongle can be added to any keyboard running ZMK. The result is a split keyboard with the dongle as "central". There are a number of advantages to adding a dongle, but also some disadvantages:

Benefits:

  • The "central" dongle results in increased battery life for the keyboard/former "central", as it is now a peripheral.
  • It is easier to connect to the host device.

Disadvantages:

  • An extra microcontroller is needed.
  • The keyboard becomes unusable without the dongle.
note

Depending on how the dongle is used, there are some additional latency considerations to keep in mind. On average, the latency increase is around 3.75ms, in worst case scenario, the latency increase can be up to 7.5ms compared to a unibody keyboard.

Editing a Keyboard Definition to Support a Dongle

You will modify the files defining your keyboard to support a dongle. The recommended approach to doing so (found below) allows you to easily enable a dongle, but it is disabled by default. This is done to ensure that backwards compatibility is maintained for users who do not wish to use a dongle.

Shield Configuration Files

Start by adding the dongle body to the shield configuration.

Kconfig.shield
config SHIELD_MY_KEYBOARD_DONGLE
def_bool $(shields_list_contains,my_keyboard_dongle)

Next, add the dongle configuration to your keyboard's Kconfig.defconfig.

Kconfig.defconfig
if SHIELD_MY_KEYBOARD_DONGLE

config ZMK_KEYBOARD_NAME
default "My Board"

config ZMK_SPLIT_ROLE_CENTRAL
default y

config ZMK_SPLIT
default y


# Increase the transmit power of the dongle
choice BT_CTLR_TX_PWR
default BT_CTLR_TX_PWR_PLUS_8
endchoice

endif

if SHIELD_MY_KEYBOARD && !ZMK_SPLIT
config ZMK_KEYBOARD_NAME
default "My Board"
endif

Dongle Overlay File

Replace the kscan with kscan-mock in the dongle overlay.

warning

Your keyboard's matrix transform must be both defined and selected under the chosen node either here or in a my_keyboard.dtsi file.

my_keyboard_dongle.overlay
// import the default shield configuration
#include "my_keyboard.dtsi"

/ {
chosen {
zmk,kscan = &mock_kscan;
};

mock_kscan: kscan_1 {
compatible = "zmk,kscan-mock";

columns = <0>;
rows = <0>;
events = <0>;
};
};

Enabling the Dongle

When the above has been implemented in the keyboard definition.

The dongle can be enabled by implementing the following changes in the user config file.

For a split keyboard, change this

config/my_keyboard_left.conf
# Disable central role to use dongle
CONFIG_ZMK_SPLIT_ROLE_CENTRAL=n

For a unibody keyboard, change this

config/my_keyboard.conf
# Enable split functionality, this will put the unibody keyboard in peripheral mode
CONFIG_ZMK_SPLIT=y

Building the firmware

Add the appropriate lines to your build.yml file to build the firmware for your dongle, in addition to the other parts of your keyboard.

include:
# -----------------------------------------
# Your other keyboard parts here
# -----------------------------------------
- board: nice_nano_v2
shield: my_keyboard_dongle
- board: nice_nano_v2
shield: settings_reset
warning

Before flashing your new firmware, flash the settings_reset UF2 firmware on all devices.

note

Any microcontroller with BLE support can be used as a dongle.