| name | zephyr-bluetooth-le |
| description | Expert guidance for Bluetooth Low Energy (BLE) development in Zephyr OS. Covers GAP roles (peripheral, central, broadcaster, observer), GATT services and characteristics, advertising, scanning, connections, pairing/bonding, and built-in services (BAS, DIS, HRS, NUS). Use when implementing BLE functionality, creating custom GATT services, configuring advertising data, handling connections, or troubleshooting BLE issues. |
Zephyr Bluetooth LE
Quick Start
- Enable BLE:
CONFIG_BT=y in prj.conf
- Choose GAP Role: See GAP Roles section
- Initialize: Call
bt_enable(NULL) in main()
- Define Services: Use GATT macros or built-in services
- Start Advertising/Scanning: Based on role
Core Initialization Pattern
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
int main(void)
{
int err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return 0;
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
settings_load();
}
}
GAP Roles
| Role | Kconfig | Description | Key APIs |
|---|
| Peripheral | CONFIG_BT_PERIPHERAL=y | Connectable advertiser, GATT server | bt_le_adv_start(), bt_gatt_service_register() |
| Central | CONFIG_BT_CENTRAL=y | Scans and connects, GATT client | bt_le_scan_start(), bt_conn_le_create() |
| Broadcaster | CONFIG_BT_BROADCASTER=y | Non-connectable advertiser | bt_le_adv_start() with non-conn params |
| Observer | CONFIG_BT_OBSERVER=y | Passive scanner | bt_le_scan_start() |
Detailed References
Common Patterns
Peripheral (GATT Server)
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HRS_VAL)),
};
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME,
sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
Central (GATT Client)
static void scan_cb(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
bt_le_scan_stop();
bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
BT_LE_CONN_PARAM_DEFAULT, &conn);
}
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, scan_cb);
Connection Callbacks
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed (err 0x%02x)\n", err);
} else {
printk("Connected\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected (reason 0x%02x)\n", reason);
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
Minimum Kconfig for Peripheral
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="My Device"
Minimum Kconfig for Central
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_GATT_CLIENT=y
Security (Pairing/Bonding)
Enable SMP: CONFIG_BT_SMP=y
bt_conn_set_security(conn, BT_SECURITY_L2);
static struct bt_conn_auth_cb auth_cb = {
.passkey_display = passkey_display,
.passkey_confirm = passkey_confirm,
.cancel = auth_cancel,
};
bt_conn_auth_cb_register(&auth_cb);
Security levels:
BT_SECURITY_L1: No encryption
BT_SECURITY_L2: Encrypted, no MITM protection
BT_SECURITY_L3: Encrypted + MITM (legacy pairing)
BT_SECURITY_L4: Encrypted + MITM (LE Secure Connections)
Persistent Storage
For bonding persistence:
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
Call settings_load() after bt_enable().
Related Skills
- zephyr-kconfig: Configure
CONFIG_BT_* options
- zephyr-devicetree: Flash partitions for bonding storage
- zephyr-shell-commands: BLE shell for debugging (
CONFIG_BT_SHELL=y)
- zephyr-settings: Persistent storage backend selection
- zephyr-cbor: CBOR encoding/decoding for SMP over BLE payloads