Cách xây dựng ESP32 Mesh / ESP8266 Mesh Network để gửi dữ liệu cảm biến
Trong bài viết này, cùng tìm hiểu về xây dựng mạng lưới ESP32 Mesh + ESP8266 Mesh. Mạng lưới này cho phép nhiều thiết bị (Node) có thể giao tiếp với nhau thông qua mạng cục bộ không dây, chúng được hỗ trợ trên cả mạch ESP32 lẫn ESP8266.
ESP Mesh là gì?
ESP Mesh được hiểu là một giao thức mạng được xây dựng dựa trên WiFi, cho phép nhiều thiết bị (có thể gọi là Node) ở cách xa nhau có thể kết nối với nhau trong một mạng WLAN (còn gọi là mạng cục bộ không dây).
ESP32 Mesh có khả năng tự tổ chức và phục hồi, nghĩa là hệ thống mạng này sẽ được xây dựng và duy trì tự động.
Kiến trúc mạng WiFi truyền thống
Trong kiến trúc mạng WiFi, một Single Node (điểm truy cập – Ascess point, còn được gọi là bộ định tuyến) sẽ kết nối với tất cả các nodes khác (stations).
Trong đó, mỗi nodes có thể giao tiếp với nhau bằng điểm truy cập. Tuy nhiên, khả năng này sẽ bị giới hạn tùy vào phạm vi phủ sóng WiFi của điểm truy cập. Các nodes phải nằm trong phạm vi kết nối của điểm truy cập, nhưng với ESP Mesh thì bạn không cần phải lo lắng về vấn đề này.
Kiến trúc mạng ESP Mesh
Trong kiến trúc mạng ESP Mesh, các Node không cần kết nối với 1 nút trung tâm. Các Node này có trách nhiệm chuyển tiếp đường truyền cho nhau, giúp nhiều thiết bị có thể kết nối với nhau và trải rộng trên một khu vực địa lý rộng lớn.
Trong đó, các nodes có thể tự tổ chức và giao tiếp với nhau để đảm bảo gói tin truyền tải được gửi đến đúng node đích cuối cùng. Nếu node nào bị xóa khỏi mạng, chúng cũng có thể tự tổ chức để đảm bảo các gói sẽ được đến đúng đích như mong muốn.
Giới thiệu thư viện painlessMesh
Thư viện painlessMesh cho phép chúng ta khởi tạo một mạng lưới ESP Mesh dựa trên bảng mạch ESP32 và ESP8266 dễ dàng.
Bạn có thể cài đặt thư viện này trong trình quản lý thư viện có sẵn của Arduino, bằng cách click theo thứ tự Tools >> Manage Libraries >> Tìm tên thư viện painlessMesh và cài đặt phiên bản mới nhất.
Tuy nhiên, thư viện này sẽ cần một số phụ thuộc của những thư viện khác. Khi click chọn Install, một cửa sổ mới sẽ hiển thị và yêu cầu bạn cài đặt tất cả các phần phụ thuộc còn thiếu, bạn hãy click chọn Install all:
Nếu trên cửa sổ này không hiển thị, bạn cần tự cài các phần phụ thuộc sau một cách thủ công:
- ArduinoJson (by bblanchon)
- TaskScheduler
- ESPAsyncTCP (ESP8266)
- AsyncTCP (ESP32)
Nếu bạn đang dùng PlatformIO, bạn cần thêm các dòng code bên dưới vào file platformio.ini để thêm thư viện và thay đổi tốc độ màn hình:
1. Với ESP32:
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5 ArduinoJson arduinoUnity TaskScheduler AsyncTCP
2. Với ESP8266
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5 ArduinoJson TaskScheduler ESPAsyncTCP
Chương trình cơ bản – xây dựng ESP Mesh (Tin nhắn quảng bá – Broadcast messages)
Để bắt đầu với mạng ESP Mesh, chúng ta hãy cùng thử nghiệm một ví dụ cơ bản nhất: Tạo một mạng lưới ESP32 Mesh, trong đó tất cả các mạch (Node) có thể kết nối với tất cả các mạch khác.
Tổng quan
Mình đã thử nghiệm dự án này với 4 bảng mạch (2 mạch ESP32 và 2 mạch ESP8266). Bạn có thể tùy chỉnh số lượng này tùy thích, đoạn code mình chia sẻ tương thích với cả ESP32 lẫn ESP8266.
Dưới đây là hình ảnh minh họa mạng lưới ESP32 Mesh + ESP8266 Mesh mà mình tạo:
Chương trình lập trình
Bạn copy đoạn code sau, chỉnh sửa tin nhắn (message) để dễ xác định Node gửi tin nhắn, rồi nạp vào mạch của mình nhé, code này tương thích với cả ESP32 lẫn ESP8266:
#include "painlessMesh.h" #define MESH_PREFIX "whateverYouLike" #define MESH_PASSWORD "somethingSneaky" #define MESH_PORT 5555 Scheduler userScheduler; // to control your personal task painlessMesh mesh; // User stub void sendMessage() ; // Prototype so PlatformIO doesn't complain Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage ); void sendMessage() { String msg = "Hi from node1"; msg += mesh.getNodeId(); mesh.sendBroadcast( msg ); taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 )); } // Needed for painless library void receivedCallback( uint32_t from, String &msg ) { Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str()); } void newConnectionCallback(uint32_t nodeId) { Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId); } void changedConnectionCallback() { Serial.printf("Changed connections\n"); } void nodeTimeAdjustedCallback(int32_t offset) { Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset); } void setup() { Serial.begin(115200); //mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); mesh.onReceive(&receivedCallback); mesh.onNewConnection(&newConnectionCallback); mesh.onChangedConnections(&changedConnectionCallback); mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback); userScheduler.addTask( taskSendMessage ); taskSendMessage.enable(); } void loop() { // it will run the user scheduler as well mesh.update(); }
Demo
Sau khi nạp code vào mạch, với mỗi bo mạch được kết nối với máy tính, bạn hãy mở kết nối Serial của từng mạch. Bạn có thể sử dụng Serial Monitor, hoặc bạn dùng những phần mềm như PuTTY và mở nhiều cửa sổ cho tất cả các mạch trong hệ thống mạng ESP32 Mesh của bạn.
Bạn sẽ thấy tất cả các mạch sẽ nhận được tin nhắn của nhau. Ví dụ như hình dưới là các tin nhắn từ node 2, 3 và 4 mà node 1 nhận được.
Trên màn hình Serial cũng hiển thị các thông báo khi có thay đổi trên mạng lưới ESP Mesh, chẳng hạn như khi 1 mạch rời khỏi hoặc tham gia vào mạng:
Chương trình 2 – Đọc và gửi dữ liệu từ cảm biến bằng ESP Mesh
Trong ví dụ này, mời bạn cùng tìm hiểu cách xây dựng mạng lưới để các mạch có thể trao đổi giá trị đọc được từ cảm biến. Trong đó, mạch này sẽ nhận được giá trị mà mạch kia đo được,
Chuẩn bị
- 4 mạch ESP (ESP32 hoặc ESP8266, hoặc cả 2 đều được)
- 4 cảm biến nhiệt độ BME280
- Dây Jumper
- Breadboard
Thư viện Arduino_JSON
Trong ví dụ này, các mạch sẽ trao đổi giá trị cảm biến ở định dạng JSON. Để xử lý các biến JSON dễ hơn, chúng ta sẽ sử dụng thư viện có tên là Arduino_JSON.
Bạn có thể vào trình quản lý thư viện trong Arduino (như hướng dẫn cài thư viện phía trên) để cài đặt thư viện này.
Trong trường hợp dùng VS Code và PlatformIO, bạn cần đưa các thư viện vào file platformio.ini như sau:
1. ESP32:
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5 ArduinoJson arduinoUnity AsyncTCP TaskScheduler adafruit/Adafruit Unified Sensor @ ^1.1.4 adafruit/Adafruit BME280 Library @ ^2.1.2 arduino-libraries/Arduino_JSON @ ^0.1.0
2. ESP8266
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5 ArduinoJson TaskScheduler ESPAsyncTCP adafruit/Adafruit Unified Sensor @ ^1.1.4 adafruit/Adafruit BME280 Library @ ^2.1.2 arduino-libraries/Arduino_JSON @ ^0.1.0
Kết nối phần cứng
Kết nối cảm biến BME280 vào các chân I2C của mạch ESP32 / EPS8266 như sơ đồ:
Chương trình mẫu
Đoạn code sau đây sẽ giúp mạch đọc giá trị nhiệt độ, độ ẩm và áp suất từ cảm biến, sau đó gửi tất cả các thông tin này tới những mạch khác thông qua mạng lưới ESP32 Mesh. Các kết quả này được gửi dưới dạng chuỗi JSON và có chứa số node để xác định nó được gửi từ mạch nào:
#include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> #include "painlessMesh.h" #include <Arduino_JSON.h> // MESH Details #define MESH_PREFIX "RNTMESH" //name for your MESH #define MESH_PASSWORD "MESHpassword" //password for your MESH #define MESH_PORT 5555 //default port //BME object on the default I2C pins Adafruit_BME280 bme; //Number for this node int nodeNumber = 2; //String to send to other nodes with sensor readings String readings; Scheduler userScheduler; // to control your personal task painlessMesh mesh; // User stub void sendMessage() ; // Prototype so PlatformIO doesn't complain String getReadings(); // Prototype for sending sensor readings //Create tasks: to send messages and get readings; Task taskSendMessage(TASK_SECOND * 5 , TASK_FOREVER, &sendMessage); String getReadings () { JSONVar jsonReadings; jsonReadings["node"] = nodeNumber; jsonReadings["temp"] = bme.readTemperature(); jsonReadings["hum"] = bme.readHumidity(); jsonReadings["pres"] = bme.readPressure()/100.0F; readings = JSON.stringify(jsonReadings); return readings; } void sendMessage () { String msg = getReadings(); mesh.sendBroadcast(msg); } //Init BME280 void initBME(){ if (!bme.begin(0x76)) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1); } } // Needed for painless library void receivedCallback( uint32_t from, String &msg ) { Serial.printf("Received from %u msg=%s\n", from, msg.c_str()); JSONVar myObject = JSON.parse(msg.c_str()); int node = myObject["node"]; double temp = myObject["temp"]; double hum = myObject["hum"]; double pres = myObject["pres"]; Serial.print("Node: "); Serial.println(node); Serial.print("Temperature: "); Serial.print(temp); Serial.println(" C"); Serial.print("Humidity: "); Serial.print(hum); Serial.println(" %"); Serial.print("Pressure: "); Serial.print(pres); Serial.println(" hpa"); } void newConnectionCallback(uint32_t nodeId) { Serial.printf("New Connection, nodeId = %u\n", nodeId); } void changedConnectionCallback() { Serial.printf("Changed connections\n"); } void nodeTimeAdjustedCallback(int32_t offset) { Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset); } void setup() { Serial.begin(115200); initBME(); //mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); mesh.onReceive(&receivedCallback); mesh.onNewConnection(&newConnectionCallback); mesh.onChangedConnections(&changedConnectionCallback); mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback); userScheduler.addTask(taskSendMessage); taskSendMessage.enable(); } void loop() { // it will run the user scheduler as well mesh.update(); }
Bạn hãy nạp code vào các mạch của mình (mỗi mạch có 1 số thứ tự node khác nhau), bạn sẽ thấy mỗi mạch đang nhận được tin nhắn từ tất cả các mạch khác thông qua ESP32 Mesh Network.
Lời kết
Trong bài viết trên, IoTZone đã hướng dẫn bạn chi tiết về mạng lưới EPS32 Mesh, với 2 dự án từ cơ bản đến nâng cao. Chúc bạn thành công! Hiện tại IoTZone có cung cấp đa dạng các mạch EPS32 để phục vụ dự án cho bạn, bạn có thể xem qua tại link sau: ESP32 LoRa Heltec.
IoTZone – Chuyên cung cấp thiết bị điện tử & tài liệu cho Makers
- Website: https://www.iotzone.vn/
- Fanpage: https://www.facebook.com/Iotzonemaker
- SDT: 0364174499
- Zalo: https://zalo.me/0364174499