Arduino Custom WebApp Ví Dụ Hướng Dẫn Giao Diện Web Đơn Giản Cho Người Mới Bắt Đầu

Tổng Quan

Ví dụ này cung cấp một template hoàn chỉnh để tạo ứng dụng web tùy chỉnh của riêng bạn, tích hợp liền mạch với thư viện DIYables WebApps.

Arduino custom webapp example - build your own web interface tutorial

Template CustomWebApp hoàn hảo cho người mới bắt đầu muốn thêm giao diện web riêng vào hệ sinh thái DIYables WebApps! Hướng dẫn này sẽ chỉ cho bạn cách xây dựng một trang web đơn giản với trao đổi dữ liệu hai chiều thời gian thực giữa trình duyệt web và Arduino qua WebSocket có thể:

  • Gửi tin nhắn văn bản từ trình duyệt web đến Arduino ngay lập tức qua WebSocket
  • Nhận tin nhắn từ Arduino và hiển thị chúng thời gian thực trên trang web
  • Duy trì kết nối WebSocket liên tục cho việc giao tiếp không ngừng
  • Tự động kết nối lại khi mất kết nối WebSocket
  • Hoạt động trên thiết bị di động với thiết kế responsive

Được thiết kế cho Arduino Uno R4 WiFi và DIYables STEM V4 IoT - template này tích hợp hoàn hảo với các ứng dụng web DIYables hiện có và cung cấp nền tảng để xây dựng giao diện IoT tùy chỉnh của riêng bạn!

Template này cung cấp mã code tối thiểu để bạn bắt đầu. Người dùng có thể phát triển các ứng dụng web phức tạp của riêng mình bằng cách chỉnh sửa template này. Khuyến nghị có kiến thức lập trình web cơ bản (HTML, CSS, JavaScript) để tùy chỉnh giao diện web và thêm các tính năng nâng cao.

Bạn Sẽ Học Được Gì

  • Cách tạo ứng dụng web tùy chỉnh tích hợp với thư viện DIYables WebApps
  • Cách thêm trang tùy chỉnh vào hệ sinh thái ứng dụng web DIYables
  • Cách gửi tin nhắn văn bản từ trình duyệt web đến Arduino
  • Cách gửi dữ liệu từ Arduino đến trình duyệt web
  • Cách xử lý kết nối WebSocket và tự động kết nối lại
  • Cách tạo giao diện web responsive cho mobile
  • Cách sử dụng hệ thống template DIYables WebApps để phát triển nhanh

Tính Năng

  • Tích Hợp DIYables WebApps: Tích hợp liền mạch với hệ sinh thái thư viện DIYables WebApps
  • Code Template Tối Thiểu: Cung cấp nền tảng cơ bản mà bạn có thể mở rộng và tùy chỉnh
  • Phát Triển Dựa Trên Template: Điểm khởi đầu hoàn chỉnh để bạn chỉnh sửa tạo ứng dụng phức tạp
  • Nhắn Tin Văn Bản Đơn Giản: Gửi tin nhắn giữa trình duyệt web và Arduino
  • Tự Động Kết Nối Lại: Tự động kết nối lại khi mất kết nối
  • Mobile Responsive: Hoạt động hoàn hảo trên điện thoại, tablet và máy tính
  • Thân Thiện Với Người Mới: Code sạch, đơn giản dễ hiểu
  • Framework Mở Rộng: Yêu cầu kiến thức lập trình web cơ bản (HTML/CSS/JavaScript) để tùy chỉnh nâng cao
  • Nền Tảng Mở Rộng: Hiện được triển khai cho Arduino Uno R4 WiFi, nhưng có thể mở rộng cho các nền tảng phần cứng khác. Xem DIYables_WebApps_ESP32

Phần Cứng Cần Thiết

1×Arduino UNO R4 WiFi
1×Alternatively, DIYables STEM V4 IoT
1×(Tùy chọn) DIYables STEM V4 IoT
1×Cáp USB Type-C
1×(Khuyến nghị) Screw Terminal Block Shield for Arduino UNO R4
1×(Khuyến nghị) Breadboard Shield for Arduino UNO R4
1×(Khuyến nghị) Enclosure for Arduino UNO R4
1×(Khuyến nghị) Power Splitter for Arduino UNO R4
1×(Khuyến nghị) Prototyping Base Plate & Breadboard Kit for Arduino UNO

