ESP32 Bluetooth Chat Example Hướng Dẫn Giao Diện Nhắn Tin Hai Chiều

Tổng Quan

Ví dụ Bluetooth Chat cho phép nhắn tin văn bản hai chiều giữa ESP32 và smartphone thông qua ứng dụng DIYables Bluetooth STEM. Được thiết kế cho các board ESP32 với hỗ trợ cả BLE (Bluetooth Low Energy)Classic Bluetooth. Gửi và nhận tin nhắn văn bản thời gian thực, triển khai xử lý lệnh tùy chỉnh, và tạo cầu nối Serial Monitor với Bluetooth — hoàn hảo cho việc debug, điều khiển từ xa và các dự án tương tác.

Ví dụ này hỗ trợ hai chế độ Bluetooth:

  • ESP32 BLE (Bluetooth Low Energy): Hoạt động trên cả Android và iOS
  • ESP32 Classic Bluetooth: Chỉ hoạt động trên Android. iOS không hỗ trợ Classic Bluetooth. Sử dụng BLE nếu bạn cần hỗ trợ iOS.
ESP32 Bluetooth chat example - hướng dẫn giao diện nhắn tin hai chiều

Tính Năng

  • Nhắn Tin Hai Chiều: Gửi và nhận tin nhắn văn bản thời gian thực
  • Chế Độ Echo: Tự động phản hồi lại tin nhắn nhận được từ app
  • Xử Lý Lệnh: Xử lý các lệnh văn bản tùy chỉnh (ping, status, time, heap)
  • Tin Nhắn Định Kỳ: Gửi cập nhật trạng thái tự động theo khoảng thời gian có thể cấu hình
  • Cầu Nối Serial-to-Bluetooth: Nhập tin nhắn trong Serial Monitor và gửi đến app
  • BLE & Classic Bluetooth: Chọn chế độ Bluetooth phù hợp với dự án của bạn
  • Đa Nền Tảng: Chế độ BLE hoạt động trên cả Android và iOS; Classic Bluetooth hoạt động trên Android
  • Tùy Chọn Tiết Kiệm Pin: Chế độ BLE tiêu thụ ít pin hơn Classic Bluetooth

Linh Kiện Cần Thiết

1×mô-đun phát triển ESP-WROOM-32
1×Alternatively, ESP32 Uno-form board
1×Alternatively, ESP32 S3 Uno-form board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×breadboard
1×dây jumper
1×(Khuyến nghị) Screw Terminal Expansion Board for ESP32
1×(Khuyến nghị) Breakout Expansion Board for ESP32
1×(Khuyến nghị) Power Splitter for ESP32

Or you can buy the following kits:

1×DIYables ESP32 Starter Kit (ESP32 included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)

Code ESP32

Các Bước Nhanh

Thực hiện theo các hướng dẫn từng bước:

  • Nếu đây là lần đầu tiên bạn sử dụng ESP32, hãy tham khảo hướng dẫn về ESP32 - Cài Đặt Phần Mềm.
  • Kết nối board ESP32 với máy tính của bạn bằng cáble USB.
  • Khởi chạy Arduino IDE trên máy tính của bạn.
  • Chọn board ESP32 và COM port phù hợp.
  • Điều hướng đến biểu tượng Libraries ở thanh bên trái của Arduino IDE.
  • Tìm kiếm "DIYables Bluetooth", sau đó tìm thư viện DIYables Bluetooth của DIYables
  • Nhấp nút Install để cài đặt thư viện.
ESP32 diyables Bluetooth thư viện
  • Bạn sẽ được yêu cầu cài đặt một số thư viện phụ thuộc khác
  • Nhấp nút Install All để cài đặt tất cả các thư viện phụ thuộc.
ESP32 diyables Bluetooth dependency

Chọn một trong hai chế độ Bluetooth dưới đây tùy thuộc vào nhu cầu của bạn:

Code ESP32 Classic Bluetooth (chỉ hoạt động với app trên Android)

