Belajar ESP32: Bluetooth Connection

Selama seri artikel ini, ESP32 kita sudah bisa membaca sensor, menampilkan data di layar OLED, menghasilkan sinyal PWM, dan berkomunikasi via protokol serial seperti UART, SPI, dan I2C. Semua itu masih bersifat lokal — perangkat-perangkat yang berkomunikasi terhubung lewat kabel.

Sekarang saatnya kita melangkah lebih jauh: membuat ESP32 berkomunikasi secara nirkabel dengan smartphone menggunakan Bluetooth. Di artikel ini kita akan membahas dua teknologi Bluetooth yang didukung ESP32 secara built-in — Bluetooth Classic dan Bluetooth Low Energy (BLE) — lengkap dengan praktik mengendalikan LED dari HP dan menampilkan status koneksi di layar OLED.


Bluetooth pada ESP32

Salah satu keunggulan utama ESP32 dibanding mikrokontroler sekelasnya adalah konektivitas nirkabel yang sudah tertanam langsung di chip — tanpa modul tambahan. ESP32 mendukung:

  • Wi-Fi (802.11 b/g/n)
  • Bluetooth Classic (Bluetooth BR/EDR — Basic Rate/Enhanced Data Rate)
  • Bluetooth Low Energy / BLE (Bluetooth 4.2 & 5.0)

Keduanya — Bluetooth Classic dan BLE — bisa berjalan di ESP32 yang sama, meskipun tidak bisa aktif bersamaan secara simultan (Classic dan BLE menggunakan hardware radio yang sama, sehingga kita harus memilih salah satu dalam satu program).

Lalu apa bedanya? Mari kita pahami dulu sebelum masuk ke kode.


Bluetooth Classic vs Bluetooth Low Energy

Keduanya adalah teknologi Bluetooth, tapi dirancang untuk tujuan yang berbeda.

AspekBluetooth ClassicBluetooth Low Energy (BLE)
Konsumsi dayaTinggi (selalu aktif)Sangat rendah (mode sleep)
Kecepatan dataHingga 3 MbpsHingga 1 Mbps (umumnya jauh lebih sedikit)
Jangkauan~10–100 meter~10–50 meter
Paradigma koneksiSerial stream (mirip UART)Server-Client berbasis Service & Characteristic
Kemudahan penggunaanSederhana, mirip SerialLebih kompleks, butuh GATT
Cocok untukAudio, transfer file, data kontinuSensor periodik, IoT hemat baterai, wearable
Kompatibilitas HPAndroid sajaAndroid & iPhone

Singkatnya: jika Anda perlu koneksi sederhana yang cepat diimplementasikan dan hanya untuk Android, gunakan Bluetooth Classic. Jika Anda butuh hemat daya, kompatibel dengan iPhone, atau ingin membuat perangkat IoT berstandar industri, gunakan BLE.


Persiapan Hardware

Untuk semua latihan di artikel ini, komponen yang dibutuhkan:

KomponenFungsi
ESP32 DevKitMikrokontroler utama
LED + Resistor 330ΩOutput yang akan dikendalikan
OLED SSD1306 (opsional)Menampilkan status koneksi
Smartphone AndroidMengirim perintah via Bluetooth

Wiring LED:

KomponenKoneksi
LED (anoda)GPIO 2 via resistor 330Ω
LED (katoda)GND

Wiring OLED SSD1306 (untuk latihan gabungan):

Pin OLEDPin ESP32
VCC3.3V
GNDGND
SDAGPIO 21
SCLGPIO 22

Aplikasi HP yang dibutuhkan:


Bagian 1: Bluetooth Classic

Cara Kerja Bluetooth Classic pada ESP32

Bluetooth Classic pada ESP32 menggunakan protokol SPP (Serial Port Profile), yang pada dasarnya mengemulasikan komunikasi serial UART melalui koneksi Bluetooth. Konsep ini sangat mirip dengan modul Bluetooth HC-05 atau HC-06 yang mungkin sudah pernah Anda gunakan dengan Arduino.