Or you can buy the following kits:

1×DIYables STEM V4 IoT Starter Kit (Arduino included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)

Cách Bắt Đầu

Bạn có thể bắt đầu xây dựng ứng dụng web tùy chỉnh cho Arduino Uno R4/DIYables STEM V4 IoT board bằng cách thực hiện các bước chính sau:

  • Chạy Template Custom App Mặc Định trên Bo Arduino
  • Kiểm Tra và Xác Minh Custom Web App Mặc Định Hoạt Động Đúng
  • Hiểu Giao Thức Giao Tiếp và Cách Hoạt Động Bên Trong
  • Chỉnh Sửa Template để Phù Hợp với Ứng Dụng Của Bạn
  • Quản Lý Nhiều Custom Web Apps - Hướng Dẫn Ngăn Ngừa Xung Đột Quan Trọng

Hãy bắt đầu từng bước một.

Chạy Template Custom App Mặc Định trên Bo Arduino

Các Bước Nhanh

  • Nếu đây là lần đầu tiên bạn sử dụng Arduino Uno R4 WiFi/DIYables STEM V4 IoT, hãy tham khảo hướng dẫn Arduino UNO R4 - Cài Đặt Phần Mềm
  • Kết nối bo Arduino Uno R4/DIYables STEM V4 IoT với máy tính bằng cáp USB
  • Khởi động Arduino IDE trên máy tính
  • Chọn bo Arduino Uno R4 phù hợp (ví dụ: Arduino Uno R4 WiFi) và cổng COM
  • Điều hướng đến biểu tượng Libraries ở thanh bên trái của Arduino IDE
  • Tìm kiếm "DIYables WebApps", sau đó tìm thư viện DIYables WebApps của DIYables
  • Nhấp nút Install để cài đặt thư viện
Arduino UNO R4 diyables webapps 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ả thư viện phụ thuộc
Arduino UNO R4 diyables webapps dependency
  • Trong Arduino IDE, đi đến File > Examples > DIYables WebApps > CustomWebApp
  • Bạn sẽ thấy 4 file tạo nên template custom web app hoàn chỉnh:
    • CustomWebApp.ino - Code Arduino chính (đây là nơi bạn thêm logic tùy chỉnh!)
    • CustomWebApp.h - File header (định nghĩa giao diện đến thư viện DIYables WebApps)
    • CustomWebApp.cpp - File triển khai (xử lý tích hợp với framework thư viện)
    • custom_page_html.h - Thiết kế trang web (tùy chỉnh giao diện web tại đây!)
  • Cấu hình WiFi bằng cách thay đổi các dòng này trong CustomWebApp.ino:
const char WIFI_SSID[] = "YOUR_WIFI_NAME"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";

Bước 5: Upload và Kiểm Tra

  • Nhấp nút Upload trên Arduino IDE để upload code lên Arduino UNO R4/DIYables STEM V4 IoT
  • Mở Serial Monitor để xem trạng thái kết nối
  • Ghi nhớ địa chỉ IP hiển thị trong Serial Monitor
  • Mở Serial Monitor
  • Kiểm tra kết quả trên Serial Monitor. Nó sẽ giống như sau:
COM6
Send
Starting Custom WebApp... INFO: Added app / INFO: Added app /custom DIYables WebApp Library Platform: Arduino Uno R4 WiFi 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/ 🔧 Custom WebApp: http://192.168.0.2/custom ==========================================
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • Nếu bạn không thấy gì, hãy khởi động lại bo Arduino.
  • Ghi nhớ đị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 smartphone hoặc PC.
  • Ví dụ: http://192.168.0.2
  • Bạn sẽ thấy trang chủ như hình dưới đây:
Arduino UNO R4 diyables webapp home page with web custom app
  • Nhấp vào link Web Custom, bạn sẽ thấy giao diện của Web Custom app như sau:
Arduino UNO R4 diyables webapp web custom app
  • Hoặc bạn cũng có thể truy cập trang trực tiếp bằng địa chỉ IP theo sau là /custom. Ví dụ: http://[IP_ADDRESS]/custom

Kiểm Tra và Xác Minh Custom Web App Mặc Định Hoạt Động Đúng

Khi bạn chạy template CustomWebApp mặc định, đây là những gì bạn sẽ thấy:

Trên Giao Diện Web:

  • Trạng thái kết nối: Hiển thị "Connected" màu xanh khi WebSocket hoạt động
  • Hộp nhập tin nhắn: Trường văn bản để gõ tin nhắn gửi đến Arduino
  • Nút Send: Nhấp để gửi tin nhắn (hoặc nhấn Enter)
  • Hiển thị tin nhắn Arduino: Hiển thị tin nhắn nhận từ Arduino bằng chữ xanh

Hoạt động của Arduino:

  • Phản hồi Echo: Khi bạn gửi "Hello" từ web, Arduino phản hồi với "Echo: Hello"
  • Cập nhật định kỳ: Arduino gửi tin nhắn uptime mỗi 5 giây: "Arduino uptime: X seconds"
  • Serial Monitor: Tất cả tin nhắn nhận được được ghi lại để debug

Kiểm tra giao tiếp:

  1. Gõ tin nhắn vào hộp nhập (ví dụ: "test message")
  2. Nhấp Send hoặc nhấn Enter
  3. Kiểm tra Serial Monitor - bạn sẽ thấy: "Received from web: test message"
  4. Kiểm tra trang web - bạn sẽ thấy: "Echo: test message"
  5. Đợi vài giây - bạn sẽ thấy tin nhắn uptime định kỳ được cập nhật mỗi 3 giây (ví dụ: "Arduino uptime: 15 seconds", "Arduino uptime: 18 seconds", v.v.)

Hiểu Giao Thức Giao Tiếp và Cách Hoạt Động Bên Trong

Hiểu cơ chế bên trong giúp bạn tùy chỉnh template một cách hiệu quả.

Hệ Thống Định Danh App

Template CustomWebApp sử dụng các thẻ tin nhắn duy nhất (gọi là "App Identifiers") giúp code Arduino và web client lọc tin nhắn thuộc về chúng. Điều này rất quan trọng vì ứng dụng của bạn có thể bao gồm nhiều web app, và mỗi app cần xử lý chỉ tin nhắn của riêng mình trong khi bỏ qua những tin nhắn khác:

Phía Arduino (CustomWebApp.h & CustomWebApp.cpp)

// Trong CustomWebApp.h class CustomWebAppPage : public DIYablesWebAppPageBase { private: // WebSocket message identifier cho custom app này static const String APP_IDENTIFIER; // ... }; // Trong CustomWebApp.cpp const String CustomWebAppPage::APP_IDENTIFIER = "CUSTOM:"; // Sử dụng trong handleWebSocketMessage: if (message.startsWith(APP_IDENTIFIER)) { String payload = message.substring(APP_IDENTIFIER.length()); // Xử lý payload sạch không có identifier } // Sử dụng trong sendToWeb: broadcastToAllClients(APP_IDENTIFIER + message);

Phía JavaScript (custom_page_html.h)

// WebSocket message identifier cho custom app này const APP_IDENTIFIER = 'CUSTOM:'; // Sử dụng khi nhận: if (event.data.startsWith(APP_IDENTIFIER)) { let message = event.data.substring(APP_IDENTIFIER.length); // Xử lý tin nhắn sạch không có identifier } // Sử dụng khi gửi: ws.send(APP_IDENTIFIER + userInput);

Lợi ích của thiết kế này:

  • Nguồn duy nhất của sự thật: Thay đổi identifier ở một nơi cho mỗi ngôn ngữ
  • Không có chuỗi ma thuật: Loại bỏ "CUSTOM:" được mã hóa cứng trong code
  • An toàn kiểu: Sử dụng hằng số ngăn ngừa lỗi gõ
  • Có thể mở rộng: Dễ dàng tạo nhiều custom app với identifier khác nhau
  • Tránh xung đột dữ liệu giữa nhiều app: Mỗi app sử dụng identifier duy nhất để ngăn ngừa can thiệp tin nhắn
  • Chuyên nghiệp: Tuân theo nguyên tắc thiết kế hướng đối tượng

Ghi chú quan trọng:

  • Bạn có thể giữ identifier hiện tại "CUSTOM:" khi chỉnh sửa template custom web app này để phù hợp với dự án của bạn. Tuy nhiên, khi bạn tạo nhiều hơn một custom app, hãy chắc chắn thay đổi nó để tránh xung đột.
  • Nếu thay đổi identifier, hãy đảm bảo rằng giá trị trong JavaScript (file .h) và code Arduino (file .cpp) giống nhau (ví dụ: cả hai đều sử dụng "TEMP:" hoặc cả hai đều sử dụng "SENSOR:").
  • Identifier được dành riêng bởi built-in apps: Những identifier sau đã được sử dụng bởi các ứng dụng built-in DIYables WebApps và nên tránh:
    • Main app identifiers: "CHAT:", "MONITOR:", "PLOTTER:", "DIGITAL_PINS:", "JOYSTICK:", "SLIDER:", "TABLE:", "RTC:", "ROTATOR:", "GAUGE:"
    • Sub-protocol identifiers: "TIME:", "DATETIME:", "JOYSTICK_CONFIG:", "PLOTTER_DATA:", "PLOTTER_CONFIG:", "SLIDER_VALUES:", "TABLE_CONFIG:", "TABLE_DATA:", "VALUE_UPDATE:", "PIN_CONFIG:", "PIN_STATES:", "PIN_UPDATE:"

    Luồng Giao Tiếp

    Từ Trang Web đến Arduino:

    Khi bạn gõ tin nhắn trên giao diện web và nhấp nút send, ví dụ: Hello, luồng sau sẽ xảy ra:

    1. JavaScript thêm identifier: JavaScript tự động thêm app identifier (là "CUSTOM:" trong template này) sử dụng hằng số APP_IDENTIFIER, sau đó gửi tin nhắn đến Arduino qua WebSocket. Tin nhắn thực tế được gửi là: CUSTOM:Hello
    2. Thư viện DIYables WebApps nhận: Thư viện nhận tin nhắn CUSTOM:Hello và chuyển nó đến method CustomWebAppPage::handleWebSocketMessage của bạn
    3. Class CustomWebAppPage loại bỏ identifier: Trong handleWebSocketMessage, class CustomWebAppPage kiểm tra xem tin nhắn có bắt đầu với APP_IDENTIFIER của nó không, loại bỏ identifier bằng .substring(APP_IDENTIFIER.length()), sau đó chuyển tin nhắn còn lại Hello bằng cách gọi callback function được triển khai trong file .ino của bạn
    4. Ứng dụng của bạn xử lý: Ứng dụng của bạn trong file .ino nhận chỉ Hello và có thể xử lý tin nhắn tùy thuộc vào logic tùy chỉnh của bạn. Template hiện tại chỉ in nó ra và gửi lại phản hồi

    Từ Arduino đến Trang Web:

    Khi Arduino của bạn muốn gửi dữ liệu đến giao diện web, ví dụ: Temperature: 25°C, luồng sau sẽ xảy ra:

    1. Ứng dụng của bạn gọi sendToWeb(): Trong file .ino của bạn, bạn gọi customPage.sendToWeb("Temperature: 25°C") để gửi dữ liệu đến trình duyệt web
    2. Class CustomWebAppPage thêm identifier và broadcast: Class CustomWebAppPage tự động thêm app identifier sử dụng hằng số APP_IDENTIFIER vào tin nhắn của bạn và broadcast CUSTOM:Temperature: 25°C đến tất cả web client đã kết nối qua WebSocket
    3. JavaScript nhận và lọc tin nhắn: Trình duyệt web nhận CUSTOM:Temperature: 25°C thông qua event handler ws.onmessage, nhưng JavaScript chỉ xử lý tin nhắn bắt đầu với APP_IDENTIFIER và loại bỏ identifier bằng .substring(APP_IDENTIFIER.length())
    4. Trang web hiển thị tin nhắn sạch: Template hiện tại hiển thị tin nhắn sạch Temperature: 25°C (không có identifier) trong phần "Message from Arduino". Bạn có thể tùy chỉnh JavaScript để phân tích và hiển thị dữ liệu theo những cách khác nhau tùy thuộc vào nhu cầu ứng dụng của bạn

    Tổng Quan Kiến Trúc

    Ví dụ CustomWebApp bao gồm bốn file chính:

    1. CustomWebApp.ino - Sketch Arduino chính với logic ứng dụng của bạn
    2. CustomWebApp.h - File header định nghĩa custom page class (giao diện thư viện)
    3. CustomWebApp.cpp - Triển khai với logic giao tiếp (code thư viện)
    4. custom_page_html.h - Giao diện HTML tách biệt để dễ tùy chỉnh

