#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <ArduinoJson.h>
#include <WiFi.h>
// --- BLE UUID Definitions ---
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
// Global Variables
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
unsigned long lastMillis = 0;
// WiFi & API Storage
String savedSSID = "";
String savedPassword = "";
String savedApiKey = "";
// Hardware Pin Definitions
int sensorPin = 0;
const int LED_PIN = 8;
const int PWM_PIN = 3;
// PWM Configuration (v3.0+ SDK Compatible)
const int freq = 5000;
const int resolution = 8;
// BLE Server Connection Callbacks
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 to remain visible for authorized devices
pServer->getAdvertising()->start();
}
};
// BLE Characteristic Write Callbacks
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: WiFi + API Key Setup
// Expected Format: "WIFI:ssid:password:apikey"
else if (value.startsWith("WIFI:")) {
String payload = value.substring(5);
int first = payload.indexOf(':');
int second = payload.indexOf(':', first + 1);
if (first == -1) {
Serial.println("WIFI format error!");
return;
}
savedSSID = payload.substring(0, first);
savedPassword = payload.substring(first + 1, second != -1 ? second : payload.length());
savedApiKey = second != -1 ? payload.substring(second + 1) : "";
Serial.println("SSID: " + savedSSID);
Serial.println("Password: " + savedPassword);
Serial.println("API Key: " + savedApiKey);
WiFi.begin(savedSSID.c_str(), savedPassword.c_str());
Serial.print("Connecting to WiFi");
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 20) {
delay(500);
Serial.print(".");
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
String ip = WiFi.localIP().toString();
Serial.println("\nWiFi Connected! IP: " + ip);
pCharacteristic->setValue(("IP:" + ip).c_str());
pCharacteristic->notify();
} else {
Serial.println("\nWiFi connection failed!");
pCharacteristic->setValue("WIFI_FAIL");
pCharacteristic->notify();
}
}
// Scenario 3: PWM Control
// Expected 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();
if (tag == "ldr1") {
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);
digitalWrite(LED_PIN, HIGH);
ledcAttach(PWM_PIN, freq, resolution);
// Initialize BLE Device
BLEDevice::init("ESP32-C3-FIIX");
// --- BLE SECURITY & STATIC PASSKEY CONFIGURATION ---
// Enable MITM (Man-in-the-middle) protection and encryption
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); // Save pairing bond on smartphone storage
pSecurity->setCapability(ESP_IO_CAP_OUT); // Triggers native OS numeric passkey prompt
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
// Set 6-digit static passkey (Change it if needed)
uint32_t passkey = 123456;
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
// ---------------------------------------------------
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
// --- ENCRYPT CHARACTERISTIC ACCESS PERMISSIONS ---
// Restrict read/write operations to authenticated/paired devices only
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_WRITE_NR
);
pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
// ---------------------------------------------------
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
// Start advertising permanently under passkey protection
pServer->getAdvertising()->start();
Serial.println("BLE Ready with Passkey Security (123456)...");
}
void loop() {
// Telemetry loop for sending JSON payloads to the app
if (deviceConnected) {
if (millis() - lastMillis > 2000) {
int sensorValue1 = random(100, 1024);
int sensorValue3 = random(100, 1024);
String mockDataStr = "123456789123456789";
StaticJsonDocument<128> doc;
doc["ldr1"] = sensorValue1;
doc["ldr2"] = String(map(analogRead(0), 0, 4095, 100, 0)) + "%";
doc["ldr3"] = sensorValue3;
doc["ldr4"] = mockDataStr;
if (digitalRead(LED_PIN) == HIGH) {
doc["aa"] = "OFF";
} else {
doc["aa"] = "ON";
}
char buffer[128];
serializeJson(doc, buffer);
pCharacteristic->setValue(buffer);
pCharacteristic->notify();
Serial.print("JSON Sent to App: ");
Serial.println(buffer);
lastMillis = millis();
}
}
}
//=========IR BLE============
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <WiFi.h>
#include <IRremote.hpp>
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define IR_SEND_PIN 2
#define IR_RECEIVE_PIN 3
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
// =====================
// COMMAND BUFFER (CRITICAL FIX)
// =====================
String pendingValue = "";
bool hasCommand = false;
// =====================
// STRING SPLIT
// =====================
String getValue(String data, char separator, int index) {
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
// =====================
// BLE CALLBACK (ONLY STORE DATA)
// =====================
class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = pCharacteristic->getValue();
value.trim();
if (value.length() == 0) return;
Serial.print("BLE'den Gelen: ");
Serial.println(value);
if (value.startsWith("SEND:")) {
pendingValue = value;
hasCommand = true;
}
}
};
// =====================
// BLE SERVER CALLBACKS
// =====================
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println(">>> Device Connected");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println(">>> Device Disconnected");
pServer->getAdvertising()->start();
}
};
void setup() {
Serial.begin(115200);
// IR INIT
IrSender.begin(IR_SEND_PIN);
IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);
// BLE INIT
BLEDevice::init("ESP32-C3-FIIX");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_WRITE_NR
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
pServer->getAdvertising()->start();
Serial.println("BLE Ready...");
}
// =====================
// LOOP (IR EXECUTION HERE)
// =====================
void loop() {
// =====================
// HANDLE BLE COMMAND
// =====================
if (hasCommand) {
hasCommand = false;
String value = pendingValue;
String protocol = getValue(value, ':', 1);
String addressStr = getValue(value, ':', 2);
String commandStr = getValue(value, ':', 3);
addressStr.trim();
commandStr.trim();
uint16_t address = strtoul(addressStr.c_str(), NULL, 16);
uint8_t command = (uint8_t)strtoul(commandStr.c_str(), NULL, 16);
Serial.printf("ADDR: 0x%04X CMD: 0x%02X\n", address, command);
if (protocol == "NEC") {
IrSender.sendNEC(address, command, 0);
Serial.println("NEC SENT (LOOP)");
}
else if (protocol == "LG") {
IrSender.sendLG(address, command, 0);
Serial.println("LG SENT (LOOP)");
}
}
// =====================
// IR RECEIVER -> BLE NOTIFY
// =====================
if (IrReceiver.decode()) {
if (deviceConnected && IrReceiver.decodedIRData.protocol != UNKNOWN) {
String protocol = "UNKNOWN";
if (IrReceiver.decodedIRData.protocol == NEC) protocol = "NEC";
else if (IrReceiver.decodedIRData.protocol == LG) protocol = "LG";
String address = String(IrReceiver.decodedIRData.address, HEX);
String command = String(IrReceiver.decodedIRData.command, HEX);
String payload = "IR:" + protocol + ":0x" + address + ":0x" + command;
pCharacteristic->setValue(payload.c_str());
pCharacteristic->notify();
Serial.println("IR -> BLE: " + payload);
}
IrReceiver.resume();
}
}