Dari sisi programmer, Bluetooth Classic di ESP32 terasa seperti bekerja dengan Serial biasa — ada fungsi read(), write(), print(), println(), dan available(). Inilah yang membuatnya sangat mudah digunakan.

Library yang digunakan adalah BluetoothSerial.h, yang sudah termasuk dalam paket ESP32 Arduino Core dan tidak perlu diinstal secara terpisah.

Latihan 1: Komunikasi Dua Arah Dasar (Serial ↔ Bluetooth)

Ini adalah program dasar yang menjembatani Serial Monitor di komputer dengan aplikasi Bluetooth di HP. Apa yang diketik di Serial Monitor akan dikirim ke HP, dan sebaliknya.

#include "BluetoothSerial.h"

// Cek apakah Bluetooth dikompilasi dengan benar
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak aktif! Periksa konfigurasi board ESP32 Anda.
#endif

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);

  // Mulai Bluetooth dengan nama perangkat "ESP32-SMSRV"
  SerialBT.begin("ESP32-SMSRV");

  Serial.println("Bluetooth aktif. Cari perangkat 'ESP32-SMSRV' di HP Anda.");
}

void loop() {
  // Jika ada data dari Serial Monitor, kirim ke HP via Bluetooth
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }

  // Jika ada data dari HP via Bluetooth, tampilkan di Serial Monitor
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }

  delay(20);
}

Cara menjalankan:

  1. Upload kode ke ESP32
  2. Buka Serial Monitor (baud rate 115200)
  3. Di HP, buka Settings → Bluetooth, cari dan pair dengan “ESP32-SMSRV”
  4. Buka aplikasi Serial Bluetooth Terminal, masuk ke menu Devices, pilih ESP32-SMSRV
  5. Ketuk tombol connect (ikon plug di pojok atas), tunggu hingga muncul “Connected”
  6. Ketik pesan dari HP → muncul di Serial Monitor. Ketik dari Serial Monitor → muncul di HP

Penjelasan Kode

BluetoothSerial SerialBT; — membuat objek Bluetooth Serial, analog dengan objek Serial yang biasa kita gunakan.

SerialBT.begin("ESP32-SMSRV"); — memulai Bluetooth dan mengumumkan nama perangkat. Nama inilah yang akan muncul di daftar Bluetooth HP Anda. Bisa diganti sesuai keinginan.

SerialBT.write() / SerialBT.read() / SerialBT.available() — fungsi-fungsi ini identik dengan fungsi Serial biasa, hanya saja data mengalir melalui koneksi Bluetooth, bukan kabel USB.


Latihan 2: Kontrol LED ON/OFF dari HP via Bluetooth Classic

Ini adalah praktik yang paling relevan untuk proyek IoT nyata — mengirim perintah teks sederhana dari HP untuk mengendalikan output di ESP32.

Perintah yang digunakan:

  • Ketik ON → LED menyala
  • Ketik OFF → LED mati
#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak aktif!
#endif

BluetoothSerial SerialBT;

const int ledPin = 2;
String pesanMasuk = "";

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  SerialBT.begin("ESP32-LEDControl");
  Serial.println("Bluetooth aktif. Kirim 'ON' atau 'OFF' dari HP.");
}

void prosesPesan(String pesan) {
  pesan.trim();  // hapus spasi dan karakter newline
  pesan.toUpperCase();  // ubah ke huruf kapital agar tidak case-sensitive

  if (pesan == "ON") {
    digitalWrite(ledPin, HIGH);
    SerialBT.println("LED dinyalakan.");
    Serial.println("[BT] Perintah: ON -> LED ON");
  } else if (pesan == "OFF") {
    digitalWrite(ledPin, LOW);
    SerialBT.println("LED dimatikan.");
    Serial.println("[BT] Perintah: OFF -> LED OFF");
  } else {
    SerialBT.println("Perintah tidak dikenal. Gunakan 'ON' atau 'OFF'.");
    Serial.print("[BT] Perintah tidak dikenal: ");
    Serial.println(pesan);
  }
}

