|
|
@@ -1,21 +1,35 @@
|
|
|
#include <BLEDevice.h>
|
|
|
#include <BLEServer.h>
|
|
|
#include <BLEUtils.h>
|
|
|
+#include <BLEScan.h>
|
|
|
+#include <BLEAdvertisedDevice.h>
|
|
|
#include <BLE2902.h>
|
|
|
#include <ArduinoJson.h>
|
|
|
#include <map>
|
|
|
|
|
|
-std::map<int, int> connIdToIndex; // mapping connId → index di array Devices
|
|
|
+#define AUDIO_FRAME_SIZE 60
|
|
|
+uint8_t audioBuffer[AUDIO_FRAME_SIZE];
|
|
|
+int bufferIndex = 0;
|
|
|
+bool readingAudio = false;
|
|
|
+
|
|
|
+// Simpan data scan: MAC -> RSSI/TX/Name
|
|
|
+struct DeviceInfo {
|
|
|
+ int RSSI;
|
|
|
+ int TXPower;
|
|
|
+ String name;
|
|
|
+};
|
|
|
+std::map<String, DeviceInfo> scannedDevices;
|
|
|
+
|
|
|
+// Simpan device yang connect: connId -> JSON index
|
|
|
+std::map<int, int> connIdToIndex;
|
|
|
+
|
|
|
+BLEServer *pServer = nullptr;
|
|
|
+BLECharacteristic *pCharacteristic = nullptr;
|
|
|
|
|
|
-BLEServer *pServer = NULL;
|
|
|
-BLECharacteristic *pCharacteristic = NULL;
|
|
|
int connectedClients = 0;
|
|
|
-bool deviceConnected = false;
|
|
|
-uint32_t value = 0;
|
|
|
-unsigned int lastTime = 0;
|
|
|
|
|
|
-StaticJsonDocument<512> doc; // dokumen utama
|
|
|
-JsonArray devices = doc.createNestedArray("Devices"); // array untuk semua device
|
|
|
+StaticJsonDocument<2048> doc;
|
|
|
+JsonArray devices;
|
|
|
|
|
|
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
|
|
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
|
|
@@ -24,18 +38,33 @@ class MyServerCallbacks : public BLEServerCallbacks {
|
|
|
void onConnect(BLEServer *pServer, ble_gap_conn_desc *desc) override {
|
|
|
connectedClients++;
|
|
|
|
|
|
- // Buat object untuk device baru
|
|
|
+ if (devices.isNull()) devices = doc.createNestedArray("Devices");
|
|
|
+
|
|
|
JsonObject device = devices.createNestedObject();
|
|
|
- device["mac"] = BLEAddress(desc->peer_ota_addr).toString().c_str();
|
|
|
- device["connectedID"] = pServer->getConnId();
|
|
|
+ int connId = pServer->getConnId();
|
|
|
+ device["connectedID"] = connId;
|
|
|
device["connInterval"] = desc->conn_itvl;
|
|
|
device["latency"] = desc->conn_latency;
|
|
|
device["timeout"] = desc->supervision_timeout;
|
|
|
|
|
|
- // Simpan mapping connId → index device
|
|
|
- connIdToIndex[pServer->getConnId()] = devices.size() - 1;
|
|
|
+ // Gunakan MAC dari scannedDevices jika ada RSSI terakhir
|
|
|
+ // Biasanya kita tidak punya MAC real connect, bisa pakai RSSI terkuat
|
|
|
+ if (!scannedDevices.empty()) {
|
|
|
+ auto strongest = scannedDevices.begin();
|
|
|
+ for (auto it = scannedDevices.begin(); it != scannedDevices.end(); ++it) {
|
|
|
+ if (it->second.RSSI > strongest->second.RSSI) strongest = it;
|
|
|
+ }
|
|
|
+ device["mac"] = strongest->first;
|
|
|
+ device["name"] = strongest->second.name;
|
|
|
+ device["RSSI"] = strongest->second.RSSI;
|
|
|
+ device["TXPower"] = strongest->second.TXPower;
|
|
|
+ } else {
|
|
|
+ device["mac"] = "Unknown";
|
|
|
+ device["name"] = "Unknown";
|
|
|
+ }
|
|
|
+
|
|
|
+ connIdToIndex[connId] = devices.size() - 1;
|
|
|
|
|
|
- // Update status umum
|
|
|
doc["Status"] = "NEW_CONNECT";
|
|
|
doc["connectedClients"] = connectedClients;
|
|
|
|
|
|
@@ -51,20 +80,22 @@ class MyServerCallbacks : public BLEServerCallbacks {
|
|
|
int connId = pServer->getConnId();
|
|
|
if (connIdToIndex.count(connId)) {
|
|
|
int index = connIdToIndex[connId];
|
|
|
- // Hapus device dari array (buat ulang array)
|
|
|
JsonArray newDevices = doc.createNestedArray("Devices");
|
|
|
for (int i = 0; i < devices.size(); i++) {
|
|
|
- if (i == index) continue; // skip device yang disconnect
|
|
|
+ if (i == index) continue;
|
|
|
JsonObject oldDevice = devices[i];
|
|
|
JsonObject newDevice = newDevices.createNestedObject();
|
|
|
- newDevice["mac"] = oldDevice["mac"];
|
|
|
newDevice["connectedID"] = oldDevice["connectedID"];
|
|
|
newDevice["connInterval"] = oldDevice["connInterval"];
|
|
|
newDevice["latency"] = oldDevice["latency"];
|
|
|
newDevice["timeout"] = oldDevice["timeout"];
|
|
|
+ if (oldDevice.containsKey("RSSI")) newDevice["RSSI"] = oldDevice["RSSI"];
|
|
|
+ if (oldDevice.containsKey("TXPower")) newDevice["TXPower"] = oldDevice["TXPower"];
|
|
|
+ if (oldDevice.containsKey("mac")) newDevice["mac"] = oldDevice["mac"];
|
|
|
+ if (oldDevice.containsKey("name")) newDevice["name"] = oldDevice["name"];
|
|
|
}
|
|
|
- devices = newDevices; // update devices
|
|
|
- connIdToIndex.erase(connId); // hapus mapping
|
|
|
+ devices = newDevices;
|
|
|
+ connIdToIndex.erase(connId);
|
|
|
}
|
|
|
|
|
|
serializeJson(doc, Serial);
|
|
|
@@ -72,22 +103,56 @@ class MyServerCallbacks : public BLEServerCallbacks {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
|
|
|
+ void onResult(BLEAdvertisedDevice advertisedDevice) override {
|
|
|
+ Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
|
|
|
+ String mac = advertisedDevice.getAddress().toString();
|
|
|
+ // String name = advertisedDevice.getName();
|
|
|
+ String name = advertisedDevice.haveName() ? advertisedDevice.getName() : "Unknown";
|
|
|
+ int rssi = advertisedDevice.getRSSI();
|
|
|
+ int txPower = advertisedDevice.getTXPower();
|
|
|
+
|
|
|
+ // Simpan ke scannedDevices
|
|
|
+ scannedDevices[mac] = { rssi, txPower, name };
|
|
|
+
|
|
|
+ for (auto &pair : connIdToIndex) {
|
|
|
+ int index = pair.second;
|
|
|
+ JsonObject device = devices[index];
|
|
|
+ // Di sini kita tidak bisa cocokkan MAC karena connect MAC random,
|
|
|
+ // tapi bisa update semua RSSI terakhir dari scannedDevices
|
|
|
+ if (scannedDevices.count(mac)) {
|
|
|
+ device["Name"] = scannedDevices[mac].name;
|
|
|
+ device["RSSI"] = scannedDevices[mac].RSSI;
|
|
|
+ device["TXPower"] = scannedDevices[mac].TXPower;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+BLEScan *pBLEScan;
|
|
|
+
|
|
|
void setup() {
|
|
|
Serial.begin(115200);
|
|
|
pinMode(LED_BUILTIN, OUTPUT);
|
|
|
|
|
|
BLEDevice::init("ESP32");
|
|
|
|
|
|
+ // Setup scan
|
|
|
+ pBLEScan = BLEDevice::getScan();
|
|
|
+ pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
|
|
+ pBLEScan->setActiveScan(true);
|
|
|
+ pBLEScan->setInterval(100);
|
|
|
+ pBLEScan->setWindow(99);
|
|
|
+
|
|
|
+ // Setup server
|
|
|
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_INDICATE);
|
|
|
pCharacteristic->addDescriptor(new BLE2902());
|
|
|
-
|
|
|
pService->start();
|
|
|
|
|
|
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
|
|
@@ -95,51 +160,27 @@ void setup() {
|
|
|
pAdvertising->setScanResponse(false);
|
|
|
pAdvertising->setMinPreferred(0x0);
|
|
|
BLEDevice::startAdvertising();
|
|
|
-
|
|
|
- // Serial.println("Waiting for client connections to notify...");
|
|
|
- // Serial.println("Type 'disconnect <connId>' to disconnect a client.");
|
|
|
}
|
|
|
|
|
|
-void loop() {
|
|
|
-
|
|
|
- if (connectedClients > 0) {
|
|
|
- pCharacteristic->setValue((uint8_t *)&value, 4);
|
|
|
- pCharacteristic->notify();
|
|
|
- value++;
|
|
|
- delay(100);
|
|
|
-
|
|
|
+unsigned long lastScanTime = 0;
|
|
|
+const unsigned long scanInterval = 1000; // 1 detik
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- if (Serial.available()) {
|
|
|
- String cmd = Serial.readStringUntil('\n');
|
|
|
- cmd.trim();
|
|
|
- digitalWrite(LED_BUILTIN, HIGH);
|
|
|
- if (cmd.startsWith("DISCONNECT:")) {
|
|
|
-
|
|
|
- int connId = cmd.substring(11).toInt();
|
|
|
- // Serial.println("Arduino will disconnect connID: " + String(connId));
|
|
|
- // panggil fungsi BLE untuk disconnect
|
|
|
- pServer->disconnect(connId); // sesuai API ESP32 BLE
|
|
|
- }
|
|
|
- }
|
|
|
- digitalWrite(LED_BUILTIN, LOW);
|
|
|
+void loop() {
|
|
|
+ digitalWrite(LED_BUILTIN, connectedClients > 0 ? HIGH : LOW);
|
|
|
|
|
|
- if (connectedClients == 0 && deviceConnected) {
|
|
|
- delay(500);
|
|
|
- pServer->startAdvertising();
|
|
|
- // Serial.println("No clients connected, restarting advertising");
|
|
|
- deviceConnected = false;
|
|
|
- }
|
|
|
+ // Scan BLE setiap 1 detik
|
|
|
+ // if (millis() - lastScanTime > scanInterval) {
|
|
|
+ // lastScanTime = millis();
|
|
|
+ // pBLEScan->start(0, nullptr, false); // non-blocking scan
|
|
|
+ // }
|
|
|
|
|
|
- if (connectedClients > 0 && !deviceConnected) {
|
|
|
- deviceConnected = true;
|
|
|
+ pBLEScan->start(2, false); // non-blocking scan
|
|
|
+ // Kirim JSON update ke Serial
|
|
|
+ static unsigned long lastJsonTime = 0;
|
|
|
+ if (millis() - lastJsonTime > scanInterval) {
|
|
|
+ lastJsonTime = millis();
|
|
|
+ doc["connectedClients"] = connectedClients;
|
|
|
+ serializeJson(doc, Serial);
|
|
|
+ Serial.println();
|
|
|
}
|
|
|
-
|
|
|
- // if (millis() - lastTime >= 1000) {
|
|
|
- // // Serial.println(json);
|
|
|
- // serializeJson(doc, Serial);
|
|
|
- // Serial.println();
|
|
|
- // lastTime = millis();
|
|
|
- // }
|
|
|
}
|