Lưu ý: Classic Bluetooth KHÔNG được hỗ trợ trên iOS. Nếu bạn cần hỗ trợ iOS, hãy sử dụng code BLE bên dưới.

  • Trong Arduino IDE, đi đến File Examples DIYables Bluetooth Esp32Bluetooth_Chat example, hoặc sao chép code trên và dán vào editor của Arduino IDE
/* * DIYables Bluetooth Library - ESP32 Classic Bluetooth Chat Example * Works with DIYables Bluetooth STEM app on Android * Note: Classic Bluetooth is NOT supported on iOS. Use BLE examples for iOS support. * * This example demonstrates the Bluetooth Chat feature: * - Two-way text messaging via Bluetooth * - Receive messages from mobile app * - Send messages to mobile app * * Compatible Boards: * - ESP32 (all variants with Classic Bluetooth) * - ESP32-WROOM-32 * - ESP32-DevKitC * - ESP32-WROVER * * Note: Select "Huge APP (3MB No OTA/1MB SPIFFS)" partition scheme * in Arduino IDE: Tools > Partition Scheme * * Setup: * 1. Upload the sketch to your ESP32 * 2. Open Serial Monitor (115200 baud) to see connection status and messages * 3. Use DIYables Bluetooth App to connect and chat * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothChat.h> #include <platforms/DIYables_Esp32Bluetooth.h> // Create Bluetooth instances DIYables_Esp32Bluetooth bluetooth("ESP32_Chat"); DIYables_BluetoothServer bluetoothServer(bluetooth); // Create Chat app instance DIYables_BluetoothChat bluetoothChat; // Variables for periodic messages unsigned long lastMessageTime = 0; const unsigned long MESSAGE_INTERVAL = 10000; // Send message every 10 seconds int messageCount = 0; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 Chat Example"); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add chat app to server bluetoothServer.addApp(&bluetoothChat); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothChat.send("Hello! ESP32 is ready to chat."); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); messageCount = 0; }); // Set up callback for received chat messages bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Echo the message back String response = "Echo: "; response += message; bluetoothChat.send(response); // You can add custom command handling here if (message.equalsIgnoreCase("ping")) { bluetoothChat.send("pong!"); } else if (message.equalsIgnoreCase("status")) { bluetoothChat.send("ESP32 is running normally"); } else if (message.equalsIgnoreCase("time")) { String timeMsg = "Uptime: "; timeMsg += String(millis() / 1000); timeMsg += " seconds"; bluetoothChat.send(timeMsg); } else if (message.equalsIgnoreCase("heap")) { String heapMsg = "Free heap: "; heapMsg += String(ESP.getFreeHeap()); heapMsg += " bytes"; bluetoothChat.send(heapMsg); } }); Serial.println("Waiting for Bluetooth connection..."); Serial.println("Type 'ping', 'status', 'time', or 'heap' in the app to test commands"); } void loop() { // Handle Bluetooth server communications bluetoothServer.loop(); // Send periodic status message (only when connected) if (bluetooth.isConnected() && millis() - lastMessageTime >= MESSAGE_INTERVAL) { lastMessageTime = millis(); messageCount++; String statusMsg = "Status update #"; statusMsg += String(messageCount); statusMsg += " - All systems operational"; bluetoothChat.send(statusMsg); Serial.print("Sent: "); Serial.println(statusMsg); } // Optional: Read from Serial and send to Bluetooth if (Serial.available()) { String serialMsg = Serial.readStringUntil('\n'); serialMsg.trim(); if (serialMsg.length() > 0 && bluetooth.isConnected()) { bluetoothChat.send(serialMsg); Serial.print("Sent from Serial: "); Serial.println(serialMsg); } } delay(10); }
  • Nhấp nút Upload trên Arduino IDE để upload code lên ESP32
  • Mở Serial Monitor
  • Kiểm tra kết quả trên Serial Monitor. Nó trông giống như sau:
COM6
Send
DIYables Bluetooth - ESP32 Chat Example Waiting for Bluetooth connection... Type 'ping', 'status', 'time', or 'heap' in the app to test commands
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Code ESP32 BLE (hoạt động với app trên cả Android và iOS)

  • Trong Arduino IDE, đi đến File Examples DIYables Bluetooth Esp32BLE_Chat example, hoặc sao chép code trên và dán vào editor của Arduino IDE
/* * DIYables Bluetooth Library - ESP32 BLE Chat Example * Works with DIYables Bluetooth STEM app on Android and iOS * * This example demonstrates the Bluetooth Chat feature: * - Two-way text messaging via Bluetooth * - Receive messages from mobile app * - Send messages to mobile app * * Compatible Boards: * - ESP32-WROOM-32 * - ESP32-DevKitC * - ESP32-WROVER * - ESP32-S3 * - ESP32-C3 * - Any ESP32 board supporting BLE * * Note: Select "Huge APP (3MB No OTA/1MB SPIFFS)" partition scheme * in Arduino IDE: Tools > Partition Scheme * * Setup: * 1. Upload the sketch to your ESP32 * 2. Open Serial Monitor (115200 baud) to see connection status and messages * 3. Use DIYables Bluetooth App to connect and chat * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothChat.h> #include <platforms/DIYables_Esp32BLE.h> // BLE Configuration const char* DEVICE_NAME = "ESP32BLE_Chat"; const char* SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214"; const char* TX_UUID = "19B10001-E8F2-537E-4F6C-D104768A1214"; const char* RX_UUID = "19B10002-E8F2-537E-4F6C-D104768A1214"; // Create Bluetooth instances DIYables_Esp32BLE bluetooth(DEVICE_NAME, SERVICE_UUID, TX_UUID, RX_UUID); DIYables_BluetoothServer bluetoothServer(bluetooth); // Create Chat app instance DIYables_BluetoothChat bluetoothChat; // Variables for periodic messages unsigned long lastMessageTime = 0; const unsigned long MESSAGE_INTERVAL = 10000; // Send message every 10 seconds int messageCount = 0; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 BLE Chat Example"); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add chat app to server bluetoothServer.addApp(&bluetoothChat); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothChat.send("Hello! ESP32 BLE is ready to chat."); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); messageCount = 0; }); // Set up callback for received chat messages bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Echo the message back String response = "Echo: "; response += message; bluetoothChat.send(response); // Custom command handling if (message.equalsIgnoreCase("ping")) { bluetoothChat.send("pong!"); } else if (message.equalsIgnoreCase("status")) { bluetoothChat.send("ESP32 BLE is running normally"); } else if (message.equalsIgnoreCase("time")) { String timeMsg = "Uptime: "; timeMsg += String(millis() / 1000); timeMsg += " seconds"; bluetoothChat.send(timeMsg); } else if (message.equalsIgnoreCase("heap")) { String heapMsg = "Free heap: "; heapMsg += String(ESP.getFreeHeap()); heapMsg += " bytes"; bluetoothChat.send(heapMsg); } }); Serial.println("Waiting for Bluetooth connection..."); Serial.println("Type 'ping', 'status', 'time', or 'heap' in the app to test commands"); } void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastMessageTime >= MESSAGE_INTERVAL) { lastMessageTime = millis(); messageCount++; String statusMsg = "Status update #"; statusMsg += String(messageCount); statusMsg += " - All systems operational"; bluetoothChat.send(statusMsg); Serial.print("Sent: "); Serial.println(statusMsg); } if (Serial.available()) { String serialMsg = Serial.readStringUntil('\n'); serialMsg.trim(); if (serialMsg.length() > 0 && bluetooth.isConnected()) { bluetoothChat.send(serialMsg); Serial.print("Sent from Serial: "); Serial.println(serialMsg); } } delay(10); }
  • Nhấp nút Upload trên Arduino IDE để upload code lên ESP32
  • Mở Serial Monitor
  • Kiểm tra kết quả trên Serial Monitor. Nó trông giống như sau:
COM6
Send
DIYables Bluetooth - ESP32 BLE Chat Example Waiting for Bluetooth connection... Type 'ping', 'status', 'time', or 'heap' in the app to test commands
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Ứng Dụng Di Động

  • Cài đặt DIYables Bluetooth App trên smartphone của bạn: Android | iOS
  • Nếu bạn đang sử dụng code ESP32 Classic Bluetooth, bạn cần ghép nối ESP32 với điện thoại Android trước khi mở app:
    • Vào Settings > Bluetooth của điện thoại
    • Đảm bảo Bluetooth được bật
    • Điện thoại sẽ quét các thiết bị có sẵn
    • Tìm và nhấn "ESP32_Chat" trong danh sách thiết bị có sẵn
    • Xác nhận yêu cầu ghép nối (không cần PIN)
    • Đợi cho đến khi hiển thị "Paired" dưới tên thiết bị
  • Nếu bạn đang sử dụng code ESP32 BLE, không cần ghép nối. Chỉ cần chuyển sang bước tiếp theo.
  • Mở DIYables Bluetooth App
  • Khi mở app lần đầu tiên, nó sẽ yêu cầu quyền. Vui lòng cấp các quyền sau:
    • Quyền Nearby Devices (Android 12+) / quyền Bluetooth (iOS) - cần thiết để quét và kết nối với các thiết bị Bluetooth
    • Quyền Location (chỉ Android 11 và thấp hơn) - được yêu cầu bởi các phiên bản Android cũ để quét thiết bị BLE
  • Đảm bảo Bluetooth được bật trên điện thoại
  • Trên màn hình chính, nhấn nút Connect. App sẽ quét cả thiết bị BLE và Classic Bluetooth.
diyables Bluetooth app - home screen with scan nút nhấn
  • Tìm và nhấn thiết bị của bạn trong kết quả quét để kết nối:
    • Đối với Classic Bluetooth: nhấn "ESP32_Chat"
    • Đối với BLE: nhấn "ESP32BLE_Chat"
  • Sau khi kết nối, app tự động quay về màn hình chính. Chọn ứng dụng Chat từ menu app.
diyables Bluetooth app - home screen with chat app

Lưu ý: Bạn có thể nhấn biểu tượng cài đặt trên màn hình chính để ẩn/hiện các app trên màn hình chính. Để biết thêm chi tiết, xem DIYables Bluetooth App User Manual.

  • Nhập tin nhắn vào ô nhập văn bản và nhấn Send
diyables Bluetooth app - chat screen

Bây giờ hãy nhìn lại Serial Monitor trên Arduino IDE. Bạn sẽ thấy:

COM6
Send
Bluetooth connected! Received: Hello Received: ping Received: status Sent: Status update #1 - All systems operational
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • Nhập tin nhắn trong app và quan sát phản hồi thời gian thực trong Serial Monitor
  • Thử các lệnh tích hợp: ping, status, time, heap
  • Bạn cũng có thể nhập tin nhắn trong Serial Monitor và chúng sẽ được gửi đến app

Tùy Chỉnh Sáng Tạo - Điều Chỉnh Code Cho Dự Án Của Bạn

Nhận Tin Nhắn Từ App

Sử dụng callback onChatMessage() để xử lý tin nhắn nhận được từ app. Bạn có thể định nghĩa bất kỳ từ lệnh tùy chỉnh nào phù hợp với dự án của mình — ESP32 sẽ phản ứng tương ứng:

bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Xử lý tin nhắn if (message == "LED_ON") { digitalWrite(2, HIGH); bluetoothChat.send("LED turned ON"); } else if (message == "LED_OFF") { digitalWrite(2, LOW); bluetoothChat.send("LED turned OFF"); } else { bluetoothChat.send("Unknown command: " + message); } });

Bạn có thể thêm nhiều lệnh tùy chỉnh bằng cách thêm nhiều khối else if. Ví dụ, thêm RELAY_ON / RELAY_OFF để điều khiển relay, hoặc READ để kích hoạt đọc cảm biến — bất kỳ từ nào bạn nhập trong app đều trở thành lệnh.

Gửi Tin Nhắn Đến App

Bạn có thể gửi tin nhắn văn bản từ ESP32 đến app bất kỳ lúc nào:

// Gửi tin nhắn văn bản đơn giản bluetoothChat.send("Hello from ESP32!"); // Gửi dữ liệu cảm biến dưới dạng văn bản float temperature = 25.3; bluetoothChat.send("Temperature: " + String(temperature) + "°C"); // Gửi cập nhật trạng thái bluetoothChat.send("System ready");

Xử Lý Sự Kiện Kết Nối

Bạn có thể phát hiện khi app kết nối hoặc ngắt kết nối khỏi ESP32:

// Được gọi khi app kết nối với ESP32 bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothChat.send("Welcome! ESP32 is ready to chat."); }); // Được gọi khi app ngắt kết nối khỏi ESP32 bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); }); // Kiểm tra trạng thái kết nối ở bất kỳ đâu trong code if (bluetoothServer.isConnected()) { bluetoothChat.send("Still connected!"); }

Cầu Nối Serial-to-Bluetooth

Chuyển tiếp tin nhắn được nhập trong Arduino IDE Serial Monitor đến app Bluetooth:

void loop() { bluetoothServer.loop(); // Đọc từ Serial và gửi đến Bluetooth if (Serial.available()) { String serialMsg = Serial.readStringUntil('\n'); serialMsg.trim(); if (serialMsg.length() > 0 && bluetooth.isConnected()) { bluetoothChat.send(serialMsg); Serial.print("Sent from Serial: "); Serial.println(serialMsg); } } delay(10); }

Cách Sử Dụng Chat

Điều Khiển Giao Diện App

Giao diện chat trong DIYables Bluetooth App cung cấp:

  • Danh Sách Tin Nhắn: Danh sách có thể cuộn hiển thị tin nhắn đã gửi và nhận
  • Ô Nhập Văn Bản: Nhập tin nhắn của bạn ở dưới cùng
  • Nút Send: Nhấn để gửi tin nhắn đã nhập
  • Auto-scroll: Tự động cuộn đến tin nhắn mới nhất

Lệnh Tích Sẵn

Code ví dụ bao gồm các lệnh tích sẵn sau:

  • ping → Phản hồi với "pong!"
  • status → Báo cáo trạng thái chạy của ESP32
  • time → Hiển thị thời gian hoạt động bằng giây
  • heap → Hiển thị bộ nhớ heap còn trống bằng byte

Ví Dụ Lập Trình

Chat Echo Cơ Bản

void setup() { // Thiết lập callback chat bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Echo tin nhắn trở lại bluetoothChat.send("Echo: " + message); }); }

Điều Khiển LED Dựa Trên Lệnh

const int LED_PIN = 2; // LED tích hợp const int RED_PIN = 16; const int GREEN_PIN = 17; const int BLUE_PIN = 18; void setup() { pinMode(LED_PIN, OUTPUT); pinMode(RED_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "LED ON") { digitalWrite(LED_PIN, HIGH); bluetoothChat.send("LED is now ON"); } else if (cmd == "LED OFF") { digitalWrite(LED_PIN, LOW); bluetoothChat.send("LED is now OFF"); } else if (cmd == "RED") { digitalWrite(RED_PIN, HIGH); digitalWrite(GREEN_PIN, LOW); digitalWrite(BLUE_PIN, LOW); bluetoothChat.send("Red LED activated"); } else if (cmd == "GREEN") { digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, HIGH); digitalWrite(BLUE_PIN, LOW); bluetoothChat.send("Green LED activated"); } else if (cmd == "BLUE") { digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, LOW); digitalWrite(BLUE_PIN, HIGH); bluetoothChat.send("Blue LED activated"); } else if (cmd == "OFF") { digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, LOW); digitalWrite(BLUE_PIN, LOW); bluetoothChat.send("All LEDs off"); } else if (cmd == "HELP") { bluetoothChat.send("Commands: LED ON, LED OFF, RED, GREEN, BLUE, OFF, HELP"); } else { bluetoothChat.send("Unknown command. Type HELP for list."); } }); }

Hệ Thống Truy Vấn Cảm Biến

#include <DHT.h> DHT dht(4, DHT22); void setup() { dht.begin(); bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "TEMP") { float temp = dht.readTemperature(); if (!isnan(temp)) { bluetoothChat.send("Temperature: " + String(temp, 1) + " °C"); } else { bluetoothChat.send("Error reading temperature sensor"); } } else if (cmd == "HUMIDITY") { float hum = dht.readHumidity(); if (!isnan(hum)) { bluetoothChat.send("Humidity: " + String(hum, 1) + " %"); } else { bluetoothChat.send("Error reading humidity sensor"); } } else if (cmd == "ALL") { float temp = dht.readTemperature(); float hum = dht.readHumidity(); bluetoothChat.send("Temp: " + String(temp, 1) + "°C | Humidity: " + String(hum, 1) + "%"); } else if (cmd == "HELP") { bluetoothChat.send("Commands: TEMP, HUMIDITY, ALL, HELP"); } }); }

Điều Khiển Relay Với Xác Nhận

const int RELAY_1 = 16; const int RELAY_2 = 17; bool relay1State = false; bool relay2State = false; void setup() { pinMode(RELAY_1, OUTPUT); pinMode(RELAY_2, OUTPUT); digitalWrite(RELAY_1, LOW); digitalWrite(RELAY_2, LOW); bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "R1 ON") { digitalWrite(RELAY_1, HIGH); relay1State = true; bluetoothChat.send("Relay 1: ON"); } else if (cmd == "R1 OFF") { digitalWrite(RELAY_1, LOW); relay1State = false; bluetoothChat.send("Relay 1: OFF"); } else if (cmd == "R2 ON") { digitalWrite(RELAY_2, HIGH); relay2State = true; bluetoothChat.send("Relay 2: ON"); } else if (cmd == "R2 OFF") { digitalWrite(RELAY_2, LOW); relay2State = false; bluetoothChat.send("Relay 2: OFF"); } else if (cmd == "STATUS") { bluetoothChat.send("Relay 1: " + String(relay1State ? "ON" : "OFF")); bluetoothChat.send("Relay 2: " + String(relay2State ? "ON" : "OFF")); } else if (cmd == "HELP") { bluetoothChat.send("Commands: R1 ON, R1 OFF, R2 ON, R2 OFF, STATUS, HELP"); } }); }

Kỹ Thuật Lập Trình Nâng Cao

Cập Nhật Trạng Thái Định Kỳ

unsigned long lastMessageTime = 0; const unsigned long MESSAGE_INTERVAL = 10000; // 10 giây void loop() { bluetoothServer.loop(); // Gửi cập nhật trạng thái định kỳ (chỉ khi có kết nối) if (bluetooth.isConnected() && millis() - lastMessageTime >= MESSAGE_INTERVAL) { lastMessageTime = millis(); messageCount++; String statusMsg = "Status update #" + String(messageCount); statusMsg += " - Uptime: " + String(millis() / 1000) + "s"; statusMsg += " - Heap: " + String(ESP.getFreeHeap()) + " bytes"; bluetoothChat.send(statusMsg); } delay(10); }

Ghi Log Tin Nhắn

// Ghi log tất cả tin nhắn vào Serial với timestamp bluetoothChat.onChatMessage([](const String& message) { unsigned long timestamp = millis() / 1000; Serial.print("["); Serial.print(timestamp); Serial.print("s] Received: "); Serial.println(message); // Xử lý và phản hồi String response = processCommand(message); bluetoothChat.send(response); Serial.print("["); Serial.print(millis() / 1000); Serial.print("s] Sent: "); Serial.println(response); }); String processCommand(const String& cmd) { if (cmd.equalsIgnoreCase("ping")) return "pong!"; if (cmd.equalsIgnoreCase("status")) return "All systems operational"; if (cmd.equalsIgnoreCase("time")) return "Uptime: " + String(millis() / 1000) + "s"; return "Echo: " + cmd; }

Trình Phân Tích Lệnh Với Tham Số

bluetoothChat.onChatMessage([](const String& message) { // Phân tích lệnh và tham số (định dạng: "COMMAND ARG") int spaceIndex = message.indexOf(' '); String command, argument; if (spaceIndex > 0) { command = message.substring(0, spaceIndex); argument = message.substring(spaceIndex + 1); } else { command = message; argument = ""; } command.toUpperCase(); if (command == "PWM") { int value = argument.toInt(); value = constrain(value, 0, 255); analogWrite(16, value); bluetoothChat.send("PWM set to " + String(value)); } else if (command == "DELAY") { int ms = argument.toInt(); bluetoothChat.send("Waiting " + String(ms) + "ms..."); delay(ms); bluetoothChat.send("Done!"); } else if (command == "PIN") { // Định dạng: "PIN 13 HIGH" hoặc "PIN 13 LOW" int secondSpace = argument.indexOf(' '); if (secondSpace > 0) { int pin = argument.substring(0, secondSpace).toInt(); String state = argument.substring(secondSpace + 1); state.toUpperCase(); digitalWrite(pin, state == "HIGH" ? HIGH : LOW); bluetoothChat.send("Pin " + String(pin) + " set " + state); } } });

Ví Dụ Tích Hợp Phần Cứng

Điều Khiển Servo Qua Chat

#include <ESP32Servo.h> Servo myServo; const int SERVO_PIN = 13; void setup() { myServo.attach(SERVO_PIN); bluetoothChat.onChatMessage([](const String& message) { // Chấp nhận lệnh góc như "90" hoặc "SERVO 90" String cmd = message; cmd.toUpperCase(); int angle = -1; if (cmd.startsWith("SERVO ")) { angle = cmd.substring(6).toInt(); } else { angle = cmd.toInt(); if (angle == 0 && cmd != "0") angle = -1; // Không phải số } if (angle >= 0 && angle <= 180) { myServo.write(angle); bluetoothChat.send("Servo moved to " + String(angle) + "°"); } else if (cmd == "SWEEP") { bluetoothChat.send("Sweeping servo..."); for (int a = 0; a <= 180; a += 5) { myServo.write(a); delay(30); } for (int a = 180; a >= 0; a -= 5) { myServo.write(a); delay(30); } bluetoothChat.send("Sweep complete"); } }); }

Điều Khiển Động Cơ Qua Chat

const int MOTOR_PWM = 16; const int MOTOR_DIR1 = 18; const int MOTOR_DIR2 = 19; void setup() { pinMode(MOTOR_PWM, OUTPUT); pinMode(MOTOR_DIR1, OUTPUT); pinMode(MOTOR_DIR2, OUTPUT); bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "FORWARD") { digitalWrite(MOTOR_DIR1, HIGH); digitalWrite(MOTOR_DIR2, LOW); analogWrite(MOTOR_PWM, 200); bluetoothChat.send("Motor running forward"); } else if (cmd == "REVERSE") { digitalWrite(MOTOR_DIR1, LOW); digitalWrite(MOTOR_DIR2, HIGH); analogWrite(MOTOR_PWM, 200); bluetoothChat.send("Motor running reverse"); } else if (cmd == "STOP") { analogWrite(MOTOR_PWM, 0); bluetoothChat.send("Motor stopped"); } else if (cmd.startsWith("SPEED ")) { int speed = cmd.substring(6).toInt(); speed = constrain(speed, 0, 255); analogWrite(MOTOR_PWM, speed); bluetoothChat.send("Motor speed: " + String(speed)); } }); }

BLE vs Classic Bluetooth - Chọn Loại Nào?

Tính NăngBLE (Esp32BLE_Chat)Classic Bluetooth (Esp32Bluetooth_Chat)
Hỗ Trợ iOS✓ Có✗ Không
Hỗ Trợ Android✓ Có✓ Có
Tiêu Thụ PinThấpCao hơn
Phạm Vi~30-100m~10-100m
Tốc Độ Dữ LiệuThấp hơnCao hơn
Yêu Cầu Ghép NốiKhông (tự động kết nối)Có (ghép nối thủ công)
Tốt Nhất ChoTiết kiệm pin, đa nền tảngThông lượng cao, chỉ Android

Khắc Phục Sự Cố

Các Vấn Đề Thường Gặp

1. Không thể t