ESP32 IDF

ESP32 IDF BLE 클라이언트

임베디드 친구 2024. 11. 6. 12:59
반응형

이번 포스팅에서는 ESP32 IDF를 활용하여 BLE 클라이언트를 구현하는 방법을 살펴보겠습니다. 이 포스트는 ESP32와 Bluetooth Low Energy(BLE)에 관심이 있는 개발자들을 대상으로 하며, 특히 BLE 클라이언트의 역할과 구현 방법에 대해 깊이 있게 설명합니다. 이 포스트를 통해 ESP32의 BLE 클라이언트를 설정하고 활용하는 방법을 쉽게 이해할 수 있도록 돕고자 합니다.

ESP32는 BLE(저전력 블루투스) 모드를 지원하며, 이를 통해 다양한 센서 장치와 통신할 수 있습니다. 오늘은 BLE 클라이언트를 구현하는 과정을 예제를 통해 하나하나 설명해 보겠습니다.

BLE 클라이언트란?

BLE 클라이언트는 BLE 네트워크 내에서 특정 BLE 서버(예: 심박수 센서나 온도 센서 등)와 연결하여 데이터를 읽어오는 역할을 합니다. 클라이언트는 서버가 제공하는 특성(characteristics)에 접근하여 값을 읽거나, 알림(notification)을 받을 수 있습니다. 간단히 말해, 클라이언트는 데이터를 요청하고 서버는 데이터를 제공하는 구조입니다.

BLE 클라이언트 구현을 위해 ESP32의 BLE 라이브러리를 사용할 것입니다. 이제 코드를 통해 클라이언트를 설정하고, 서버와 통신하는 방법을 알아보겠습니다.

BLE 클라이언트 코드 구현

다음은 BLE 클라이언트를 구현하는 전체 코드입니다. 이 코드는 BLE 서버에 연결하고, 서버에서 데이터를 읽어오는 과정을 포함하고 있습니다.

#include <stdio.h>
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_bt_defs.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define TAG "BLE_CLIENT"
#define REMOTE_SERVICE_UUID 0x180A
#define REMOTE_CHARACTERISTIC_UUID 0x2A29

static esp_gattc_char_elem_t *char_elem_result = NULL;
static esp_gattc_descr_elem_t *descr_elem_result = NULL;
static bool connect = false;
static bool get_server = false;
static esp_gatt_if_t client_if;
static uint16_t conn_id;

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
    switch (event) {
        case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
            ESP_LOGI(TAG, "Scan parameters set");
            esp_ble_gap_start_scanning(30);
            break;
        case ESP_GAP_BLE_SCAN_RESULT_EVT:
            if (param->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
                ESP_LOGI(TAG, "Device found: %s", param->scan_rst.bda);
            }
            break;
        case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
            ESP_LOGI(TAG, "Scan stopped");
            break;
        default:
            break;
    }
}

static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
    switch (event) {
        case ESP_GATTC_REG_EVT:
            ESP_LOGI(TAG, "ESP_GATTC_REG_EVT, status %d, client_if %d", param->reg.status, gattc_if);
            client_if = gattc_if;
            break;
        case ESP_GATTC_CONNECT_EVT:
            ESP_LOGI(TAG, "ESP_GATTC_CONNECT_EVT, conn_id %d, gatt_if %d", param->connect.conn_id, gattc_if);
            conn_id = param->connect.conn_id;
            connect = true;
            break;
        case ESP_GATTC_OPEN_EVT:
            if (param->open.status == ESP_GATT_OK) {
                ESP_LOGI(TAG, "Connected to server");
                get_server = true;
            } else {
                ESP_LOGE(TAG, "Failed to connect to server");
            }
            break;
        case ESP_GATTC_DISCONNECT_EVT:
            ESP_LOGI(TAG, "ESP_GATTC_DISCONNECT_EVT, reason %d", param->disconnect.reason);
            connect = false;
            get_server = false;
            break;
        default:
            break;
    }
}

void app_main() {
    esp_err_t ret;

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        ESP_LOGE(TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_ble_gap_register_callback(gap_event_handler);
    if (ret) {
        ESP_LOGE(TAG, "gap register error, error code = %x", ret);
        return;
    }

    ret = esp_ble_gattc_register_callback(gattc_event_handler);
    if (ret) {
        ESP_LOGE(TAG, "gattc register error, error code = %x", ret);
        return;
    }

    ret = esp_ble_gattc_app_register(0);
    if (ret) {
        ESP_LOGE(TAG, "gattc app register error, error code = %x", ret);
        return;
    }

    ESP_LOGI(TAG, "BLE Client Initialized");
}

코드 설명

위 코드에서는 BLE 클라이언트를 설정하고 서버에 연결하는 과정을 보여주고 있습니다. 주요 기능은 다음과 같습니다.

  1. BLE 컨트롤러 초기화 및 활성화:
    • esp_bt_controller_init()esp_bt_controller_enable()을 사용하여 BLE 컨트롤러를 초기화하고 활성화합니다.
    • 클래식 블루투스 모드를 사용하지 않기 때문에 esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)를 사용하여 메모리를 해제합니다.
  2. Bluedroid 초기화 및 활성화:
    • esp_bluedroid_init()esp_bluedroid_enable()을 호출하여 Bluedroid 스택을 초기화하고 활성화합니다.
  3. GAP 및 GATTC 콜백 등록:
    • esp_ble_gap_register_callback()을 통해 GAP 이벤트 핸들러를 등록합니다. 이를 통해 장치 검색과 같은 GAP 이벤트를 처리할 수 있습니다.
    • esp_ble_gattc_register_callback()을 통해 GATT 클라이언트 이벤트 핸들러를 등록합니다.
    • BLE 연결, 서버 찾기, 데이터 수신 등의 이벤트를 처리하기 위해 gattc_event_handler() 콜백 함수를 정의했습니다.
  4. BLE 연결 및 데이터 수신:
    • ESP_GATTC_CONNECT_EVTESP_GATTC_OPEN_EVT에서 연결 상태를 확인하고 서버와의 연결 여부를 알 수 있습니다.

결과 확인

BLE 클라이언트를 실행하면 ESP32 장치는 BLE 서버에 연결을 시도하고, 연결이 성공하면 데이터를 읽을 준비를 합니다. BLE 서버와의 연결 상태나 데이터를 읽는 상황은 로그로 출력되므로, VS Code의 터미널이나 시리얼 모니터를 통해 확인할 수 있습니다.

결론

이번 포스팅에서는 ESP32 IDF를 활용하여 BLE 클라이언트를 설정하고 서버와 연결하는 방법에 대해 알아보았습니다. BLE 클라이언트를 통해 다양한 BLE 서버 장치와의 통신을 구현할 수 있으며, 이를 통해 데이터를 수집하거나 특정 작업을 수행할 수 있습니다. BLE는 IoT 환경에서 매우 중요한 역할을 하기 때문에 ESP32의 BLE 기능을 잘 활용하면 많은 응용 프로그램을 만들 수 있을 것입니다.

반응형

'ESP32 IDF' 카테고리의 다른 글

ESP32 IDF PWM  (0) 2024.11.08
ESP32 IDF FreeRTOS  (0) 2024.11.07
ESP32 IDF BLE 서버  (0) 2024.11.05
ESP32 IDF 웹 서버(Web Server)  (0) 2024.11.04
ESP32 IDF Wi-Fi 기능 살펴보기  (0) 2024.11.03