ESP32 minimal BLE Device Information Service (DIS) example
This example demonstrates how to implement a minimal BLE Device Information Service (DIS) on the ESP32 using the ESP-IDF framework and the espressif/ble_services
component.
Prerequisites
Add the following managed components to your project:
example.sh
idf.py add-dependency "espressif/ble_services^1.0.0"
idf.py add-dependency "espressif/ble_conn_mgr:^1.0.0"
Also, you need to configure the following options in your sdkconfig
(or use idf.py menuconfig
):
example.txt
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
CONFIG_BT_NIMBLE_LOG_LEVEL_INFO=y
CONFIG_BT_NIMBLE_LOG_LEVEL=1
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3
CONFIG_BT_NIMBLE_MAX_BONDS=3
CONFIG_BT_NIMBLE_MAX_CCCDS=8
CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=4096
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y
CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y
CONFIG_BT_NIMBLE_GATT_SERVER=y
CONFIG_BT_NIMBLE_PRINT_ERR_NAME=y
CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="nimble"
CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31
CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=517
CONFIG_BT_NIMBLE_ATT_MAX_PREP_ENTRIES=64
CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE=0
CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12
CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=256
CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=24
CONFIG_BT_NIMBLE_MSYS_2_BLOCK_SIZE=320
CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=24
CONFIG_BT_NIMBLE_TRANSPORT_ACL_SIZE=255
CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70
CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=30
CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=8
CONFIG_BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT=1
CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4
CONFIG_BT_NIMBLE_RPA_TIMEOUT=900
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y
CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS=2000
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=y
CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT=3
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_2M_PHY=y
CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY=y
CONFIG_BT_NIMBLE_WHITELIST_SIZE=12
CONFIG_BT_NIMBLE_USE_ESP_TIMER=y
CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE=y
CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER=y
CONFIG_BT_NIMBLE_PROX_SERVICE=y
CONFIG_BT_NIMBLE_ANS_SERVICE=y
CONFIG_BT_NIMBLE_CTS_SERVICE=y
CONFIG_BT_NIMBLE_HTP_SERVICE=y
CONFIG_BT_NIMBLE_IPSS_SERVICE=y
CONFIG_BT_NIMBLE_TPS_SERVICE=y
CONFIG_BT_NIMBLE_IAS_SERVICE=y
CONFIG_BT_NIMBLE_LLS_SERVICE=y
CONFIG_BT_NIMBLE_SPS_SERVICE=y
CONFIG_BT_NIMBLE_HR_SERVICE=y
CONFIG_BT_NIMBLE_DIS_SERVICE=y
CONFIG_BT_NIMBLE_SVC_DIS_MANUFACTURER_NAME=y
CONFIG_BT_NIMBLE_SVC_DIS_SERIAL_NUMBER=y
CONFIG_BT_NIMBLE_SVC_DIS_HARDWARE_REVISION=y
CONFIG_BT_NIMBLE_SVC_DIS_FIRMWARE_REVISION=y
CONFIG_BT_NIMBLE_GAP_SERVICE=y
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM=0
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ENC=0
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHN=0
CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHR=0
CONFIG_BT_NIMBLE_SVC_GAP_CAR_CHAR_NOT_SUPP=y
CONFIG_BT_NIMBLE_SVC_GAP_CENT_ADDR_RESOLUTION=-1
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL=0
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL=0
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SLAVE_LATENCY=0
CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SUPERVISION_TMO=0
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM=0
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_ENC=0
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHEN=0
CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHOR=0
CONFIG_BT_NIMBLE_SVC_GAP_GATT_SECURITY_LEVEL=y
CONFIG_BT_NIMBLE_HCI_UART_FLOW_CTRL=0
CONFIG_BT_NIMBLE_HCI_UART_RTS_PIN=19
CONFIG_BT_NIMBLE_HCI_UART_CTS_PIN=23
CONFIG_BT_NIMBLE_EATT_CHAN_NUM=0
CONFIG_BT_CTRL_BLE_MAX_ACT=6
CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=6
CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
CONFIG_BT_BLE_CCA_MODE_NONE=y
CONFIG_BT_BLE_CCA_MODE=0
CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100
CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20
CONFIG_BT_CTRL_BLE_SCAN_DUPL=y
CONFIG_BT_CTRL_BLE_MASTER=y
CONFIG_BT_CTRL_BLE_SCAN=y
CONFIG_BT_CTRL_BLE_SECURITY_ENABLE=y
CONFIG_BT_CTRL_BLE_ADV=y
CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
CONFIG_ESP_PHY_ENABLE_USB=y
CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y
CONFIG_ESP_WIFI_ENABLE_SAE_PK=y
CONFIG_ESP_WIFI_ENABLE_SAE_H2E=y
CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y
CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
CONFIG_UNITY_ENABLE_FLOAT=y
CONFIG_UNITY_ENABLE_DOUBLE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_WIFI_PROV_BLE_SEC_CONN=y
CONFIG_BLE_CONN_MGR_ROLE_PERIPHERAL=y
CONFIG_BLE_CONN_MGR_ROLE=0
CONFIG_BLE_CONN_MGR_WAIT_DURATION=31
CONFIG_BLE_DIS=y
CONFIG_BLE_DIS_STR_MAX=32
CONFIG_BLE_DIS_MODEL="ESP"
CONFIG_BLE_DIS_MANUF="Manufacturer"
CONFIG_BLE_DIS_SYSTEM_ID="System"
CONFIG_BLE_DIS_PNP=y
CONFIG_BLE_DIS_PNP_VID_SRC=1
CONFIG_BLE_DIS_PNP_VID=0
CONFIG_BLE_DIS_PNP_PID=0
CONFIG_BLE_DIS_PNP_VER=1
CONFIG_NIMBLE_ENABLED=y
CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
CONFIG_NIMBLE_MAX_CONNECTIONS=3
CONFIG_NIMBLE_MAX_BONDS=3
CONFIG_NIMBLE_MAX_CCCDS=8
CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0
CONFIG_NIMBLE_PINNED_TO_CORE_0=y
CONFIG_NIMBLE_PINNED_TO_CORE=0
CONFIG_NIMBLE_TASK_STACK_SIZE=4096
CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096
CONFIG_NIMBLE_ROLE_PERIPHERAL=y
CONFIG_NIMBLE_ROLE_BROADCASTER=y
CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME="nimble"
CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31
CONFIG_NIMBLE_ATT_PREFERRED_MTU=517
CONFIG_NIMBLE_SVC_GAP_APPEARANCE=0
CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12
CONFIG_BT_NIMBLE_ACL_BUF_COUNT=24
CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30
CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8
CONFIG_NIMBLE_RPA_TIMEOUT=900
CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y
CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_DIS=y
main.cpp
In main.c
or main.cpp
, include the BLE header file:
example.cpp
#include "BLE.hpp"
In the app_main()
function, you need to add
example.cpp
ESP_ERROR_CHECK(esp_event_loop_create_default());
to the beginning of the function, unless you already create an event loop!
Only after creating the event loop, you can call InitBLE()
to initialize the BLE stack and start advertising.
example.cpp
#include <stdio.h>
## `BLE.hpp`
```hpp
#pragma once
void InitBLE();
BLE.cpp
example.cpp
#include "BLE.hpp"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_idf_version.h"
#include "esp_random.h"
#include "esp_mac.h"
#include "esp_system.h"
#include "nimble/nimble_port.h"
#include "esp_ble_conn_mgr.h"
#include "esp_dis.h"
static const char *TAG = "BLE";
static void app_ble_dis_init(void)
{
esp_ble_dis_init();
esp_ble_dis_pnp_t pnp_id = {
.src = CONFIG_BLE_DIS_PNP_VID_SRC,
.vid = CONFIG_BLE_DIS_PNP_VID,
.pid = CONFIG_BLE_DIS_PNP_PID,
.ver = CONFIG_BLE_DIS_PNP_VER
};
static char mac_str[19] = {0};
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT));
sprintf(mac_str, MACSTR, MAC2STR(mac));
esp_ble_dis_set_model_number("MyModel");
esp_ble_dis_set_serial_number(mac_str);
esp_ble_dis_set_firmware_revision("R1.2.3");
esp_ble_dis_set_hardware_revision("Rev2");
esp_ble_dis_set_software_revision("v0.1.2");
esp_ble_dis_set_manufacturer_name("MyCompany");
esp_ble_dis_set_system_id("My system ID");
esp_ble_dis_set_pnp_id(&pnp_id);
}
static void app_ble_conn_event_handler(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
{
if (base != BLE_CONN_MGR_EVENTS) {
return;
}
esp_ble_dis_pnp_t pnp_id;
const char *model_number = NULL;
const char *serial_number = NULL;
const char *firmware_revision = NULL;
const char *hardware_revision = NULL;
const char *software_revision = NULL;
const char *manufacturer = NULL;
const char *system_id = NULL;
switch (id) {
case ESP_BLE_CONN_EVENT_CONNECTED:
ESP_LOGI(TAG, "ESP_BLE_CONN_EVENT_CONNECTED");
esp_ble_dis_get_pnp_id(&pnp_id);
esp_ble_dis_get_model_number(&model_number);
esp_ble_dis_get_serial_number(&serial_number);
esp_ble_dis_get_firmware_revision(&firmware_revision);
esp_ble_dis_get_hardware_revision(&hardware_revision);
esp_ble_dis_get_software_revision(&software_revision);
esp_ble_dis_get_manufacturer_name(&manufacturer);
esp_ble_dis_get_system_id(&system_id);
ESP_LOGI(TAG, "Model name %s", model_number);
ESP_LOGI(TAG, "Serial Number %s", serial_number);
ESP_LOGI(TAG, "Firmware revision %s", firmware_revision);
ESP_LOGI(TAG, "Hardware revision %s", hardware_revision);
ESP_LOGI(TAG, "Software revision %s", software_revision);
ESP_LOGI(TAG, "Manufacturer name %s", manufacturer);
ESP_LOGI(TAG, "System ID %s", system_id);
ESP_LOGI(TAG, "PnP ID Vendor ID Source 0x%0x, Vendor ID 0x%02x, Product ID 0x%02x, Product Version 0x%02x",
pnp_id.src, pnp_id.vid, pnp_id.pid, pnp_id.ver);
break;
case ESP_BLE_CONN_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "ESP_BLE_CONN_EVENT_DISCONNECTED");
break;
default:
break;
}
}
void InitBLE(void)
{
esp_nimble_init();
esp_ble_conn_config_t config = {
.device_name = "MTX-ZR",
.broadcast_data = "Metexon",
};
esp_err_t ret;
// Initialize NVS
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
esp_event_handler_register(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler, NULL);
esp_ble_conn_init(&config);
app_ble_dis_init();
if (esp_ble_conn_start() != ESP_OK) {
esp_ble_conn_stop();
esp_ble_conn_deinit();
esp_event_handler_unregister(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler);
}
}
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow