我正在尝试使用库 painlessMesh 构建 3 个 ESP32 的网格,这似乎是一个非常智能的工具(https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/ esp-wifi-mesh.html)
每个板应连续执行快速 BLE 扫描(约 2 秒),然后通过网格广播结果,直到根节点,以字符串的形式。 然后根节点应该处理扫描数据。
我使用任务调度程序来管理 2 个主要任务(执行扫描、广播结果),使用 TaskScheduler (https://github.com/arkhipenko/TaskScheduler)
首先,我遵循了 RandomNerds 的这个很棒的指南(https://randomnerdtutorials.com/esp-mesh-esp32-esp8266-painlessmesh/):它允许我让 3 个板正常工作,连接非常快并进行广播一条简单的“来自 board X 的问候”消息。
无论如何,当我引入执行 2 秒 BLE 扫描的功能时,突然之间,板子不再能够相互识别。通电后,它们不会连接到网格(假设板 1 和板 2 现在加载了 BLE 扫描代码:它们不会找到彼此。如果板 3 加载了简单的“hello”代码,它可能会识别板1 并连接,但不连接板 2)。
他们很少能够按照预期进行连接和工作,但我不知道为什么。无论如何,几秒钟后他们就会断开连接。
每个板都加载了完全相同的代码,除了用于标识板的字符串 BOARD_NAME(范围 1 到 3)。
抱歉意大利评论
#include "painlessMesh.h" //libreria per usare il protocollo ESP-WIFI-MESH
//direttive per la scansione BLE
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
//dettagli della mesh che stiamo realizzando. la rete si occupa da sola di
//mandare in giro i messaggi per tutta la rete.
#define MESH_PREFIX "meshName" //nome della rete
#define MESH_PASSWORD "password123" //password per la rete
#define MESH_PORT 5555 //porta tcp sul quale far girare il server. default: 5555.
String BOARD_NAME = "1"; //nome/numero della board
int scanTime = 2; //BLE Scan duration (seconds)
BLEScan* pBLEScan; //oggetto BLEScan
String jsonString;
bool scanCompleted;
Scheduler userScheduler;
painlessMesh mesh; //oggetto rete
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
//Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
// User stub
void transmitData() ; //prototipo di sendMessage(), da non rimuovere
void scan(); //prototipo di scan(), da non rimuovere
//TASKS
Task transmit( TASK_SECOND * 4 , TASK_FOREVER, &transmitData );
Task bleScan(TASK_SECOND * 3, TASK_FOREVER, &scan);
void scan() {
scanCompleted = false;
Serial.print(F("Board "));
Serial.print(BOARD_NAME);
Serial.print(F(" is scanning...\n"));
BLEScanResults foundDevices = pBLEScan->start(scanTime, false); //salva i risultati della scansione in foundDevices
//creazione array JSON
StaticJsonDocument<1024> scanResultsJson;
JsonArray devicesArray = scanResultsJson.to<JsonArray>();
for (int i = 0; i < foundDevices.getCount(); i++) { //salva nell-iesima posizione dell'array l'i-esimo device (mac, RSSI)
BLEAdvertisedDevice device = foundDevices.getDevice(i);
JsonObject deviceJson = devicesArray.createNestedObject();
deviceJson["mac_address"] = device.getAddress().toString();
deviceJson["rssi"] = device.getRSSI();
deviceJson["boardName"] = BOARD_NAME; //inseriamolo per capire quale board ha fatto il rilevamento
//Serial.printf("Device %d: MAC Address: %s, RSSI: %d\n", i+1, device.getAddress().toString().c_str(), device.getRSSI());
}
//"stringhifichiamo" il JSON per spedirlo con la painlessMesh
serializeJson(scanResultsJson, jsonString);
scanCompleted = true;
//Serial.print("JsonString: ");
//Serial.println(jsonString);
}
void transmitData() {
if (scanCompleted){
Serial.println(BOARD_NAME + " is trying to broadcast...");
mesh.sendBroadcast(jsonString);
jsonString = "";
pBLEScan->clearResults();
}
}
// Callback necessari per fare in modo che la rete sia sempre up to date
void receivedCallback( uint32_t from, String &msg ) {
Serial.println("Nuovo messaggio: " + msg);
}
//questa funzione viene eseguita ogni volta che un nuovo nodo si connette alla rete
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("Nuovo nodo, nodeId = %u\n", nodeId);
}
//questa viene eseguita quando cambia la connessione con un nodo (un nodo entra o lascia la rete)
void changedConnectionCallback() {
Serial.printf("Cambiamento di rete\n");
}
//questa viene eseguita quando la rete aggiusta il timing, così tutti sono in Sync
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}
void setup() {
Serial.begin(115200);
//Scegliere il messaggio di Debug che più aggrada sua maestà sviluppatore
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION | GENERAL ); // set before init() so that you can see mesh startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); //inizializzazione della mesh con i parametri prima definiti
//assegniamo ad ogni evento la relativa funzione.
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
//BLE Functions
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100); //distanza temporale tra due scansioni, in ms
pBLEScan->setWindow(99); // finestra di tempo in cui deve scansionare, tra due scansioni. dev'essere <= al valore della riga sopra per chiare ragioni
//TASKS
userScheduler.addTask(transmit); //aggiungiamo allo scheduler il compito di trasmettere il msg
userScheduler.addTask(bleScan);
bleScan.enable();
transmit.enable();
}
void loop() {
mesh.update(); //mantiene la mesh in esecuzione ed anche lo scheduler
}
我坚信“扫描”任务中的
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
是所有邪恶的根源,因为当该任务未启用时一切正常。我知道这个特定的行在进行扫描时“停止”代码,但我不明白为什么它会导致连接问题,也不明白如何解决它。
我已经查过了:
希望有人可以提供帮助,谷歌搜索我发现其他人在过去几年中也遇到了类似的连接问题。
提前非常感谢大家。
按照评论中@MichaelKotzjan的建议,我一切都工作得很好。
代码更改:
我添加了一个void函数
void EndofScan() {
pBLEScan->start(scanTime, EndofScan);
}
并且仅在
void setup(){}
中使用调用一次
foundDevices = pBLEScan->start(scanTime, true);
其中foundDevices是全局声明的
BLEScanResult
对象,用于包含扫描结果。它是全球性的,因此可以在其他任何地方使用。
通过这样做,我们实现了异步执行的 BLE 扫描。
代码:
#include "painlessMesh.h" //libreria per usare il protocollo ESP-WIFI-MESH
//direttive per la scansione BLE
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
//dettagli della mesh che stiamo realizzando. la rete si occupa da sola di
//mandare in giro i messaggi per tutta la rete.
#define MESH_PREFIX "meshName" //nome della rete
#define MESH_PASSWORD "password123" //password per la rete
#define MESH_PORT 5555 //porta tcp sul quale far girare il server. default: 5555. credo servirà per fare la dashboard finale
String BOARD_NAME = "1"; //nome/numero della board
int scanTime = 3; //BLE Scan duration (seconds). non deve essere maggiore del primo parametro di Task bleScan, altrimenti c'è un conflitto.
BLEScan* pBLEScan; //oggetto BLEScan
String jsonString;
bool scanCompleted;
BLEScanResults foundDevices;
String receivedMessage;
Scheduler userScheduler;
painlessMesh mesh; //oggetto rete
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
//Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
// User stub
void transmitData() ; //prototipo di sendMessage(), da non rimuovere
void scan(); //prototipo di scan(), da non rimuovere
void EndofScan();
//TASKS
Task transmit( TASK_SECOND * 4 , TASK_FOREVER, &transmitData );
Task bleScan(TASK_SECOND * 4, TASK_FOREVER, &scan);
void scan() {
Serial.print(F("Board "));
Serial.print(BOARD_NAME);
Serial.print(F(" is scanning...\n"));
//creazione array JSON
StaticJsonDocument<1024> scanResultsJson;
JsonArray devicesArray = scanResultsJson.to<JsonArray>();
for (int i = 0; i < foundDevices.getCount(); i++) { //salva nell-iesima posizione dell'array l'i-esimo device (mac, RSSI)
BLEAdvertisedDevice device = foundDevices.getDevice(i);
JsonObject deviceJson = devicesArray.createNestedObject();
deviceJson["mac_address"] = device.getAddress().toString();
deviceJson["rssi"] = device.getRSSI();
deviceJson["boardName"] = BOARD_NAME; //inseriamolo per capire quale board ha fatto il rilevamento
//Serial.printf("Device %d: MAC Address: %s, RSSI: %d\n", i+1, device.getAddress().toString().c_str(), device.getRSSI());
}
//"stringhifichiamo" il JSON per spedirlo con la painlessMesh
serializeJson(scanResultsJson, jsonString);
//Serial.print("JsonString: ");
//Serial.println(jsonString);
}
void EndofScan() {
pBLEScan->start(scanTime, EndofScan);
}
void transmitData() {
Serial.println(BOARD_NAME + " is trying to broadcast...");
mesh.sendBroadcast(jsonString);
}
const int MAX_SIZE = 150;
String boardScans[MAX_SIZE];
// Callback necessari per fare in modo che la rete sia sempre up to date
void receivedCallback( uint32_t from, String &msg ) {
Serial.println("Nuovo messaggio: " + msg);
receivedMessage = msg;
char lastChar = receivedMessage.charAt(receivedMessage.length() - 1);
int i = int(String(lastChar));
boardScans[i] = receivedMessage+"agg: "+String(matistaiaggiornando);
Serial.println("Nuovo messaggio ricevuto da BOARD "+String(lastChar)+" salvato in receivedMessage");
}
//questa funzione viene eseguita ogni volta che un nuovo nodo si connette alla rete
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("Nuovo nodo, nodeId = %u\n", nodeId);
}
//questa viene eseguita quando cambia la connessione con un nodo (un nodo entra o lascia la rete)
void changedConnectionCallback() {
Serial.printf("Cambiamento di rete\n");
}
//questa viene eseguita quando la rete aggiusta il timing, così tutti sono in Sync
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}
void setup() {
Serial.begin(115200);
//Scegliere il messaggio di Debug che più aggrada sua maestà sviluppatore
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION | GENERAL ); // set before init() so that you can see mesh startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); //inizializzazione della mesh con i parametri prima definiti
mesh.setRoot(true);
//assegniamo ad ogni evento la relativa funzione.
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
//BLE Functions
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(200); //distanza temporale tra due scansioni, in ms
pBLEScan->setWindow(199); // finestra di tempo in cui deve scansionare, tra due scansioni. dev'essere <= al valore della riga sopra per chiare ragioni
foundDevices = pBLEScan->start(scanTime, true); //salva i risultati della scansione in foundDevices
//TASKS
userScheduler.addTask(transmit); //aggiungiamo allo scheduler il compito di trasmettere il msg
userScheduler.addTask(bleScan);
bleScan.enable();
transmit.enable();
}
void loop() {
mesh.update(); //mantiene la mesh in esecuzione ed anche lo scheduler
}