void loop() {
  while (SerialBT.available()) {
    char c = (char)SerialBT.read();

    if (c == '\n' || c == '\r') {
      // Newline = akhir pesan, proses sekarang
      if (pesanMasuk.length() > 0) {
        prosesPesan(pesanMasuk);
        pesanMasuk = "";
      }
    } else {
      pesanMasuk += c;  // kumpulkan karakter satu per satu
    }
  }
}

Cara penggunaan:

  1. Upload kode, pair HP dengan “ESP32-LEDControl”
  2. Di Serial Bluetooth Terminal, ketik ON lalu tekan Enter → LED menyala
  3. Ketik OFF lalu tekan Enter → LED mati
  4. ESP32 akan membalas konfirmasi teks ke aplikasi di HP

Tips pengaturan Serial Bluetooth Terminal: Pastikan di menu Settings pada aplikasi, opsi “Send on enter” diaktifkan dan newline character diatur ke \n atau CR+LF agar pesan terkirim saat tombol Enter ditekan.


Latihan 3: Bluetooth Classic dengan Callback Status Koneksi

Seringkali kita perlu tahu apakah HP sedang terhubung atau tidak. Library BluetoothSerial menyediakan mekanisme callback untuk ini.

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak aktif!
#endif

BluetoothSerial SerialBT;

const int ledPin    = 2;
const int statusPin = 5;  // LED indikator koneksi (opsional)
bool btTerhubung    = false;

// Callback dipanggil otomatis saat status koneksi berubah
void callbackBluetooth(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    Serial.println("[BT] HP terhubung!");
    btTerhubung = true;
  } else if (event == ESP_SPP_CLOSE_EVT) {
    Serial.println("[BT] HP terputus.");
    btTerhubung = false;
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  pinMode(statusPin, OUTPUT);

  SerialBT.register_callback(callbackBluetooth);
  SerialBT.begin("ESP32-Status");

  Serial.println("Bluetooth aktif.");
}

void loop() {
  // Nyalakan LED status jika terhubung
  digitalWrite(statusPin, btTerhubung ? HIGH : LOW);

  if (SerialBT.available()) {
    String pesan = SerialBT.readStringUntil('\n');
    pesan.trim();
    pesan.toUpperCase();

    if (pesan == "ON")  { digitalWrite(ledPin, HIGH); SerialBT.println("LED ON"); }
    if (pesan == "OFF") { digitalWrite(ledPin, LOW);  SerialBT.println("LED OFF"); }
  }

  delay(10);
}

Dengan register_callback(), kita bisa mendeteksi event ESP_SPP_SRV_OPEN_EVT (HP baru connect) dan ESP_SPP_CLOSE_EVT (HP disconnect) sehingga bisa merespons perubahan koneksi secara real-time.


Bagian 2: Bluetooth Low Energy (BLE)

Memahami Konsep BLE

BLE bekerja dengan cara yang sangat berbeda dari Bluetooth Classic. Tidak ada “koneksi serial” yang sederhana — BLE menggunakan arsitektur GATT (Generic Attribute Profile) yang hierarkis.

Ini adalah bagian terpenting untuk dipahami sebelum menulis satu baris kode BLE pun.

Hierarki GATT

Bayangkan sebuah buku (perangkat BLE). Di dalam buku ada beberapa bab (Service). Di dalam setiap bab ada beberapa sub-topik (Characteristic). Setiap sub-topik memiliki isi (Value) dan keterangan tambahan (Descriptor).

Perangkat BLE
└── Profile
    ├── Service A (misal: "Kontrol LED")
    │   ├── Characteristic 1 (misal: "Status LED") → Value: "ON"
    │   └── Characteristic 2 (misal: "Kecerahan") → Value: 128
    └── Service B (misal: "Sensor Suhu")
        └── Characteristic 1 (misal: "Temperatur") → Value: 27.5

Service — kelompok fungsi terkait. Misalnya service “Heart Rate” atau service “Battery Level”.

