#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <ArduinoJson.h>
// --- BLE UUID Definitions ---
// Using the same UUID for both Read and Write for simplicity and stability.
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Global Variables
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
unsigned long lastMillis = 0;
// Hardware Pin Definitions
const int LED_PIN = 8; // Standard On/Off LED
const int PWM_PIN = 7; // Dimmer/Speed control pin (ESP32-C3 GPIO 7)
// PWM Configuration (v3.0+ SDK Compatible)
const int freq = 5000; // Frequency in Hz
const int resolution = 8; // 8-bit resolution (Values 0-255)
// Callback class to handle BLE Connection events
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println(">>> Device Connected");
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println(">>> Device Disconnected");
// Restart advertising so other devices can find the ESP32
pServer->getAdvertising()->start();
}
};
// Callback class to handle Data received from the Mobile App
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = String(pCharacteristic->getValue().c_str());
if (value.length() > 0) {
Serial.print("Command Received: ");
Serial.println(value);
// Scenario 1: Simple On/Off (Standard Switch)
if (value == "A") {
digitalWrite(LED_PIN, HIGH);
Serial.println("LED State: ON");
}
else if (value == "B") {
digitalWrite(LED_PIN, LOW);
Serial.println("LED State: OFF");
}
// Scenario 2: PWM Control (Format "tag:value", e.g., "ldr1:5")
else if (value.indexOf(':') != -1) {
int colonIndex = value.indexOf(':');
String tag = value.substring(0, colonIndex);
int val = value.substring(colonIndex + 1).toInt();
// Check if the tag matches our assigned tag
if (tag == "ldr1") {
// Map 0-9 input to 0-255 for the 8-bit PWM resolution
int brightness = map(val, 0, 9, 0, 255);
ledcWrite(PWM_PIN, brightness);
Serial.printf("PWM Intensity set to: %d\n", brightness);
}
}
}
}
};
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
// --- PWM INITIALIZATION (ESP32 Core v3.0+) ---
// In the new SDK, ledcAttach replaces ledcSetup and ledcAttachPin
ledcAttach(PWM_PIN, freq, resolution);
// Initialize BLE Device
BLEDevice::init("ESP32-C3-FIIX");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create Characteristic with Read, Write, and Notify properties
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_WRITE_NR // Supports fast writing
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->addDescriptor(new BLE2902()); // Required for Notifications
// Start the Service and begin Advertising
pService->start();
pServer->getAdvertising()->start();
Serial.println("BLE Ready (v3.0 SDK Environment)...");
}
void loop() {
// Only send data if a smartphone is connected
if (deviceConnected) {
// Send sensor data every 2 seconds
if (millis() - lastMillis > 2000) {
// Simulate random sensor readings
int sensorValue1 = random(100, 1024);
int sensorValue2 = random(100, 1024);
int sensorValue3 = random(100, 1024);
int sensorValue4 = random(100, 1024);
// Create a JSON Document
StaticJsonDocument<128> doc;
doc["ldr1"] = sensorValue1;
doc["ldr2"] = sensorValue2;
doc["ldr3"] = sensorValue3;
doc["ldr4"] = sensorValue4;
// Serialize JSON to a string buffer
char buffer[128];
serializeJson(doc, buffer);
// Send the JSON string via BLE Notification
pCharacteristic->setValue(buffer);
pCharacteristic->notify();
Serial.print("JSON Sent to App: ");
Serial.println(buffer);
lastMillis = millis();
}
}
}