Chỉnh Sửa Template để Phù Hợp với Ứng Dụng Của Bạn

Template được thiết kế để dễ dàng tùy chỉnh theo nhu cầu cụ thể của bạn. Đây là cách để điều chỉnh nó:

1. Tích Hợp Phần Cứng

Thêm Khởi Tạo Phần Cứng

Trong hàm setup() của CustomWebApp.ino:

void setup() { Serial.begin(9600); // Thêm khởi tạo phần cứng của bạn tại đây pinMode(LED_BUILTIN, OUTPUT); // LED built-in pinMode(3, OUTPUT); // Chân đầu ra PWM pinMode(4, INPUT_PULLUP); // Chân đầu vào button với pullup pinMode(A0, INPUT); // Chân đầu vào analog sensor // Khởi tạo cảm biến, màn hình, động cơ, v.v. // servo.attach(9); // lcd.begin(16, 2); // Phần còn lại của setup... webAppsServer.addApp(&homePage); webAppsServer.addApp(&customPage); webAppsServer.begin(WIFI_SSID, WIFI_PASSWORD);

Xử Lý Lệnh Tùy Chỉnh

Mở rộng callback function để xử lý lệnh tùy chỉnh của bạn:

customPage.onCustomMessageReceived([](const String& message) { Serial.println("Received: " + message); // Điều khiển LED if (message == "led_on") { digitalWrite(LED_BUILTIN, HIGH); customPage.sendToWeb("LED turned ON"); } else if (message == "led_off") { digitalWrite(LED_BUILTIN, LOW); customPage.sendToWeb("LED turned OFF"); } // Điều khiển Servo else if (message.startsWith("servo:")) { int angle = message.substring(6).toInt(); // Lấy số sau "servo:" // servo.write(angle); customPage.sendToWeb("Servo moved to " + String(angle) + " degrees"); } // Yêu cầu đọc cảm biến else if (message == "get_temperature") { float temp = readTemperatureSensor(); // Hàm cảm biến của bạn customPage.sendToWeb("Temperature: " + String(temp) + "°C"); } // Thêm nhiều lệnh tùy chỉnh khác tại đây });

Gửi Dữ Liệu Cảm Biến Thời Gian Thực

void loop() { webAppsServer.loop(); // Gửi dữ liệu cảm biến mỗi 3 giây static unsigned long lastSend = 0; if (millis() - lastSend > 3000) { // Đọc cảm biến của bạn int lightLevel = analogRead(A0); bool buttonPressed = !digitalRead(4); // Đảo ngược do pullup float temperature = readTemperatureSensor(); // Gửi đến giao diện web customPage.sendToWeb("Light: " + String(lightLevel)); customPage.sendToWeb("Button: " + String(buttonPressed ? "Pressed" : "Released")); customPage.sendToWeb("Temp: " + String(temperature) + "°C"); lastSend = millis(); } }

2. Tùy Chỉnh Giao Diện Web

Chỉnh Sửa Bố Cục HTML

Chỉnh sửa HTML trong custom_page_html.h để thay đổi giao diện:

<!-- Thêm điều khiển mới --> <div> <h3>🔌 Điều Khiển Thiết Bị</h3> <button onclick="send('led_on')">BẬT LED</button> <button onclick="send('led_off')">TẮT LED</button> <br><br> <label>Góc Servo:</label> <input type="range" id="servoSlider" min="0" max="180" value="90" onchange="send('servo:' + this.value)"> <span id="servoValue">90°</span> </div> <div> <h3>📊 Dữ Liệu Cảm Biến</h3> <div>Nhiệt độ: <span id="tempValue">--°C</span></div> <div>Mức ánh sáng: <span id="lightValue">--</span></div> <div>Trạng thái nút: <span id="buttonValue">--</span></div> </div>

Tùy Chỉnh Xử Lý JavaScript

Cập nhật hàm ws.onmessage để xử lý các loại dữ liệu cụ thể:

ws.onmessage = function(event) { if (event.data.startsWith(APP_IDENTIFIER)) { let message = event.data.substring(APP_IDENTIFIER.length); // Hiển thị tất cả tin nhắn trong khu vực chung document.getElementById('rawMessage').textContent = message; // Xử lý các loại tin nhắn cụ thể if (message.startsWith('Temperature:')) { let temp = message.split(':')[1].trim(); document.getElementById('tempValue').textContent = temp; } else if (message.startsWith('Light:')) { let light = message.split(':')[1].trim(); document.getElementById('lightValue').textContent = light; } else if (message.startsWith('Button:')) { let button = message.split(':')[1].trim(); document.getElementById('buttonValue').textContent = button; } } };

Thêm Styling

Tùy chỉnh CSS cho ứng dụng của bạn:

<style> .control-panel { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; padding: 20px; margin: 10px 0; color: white; } .sensor-display { background: #f8f9fa; border: 2px solid #e9ecef; border-radius: 10px; padding: 15px; margin: 10px 0; } button { background: #007bff; color: white; border: none; padding: 10px 20px; border-radius: 5px; margin: 5px; cursor: pointer; } button:hover { background: #0056b3; } </style>

Other Customization

Beyond modifying the web interface and hardware integration, you can also customize how your app appears in the DIYables WebApps ecosystem:

1. Customize App Path

You can change the URL path where your custom web app is accessible by modifying the constructor in your header file:

Default Path:

// In CustomWebApp.cpp - Default path is "/custom" CustomWebAppPage::CustomWebAppPage() : DIYablesWebAppPageBase("/custom") { }

Custom Path Examples:

// Temperature monitoring app CustomWebAppPage::CustomWebAppPage() : DIYablesWebAppPageBase("/new-path") { } // Accessible at: http://[IP_ADDRESS]/new-path

Important Notes:

  • Path must start with "/": Always begin your path with a forward slash
  • Use descriptive names: Choose paths that clearly describe your app's function
  • Avoid conflicts: Don't use paths already taken by built-in apps like /chat, /monitor, /plotter, etc.
  • Use lowercase and hyphens: Follow web URL conventions for better compatibility

2. Customize App Card on Home Page

You can customize how your app appears on the DIYables WebApps home page by modifying the getNavigationInfo() method in your implementation file:

Basic App Card:

// In CustomWebApp.cpp String CustomWebAppPage::getNavigationInfo() const { return "<a href=\"" + getPagePath() + "\" class=\"app-card\">" "<h3>🔧 Custom App</h3>" "<p>My custom web application</p>" "</a>"; }

Advanced App Card with Inline CSS:

// In CustomWebApp.cpp String CustomWebAppPage::getNavigationInfo() const { return "<a href=\"" + getPagePath() + "\" class=\"app-card\" " "style=\"background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);\">" "<h3>🌡️ Temperature Monitor</h3>" "<p>Real-time temperature monitoring</p>" "</a>"; }

Manage Multiple Custom Web Apps - Essential Conflict Prevention Guide

When developing multiple custom web applications, it's crucial to avoid conflicts between different apps. Let's suppose that we want to add three custom apps named "Temperature Monitor", "Motor Controller", and "Sensor Dashboard" to our Arduino project. Here's how to ensure they work together harmoniously:

1. Use Unique App Identifiers

Each custom web app must have a unique identifier to prevent message conflicts:

Example: Temperature Monitor App

// In TemperatureApp.cpp const String TemperatureAppPage::APP_IDENTIFIER = "TEMP:"; // JavaScript in temperature_page_html.h const APP_IDENTIFIER = 'TEMP:';

Example: Motor Controller App

// In MotorApp.cpp const String MotorAppPage::APP_IDENTIFIER = "MOTOR:"; // JavaScript in motor_page_html.h const APP_IDENTIFIER = 'MOTOR:';

Example: Sensor Dashboard App

// In SensorApp.cpp const String SensorAppPage::APP_IDENTIFIER = "SENSOR:"; // JavaScript in sensor_page_html.h const APP_IDENTIFIER = 'SENSOR:';

2. Use Unique Page Paths

Each web app needs a unique URL path:

// Temperature App TemperatureAppPage::TemperatureAppPage() : DIYablesWebAppPageBase("/temperature") { } // Motor Controller App MotorAppPage::MotorAppPage() : DIYablesWebAppPageBase("/motor") { } // Sensor Dashboard App SensorAppPage::SensorAppPage() : DIYablesWebAppPageBase("/sensors") { }

3. Use Unique Class Names

Avoid naming conflicts by using descriptive class names:

// Instead of multiple "CustomWebAppPage" classes class TemperatureMonitorPage : public DIYablesWebAppPageBase { }; class MotorControllerPage : public DIYablesWebAppPageBase { }; class SensorDashboardPage : public DIYablesWebAppPageBase { };

4. Organize Multiple Apps in One Project

Here's how to structure a project with multiple custom apps:

// In main .ino file #include "TemperatureApp.h" #include "MotorApp.h" #include "SensorApp.h" // Create instances DIYablesHomePage homePage; TemperatureMonitorPage tempPage; MotorControllerPage motorPage; SensorDashboardPage sensorPage; void setup() { // Add all pages to server webAppsServer.addApp(&homePage); // pre-built app webAppsServer.addApp(&tempPage); webAppsServer.addApp(&motorPage); webAppsServer.addApp(&sensorPage); webAppsServer.begin(WIFI_SSID, WIFI_PASSWORD); // Set up callbacks for each app tempPage.onTemperatureMessageReceived([](const String& message) { // Handle temperature app messages }); motorPage.onMotorMessageReceived([](const String& message) { // Handle motor app messages }); sensorPage.onSensorMessageReceived([](const String& message) { // Handle sensor app messages }); }

5. Best Practices for Multiple Apps

File Organization
MyProject/ ├── MyProject.ino // Main sketch ├── TemperatureApp.h // Temperature app header ├── TemperatureApp.cpp // Temperature app implementation ├── temperature_page_html.h // Temperature app web page ├── MotorApp.h // Motor app header ├── MotorApp.cpp // Motor app implementation ├── motor_page_html.h // Motor app web page ├── SensorApp.h // Sensor app header ├── SensorApp.cpp // Sensor app implementation └── sensor_page_html.h // Sensor app web page

Navigation Between Apps

Update the getNavigationInfo() method in each app to provide easy navigation:

String TemperatureMonitorPage::getNavigationInfo() const { return "<a href=\"" + getPagePath() + "\" class=\"app-card temperature\">" "<h3>🌡️ Temperature Monitor</h3>" "<p>View real-time temperature data</p>" "</a>"; } String MotorControllerPage::getNavigationInfo() const { return "<a href=\"" + getPagePath() + "\" class=\"app-card motor\">" "<h3>⚙️ Motor Controller</h3>" "<p>Control servo and stepper motors</p>" "</a>"; }

6. Testing Multiple Apps

When testing multiple apps:

  1. Test each app individually first
  2. Check Serial Monitor for message conflicts
  3. Verify unique identifiers are working correctly
  4. Test navigation between different apps
  5. Monitor memory usage with multiple apps loaded

By following these guidelines, you can create multiple custom web applications that work together seamlessly without interfering with each other or with other DIYables WebApps.

Real-World Example

Want to see a complete project built using this custom web app template? Check out this color sensor project that demonstrates how to create a fully functional web application:

📱 Tutorial for Web App: Arduino Uno R4 - Color Sensor via Web

This example shows a complete implementation featuring:

  • Real-time color detection display
  • Interactive web interface for sensor readings
  • WebSocket communication for instant updates
  • Mobile-responsive design

🎥 Video Tutorial: Watch the complete build and demonstration on YouTube

This project is an excellent reference for understanding how to adapt the custom web app template for your own sensor projects!