Characteristic — unit data terkecil yang bisa dibaca/ditulis. Setiap characteristic punya properties yang mendefinisikan apa yang bisa dilakukan:

  • READ — client bisa membaca nilainya
  • WRITE — client bisa menulis nilai baru
  • NOTIFY — server akan otomatis mengirim notifikasi ke client saat nilai berubah
  • INDICATE — seperti NOTIFY tapi dengan konfirmasi (ACK)

UUID — setiap Service dan Characteristic diidentifikasi oleh UUID (128-bit string unik). Bisa menggunakan UUID standar dari Bluetooth SIG, atau membuat sendiri di uuidgenerator.net.

BLE Server vs BLE Client

Dalam arsitektur BLE, ada dua peran:

  • Server — perangkat yang menyimpan data dan mengumumkan keberadaannya (advertising). Dalam konteks kita: ESP32 adalah BLE Server.
  • Client — perangkat yang mencari server dan membaca/menulis datanya. Dalam konteks kita: HP kita adalah BLE Client.

Latihan 1: BLE Server Dasar

Program berikut membuat ESP32 menjadi BLE Server yang meng-advertise satu service dengan satu characteristic yang bisa dibaca dan ditulis.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// UUID bisa dibuat bebas menggunakan https://www.uuidgenerator.net/
#define SERVICE_UUID "b7403aed-d49b-47cb-b4d0-298470d5924d"
#define CHARACTERISTIC_UUID "b9dd4f09-daf8-424d-8387-80429b4b85d7"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

// Callback server: dipanggil saat client connect/disconnect
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
Serial.println("[BLE] Client terhubung!");
}

void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
Serial.println("[BLE] Client terputus. Kembali advertising...");
// Restart advertising agar bisa dideteksi lagi
BLEDevice::startAdvertising();
}
};

// Callback characteristic: dipanggil saat client menulis nilai
class MyCharCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = pCharacteristic->getValue().c_str();
if (value.length() > 0) {
Serial.print("[BLE] Nilai baru diterima: ");
Serial.println(value);
}
}
};

void setup() {
Serial.begin(115200);
Serial.println("Memulai BLE Server...");

// 1. Inisialisasi perangkat BLE dengan nama
BLEDevice::init("ESP32-BLE-SMSRV");

// 2. Buat server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());

// 3. Buat service
BLEService *pService = pServer->createService(SERVICE_UUID);

// 4. Buat characteristic dengan property READ dan WRITE
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCharCallbacks());

// 5. Set nilai awal characteristic
pCharacteristic->setValue("Hello from ESP32!");

// 6. Start service
pService->start();

// 7. Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
BLEDevice::startAdvertising();

Serial.println("BLE Server aktif. Cari 'ESP32-BLE-SMSRV' di HP Anda.");
}

void loop() {
delay(1000);
}

Cara menguji dengan nRF Connect:

  1. Upload kode
  2. Buka aplikasi nRF Connect di HP
  3. Tab Scanner → tap Scan → cari dan tap ESP32-BLE-SMSRV
  4. Tap Connect
  5. Anda akan melihat service dengan UUID yang kita definisikan
  6. Tap characteristic → baca nilainya (“Hello from ESP32!”)
  7. Tap ikon pensil (Write) → tulis nilai baru → Serial Monitor menampilkannya

Latihan 2: BLE dengan NOTIFY — Server Mengirim Data ke HP Secara Otomatis

Property NOTIFY memungkinkan ESP32 secara aktif mendorong (push) data ke HP setiap ada perubahan, tanpa HP harus polling/request terus-menerus. Ini sangat efisien untuk mengirimkan pembacaan sensor.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h> // Descriptor untuk mengaktifkan Notify

#define SERVICE_UUID "b5ef7c48-b4a2-4a43-987e-2e880a0cfc20"
#define CHARACTERISTIC_UUID "69a802c2-e383-4b30-82c0-60d2a5d2d3a3"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
int counter = 0;

class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
Serial.println("[BLE] Client terhubung.");
}
void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
Serial.println("[BLE] Client terputus.");
BLEDevice::startAdvertising();
}
};

