در این مقاله BLE را از نگاه مهندسی بررسی میکنیم: نقش central و peripheral، advertising، GATT، سرویسها، characteristicها، روشهای read/write/notify و طراحی پکتهای سبک برای پروژههای واقعی ESP32.
BLE یا Bluetooth Low Energy نسخه کممصرف بلوتوث است که برای تبادل دادههای کوتاه، سنسورها، تجهیزات پوشیدنی، تنظیمات محلی دستگاه و کنترل نزدیک طراحی شده است. در ESP32، BLE معمولا زمانی انتخاب خوبی است که بخواهیم بدون Wi-Fi و بدون مصرف زیاد انرژی، موبایل را به برد متصل کنیم.
برخلاف بلوتوث کلاسیک که برای صدا و جریان داده پیوسته مناسبتر است، BLE ارتباط را به رویدادهای کوتاه و قابل کنترل تقسیم میکند. همین ویژگی باعث میشود برای ارسال وضعیت سنسور، فرمان روشن و خاموش، تغییر تنظیمات، یا خواندن مقدارهای دورهای عالی باشد.
قبل از اتصال، peripheral بستههای advertising ارسال میکند تا central بتواند آن را پیدا کند. این بستهها کوچک هستند و معمولا شامل نام دستگاه، UUID سرویس، manufacturer data یا چند flag ساده میشوند.
| فیلد | کاربرد | نکته طراحی |
|---|---|---|
| Device Name | نمایش نام دستگاه در اسکن موبایل | کوتاه و قابل تشخیص باشد. |
| Service UUID | معرفی سرویس اصلی دستگاه | برای فیلتر کردن سریع در اپ موبایل مفید است. |
| Manufacturer Data | ارسال چند بایت اختصاصی | برای نسخه سختافزار یا وضعیت کوتاه مناسب است. |
بعد از اتصال، بیشتر کار ما با GATT انجام میشود. یک سرویس مجموعهای از characteristicهاست. هر characteristic یک مقدار دارد و میتواند قابلیت read، write، notify یا indicate داشته باشد.
برای مثال اگر ESP32 یک سنسور دما باشد، میتوان یک سرویس اختصاصی ساخت و داخل آن characteristic مقدار دما را قرار داد. موبایل آن characteristic را میخواند یا برای notification مشترک میشود.
نمونه زیر با Arduino Core برای ESP32 نوشته شده است. برد مثل یک peripheral دیده میشود، یک سرویس میسازد و مقدار characteristic را هر دو ثانیه با notification ارسال میکند.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define SERVICE_UUID "8f4a0001-3b7f-4b9a-9a52-1c7e10100001"
#define SENSOR_UUID "8f4a0002-3b7f-4b9a-9a52-1c7e10100002"
BLECharacteristic *sensorChar;
bool deviceConnected = false;
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *server) override {
deviceConnected = true;
}
void onDisconnect(BLEServer *server) override {
deviceConnected = false;
server->getAdvertising()->start();
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("LCENJ-ESP32-BLE");
BLEServer *server = BLEDevice::createServer();
server->setCallbacks(new ServerCallbacks());
BLEService *service = server->createService(SERVICE_UUID);
sensorChar = service->createCharacteristic(
SENSOR_UUID,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
sensorChar->addDescriptor(new BLE2902());
sensorChar->setValue("{\"counter\":0}");
service->start();
BLEAdvertising *advertising = server->getAdvertising();
advertising->addServiceUUID(SERVICE_UUID);
advertising->setScanResponse(true);
advertising->start();
}
void loop() {
static uint32_t counter = 0;
String payload = "{\"counter\":" + String(counter++) + "}";
sensorChar->setValue(payload.c_str());
if (deviceConnected) {
sensorChar->notify();
}
delay(2000);
}
در این نمونه یک characteristic قابل نوشتن داریم. اگر موبایل مقدار LED:ON یا LED:OFF بفرستد، ESP32 خروجی را تغییر میدهد.
#define CONTROL_UUID "8f4a0003-3b7f-4b9a-9a52-1c7e10100003"
#define LED_PIN 2
class ControlCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *c) override {
String value = c->getValue().c_str();
value.trim();
if (value == "LED:ON") {
digitalWrite(LED_PIN, HIGH);
} else if (value == "LED:OFF") {
digitalWrite(LED_PIN, LOW);
}
Serial.println("BLE command: " + value);
}
};
// داخل setup بعد از ساخت service:
pinMode(LED_PIN, OUTPUT);
BLECharacteristic *controlChar = service->createCharacteristic(
CONTROL_UUID,
BLECharacteristic::PROPERTY_WRITE
);
controlChar->setCallbacks(new ControlCallbacks());
برای بیشتر پروژههای الکترونیکی، payload باید کوتاه، قابل تشخیص و قابل توسعه باشد. اگر داده ساده است، یک متن کوتاه مثل LED:ON کافی است. اگر چند فیلد دارید، JSON کوچک یا فرمت کلید-مقدار مناسبتر است.
{"type":"sensor","temp":27.4,"battery":83}
برای دادههای پرتکرار، ارسال JSON طولانی میتواند باعث کاهش پایداری شود. در این حالت میتوانید از پکت باینری کوتاه استفاده کنید؛ مثلا یک بایت نوع پیام، دو بایت مقدار سنسور و یک بایت checksum.
BLE برای payloadهای کوچک عالی است، اما برای فایلهای بزرگ یا stream سریع مناسب نیست مگر با طراحی دقیق. سه پارامتر مهم روی سرعت و پایداری اثر دارند:
برای سنسورها، ارسال هر 500 میلیثانیه تا چند ثانیه معمولا پایدارتر از ارسال پیوسته است. برای دادههای چندبایتی، payload را کوتاه و قابل parse نگه دارید.
نمونههای کامل Arduino برای BLE Server، دریافت دستور LED و اسکن دستگاهها داخل پکیج همین مقاله قرار دارد.
دانلود نمونه کدهای ESP32BLE در ESP32 بهترین انتخاب برای ارتباط کممصرف، تنظیمات محلی، سنسورهای نزدیک و کنترل ساده با موبایل است. اگر advertising، نقش central/peripheral، سرویسهای GATT و روش read/write/notify را درست طراحی کنید، ارتباط پایدار و قابل توسعهای خواهید داشت.