# 6.9 Practical Implementation with ESP32

<span class="ng-star-inserted">This chapter provides a hands-on project to demonstrate the core concepts of a BLE peripheral device using an ESP32. We will move beyond a simple serial example and create a simulated </span>**<span class="ng-star-inserted">BLE Heart Rate Sensor</span>**<span class="ng-star-inserted">. This is a standard profile that teaches the essential concepts of services, characteristics, and notifications.</span>

### <span class="ng-star-inserted">Project: Create a BLE Heart Rate Sensor</span>

**<span class="ng-star-inserted">Goal:</span>**<span class="ng-star-inserted"> Configure the ESP32 to act as a BLE peripheral that advertises the standard Heart Rate service. When a central device (like a smartphone) connects and enables notifications, the ESP32 will periodically send a simulated heart rate measurement.</span>

**<span class="ng-star-inserted">You Will Need:</span>**

- <span class="ng-star-inserted">An ESP32 development board.</span>
- <span class="ng-star-inserted">The Arduino IDE with the ESP32 board package installed.</span>
- <span class="ng-star-inserted">A smartphone with a BLE scanner app (e.g., "nRF Connect for Mobile" or "LightBlue").</span>

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

// Standard Bluetooth Service and Characteristic UUIDs for Heart Rate
#define SERVICE_UUID        "0000180d-0000-1000-8000-00805f9b34fb" // Heart Rate Service
#define CHARACTERISTIC_UUID "00002a37-0000-1000-8000-00805f9b34fb" // Heart Rate Measurement

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;

// This class handles server events like client connect/disconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      Serial.println("Client Connected");
    }

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      Serial.println("Client Disconnected");
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE Heart Rate Sensor...");

  // 1. Initialize the BLE device and set its name
  BLEDevice::init("ESP32 Heart Rate Sensor");

  // 2. Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); // Set the event handler

  // 3. Create the BLE Service using the standard Heart Rate UUID
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // 4. Create a BLE Characteristic for the Heart Rate Measurement
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  // 5. Add a 2902 descriptor to the characteristic. This is ESSENTIAL
  // for the client to be able to enable notifications.
  pCharacteristic->addDescriptor(new BLE2902());

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

  // 7. Start advertising, so other BLE devices can find this one
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID); // Advertise our service
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  
  Serial.println("Characteristic defined! Now you can scan for 'ESP32 Heart Rate Sensor' on your phone.");
}

void loop() {
  // Check if a client is connected
  if (deviceConnected) {
    // Generate a simulated heart rate value
    // The first byte is a flag (0), the second is the 8-bit heart rate value
    static uint8_t heartRate = 60;
    heartRate++;
    if (heartRate > 100) {
      heartRate = 60; // Reset after 100
    }
    
    uint8_t heartRateData[2] = {0, heartRate};
    
    // Set the characteristic's new value
    pCharacteristic->setValue(heartRateData, 2);
    
    // Send a notification to the connected client
    pCharacteristic->notify();
    
    Serial.print("Heart Rate Notification Sent: ");
    Serial.println(heartRate);
  }
  delay(1000);
}
```

### <span class="ng-star-inserted">Code Walkthrough</span>

1. **<span class="ng-star-inserted">Initialization:</span>**<span class="ng-star-inserted"> We initialize the BLE stack using </span>`<span class="inline-code ng-star-inserted">BLEDevice::init()</span>`<span class="ng-star-inserted"> and give our device a public name.</span>
2. **<span class="ng-star-inserted">Server and Service:</span>**<span class="ng-star-inserted"> We create a </span>`<span class="inline-code ng-star-inserted">BLEServer</span>`<span class="ng-star-inserted"> to manage connections and a </span>`<span class="inline-code ng-star-inserted">BLEService</span>`<span class="ng-star-inserted"> to hold our data. We use the official UUID for the "Heart Rate Service."</span>
3. **<span class="ng-star-inserted">Characteristic:</span>**<span class="ng-star-inserted"> Inside the service, we create a </span>`<span class="inline-code ng-star-inserted">BLECharacteristic</span>`<span class="ng-star-inserted"> for the "Heart Rate Measurement." We set its properties to allow a client to both </span><span class="inline-code ng-star-inserted">READ</span><span class="ng-star-inserted"> the value and subscribe to </span><span class="inline-code ng-star-inserted">NOTIFY</span><span class="ng-star-inserted"> (notifications).</span>
4. **<span class="ng-star-inserted">Descriptor (BLE2902):</span>**<span class="ng-star-inserted"> This is a critical step. The </span><span class="inline-code ng-star-inserted">BLE2902</span><span class="ng-star-inserted"> descriptor is the Client Characteristic Configuration Descriptor (CCCD). A client (your phone) writes to this descriptor to tell the server (the ESP32) that it wants to receive notifications. Without this, notifications will not work.</span>
5. **<span class="ng-star-inserted">Advertising:</span>**<span class="ng-star-inserted"> We start advertising and include the Service UUID. This tells scanning devices what services we offer before they even connect.</span>
6. **<span class="ng-star-inserted">The Loop:</span>**<span class="ng-star-inserted"> In the main loop, we check if a client is connected. If so, we generate a new simulated heart rate value, update the characteristic with </span>`<span class="inline-code ng-star-inserted">setValue()</span>`<span class="ng-star-inserted">, and then send it to the client using </span>`<span class="inline-code ng-star-inserted">notify()</span>`<span class="ng-star-inserted">.</span>

### <span class="ng-star-inserted">How to Test It</span>

1. <span class="ng-star-inserted">Upload the code to your ESP32.</span>
2. <span class="ng-star-inserted">Open the Arduino Serial Monitor to see the status messages.</span>
3. <span class="ng-star-inserted">On your smartphone, open a BLE scanner app (like nRF Connect for Mobile).</span>
4. **<span class="ng-star-inserted">Scan</span>**<span class="ng-star-inserted"> for devices. You should see "ESP32 Heart Rate Sensor" in the list.</span>
5. **<span class="ng-star-inserted">Connect</span>**<span class="ng-star-inserted"> to the device. In the Serial Monitor, you should see "Client Connected."</span>
6. <span class="ng-star-inserted">Find the </span>**<span class="ng-star-inserted">Heart Rate Service</span>**<span class="ng-star-inserted"> and expand it to see the </span>**<span class="ng-star-inserted">Heart Rate Measurement</span>**<span class="ng-star-inserted"> characteristic.</span>
7. <span class="ng-star-inserted">Tap the "subscribe" or "enable notifications" icon (often a single or triple downward arrow).</span>
8. <span class="ng-star-inserted">You should now see the value updating in your app every second, and the Serial Monitor will show the "Notification Sent" logs.</span>