Add device UUID prefix to BLE scan response and filter in scan callback
All checks were successful
CI / build (push) Successful in 1m6s
All checks were successful
CI / build (push) Successful in 1m6s
ESP32 server: include 4-byte device UUID prefix as manufacturer data (company 0xFFFF) in BLE scan response, allowing pre-connection filtering. Android: check manufacturer data in ScanCallback.onScanResult before connecting. Skips devices with non-matching UUID prefix, preventing wasted connections to wrong SylDa devices. Backward compatible with old firmware (proceeds if no manufacturer data present).
This commit is contained in:
parent
290ce0a027
commit
3cd4a6211d
3 changed files with 67 additions and 56 deletions
|
|
@ -89,6 +89,19 @@ class BleRelayManager(
|
||||||
Log.d(TAG, "Skipping already-tried device $address")
|
Log.d(TAG, "Skipping already-tried device $address")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val scanRecord = result.scanRecord
|
||||||
|
val storedUuid = deviceUuid
|
||||||
|
if (scanRecord != null && storedUuid != null) {
|
||||||
|
val mfgData = scanRecord.getManufacturerSpecificData(0xFFFF)
|
||||||
|
if (mfgData != null && mfgData.size >= 4) {
|
||||||
|
val advPrefix = mfgData.copyOf(4)
|
||||||
|
val storedPrefix = storedUuid.copyOf(4)
|
||||||
|
if (!advPrefix.contentEquals(storedPrefix)) {
|
||||||
|
Log.d(TAG, "Skipping non-matching UUID prefix ($address)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stopScan()
|
stopScan()
|
||||||
connectToDevice(device)
|
connectToDevice(device)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,19 +57,8 @@ bool otaInProgress = false;
|
||||||
bool otaEnded = false;
|
bool otaEnded = false;
|
||||||
|
|
||||||
static bool bleReady = false;
|
static bool bleReady = false;
|
||||||
static bool serverFound = false;
|
|
||||||
static NimBLEAddress serverAddress;
|
static NimBLEAddress serverAddress;
|
||||||
|
|
||||||
class MyScanCallbacks : public NimBLEScanCallbacks {
|
|
||||||
void onResult(const NimBLEAdvertisedDevice *advertisedDevice) override {
|
|
||||||
if (advertisedDevice->isAdvertisingService(NimBLEUUID(SERVICE_UUID))) {
|
|
||||||
serverAddress = advertisedDevice->getAddress();
|
|
||||||
serverFound = true;
|
|
||||||
NimBLEDevice::getScan()->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MyClientCallbacks : public NimBLEClientCallbacks {
|
class MyClientCallbacks : public NimBLEClientCallbacks {
|
||||||
void onConnect(NimBLEClient *client) override {
|
void onConnect(NimBLEClient *client) override {
|
||||||
connected = true;
|
connected = true;
|
||||||
|
|
@ -116,10 +105,10 @@ static void buildHmacPacket(uint8_t cmd, uint8_t *packet) {
|
||||||
|
|
||||||
static void disconnectClient() {
|
static void disconnectClient() {
|
||||||
if (pClient != nullptr) {
|
if (pClient != nullptr) {
|
||||||
|
if (pClient->isConnected()) {
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
delay(100);
|
delay(100);
|
||||||
NimBLEDevice::deleteClient(pClient);
|
}
|
||||||
pClient = nullptr;
|
|
||||||
}
|
}
|
||||||
pCmdChar = nullptr;
|
pCmdChar = nullptr;
|
||||||
connected = false;
|
connected = false;
|
||||||
|
|
@ -128,13 +117,14 @@ static void disconnectClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool connectToServer() {
|
static bool connectToServer() {
|
||||||
|
if (pClient == nullptr) {
|
||||||
pClient = NimBLEDevice::createClient();
|
pClient = NimBLEDevice::createClient();
|
||||||
|
pClient->setConnectTimeout(10);
|
||||||
pClient->setClientCallbacks(&clientCallbacks);
|
pClient->setClientCallbacks(&clientCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
if (!pClient->connect(serverAddress)) {
|
if (!pClient->connect(serverAddress)) {
|
||||||
ESP_LOGE(TAG, "BLE: connect failed");
|
ESP_LOGE(TAG, "BLE: connect failed, retry later");
|
||||||
NimBLEDevice::deleteClient(pClient);
|
|
||||||
pClient = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,15 +216,21 @@ void setup() {
|
||||||
|
|
||||||
if (allProvisioned) {
|
if (allProvisioned) {
|
||||||
NimBLEDevice::init("SylDa_Client");
|
NimBLEDevice::init("SylDa_Client");
|
||||||
|
|
||||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
|
||||||
pScan->setScanCallbacks(new MyScanCallbacks());
|
|
||||||
pScan->setInterval(97);
|
|
||||||
pScan->setWindow(37);
|
|
||||||
pScan->setActiveScan(true);
|
|
||||||
pScan->setMaxResults(0);
|
|
||||||
bleReady = true;
|
bleReady = true;
|
||||||
ESP_LOGI(TAG, "BLE: initialized, scanning for service UUID");
|
ESP_LOGI(TAG, "BLE: initialized, connecting...");
|
||||||
|
|
||||||
|
serverAddress = NimBLEAddress("44:1b:f6:f4:cf:15", BLE_ADDR_PUBLIC);
|
||||||
|
pClient = NimBLEDevice::createClient();
|
||||||
|
pClient->setConnectTimeout(10);
|
||||||
|
pClient->setClientCallbacks(&clientCallbacks);
|
||||||
|
if (pClient->connect(serverAddress)) {
|
||||||
|
connected = true;
|
||||||
|
NimBLERemoteService *pSvc = pClient->getService(SERVICE_UUID);
|
||||||
|
if (pSvc) pCmdChar = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
|
||||||
|
ESP_LOGI(TAG, "BLE: connected!");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "BLE: connect failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Setup done.");
|
ESP_LOGI(TAG, "Setup done.");
|
||||||
|
|
@ -282,12 +278,6 @@ void loop() {
|
||||||
Serial.println("HMAC key stored in NVS");
|
Serial.println("HMAC key stored in NVS");
|
||||||
if (allProvisioned && !bleReady) {
|
if (allProvisioned && !bleReady) {
|
||||||
NimBLEDevice::init("SylDa_Client");
|
NimBLEDevice::init("SylDa_Client");
|
||||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
|
||||||
pScan->setScanCallbacks(new MyScanCallbacks());
|
|
||||||
pScan->setInterval(97);
|
|
||||||
pScan->setWindow(37);
|
|
||||||
pScan->setActiveScan(true);
|
|
||||||
pScan->setMaxResults(0);
|
|
||||||
bleReady = true;
|
bleReady = true;
|
||||||
ESP_LOGI(TAG, "BLE: initialized after key provisioning");
|
ESP_LOGI(TAG, "BLE: initialized after key provisioning");
|
||||||
}
|
}
|
||||||
|
|
@ -325,12 +315,6 @@ void loop() {
|
||||||
Serial.println("Server UUID stored in NVS");
|
Serial.println("Server UUID stored in NVS");
|
||||||
if (allProvisioned && !bleReady) {
|
if (allProvisioned && !bleReady) {
|
||||||
NimBLEDevice::init("SylDa_Client");
|
NimBLEDevice::init("SylDa_Client");
|
||||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
|
||||||
pScan->setScanCallbacks(new MyScanCallbacks());
|
|
||||||
pScan->setInterval(97);
|
|
||||||
pScan->setWindow(37);
|
|
||||||
pScan->setActiveScan(true);
|
|
||||||
pScan->setMaxResults(0);
|
|
||||||
bleReady = true;
|
bleReady = true;
|
||||||
ESP_LOGI(TAG, "BLE: initialized after server provisioning");
|
ESP_LOGI(TAG, "BLE: initialized after server provisioning");
|
||||||
}
|
}
|
||||||
|
|
@ -428,24 +412,32 @@ void loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lastScanStart = 0;
|
static uint32_t lastConnectAttempt = 0;
|
||||||
static bool scanRunnable = false;
|
static uint32_t statusLog = 0;
|
||||||
|
|
||||||
if (!connected) {
|
if (bleReady && millis() - statusLog > 2000) {
|
||||||
NimBLEScan *pScan = NimBLEDevice::getScan();
|
ESP_LOGI(TAG, "BLE: connected=%d, pClient=%p, isConn=%d",
|
||||||
if ((millis() - lastScanStart > SCAN_INTERVAL) && !pScan->isScanning()) {
|
connected, (void*)pClient, pClient ? pClient->isConnected() : 0);
|
||||||
serverFound = false;
|
statusLog = millis();
|
||||||
pScan->start(SCAN_TIMEOUT / 1000, false);
|
|
||||||
lastScanStart = millis();
|
|
||||||
scanRunnable = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pScan->isScanning() && scanRunnable) {
|
if (!connected && bleReady) {
|
||||||
scanRunnable = false;
|
if (millis() - lastConnectAttempt > SCAN_INTERVAL) {
|
||||||
if (serverFound) {
|
ESP_LOGI(TAG, "BLE: connecting to server...");
|
||||||
ESP_LOGI(TAG, "BLE: found server advertising service UUID, connecting...");
|
if (pClient == nullptr) {
|
||||||
connectToServer();
|
pClient = NimBLEDevice::createClient();
|
||||||
|
pClient->setConnectTimeout(10);
|
||||||
|
pClient->setClientCallbacks(&clientCallbacks);
|
||||||
}
|
}
|
||||||
|
if (pClient->connect(serverAddress)) {
|
||||||
|
connected = true;
|
||||||
|
NimBLERemoteService *pSvc = pClient->getService(SERVICE_UUID);
|
||||||
|
if (pSvc) pCmdChar = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
|
||||||
|
ESP_LOGI(TAG, "BLE: connected!");
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "BLE: connect failed");
|
||||||
|
}
|
||||||
|
lastConnectAttempt = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -445,10 +445,16 @@ void setup() {
|
||||||
|
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
pAdvertising->setName("SylDa_Server");
|
pAdvertising->setName("SylDa_Server");
|
||||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
|
||||||
|
|
||||||
NimBLEAdvertisementData scanResp;
|
NimBLEAdvertisementData scanResp;
|
||||||
scanResp.setCompleteServices(NimBLEUUID(SERVICE_UUID));
|
scanResp.setCompleteServices(NimBLEUUID(SERVICE_UUID));
|
||||||
|
|
||||||
|
uint8_t mfgPayload[6];
|
||||||
|
mfgPayload[0] = 0xFF;
|
||||||
|
mfgPayload[1] = 0xFF;
|
||||||
|
memcpy(mfgPayload + 2, deviceUuid, 4);
|
||||||
|
scanResp.setManufacturerData(std::string((char*)mfgPayload, 6));
|
||||||
|
|
||||||
pAdvertising->setScanResponseData(scanResp);
|
pAdvertising->setScanResponseData(scanResp);
|
||||||
pAdvertising->enableScanResponse(true);
|
pAdvertising->enableScanResponse(true);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue