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.
| Aspek | Bluetooth Classic | Bluetooth Low Energy (BLE) |
|---|---|---|
| Konsumsi daya | Tinggi (selalu aktif) | Sangat rendah (mode sleep) |
| Kecepatan data | Hingga 3 Mbps | Hingga 1 Mbps (umumnya jauh lebih sedikit) |
| Jangkauan | ~10–100 meter | ~10–50 meter |
| Paradigma koneksi | Serial stream (mirip UART) | Server-Client berbasis Service & Characteristic |
| Kemudahan penggunaan | Sederhana, mirip Serial | Lebih kompleks, butuh GATT |
| Cocok untuk | Audio, transfer file, data kontinu | Sensor periodik, IoT hemat baterai, wearable |
| Kompatibilitas HP | Android saja | Android & 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:
| Komponen | Fungsi |
|---|---|
| ESP32 DevKit | Mikrokontroler utama |
| LED + Resistor 330Ω | Output yang akan dikendalikan |
| OLED SSD1306 (opsional) | Menampilkan status koneksi |
| Smartphone Android | Mengirim perintah via Bluetooth |
Wiring LED:
| Komponen | Koneksi |
|---|---|
| LED (anoda) | GPIO 2 via resistor 330Ω |
| LED (katoda) | GND |
Wiring OLED SSD1306 (untuk latihan gabungan):
| Pin OLED | Pin ESP32 |
|---|---|
| VCC | 3.3V |
| GND | GND |
| SDA | GPIO 21 |
| SCL | GPIO 22 |
Aplikasi HP yang dibutuhkan:
- Bluetooth Classic: Serial Bluetooth Terminal (Android)
- BLE: nRF Connect atau LightBlue (Android & iPhone)
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:
- Upload kode ke ESP32
- Buka Serial Monitor (baud rate 115200)
- Di HP, buka Settings → Bluetooth, cari dan pair dengan “ESP32-SMSRV”
- Buka aplikasi Serial Bluetooth Terminal, masuk ke menu Devices, pilih ESP32-SMSRV
- Ketuk tombol connect (ikon plug di pojok atas), tunggu hingga muncul “Connected”
- 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:
- Upload kode, pair HP dengan “ESP32-LEDControl”
- Di Serial Bluetooth Terminal, ketik
ONlalu tekan Enter → LED menyala - Ketik
OFFlalu tekan Enter → LED mati - 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
\natauCR+LFagar 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 nilainyaWRITE— client bisa menulis nilai baruNOTIFY— server akan otomatis mengirim notifikasi ke client saat nilai berubahINDICATE— 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:
- Upload kode
- Buka aplikasi nRF Connect di HP
- Tab Scanner → tap Scan → cari dan tap ESP32-BLE-SMSRV
- Tap Connect
- Anda akan melihat service dengan UUID yang kita definisikan
- Tap characteristic → baca nilainya (“Hello from ESP32!”)
- 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
BLE2902harus 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:
- Upload kode, hubungkan HP ke ESP32-BLE-LED
- Temukan service dengan UUID
34484f96-8583-49c5-bd9b-400e93a1d1c1 - Aktifkan Notify pada characteristic
1c6abd5d-08c2-4555-9766-b1464928de1c(CHAR_TX) dengan tap ikon panah bawah berlipat - Pada characteristic
3c2ed02b-4266-4c06-b208-f7eb356c22d8(CHAR_RX), tap ikon pensil (Write) - Pilih Text (UTF-8), ketik
ON→ tap Write - 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
ONdari HP: LED menyala, OLED menampilkanLED: ON+ lingkaran terisi - Kirim perintah
OFFdari HP: LED mati, OLED menampilkanLED: OFF+ lingkaran kosong - Kirim perintah
STATUSdari HP: ESP32 membalas ringkasan status terkini
Perbandingan Implementasi Keduanya
Setelah mencoba langsung kedua teknologi, berikut perbandingan dari sisi implementasi:
| Aspek | Bluetooth Classic | BLE |
|---|---|---|
| Library | BluetoothSerial.h (built-in) | BLEDevice.h, BLEServer.h, BLE2902.h |
| Paradigma | Serial stream (seperti UART) | Service → Characteristic |
| Inisialisasi | 2 baris | 15–20 baris setup |
| Mengirim data | SerialBT.println() | pChar->setValue(); pChar->notify(); |
| Menerima data | SerialBT.read() di loop | Callback onWrite() di class |
| Deteksi koneksi | register_callback() | Override onConnect()/onDisconnect() |
| Kompatibilitas HP | Android saja | Android & 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
BluetoothSerialdan 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
BLE2902wajib ditambahkan untuk mengaktifkan fitur NOTIFY - Kedua teknologi bisa dikombinasikan dengan komponen lain seperti OLED untuk membuat sistem yang lebih lengkap