void setup() {
Serial.begin(115200);

BLEDevice::init("ESP32-Notify");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());

BLEService *pService = pServer->createService(SERVICE_UUID);

pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_NOTIFY
);

// Tambahkan descriptor 0x2902 — wajib ada agar NOTIFY berfungsi
pCharacteristic->addDescriptor(new BLE2902());

pService->start();
BLEDevice::startAdvertising();

Serial.println("BLE Notify Server aktif.");
}

void loop() {
if (deviceConnected) {
String data = "Count: " + String(counter++);
pCharacteristic->setValue(data.c_str());
pCharacteristic->notify(); // Kirim notifikasi ke client

Serial.print("[BLE] Notify dikirim: ");
Serial.println(data);
}

delay(2000);
}

Penting: Descriptor BLE2902 harus ditambahkan pada characteristic yang menggunakan NOTIFY. Tanpa descriptor ini, HP tidak akan dapat mengaktifkan notifikasi dari characteristic tersebut.


Latihan 3: Kontrol LED ON/OFF dari HP via BLE

Inilah implementasi BLE yang paling praktis — HP mengirim perintah, ESP32 merespons dengan menyalakan atau mematikan LED.

Kita akan menggunakan dua characteristic dalam satu service:

  • CHAR_RX (WRITE) — untuk menerima perintah dari HP
  • CHAR_TX (NOTIFY) — untuk mengirimkan balasan status ke HP

Pola dua characteristic seperti ini (RX + TX) adalah pendekatan standar dalam BLE Serial Communication, juga dikenal sebagai NUS (Nordic UART Service).

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// UUID custom untuk service dan dua characteristic
#define SERVICE_UUID "34484f96-8583-49c5-bd9b-400e93a1d1c1"
#define CHAR_RX_UUID "3c2ed02b-4266-4c06-b208-f7eb356c22d8" // Terima dari HP
#define CHAR_TX_UUID "1c6abd5d-08c2-4555-9766-b1464928de1c" // Kirim ke HP

const int ledPin = 2;
bool deviceConnected = false;

BLECharacteristic *pCharTX;

class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
Serial.println("[BLE] HP terhubung.");
}
void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
Serial.println("[BLE] HP terputus. Restart advertising...");
BLEDevice::startAdvertising();
}
};

// Callback CHAR_RX: dipanggil saat HP menulis perintah
class RxCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String perintah = pCharacteristic->getValue().c_str();
perintah.trim();
perintah.toUpperCase();

Serial.print("[BLE] Perintah diterima: ");
Serial.println(perintah);

String balasan;

if (perintah == "ON") {
digitalWrite(ledPin, HIGH);
balasan = "OK: LED ON";
} else if (perintah == "OFF") {
digitalWrite(ledPin, LOW);
balasan = "OK: LED OFF";
} else {
balasan = "ERROR: Perintah tidak dikenal";
}

// Kirim balasan ke HP via TX characteristic
if (deviceConnected) {
pCharTX->setValue(balasan.c_str());
pCharTX->notify();
Serial.print("[BLE] Balasan dikirim: ");
Serial.println(balasan);
}
}
};

void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);

BLEDevice::init("ESP32-BLE-LED");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());

BLEService *pService = pServer->createService(SERVICE_UUID);

// Characteristic RX: menerima perintah dari HP (WRITE)
BLECharacteristic *pCharRX = pService->createCharacteristic(
CHAR_RX_UUID,
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_WRITE_NR
);
pCharRX->setCallbacks(new RxCallbacks());

// Characteristic TX: mengirim balasan ke HP (NOTIFY)
pCharTX = pService->createCharacteristic(
CHAR_TX_UUID,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharTX->addDescriptor(new BLE2902());

pService->start();

BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
BLEDevice::startAdvertising();

Serial.println("BLE LED Controller aktif. Kirim 'ON' atau 'OFF' dari HP.");
}

void loop() {
delay(10);
}

