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

Tujuan Pembelajaran

  1. Memahami komunikasi BLE (Bluetooth Low Energy) antara dua ESP32.
  2. Menggunakan sensor DHT11 untuk mengukur suhu dan kelembapan.
  3. Menampilkan data dari server pada LCD I2C melalui BLE client.
  4. Menguasai konsep penggunaan BLE service dan characteristic.

Dasar Teori

  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. Alat dan Bahan
  1. 2 buah modul ESP32
  2. Sensor DHT11
  3. LCD I2C 16×2
  4. Kabel jumper
  5. Breadboard
  1. Desain Rangkaian
  1. Langkah-langkah Pengerjaan

Bagian 1: Program ESP32 sebagai BLE Master (Server)

Ads Jadwal Training bisaioti Offline
NoMateriTanggalWaktuHargaLokasiViewAction
1IOT PLC SCADA Siemens7-8 Juni 202508.00 - 16.002000000SurabayaSilabusDaftar Sekarang
2IOT PLC SCADA Omron14 - 15 Juni 202508.00 - 16.002000000SurabayaSilabusDaftar Sekarang
3IOT PLC SCADA Schneider21-22 Juni 202508.00 -16.002000000SurabayaSilabusDaftar Sekarang
4IOT PLC SCADA Allen Bradley28-29 Juni 202508.00-16.002000000SurabayaSilabusDaftar Sekarang
  1. 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.
  1. 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)

  1. 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.
  1. 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);

}
  1. Pertanyaan
  1. Jelaskan fungsi dari BLE UUID dalam program di atas.
  2. Apa perbedaan antara BLE Server dan BLE Client?
  3. Bagaimana cara menghubungkan dan menampilkan data dari sensor di BLE Client?
  4. 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.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Daftar Sekarang