---
title: Keyboard Dongle
sidebar_label: Keyboard Dongle
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

:::warning
This implementation is experimental and subject to change.

The information below is for keyboards consisting of a [board and a shield](../faq.md#why-boards-and-shields-why-not-just-keyboard). The setup for keyboards consisting exclusively of a [board](../faq.md#what-is-a-board) is not yet documented.
:::

A bluetooth dongle can be added to any keyboard running ZMK. The result is a [split keyboard](./split-keyboards.md) 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](./split-keyboards.md#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](../config/index.md#shield-folder) 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 title="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`.

<Tabs
defaultValue="unibody"
values={[
{label: 'Unibody Keyboard', value: 'unibody'},
{label: 'Split Keyboard', value: 'split'},
]}
>
<TabItem value="unibody">

```kconfig title="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
```

</TabItem>
<TabItem value="split">

Modify the following `Kconfig.defconfig` file to include the dongle in the split keyboard configuration.

```kconfig title="Kconfig.defconfig"
if SHIELD_MY_KEYBOARD_DONGLE || SHIELD_MY_KEYBOARD_LEFT || SHIELD_MY_KEYBOARD_RIGHT

config ZMK_SPLIT
    default y

endif

if SHIELD_MY_KEYBOARD_DONGLE

config ZMK_KEYBOARD_NAME
    default "My Keyboard"

config ZMK_SPLIT_ROLE_CENTRAL
    default y

config ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS
    default 2

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

endif
```

Modify the `Kconfig.defconfig` file to include the following:

```kconfig title="Kconfig.defconfig"

if SHIELD_MY_KEYBOARD_LEFT

# Setting this to y will make the left half the central
# We want it to be the central when dongle is not used
config ZMK_SPLIT_ROLE_CENTRAL
    default y

# Check if the left half is the central
if ZMK_SPLIT_ROLE_CENTRAL
config ZMK_KEYBOARD_NAME
    default "My Keyboard"
        
endif # ZMK_SPLIT_ROLE_CENTRAL

endif # SHIELD_MY_KEYBOARD_LEFT
```

</TabItem>
</Tabs>

### 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.
:::

```dts title="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

```kconfig title="config/my_keyboard_left.conf"
# Disable central role to use dongle
CONFIG_ZMK_SPLIT_ROLE_CENTRAL=n
```

For a unibody keyboard, change this

```kconfig title="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.

```yaml
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](../troubleshooting/connection-issues.mdx#acquiring-a-reset-uf2) on all devices.
:::
:::note
Any microcontroller with BLE support can be used as a dongle.
:::