Cara penggunaan dengan nRF Connect:

  1. Upload kode, hubungkan HP ke ESP32-BLE-LED
  2. Temukan service dengan UUID 34484f96-8583-49c5-bd9b-400e93a1d1c1
  3. Aktifkan Notify pada characteristic 1c6abd5d-08c2-4555-9766-b1464928de1c (CHAR_TX) dengan tap ikon panah bawah berlipat
  4. Pada characteristic 3c2ed02b-4266-4c06-b208-f7eb356c22d8 (CHAR_RX), tap ikon pensil (Write)
  5. Pilih Text (UTF-8), ketik ON → tap Write
  6. LED menyala, dan characteristic TX mengirim notifikasi “OK: LED ON” ke HP

Bagian 3: Proyek Gabungan — Status Koneksi Bluetooth di OLED

Sekarang kita gabungkan semua yang sudah dipelajari: Bluetooth Classic, kontrol LED, dan tampilan status koneksi di layar OLED SSD1306. Ini adalah proyek yang paling lengkap dan mendekati implementasi IoT nyata.

Proyek ini menggunakan Bluetooth Classic (lebih simpel untuk demo ini), dan menampilkan:

  • Status koneksi Bluetooth (Connected / Waiting…)
  • Status LED saat ini (ON / OFF)
  • Perintah terakhir yang diterima
#include "BluetoothSerial.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak aktif!
#endif

// --- Konfigurasi OLED ---
#define SCREEN_WIDTH   128
#define SCREEN_HEIGHT  64
#define OLED_RESET     -1
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// --- Bluetooth ---
BluetoothSerial SerialBT;

// --- LED ---
const int ledPin = 2;

// --- State ---
bool btTerhubung    = false;
bool ledState       = false;
String perintahTerakhir = "-";
String pesanMasuk   = "";

// --- Callback status koneksi ---
void callbackBT(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    btTerhubung = true;
    Serial.println("[BT] HP terhubung!");
  } else if (event == ESP_SPP_CLOSE_EVT) {
    btTerhubung = false;
    Serial.println("[BT] HP terputus.");
  }
}

// --- Update tampilan OLED ---
void updateOLED() {
  display.clearDisplay();

  // Baris 1: Judul
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("== BT Controller ==");

  // Baris 2: Status Bluetooth
  display.setCursor(0, 14);
  display.print("BT: ");
  if (btTerhubung) {
    display.println("Connected   ");
  } else {
    display.println("Waiting...  ");
  }

  // Baris 3: Status LED
  display.setCursor(0, 28);
  display.print("LED: ");
  display.println(ledState ? "ON " : "OFF");

  // Baris 4: Perintah terakhir
  display.setCursor(0, 42);
  display.print("Cmd: ");
  display.println(perintahTerakhir);

  // Baris 5: Indikator visual LED
  if (ledState) {
    display.fillCircle(118, 56, 6, SSD1306_WHITE);  // Lingkaran penuh = ON
  } else {
    display.drawCircle(118, 56, 6, SSD1306_WHITE);  // Lingkaran kosong = OFF
  }

  display.display();
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // Inisialisasi OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println("OLED gagal diinisialisasi!");
    for (;;);
  }

  // Tampilkan layar boot
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("Memulai Bluetooth...");
  display.display();
  delay(1500);

  // Inisialisasi Bluetooth
  SerialBT.register_callback(callbackBT);
  SerialBT.begin("ESP32-OLEDControl");

  Serial.println("Sistem siap. Cari 'ESP32-OLEDControl' di HP.");
  updateOLED();
}

