ESP32 BLE: Menghubungkan ESP32 sebagai BLE Master (Server) dan BLE Client (Client) dengan LCD I2C

Tujuan Pembelajaran
- Memahami komunikasi BLE (Bluetooth Low Energy) antara dua ESP32.
- Menggunakan sensor DHT11 untuk mengukur suhu dan kelembapan.
- Menampilkan data dari server pada LCD I2C melalui BLE client.
- Menguasai konsep penggunaan BLE service dan characteristic.
Dasar Teori
- ESP32 dan BLE (Bluetooth Low Energy)
- ESP32 adalah mikrokontroler yang dilengkapi dengan fitur Wi-Fi dan BLE, menjadikannya sangat serbaguna untuk aplikasi IoT (Internet of Things). BLE (Bluetooth Low Energy) adalah salah satu mode komunikasi yang didukung ESP32, yang dirancang untuk konsumsi daya rendah dan jangkauan lebih jauh dibandingkan Bluetooth klasik. BLE sangat cocok untuk aplikasi yang memerlukan koneksi terus-menerus tetapi dengan penggunaan daya yang minimal, seperti perangkat yang memonitor kesehatan, sensor nirkabel, dan smart home.
- BLE Server dan Client: Dalam arsitektur BLE, ada dua peran utama yang dapat dimainkan perangkat: Server dan Client. BLE Server menyediakan data atau layanan yang dapat diakses oleh BLE Client. Server menyimpan data dan dapat memberikan pemberitahuan (notifikasi) ketika data diperbarui. Sebaliknya, Client berperan dalam meminta data atau menerima notifikasi dari Server.
- Konsep BLE Service dan Characteristic
- Service dalam BLE adalah kumpulan dari beberapa karakteristik yang didefinisikan bersama untuk menyediakan layanan tertentu. Setiap Service memiliki UUID unik yang mengidentifikasinya.
- Characteristic adalah unit data dalam BLE yang merepresentasikan informasi tertentu, misalnya suhu, kelembapan, detak jantung, dsb. Characteristic memiliki UUID sendiri dan dapat memiliki beberapa properti seperti READ, WRITE, dan NOTIFY.
- Dalam praktik ini, ESP32 server akan berperan sebagai penyedia layanan sensor suhu dan kelembapan (melalui DHT11), di mana nilai-nilai ini dikirimkan sebagai Characteristic yang dapat diakses oleh ESP32 client.
- Sensor DHT11
- DHT11 adalah sensor suhu dan kelembapan yang murah dan mudah digunakan. Sensor ini dapat mengukur suhu dalam rentang 0-50°C dengan toleransi ±2°C dan kelembapan dalam rentang 20-90% dengan toleransi ±5%. Sensor ini mengirimkan data digital yang mudah dibaca menggunakan mikroprosesor seperti ESP32.
- Dalam proyek ini, DHT11 digunakan oleh ESP32 server untuk mendapatkan pembacaan suhu dan kelembapan, yang kemudian dikirim ke ESP32 client melalui BLE.
- LCD I2C
- LCD I2C (Inter-Integrated Circuit) adalah antarmuka yang memungkinkan tampilan data pada LCD dengan hanya menggunakan dua pin untuk komunikasi data (SDA dan SCL). Hal ini membuat komunikasi lebih sederhana dibandingkan dengan antarmuka paralel tradisional.
- ESP32 client menggunakan LCD I2C untuk menampilkan data yang diterima dari BLE server, yaitu suhu dan kelembapan. Data ini ditampilkan dalam format yang mudah dibaca untuk monitoring secara real-time.
- Komunikasi BLE Server-Client
- Proses Komunikasi: Dalam komunikasi BLE, client akan mencari (scan) server BLE yang sesuai dan mencoba terhubung dengannya. Setelah terhubung, client dapat membaca data dari characteristic yang diiklankan oleh server atau menerima notifikasi jika ada data baru yang tersedia.
- Penggunaan NOTIFY: Properti NOTIFY digunakan pada BLE characteristic untuk memungkinkan server mengirimkan data secara otomatis ke client saat nilai berubah, tanpa perlu client meminta data berulang kali. Ini memastikan bahwa client mendapatkan data terbaru dengan lebih efisien.
- Implementasi Program
- Server: Program ESP32 server akan membaca data dari sensor DHT11 dan mengirimkannya melalui BLE characteristic dengan UUID spesifik. ESP32 server bertindak sebagai sumber data, menyimpan nilai suhu dan kelembapan, serta memperbarui client menggunakan notifikasi.
- Client: Program ESP32 client akan mencari server BLE dengan nama tertentu, terhubung ke layanan dan karakteristik yang relevan, lalu menerima data suhu dan kelembapan. Data ini kemudian ditampilkan pada LCD I2C untuk monitoring.
- Alat dan Bahan
- 2 buah modul ESP32
- Sensor DHT11
- LCD I2C 16×2
- Kabel jumper
- Breadboard
- Desain Rangkaian
- Langkah-langkah Pengerjaan
Bagian 1: Program ESP32 sebagai BLE Master (Server)
Ads Jadwal Training bisaioti Offline
No | Materi | Tanggal | Waktu | Harga | Lokasi | View | Action |
---|---|---|---|---|---|---|---|
1 | IOT PLC SCADA Siemens | 7-8 Juni 2025 | 08.00 - 16.00 | 2000000 | Surabaya | Silabus | Daftar Sekarang |
2 | IOT PLC SCADA Omron | 14 - 15 Juni 2025 | 08.00 - 16.00 | 2000000 | Surabaya | Silabus | Daftar Sekarang |
3 | IOT PLC SCADA Schneider | 21-22 Juni 2025 | 08.00 -16.00 | 2000000 | Surabaya | Silabus | Daftar Sekarang |
4 | IOT PLC SCADA Allen Bradley | 28-29 Juni 2025 | 08.00-16.00 | 2000000 | Surabaya | Silabus | Daftar Sekarang |
- Buat Rangkaian
- Sambungkan pin VCC dan GND DHT11 ke 3.3V dan GND pada ESP32.
- Sambungkan pin data DHT11 ke pin GPIO 15 pada ESP32 Server.
- Program BLE Server (Master)
- Berikut adalah kode yang akan digunakan pada ESP32 server untuk membaca data dari sensor DHT11 dan mengirimkan data tersebut melalui BLE.
#include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> #include <DHT.h> #define DHTPIN 2    // Pin DHT11 terhubung #define DHTTYPE DHT11  // Tipe sensor DHT11 DHT dht(DHTPIN, DHTTYPE); // Komentar baris berikut untuk suhu dalam Fahrenheit #define temperatureCelsius // Nama server BLE #define bleServerName "DHT11_ESP32" // Variabel untuk menyimpan nilai suhu dan kelembapan float temp; float tempF; float hum; // Timer unsigned long lastTime = 0; unsigned long timerDelay = 30000; bool deviceConnected = false; // UUID BLE #define SERVICE_UUID "91bad492-b950-4226-aa2b-4ede9fa42f59" // Karakteristik dan Deskriptor Suhu #ifdef temperatureCelsius  BLECharacteristic temperatureCelsiusCharacteristics("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);  BLEDescriptor temperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902)); #else  BLECharacteristic temperatureFahrenheitCharacteristics("f78ebbff-c8b7-4107-93de-889a6a06d408", BLECharacteristic::PROPERTY_NOTIFY);  BLEDescriptor temperatureFahrenheitDescriptor(BLEUUID((uint16_t)0x2902)); #endif // Karakteristik dan Deskriptor Kelembapan BLECharacteristic humidityCharacteristics("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY); BLEDescriptor humidityDescriptor(BLEUUID((uint16_t)0x2903)); // Callbacks untuk koneksi dan disconnection class MyServerCallbacks: public BLEServerCallbacks {  void onConnect(BLEServer* pServer) {   deviceConnected = true;  };  void onDisconnect(BLEServer* pServer) {   deviceConnected = false;  } }; void setup() {  // Memulai komunikasi serial  Serial.begin(115200);  // Memulai sensor DHT  dht.begin();  // Membuat perangkat BLE  BLEDevice::init(bleServerName);  // Membuat server BLE  BLEServer *pServer = BLEDevice::createServer();  pServer->setCallbacks(new MyServerCallbacks());  // Membuat layanan BLE  BLEService *dhtService = pServer->createService(SERVICE_UUID);  // Menambahkan karakteristik dan deskriptor BLE  #ifdef temperatureCelsius   dhtService->addCharacteristic(&temperatureCelsiusCharacteristics);   temperatureCelsiusDescriptor.setValue("DHT11 temperature Celsius");   temperatureCelsiusCharacteristics.addDescriptor(&temperatureCelsiusDescriptor);  #else   dhtService->addCharacteristic(&temperatureFahrenheitCharacteristics);   temperatureFahrenheitDescriptor.setValue("DHT11 temperature Fahrenheit");   temperatureFahrenheitCharacteristics.addDescriptor(&temperatureFahrenheitDescriptor);  #endif   // Kelembapan  dhtService->addCharacteristic(&humidityCharacteristics);  humidityDescriptor.setValue("DHT11 humidity");  humidityCharacteristics.addDescriptor(new BLE2902());  // Memulai layanan  dhtService->start();  // Memulai periklanan  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();  pAdvertising->addServiceUUID(SERVICE_UUID);  pServer->getAdvertising()->start();  Serial.println("Waiting for client connection to notify..."); } void loop() {  if (deviceConnected) {   if ((millis() - lastTime) > timerDelay) {    // Membaca suhu dalam Celsius    temp = dht.readTemperature();    // Suhu dalam Fahrenheit    tempF = dht.readTemperature(true);    // Membaca kelembapan    hum = dht.readHumidity();    // Memastikan pembacaan berhasil    if (isnan(temp) || isnan(hum)) {     Serial.println("Failed to read from DHT sensor!");     return;    }    // Memberi notifikasi suhu    #ifdef temperatureCelsius     static char temperatureCTemp[6];     dtostrf(temp, 6, 2, temperatureCTemp);     temperatureCelsiusCharacteristics.setValue(temperatureCTemp);     temperatureCelsiusCharacteristics.notify();     Serial.print("Temperature Celsius: ");     Serial.print(temp);     Serial.print(" ºC");    #else     static char temperatureFTemp[6];     dtostrf(tempF, 6, 2, temperatureFTemp);     temperatureFahrenheitCharacteristics.setValue(temperatureFTemp);     temperatureFahrenheitCharacteristics.notify();     Serial.print("Temperature Fahrenheit: ");     Serial.print(tempF);     Serial.print(" ºF");    #endif       // Memberi notifikasi kelembapan    static char humidityTemp[6];    dtostrf(hum, 6, 2, humidityTemp);    humidityCharacteristics.setValue(humidityTemp);    humidityCharacteristics.notify();     Serial.print(" - Humidity: ");    Serial.print(hum);    Serial.println(" %");       lastTime = millis();   }  } }
Bagian 2: Program ESP32 sebagai BLE Client (Client)
- Buat Rangkaian
- Sambungkan pin VCC dan GND LCD I2C ke 3.3V dan GND pada ESP32 Client.
- Sambungkan pin SDA ke GPIO 21 dan SCL ke GPIO 22 pada ESP32 Client.
- Program BLE Client
- Berikut adalah kode untuk ESP32 client yang akan menampilkan data suhu dan kelembapan pada LCD I2C.
#include <BLEDevice.h> #include <Wire.h> #include <LiquidCrystal_PCF8574.h> // Definisikan ukuran LCD dan alamat I2C LiquidCrystal_PCF8574 lcd(0x27); // Ganti alamat jika berbeda // Default Temperature is in Celsius #define temperatureCelsius // BLE Server name (the other ESP32 name running the server sketch) #define bleServerName "DHT11_ESP32" /* UUIDs for the service and characteristic we want to read */ static BLEUUID bmeServiceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); #ifdef temperatureCelsius  static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518"); #else  static BLEUUID temperatureCharacteristicUUID("f78ebbff-c8b7-4107-93de-889a6a06d408"); #endif static BLEUUID humidityCharacteristicUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99"); static boolean doConnect = false; static boolean connected = false; static BLEAddress *pServerAddress; static BLERemoteCharacteristic* temperatureCharacteristic; static BLERemoteCharacteristic* humidityCharacteristic; const uint8_t notificationOn[] = {0x1, 0x0}; char temperatureChar[6]; char humidityChar[6]; boolean newTemperature = false; boolean newHumidity = false; // Connect to BLE Server bool connectToServer(BLEAddress pAddress) {   BLEClient* pClient = BLEDevice::createClient();   pClient->connect(pAddress);   Serial.println(" - Connected to server");     BLERemoteService* pRemoteService = pClient->getService(bmeServiceUUID);   if (pRemoteService == nullptr) {    Serial.print("Failed to find service UUID: ");    Serial.println(bmeServiceUUID.toString().c_str());    return false;   }   temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);   humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);     if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {    Serial.println("Failed to find characteristic UUID");    return false;   }     temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);   humidityCharacteristic->registerForNotify(humidityNotifyCallback);   return true; } class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {  void onResult(BLEAdvertisedDevice advertisedDevice) {   if (advertisedDevice.getName() == bleServerName) {    advertisedDevice.getScan()->stop();    pServerAddress = new BLEAddress(advertisedDevice.getAddress());    doConnect = true;    Serial.println("Device found. Connecting!");   }  } }; // Temperature Notify Callback static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {  strncpy(temperatureChar, (char*)pData, sizeof(temperatureChar) - 1);  temperatureChar[sizeof(temperatureChar) - 1] = '\0'; // Pastikan null-terminated  newTemperature = true; } // Humidity Notify Callback static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {  strncpy(humidityChar, (char*)pData, sizeof(humidityChar) - 1);  humidityChar[sizeof(humidityChar) - 1] = '\0'; // Pastikan null-terminated  newHumidity = true; } // Print readings to the LCD void printReadings() {  lcd.clear();  lcd.setCursor(0, 0);  lcd.print("Temp: ");  lcd.print(temperatureChar);  #ifdef temperatureCelsius   lcd.write(223);  // Karakter derajat   lcd.print("C");  #else   lcd.write(223);  // Karakter derajat   lcd.print("F");  #endif  lcd.setCursor(0, 1);  lcd.print("Hum: ");  lcd.print(humidityChar);  lcd.print("%");  Serial.print("Temperature: ");  Serial.print(temperatureChar);  Serial.print(" Humidity: ");  Serial.print(humidityChar);  Serial.println("%"); } void setup() {  // Start serial communication  Serial.begin(115200);  Serial.println("Starting BLE Client...");  // Initialize LCD  lcd.begin(16, 2);  lcd.setBacklight(255);  lcd.home();  lcd.print("BLE Client");  BLEDevice::init("");  BLEScan* pBLEScan = BLEDevice::getScan();  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());  pBLEScan->setActiveScan(true);  pBLEScan->start(30); } void loop() {  if (doConnect == true) {   if (connectToServer(*pServerAddress)) {    Serial.println("Connected to BLE Server.");    temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);    humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);    connected = true;   } else {    Serial.println("Failed to connect to server; restart device to rescan.");   }   doConnect = false;  }  if (newTemperature && newHumidity) {   newTemperature = false;   newHumidity = false;   printReadings();  }  delay(1000); }
- Pertanyaan
- Jelaskan fungsi dari BLE UUID dalam program di atas.
- Apa perbedaan antara BLE Server dan BLE Client?
- Bagaimana cara menghubungkan dan menampilkan data dari sensor di BLE Client?
- Mengapa kita perlu mengatur BLE Characteristic dengan PROPERTY_NOTIFY?
Dengan jobsheet ini, peserta diharapkan memahami cara mengirim data sensor dari ESP32 BLE server ke ESP32 BLE client dan menampilkannya pada LCD I2C.