Ví dụ này cho thấy cách sử dụng nhiều ứng dụng web cùng lúc với thư viện DIYables ESP32 WebApps. Nó trình diễn sự tích hợp của nhiều giao diện web tương tác—như giám sát, điều khiển và liên lạc—trong một dự án duy nhất. Được thiết kế cho nền tảng ESP32, ví dụ này lý tưởng cho việc học cách kết hợp và quản lý nhiều tính năng dựa trên web cùng lúc, cung cấp nền tảng vững chắc cho các dự án IoT tiên tiến.
Tính năng
Trang chủ: Trung tâm điều hướng tập trung với liên kết tới tất cả các ứng dụng web
Giám sát Web: Giao diện giao tiếp nối tiếp thời gian thực và gỡ lỗi
Giao diện trò chuyện: Hệ thống trò chuyện tương tác với khả năng phản hồi từ ESP32
Điều khiển chân số: Điều khiển và giám sát tất cả các chân số thông qua web
Điều khiển hai thanh trượt: Hai thanh trượt độc lập để điều khiển giá trị tương tự
Joystick ảo: Điều khiển vị trí 2D cho các ứng dụng định hướng
Quản lý trạng thái thống nhất: Tất cả các giao diện chia sẻ thông tin trạng thái được đồng bộ
Cập nhật thời gian thực: Giao tiếp WebSocket để phản hồi tức thì
Cấu trúc mẫu: Nền tảng sẵn sàng tùy chỉnh cho các dự án phức tạp
Chọn bo mạch ESP32 phù hợp (ví dụ ESP32 Dev Module) và cổng COM.
Điều hướng tới biểu tượng Thư viện ở thanh bên trái của Arduino IDE.
Tìm kiếm "DIYables ESP32 WebApps", sau đó tìm thư viện DIYables ESP32 WebApps do DIYables
Nhấp vào nút Cài đặt để cài đặt thư viện.
Bạn sẽ được yêu cầu cài đặt một số phụ thuộc thư viện khác.
Nhấn Cài đặt tất cả để cài đặt tất cả các phụ thuộc thư viện.
Trên Arduino IDE, hãy vào Tệp Ví dụ DIYables ESP32 WebApps MultipleWebApps ví dụ, hoặc sao chép mã ở trên và dán nó vào trình soạn thảo của Arduino IDE
/* * DIYables WebApp Library - Multiple WebApps Example * * This example demonstrates multiple web apps of the DIYables WebApp library: * - Home page with links to multiple web apps * - Web Monitor: Real-time serial monitoring via WebSocket * - Web Slider: Dual slider control * - Web Joystick: Interactive joystick control * - Web Rotator: Interactive rotatable disc control * - Web Analog Gauge: Professional circular gauge for sensor monitoring * - Web Table: Two-column data table with real-time updates * - Web Plotter: See WebPlotter example for real-time data visualization * * Features: * - Simplified callback system - no manual command parsing needed * - Automatic state synchronization and JSON handling * - All protocol details handled by the library * - Template for hardware control * * Hardware: ESP32 Boards * * Setup: * 1. Update WiFi credentials below * 2. Upload the sketch to your Arduino * 3. Open Serial Monitor to see the IP address * 4. Navigate to the IP address in your web browser */#include <DIYables_ESP32_Platform.h>#include <DIYablesWebApps.h>// WiFi credentials - UPDATE THESE WITH YOUR NETWORKconstchar WIFI_SSID[] = "YOUR_WIFI_SSID";constchar WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";// Create WebApp server and page instancesESP32ServerFactory factory;DIYablesWebAppServerwebAppsServer(factory, 80, 81);DIYablesHomePage homePage;DIYablesWebMonitorPage webMonitorPage;DIYablesWebSliderPage webSliderPage;DIYablesWebJoystickPage webJoystickPage(false, 5); // autoReturn=false, sensitivity=5DIYablesWebRotatorPage webRotatorPage(ROTATOR_MODE_CONTINUOUS); // Continuous rotation mode (0-360°)DIYablesWebAnalogGaugePage webAnalogGaugePage(0.0, 100.0, "%"); // Range: 0-100%, units: %DIYablesWebTablePage webTablePage;// Variables to track statesint currentSlider1 = 64; // Slider 1 value (0-255)int currentSlider2 = 128; // Slider 2 value (0-255)int currentJoystickX = 0; // Current joystick X value (-100 to 100)int currentJoystickY = 0; // Current joystick Y value (-100 to 100)int currentRotatorAngle = 0; // Current rotator angle (0-360°)float currentGaugeValue = 50.0; // Current gauge value (0.0-100.0)voidsetup() {Serial.begin(9600);delay(1000);// TODO: Initialize your hardware pins hereSerial.println("DIYables ESP32 WebApp - Multiple Apps Example");// Add all web applications to the serverwebAppsServer.addApp(&homePage);webAppsServer.addApp(&webMonitorPage);webAppsServer.addApp(&webSliderPage);webAppsServer.addApp(&webJoystickPage);webAppsServer.addApp(&webRotatorPage);webAppsServer.addApp(&webAnalogGaugePage);webAppsServer.addApp(&webTablePage);// Add more web apps here (e.g., WebPlotter)// Set 404 Not Found page (optional - for better user experience)webAppsServer.setNotFoundPage(DIYablesNotFoundPage());// Configure table structure (only attribute names, values will be updated dynamically) webTablePage.addRow("Arduino Status"); webTablePage.addRow("WiFi Connected"); webTablePage.addRow("Uptime"); webTablePage.addRow("Slider 1"); webTablePage.addRow("Slider 2"); webTablePage.addRow("Joystick X"); webTablePage.addRow("Joystick Y"); webTablePage.addRow("Rotator Angle"); webTablePage.addRow("Gauge Value");// Start the WebApp serverif (!webAppsServer.begin(WIFI_SSID, WIFI_PASSWORD)) {while (1) {Serial.println("Failed to start WebApp server!");delay(1000); } } setupCallbacks();}void setupCallbacks() {// Web Monitor callback - echo messages back webMonitorPage.onWebMonitorMessage([](const String& message) {Serial.println("Web Monitor: " + message); webMonitorPage.sendToWebMonitor("Arduino received: " + message); });// Web Slider callback - handle slider values webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) {// Store the received values currentSlider1 = slider1; currentSlider2 = slider2;// Print slider values (0-255) without String concatenationSerial.print("Slider 1: ");Serial.print(slider1);Serial.print(", Slider 2: ");Serial.println(slider2);// Update table with new slider values using String() conversion webTablePage.sendValueUpdate("Slider 1", String(slider1)); webTablePage.sendValueUpdate("Slider 2", String(slider2));// TODO: Add your control logic here based on slider values// Examples:// - Control PWM: analogWrite(LED_PIN, slider1);// - Control servos: servo.write(map(slider1, 0, 255, 0, 180));// - Control motor speed: analogWrite(MOTOR_PIN, slider2);// Update gauge based on slider1 value (map 0-255 to 0-100) currentGaugeValue = map(slider1, 0, 255, 0, 100); webAnalogGaugePage.sendToWebAnalogGauge(currentGaugeValue);char gaugeStr[16]; snprintf(gaugeStr, sizeof(gaugeStr), "%.1f%%", currentGaugeValue); webTablePage.sendValueUpdate("Gauge Value", String(gaugeStr)); });// Handle slider value requests webSliderPage.onSliderValueToWeb([]() { webSliderPage.sendToWebSlider(currentSlider1, currentSlider2); });// Web Joystick callback - handle joystick movement webJoystickPage.onJoystickValueFromWeb([](int x, int y) {// Store the received values currentJoystickX = x; currentJoystickY = y;// Print joystick position values (-100 to +100)Serial.print("Joystick - X: ");Serial.print(x);Serial.print(", Y: ");Serial.println(y);Serial.print(x);Serial.print(", Y: ");Serial.println(y);// Update table with new joystick values webTablePage.sendValueUpdate("Joystick X", String(x)); webTablePage.sendValueUpdate("Joystick Y", String(y));// TODO: Add your control logic here based on joystick position// Examples:// - Control motors: if (x > 50) { /* move right */ }// - Control servos: servo.write(map(y, -100, 100, 0, 180));// - Control LEDs: analogWrite(LED_PIN, map(abs(x), 0, 100, 0, 255)); });// Handle joystick values requests (when web page loads/reconnects) webJoystickPage.onJoystickValueToWeb([]() { webJoystickPage.sendToWebJoystick(currentJoystickX, currentJoystickY); });// Web Rotator callback - handle rotation angle changes webRotatorPage.onRotatorAngleFromWeb([](float angle) {// Store the received angle currentRotatorAngle = (int)angle;// Print rotator angle (0-360°)Serial.println("Rotator angle: " + String(angle) + "°");// Update table with new rotator angle webTablePage.sendValueUpdate("Rotator Angle", String(angle, 0) + "°");// TODO: Add your control logic here based on rotator angle// Examples:// - Control servo: servo.write(map(angle, 0, 360, 0, 180));// - Control stepper motor: stepper.moveTo(angle);// - Control directional LED strip: setLEDDirection(angle); });// Handle analog gauge value requests (when web page loads/reconnects) webAnalogGaugePage.onGaugeValueRequest([]() { webAnalogGaugePage.sendToWebAnalogGauge(currentGaugeValue); });// Handle table data requests (when web page loads/reconnects) webTablePage.onTableValueRequest([]() {// Send initial values to the table webTablePage.sendValueUpdate("Arduino Status", "Running"); webTablePage.sendValueUpdate("WiFi Connected", "Yes"); webTablePage.sendValueUpdate("Uptime", "0 seconds"); webTablePage.sendValueUpdate("Slider 1", String(currentSlider1)); webTablePage.sendValueUpdate("Slider 2", String(currentSlider2)); webTablePage.sendValueUpdate("Joystick X", String(currentJoystickX)); webTablePage.sendValueUpdate("Joystick Y", String(currentJoystickY)); webTablePage.sendValueUpdate("Rotator Angle", String(currentRotatorAngle) + "°"); webTablePage.sendValueUpdate("Gauge Value", String(currentGaugeValue, 1) + "%"); });}voidloop() {// Handle WebApp server communicationswebAppsServer.loop();// Update table with current uptime every 5 secondsstaticunsignedlong lastUptimeUpdate = 0;if (millis() - lastUptimeUpdate > 5000) { lastUptimeUpdate = millis();unsignedlong uptimeSeconds = millis() / 1000;String uptimeStr = String(uptimeSeconds) + " seconds";if (uptimeSeconds >= 60) { uptimeStr = String(uptimeSeconds / 60) + "m " + String(uptimeSeconds % 60) + "s"; } webTablePage.sendValueUpdate("Uptime", uptimeStr); }// Simulate sensor data updates every 3 secondsstaticunsignedlong lastSensorUpdate = 0;if (millis() - lastSensorUpdate > 3000) { lastSensorUpdate = millis();// Simulate a sensor reading that varies over timefloat sensorValue = 50.0 + 30.0 * sin(millis() / 10000.0); // Oscillates between 20-80 currentGaugeValue = sensorValue;// Update gauge and table webAnalogGaugePage.sendToWebAnalogGauge(currentGaugeValue); webTablePage.sendValueUpdate("Gauge Value", String(currentGaugeValue, 1) + "%"); }// TODO: Add your main application code heredelay(10);}
Cấu hình thông tin đăng nhập WiFi trong mã bằng cách cập nhật các dòng này:
Nhấp vào nút Tải lên trên Arduino IDE để tải mã lên ESP32
Mở Serial Monitor
Kiểm tra kết quả trên Serial Monitor. Nó trông như hình dưới đây
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
DIYables WebApp - Multiple Apps Example
INFO: Added app /
INFO: Added app /web-monitor
INFO: Added app /web-slider
INFO: Added app /web-joystick
INFO: Added app /web-rotator
INFO: Added app /web-gauge
INFO: Added app /web-table
DIYables WebApp Library
Platform: ESP32
Network connected!
IP address: 192.168.0.2
HTTP server started on port 80
Configuring WebSocket server callbacks...
WebSocket server started on port 81
WebSocket URL: ws://192.168.0.2:81
WebSocket server started on port 81
==========================================
DIYables WebApp Ready!
==========================================
📱 Web Interface: http://192.168.0.2
🔗 WebSocket: ws://192.168.0.2:81
📋 Available Applications:
🏠 Home Page: http://192.168.0.2/
📊 Web Monitor: http://192.168.0.2/web-monitor
🎚️ Web Slider: http://192.168.0.2/web-slider
🕹️ Web Joystick: http://192.168.0.2/web-joystick
🔄 Web Rotator: http://192.168.0.2/web-rotator
⏲️ Web Analog Gauge: http://192.168.0.2/web-gauge
📊 Web Table: http://192.168.0.2/web-table
==========================================
Ln 11, Col 1
ESP32 Dev Module on COM15
2
Nếu bạn không nhìn thấy gì, khởi động lại mạch ESP32.
Ghi chú địa chỉ IP hiển thị, và nhập địa chỉ này vào thanh địa chỉ của trình duyệt web trên điện thoại thông minh hoặc máy tính của bạn.
Ví dụ: http://192.168.0.2
Bạn sẽ thấy trang chủ với tất cả các ứng dụng web như hình bên dưới:
Nhấp vào bất kỳ liên kết ứng dụng web nào (Chat, Web Monitor, Web Digital Pins, Web Slider, Web Joystick, v.v.), bạn sẽ thấy giao diện người dùng (UI) của ứng dụng web tương ứng.
Hoặc bạn cũng có thể truy cập trực tiếp từng trang bằng địa chỉ IP kèm theo đường dẫn của ứng dụng. Ví dụ: http://192.168.0.2/chat, http://192.168.0.2/web-monitor, v.v.
Khám phá tất cả các ứng dụng web: thử trò chuyện với Arduino, theo dõi đầu ra serial, điều khiển các chân số kỹ thuật số, điều chỉnh các thanh trượt, và sử dụng joystick ảo để trải nghiệm đầy đủ các tính năng của giao diện web tích hợp.
Điều hướng giao diện Web
Bảng điều khiển trang chủ
Trang chủ đóng vai trò là trung tâm điều khiển của bạn với các liên kết đến tất cả các ứng dụng:
Giám sát Web: /webmonitor - Giao diện giao tiếp nối tiếp
Trò chuyện: /chat - Nhắn tin tương tác với Arduino
Chân số kỹ thuật số: /digital-pins - Điều khiển và giám sát các chân
Thanh trượt Web: /webslider - Hai thanh trượt điều khiển tín hiệu tương tự
Joystick Web: /webjoystick - Giao diện điều khiển vị trí 2D
Các URL của ứng dụng
Truy cập trực tiếp từng giao diện:
http://[ARDUINO_IP]/ # Home page
http://[ARDUINO_IP]/webmonitor # Serial monitor interface
http://[ARDUINO_IP]/chat # Chat interface
http://[ARDUINO_IP]/digital-pins # Pin control
http://[ARDUINO_IP]/webslider # Slider controls
http://[ARDUINO_IP]/webjoystick # Joystick control
Tùy biến sáng tạo - Khơi dậy sự đổi mới của bạn
Ví dụ toàn diện này cung cấp nền tảng cho các dự án sáng tạo của bạn. Thay đổi và điều chỉnh các cấu hình dưới đây để xây dựng các ứng dụng IoT tuyệt vời phù hợp với tầm nhìn độc đáo của bạn.
Cấu hình chân kỹ thuật số
Ví dụ này đã cấu hình trước các chân cụ thể cho các mục đích khác nhau:
Các pin đầu ra (có thể điều khiển qua Web)
webDigitalPinsPage.enablePin(2, WEB_PIN_OUTPUT); // General purpose outputwebDigitalPinsPage.enablePin(3, WEB_PIN_OUTPUT); // General purpose outputwebDigitalPinsPage.enablePin(4, WEB_PIN_OUTPUT); // General purpose outputwebDigitalPinsPage.enablePin(13, WEB_PIN_OUTPUT); // Built-in LED
// Create joystick with custom settings// autoReturn=false: Joystick stays at last position when released// sensitivity=5: Only send updates when movement > 5%DIYablesWebJoystickPage webJoystickPage(false, 5);
Các biến trạng thái
Ví dụ duy trì trạng thái đồng bộ trên tất cả các giao diện:
int pinStates[16] = { LOW }; // Track pin states (pins 0-13)int currentSlider1 = 64; // Slider 1 value (0-255) - 25%int currentSlider2 = 128; // Slider 2 value (0-255) - 50%int currentJoystickX = 0; // Joystick X value (-100 to 100)int currentJoystickY = 0; // Joystick Y value (-100 to 100)
Các lệnh trò chuyện tích hợp sẵn
Giao diện trò chuyện bao gồm một số lệnh được lập trình sẵn:
Các Lệnh Cơ Bản
hello - Phản hồi chào hỏi thân thiện
time - Hiển thị thời gian hoạt động của ESP32 tính bằng giây
status - Báo cáo trạng thái ESP32 và trạng thái đèn LED
help - Liệt kê các lệnh có sẵn
Các lệnh điều khiển
led on - Bật đèn LED tích hợp
led off - Tắt đèn LED tích hợp
Phiên trò chuyện ví dụ
User: hello
ESP32: Hello! I'm your Arduino. How can I help you?
User: led on
ESP32: Built-in LED is now ON!
User: time
ESP32: I've been running for 1245 seconds.
User: status
ESP32: Status: Running smoothly! LED is ON
// Science experiment control systemconstint HEATING_ELEMENT = 9;constint COOLING_FAN = 10;constint STIRRER_MOTOR = 11;constint TEMP_SENSOR_PIN = A0;constint PH_SENSOR_PIN = A1;void setupScienceExperiment() {// Sliders for temperature and stirring control webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) {// Slider 1 controls target temperature (mapped to heating/cooling)int targetTemp = map(slider1, 0, 255, 20, 80); // 20-80°C range// Slider 2 controls stirrer speedanalogWrite(STIRRER_MOTOR, slider2);// Simple temperature control logicint currentTemp = readTemperature();if (currentTemp < targetTemp) {analogWrite(HEATING_ELEMENT, 200); // Heat onanalogWrite(COOLING_FAN, 0); // Fan off } elseif (currentTemp > targetTemp + 2) {analogWrite(HEATING_ELEMENT, 0); // Heat offanalogWrite(COOLING_FAN, 255); // Fan on } else {analogWrite(HEATING_ELEMENT, 0); // Both off (maintain)analogWrite(COOLING_FAN, 0); }Serial.println("Target: " + String(targetTemp) + "°C, Current: " + String(currentTemp) + "°C"); });// Chat interface for experiment control and data chatPage.onChatMessage([](constString& message) {String msg = message; msg.toLowerCase();if (msg.indexOf("data") >= 0) {int temp = readTemperature();float ph = readPH();String data = "Temperature: " + String(temp) + "°C, pH: " + String(ph, 2); chatPage.sendToChat(data);return; }if (msg.indexOf("start") >= 0) {// Begin experiment sequence chatPage.sendToChat("🔬 Experiment started! Monitoring conditions...");return; }if (msg.indexOf("stop") >= 0) {// Emergency stopanalogWrite(HEATING_ELEMENT, 0);analogWrite(COOLING_FAN, 0);analogWrite(STIRRER_MOTOR, 0); chatPage.sendToChat("⚠️ Experiment stopped - all systems OFF");return; } chatPage.sendToChat("Science commands: data, start, stop"); });// Monitor for automatic data logging webMonitorPage.onWebMonitorMessage([](const String& message) {if (message == "log") {int temp = readTemperature();float ph = readPH();String logEntry = String(millis()) + "," + String(temp) + "," + String(ph, 2); webMonitorPage.sendToWebMonitor(logEntry); } });}intreadTemperature() {// Read temperature sensor (example implementation)int sensorValue = analogRead(TEMP_SENSOR_PIN);returnmap(sensorValue, 0, 1023, 0, 100); // Convert to temperature}float readPH() {// Read pH sensor (example implementation)int sensorValue = analogRead(PH_SENSOR_PIN);returnmap(sensorValue, 0, 1023, 0, 14) / 10.0; // Convert to pH}
Kỹ thuật tích phân nâng cao
Đồng bộ trạng thái
void synchronizeAllStates() {// Ensure all interfaces show current state webSliderPage.sendToWebSlider(currentSlider1, currentSlider2); webJoystickPage.sendToWebJoystick(currentJoystickX, currentJoystickY);// Update all pin statesfor (int pin = 0; pin <= 13; pin++) {if (webDigitalPinsPage.isPinEnabled(pin)) { webDigitalPinsPage.updatePinState(pin, pinStates[pin]); } }Serial.println("All interface states synchronized");}
Giao tiếp giữa các giao diện
void setupCrossInterfaceCommunication() {// Joystick position affects slider maximum values webJoystickPage.onJoystickValueFromWeb([](int x, int y) {// Calculate distance from centerfloat distance = sqrt(x*x + y*y);// Limit slider maximum based on joystick distanceif (distance > 50) {// Reduce maximum slider values when joystick is far from centerint maxValue = map(distance, 50, 100, 255, 128);// You could implement dynamic slider limiting here } });// Pin states affect available chat commands webDigitalPinsPage.onPinWrite([](int pin, int state) {if (pin == 2 && state == HIGH) { chatPage.sendToChat("📢 System armed - additional commands available"); } elseif (pin == 2 && state == LOW) { chatPage.sendToChat("📢 System disarmed - limited commands only"); } });}
Khắc phục sự cố
Các vấn đề phổ biến
1. Một số giao diện không tải được
Kiểm tra xem tất cả ứng dụng có được thêm vào máy chủ trong quá trình thiết lập không
Xác nhận kết nối WebSocket trong bảng điều khiển trình duyệt
Đảm bảo đủ bộ nhớ cho tất cả các giao diện
Nêu ra những bất nhất giữa các giao diện
Triển khai các hàm gọi lại đồng bộ trạng thái
Sử dụng các biến toàn cục dùng chung để theo dõi trạng thái
Gọi các hàm đồng bộ sau các thay đổi trạng thái lớn
3. Vấn đề hiệu suất với nhiều giao diện
Giảm tần suất cập nhật cho các giao diện không quan trọng
Triển khai cập nhật có chọn lọc dựa trên giao diện đang hoạt động
Cân nhắc vô hiệu hóa các giao diện chưa sử dụng cho các dự án cụ thể
4. Giới hạn bộ nhớ
Giám sát RAM có sẵn bằng Serial.print(freeMemory())
Vô hiệu hóa các giao diện không được sử dụng khi bộ nhớ bị giới hạn
Tối ưu hóa các hàm gọi lại để giảm thiểu bộ nhớ tiêu thụ
Các thanh trượt để điều chỉnh độ sáng và kiểm soát khí hậu.
Giám sát an ninh thông qua các chân đầu vào.
Chat cho các lệnh bằng giọng nói.
Giám sát trạng thái hệ thống và ghi log.
Mẫu Phát triển Robot
Joystick để điều khiển chuyển động
Các thanh trượt để điều chỉnh tốc độ và vị trí của servo
Các chân số cho tín hiệu từ cảm biến
Chat cho giao diện lệnh
Màn hình để gỡ lỗi và thu thập dữ liệu từ xa
Tối ưu hóa Hiệu Suất
Quản lý bộ nhớ
void optimizeMemoryUsage() {// Disable unused interfaces to save memory// server.addApp(&homePage); // Always keep home page// server.addApp(&webMonitorPage); // Keep for debugging// server.addApp(&chatPage); // Optional// server.addApp(&webDigitalPinsPage); // Based on project needs// server.addApp(&webSliderPage); // Based on project needs// server.addApp(&webJoystickPage); // Based on project needs}
Điều khiển tần suất cập nhật
void controlUpdateFrequency() {staticunsignedlong lastSlowUpdate = 0;staticunsignedlong lastFastUpdate = 0;// Fast updates for critical controls (10ms)if (millis() - lastFastUpdate > 10) {// Update joystick and emergency controls lastFastUpdate = millis(); }// Slow updates for monitoring (1000ms)if (millis() - lastSlowUpdate > 1000) {// Update sensor readings and status lastSlowUpdate = millis(); }}
Các bước tiếp theo
Sau khi làm chủ ví dụ MultipleWebApps:
Tùy chỉnh cho Dự án của bạn: Loại bỏ các giao diện không được sử dụng và thêm logic đặc thù cho dự án
Thêm cảm biến: Tích hợp các giá trị cảm biến thực tế để giám sát đầu vào
Triển khai an toàn: Thêm các công tắc dừng khẩn cấp và khóa an toàn
Tạo lệnh tùy chỉnh: Mở rộng giao diện trò chuyện bằng các lệnh tùy chỉnh cho dự án
Thêm ghi dữ liệu: Sử dụng trình giám sát web cho lưu trữ dữ liệu vĩnh viễn
Tối ưu hóa cho thiết bị di động: Kiểm tra và tối ưu hóa cho việc sử dụng trên thiết bị di động
Truy cập các hướng dẫn DIYables: https://esp32io.com/tutorials/diyables-esp32-webapps
Diễn đàn cộng đồng ESP32
Ví dụ toàn diện này cung cấp nền tảng cho hầu như bất kỳ dự án ESP32 được điều khiển qua web. Bắt đầu với mẫu này và tùy chỉnh nó cho nhu cầu cụ thể của bạn!