void loop() {
  // Baca perintah masuk dari HP
  while (SerialBT.available()) {
    char c = (char)SerialBT.read();

    if (c == '\n' || c == '\r') {
      if (pesanMasuk.length() > 0) {
        pesanMasuk.trim();
        pesanMasuk.toUpperCase();

        Serial.print("[BT] Perintah: ");
        Serial.println(pesanMasuk);

        if (pesanMasuk == "ON") {
          digitalWrite(ledPin, HIGH);
          ledState = true;
          perintahTerakhir = "ON";
          SerialBT.println("LED dinyalakan.");
        } else if (pesanMasuk == "OFF") {
          digitalWrite(ledPin, LOW);
          ledState = false;
          perintahTerakhir = "OFF";
          SerialBT.println("LED dimatikan.");
        } else if (pesanMasuk == "STATUS") {
          String status = "BT: ";
          status += btTerhubung ? "Connected" : "Disconnected";
          status += " | LED: ";
          status += ledState ? "ON" : "OFF";
          SerialBT.println(status);
          perintahTerakhir = "STATUS";
        } else {
          SerialBT.println("Perintah: ON, OFF, atau STATUS");
          perintahTerakhir = "???";
        }

        updateOLED();
        pesanMasuk = "";
      }
    } else {
      pesanMasuk += c;
    }
  }

  // Update OLED setiap 1 detik untuk refresh status koneksi
  static unsigned long lastUpdate = 0;
  if (millis() - lastUpdate > 1000) {
    updateOLED();
    lastUpdate = millis();
  }

  delay(10);
}

Apa yang bisa dilakukan dengan proyek ini:

  • Saat HP belum terhubung: OLED menampilkan BT: Waiting...
  • Saat HP berhasil connect: OLED berubah menjadi BT: Connected
  • Kirim perintah ON dari HP: LED menyala, OLED menampilkan LED: ON + lingkaran terisi
  • Kirim perintah OFF dari HP: LED mati, OLED menampilkan LED: OFF + lingkaran kosong
  • Kirim perintah STATUS dari HP: ESP32 membalas ringkasan status terkini

Perbandingan Implementasi Keduanya

Setelah mencoba langsung kedua teknologi, berikut perbandingan dari sisi implementasi:

AspekBluetooth ClassicBLE
LibraryBluetoothSerial.h (built-in)BLEDevice.h, BLEServer.h, BLE2902.h
ParadigmaSerial stream (seperti UART)Service → Characteristic
Inisialisasi2 baris15–20 baris setup
Mengirim dataSerialBT.println()pChar->setValue(); pChar->notify();
Menerima dataSerialBT.read() di loopCallback onWrite() di class
Deteksi koneksiregister_callback()Override onConnect()/onDisconnect()
Kompatibilitas HPAndroid sajaAndroid & iPhone
Kemudahan⭐⭐⭐⭐⭐⭐⭐⭐
Fleksibilitas⭐⭐⭐⭐⭐⭐⭐⭐

Kesimpulan

ESP32 menyediakan dua teknologi Bluetooth yang masing-masing unggul di bidangnya:

Bluetooth Classic adalah pilihan yang tepat ketika Anda ingin implementasi cepat dengan konsep yang sederhana — mirip seperti berkomunikasi via Serial biasa, hanya saja melalui udara. Ideal untuk prototipe, proyek Android, atau situasi di mana kesederhanaan kode lebih penting dari efisiensi daya.

BLE adalah pilihan yang tepat ketika Anda membangun produk IoT yang sesungguhnya — kompatibel dengan iPhone dan Android, hemat baterai, dan mengikuti standar industri. Konsepnya lebih kompleks (Service, Characteristic, UUID, GATT), tapi memberikan fleksibilitas dan interoperabilitas yang jauh lebih besar.

Poin-poin penting yang sudah kita pelajari:

  • Bluetooth Classic menggunakan library BluetoothSerial dan pola komunikasi seperti Serial biasa
  • BLE menggunakan arsitektur GATT: Profile → Service → Characteristic
  • UUID adalah identitas unik setiap Service dan Characteristic pada BLE
  • Property Characteristic (READ, WRITE, NOTIFY) menentukan cara interaksi dengan data
  • Descriptor BLE2902 wajib ditambahkan untuk mengaktifkan fitur NOTIFY
  • Kedua teknologi bisa dikombinasikan dengan komponen lain seperti OLED untuk membuat sistem yang lebih lengkap

Referensi

Tinggalkan Komentar

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Scroll to Top