ESP-IDF ile BLE (Bluetooth Low Energy) GATT Sunucusu Yapımı

Print

Wi-Fi ağı bulunmayan ortamlarda veya cihazın ilk kurulumunda (Provisioning – telefondan cihaza Wi-Fi şifresi tanımlama) en az güç tüketen ve akıllı telefonlarla doğrudan haberleşen teknoloji BLE (Bluetooth Low Energy / Bluetooth 4.2 & 5.0) standardıdır. ESP-IDF üzerinde ESP-IDF BLE GATT sunucusu (Generic Attribute Profile) kurmak; sensör verilerini bildirim (Notification) olarak akıllı telefonlara göndermeyi ve telefondan gelen ayar komutlarını kablosuz olarak almayı sağlar.

Bu rehberde; BLE profil mimarisini (Services, Characteristics, Descriptors), hafif ve az bellek tüketen NimBLE protokol yığınını, reklam paketleri (Advertising) yayınlamayı ve telefon uygulamasıyla (nRF Connect) iki yönlü veri transferini öğreneceğiz.


BLE Mimarisi: GAP ve GATT Temelleri

BLE dünyası iki ana protokole dayanır:

  1. GAP (Generic Access Profile): Cihazın görünürlüğünü kontrol eder. Cihaz yayın yapar (Advertising: “Benim adım ESP32-Device”) ve telefonun bağlanmasını sağlar.
  2. GATT (Generic Attribute Profile): Bağlantı kurulduktan sonra verilerin nasıl yapılandırılacağını belirler:

– Service (Servis): Mantıksal bir veri grubu (örn: Çevre Algılama Servisi, UUID: 0x181A). – Characteristic (Karakteristik): Gerçek veriyi tutan değişken (örn: Sıcaklık, UUID: 0x2A6E). Özellikleri: Read, Write, Notify. – Descriptor (Tanımlayıcı): Karakteristiğin ek ayarı (örn: Bildirimleri açıp kapatma izni – CCCD).


Neden NimBLE Yığını? (Bluedroid Alternatifi)

ESP-IDF’te iki Bluetooth yığını bulunur:

  • Bluedroid: Klasik Bluetooth (BT Classic) ve BLE destekler; ancak ~120 KB RAM tüketir.
  • NimBLE (Apache NimBLE): Sadece BLE odaklıdır; son derece hafiftir, yalnızca ~30 KB RAM tüketir ve çok daha hızlı bağlanır. Modern IoT projelerinde standart tercihtir (menuconfig üzerinden seçilebilir).

Adım Adım NimBLE GATT Sunucusu Kodu

Aşağıdaki örnekte bir özel servis (0x180F – Batarya Servisi) ve okunabilir/yazılabilir bir karakteristik tanımlıyoruz:

#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"

static const char *TAG = "BLE_SERVER";
static uint8_t battery_level = 85; // %85 pil seviyesi

// 1. Karakteristik Okuma / Yazma Geri Çağırım Fonksiyonu
static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
                               struct ble_gatt_access_ctxt *ctxt, void *arg) {
    if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
        ESP_LOGI(TAG, "Telefondan Pil Seviyesi Okundu: %d%%", battery_level);
        os_mbuf_append(ctxt->om, &battery_level, sizeof(battery_level));
        return 0;
    } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
        uint8_t new_val;
        uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
        ble_hs_mbuf_to_flat(ctxt->om, &new_val, sizeof(new_val), NULL);
        ESP_LOGI(TAG, "Telefondan Yeni Değer Yazıldı: %d", new_val);
        battery_level = new_val;
        return 0;
    }
    return BLE_ATT_ERR_UNLIKELY;
}

// 2. GATT Servis ve Karakteristik Tablosu
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
    {
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(0x180F), // Battery Service UUID
        .characteristics = (struct ble_gatt_chr_def[]) {
            {
                .uuid = BLE_UUID16_DECLARE(0x2A19), // Battery Level UUID
                .access_flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
                .access_cb = gatt_svr_chr_access,
            },
            { 0 } // Sonlandırıcı
        },
    },
    { 0 } // Servis Tablosu Sonu
};

Adım 3: Reklam (Advertising) Başlatmak

Cihazın etraftaki telefonlar tarafından “ESP32-Sensor” adıyla bulunabilmesi için yayın başlatılır:

static void ble_app_advertise(void) {
    struct ble_gap_adv_params adv_params;
    struct ble_hs_adv_fields fields;

    memset(&fields, 0, sizeof(fields));
    fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
    fields.name = (uint8_t *)"ESP32-Sensor";
    fields.name_len = strlen("ESP32-Sensor");
    fields.name_is_complete = 1;

    ble_gap_adv_set_fields(&fields);

    memset(&adv_params, 0, sizeof(adv_params));
    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; // Herkese bağlanabilir mod
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // Genel keşfedilebilir mod

    ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, NULL, NULL);
    ESP_LOGI(TAG, "BLE Yayını Başladı! nRF Connect ile taranabilir.");
}

Test Etme: nRF Connect Mobil Uygulaması

Telefonunuza ücretsiz nRF Connect for Mobile uygulamasını indirip “Scan” butonuna bastığınızda:

  1. ESP32-Sensor aygıtını göreceksiniz.
  2. “Connect” dediğinizde Battery Service (0x180F) listelenecektir.
  3. Karakteristiğin yanındaki ok işaretine bastığınızda cihazdaki 85 değerini telefon ekranında anında okuyabilirsiniz!

Özet

NimBLE yığını ile ESP32 üzerinde yüksek performanslı ve ultra düşük bellekli BLE sunucuları kurabilirsiniz. Wi-Fi şifresi gerektirmeyen doğrudan telefon haberleşmesi sayesinde akıllı ev ve medikal projelerinizde kusursuz bir kullanıcı deneyimi sunabilirsiniz.

Tags , , , , ,

How can we help?