아두이노 MultipleWebApps 예제 완전한 IoT 대시보드 튜토리얼

개요

이 예제는 DIYables WebApps 라이브러리를 사용하여 여러 웹 애플리케이션을 동시에 사용하는 방법을 보여줍니다. 또한 모니터링, 제어 및 통신과 같은 여러 대화형 웹 인터페이스를 단일 프로젝트 내에서 통합하는 것을 시연합니다. Arduino Uno R4 WiFi 및 DIYables STEM V4 IoT 플랫폼용으로 설계된 이 예제는 여러 웹 기반 기능을 동시에 결합하고 관리하는 방법을 배우기에 이상적이며, 고급 IoT 프로젝트를 위한 탄탄한 기반을 제공합니다.

아두이노 다중 웹앱 예제 - 종합적인 IoT 대시보드 튜토리얼

특징

  • 홈 페이지: 모든 웹 애플리케이션에 대한 링크를 포함하는 중앙 내비게이션 허브
  • 웹 모니터: 실시간 직렬 통신 및 디버깅 인터페이스
  • 채팅 인터페이스: Arduino 응답 기능을 갖춘 대화형 채팅 시스템
  • 디지털 핀 제어: 모든 디지털 핀의 웹 기반 제어 및 모니터링
  • 듀얼 슬라이더 제어: 아날로그 값 제어를 위한 두 개의 독립 슬라이더
  • 가상 조이스틱: 방향 제어를 위한 2D 위치 제어
  • 통합 상태 관리: 모든 인터페이스가 동기화된 상태 정보를 공유
  • 실시간 업데이트: 즉시 응답을 위한 WebSocket 통신
  • 템플릿 구조: 복잡한 프로젝트를 위한 바로 맞춤화 가능한 기반
  • 플랫폼 확장성: 현재 Arduino Uno R4 WiFi에 대해 구현되었지만 다른 하드웨어 플랫폼으로 확장 가능. 참조 DIYables_WebApps_ESP32

준비물

1×아두이노 우노 R4 와이파이 쿠팡 | 아마존
1×(또는) DIYables STEM V4 IoT 쿠팡 | 아마존
1×USB 케이블 타입-A to 타입-C (USB-A PC용) 쿠팡 | 아마존
1×USB 케이블 타입-C to 타입-C (USB-C PC용) 아마존
1×(추천) 아두이노 우노 R4용 스크루 터미널 블록 쉴드 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 브레드보드 쉴드 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 케이스 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 전원 분배기 쿠팡 | 아마존
1×(추천) 아두이노 우노용 프로토타이핑 베이스 플레이트 & 브레드보드 키트 아마존
공개: 이 포스팅 에 제공된 일부 링크는 아마존 제휴 링크입니다. 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

빠른 단계

다음 지시를 단계별로 따라가세요.

  • 이것이 Arduino Uno R4 WiFi/DIYables STEM V4 IoT를 처음 사용하는 경우, Arduino IDE에서 Arduino Uno R4 WiFi/DIYables STEM V4 IoT를 위한 환경 설정 방법에 대한 튜토리얼을 참조하십시오 아두이노 우노 R4 - 소프트웨어 설치.
  • Arduino Uno R4/DIYables STEM V4 IoT 보드를 USB 케이블로 컴퓨터에 연결합니다.
  • 컴퓨터에서 Arduino IDE를 시작합니다.
  • 적절한 Arduino Uno R4 보드(예: Arduino Uno R4 WiFi) 및 COM 포트를 선택합니다.
  • Arduino IDE 왼쪽 바의 Libraries 아이콘으로 이동합니다.
  • "DIYables WebApps"를 검색한 다음 DIYables에서 제작한 DIYables WebApps 라이브러리를 찾습니다.
  • 라이브러리를 설치하려면 Install 버튼을 클릭합니다.
아두이노 우노 R4 diyables 웹앱 라이브러리
  • 다른 라이브러리 의존성 설치를 요청받게 됩니다.
  • 모든 라이브러리 의존성을 설치하려면 Install All 버튼을 클릭하세요.
아두이노 우노 R4 diyables webapps 의존성
  • Arduino IDE에서, File 예제 DIYables WebApps MultipleWebApps 예제로 이동하거나 위 코드를 복사하여 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: Arduino Uno R4 WiFi or DIYables STEM V4 IoT * * 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 <DIYablesWebApps.h> // WiFi credentials - UPDATE THESE WITH YOUR NETWORK const char WIFI_SSID[] = "YOUR_WIFI_SSID"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD"; // Create WebApp server and page instances UnoR4ServerFactory factory; DIYablesWebAppServer webAppsServer(factory, 80, 81); DIYablesHomePage homePage; DIYablesWebMonitorPage webMonitorPage; DIYablesWebSliderPage webSliderPage; DIYablesWebJoystickPage webJoystickPage(false, 5); // autoReturn=false, sensitivity=5 DIYablesWebRotatorPage webRotatorPage(ROTATOR_MODE_CONTINUOUS); // Continuous rotation mode (0-360°) DIYablesWebAnalogGaugePage webAnalogGaugePage(0.0, 100.0, "%"); // Range: 0-100%, units: % DIYablesWebTablePage webTablePage; // Variables to track states int 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) void setup() { Serial.begin(9600); delay(1000); // TODO: Initialize your hardware pins here Serial.println("DIYables WebApp - Multiple Apps Example"); // Add all web applications to the server webAppsServer.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 server if (!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 concatenation Serial.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) + "%"); }); } void loop() { // Handle WebApp server communications webAppsServer.loop(); // Update table with current uptime every 5 seconds static unsigned long lastUptimeUpdate = 0; if (millis() - lastUptimeUpdate > 5000) { lastUptimeUpdate = millis(); unsigned long 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 seconds static unsigned long lastSensorUpdate = 0; if (millis() - lastSensorUpdate > 3000) { lastSensorUpdate = millis(); // Simulate a sensor reading that varies over time float 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 here delay(10); }
  • 다음 줄들을 업데이트하여 코드에서 WiFi 자격 증명을 구성하십시오:
const char WIFI_SSID[] = "YOUR_WIFI_NETWORK"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";
  • Arduino IDE에서 Arduino UNO R4/DIYables STEM V4 IoT에 코드를 업로드하려면 Upload 버튼을 클릭하세요.
  • 시리얼 모니터를 엽니다.
  • 시리얼 모니터에서 결과를 확인하세요. 아래와 같이 보일 것입니다.
COM6
Send
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: 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/ 📊 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 ==========================================
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • 아무 것도 보이지 않는 경우 Arduino 보드를 재부팅하십시오.
  • 표시된 IP 주소를 메모하고, 이 주소를 스마트폰이나 PC의 웹 브라우저의 주소 표시줄에 입력하십시오.
  • 예: http://192.168.0.2
  • 아래 그림과 같이 모든 웹 애플리케이션이 포함된 홈 페이지가 표시됩니다.
다수의 웹앱이 탑재된 아두이노 우노 R4 diyables 웹앱 홈페이지
  • 어떤 웹 애플리케이션 링크(Chat, Web Monitor, Web Digital Pins, Web Slider, Web Joystick 등)를 클릭하면 해당 웹 애플리케이션의 UI가 표시됩니다.
  • 또는 IP 주소 뒤에 앱 경로를 따라 각 페이지에 직접 접근할 수도 있습니다. 예를 들어: http://192.168.0.2/chat, http://192.168.0.2/web-monitor 등.
  • 모든 웹 애플리케이션을 탐색해 보세요: Arduino와 채팅하고, 시리얼 출력 모니터링, 디지털 핀 제어, 슬라이더 조정, 그리고 가상 조이스틱을 사용해 통합 웹 인터페이스의 전체 기능을 체험해 보세요.

웹 인터페이스 탐색

홈 페이지 대시보드

홈 페이지는 모든 애플리케이션에 대한 링크를 포함한 제어 센터 역할을 합니다:

  • 웹 모니터: /webmonitor - 시리얼 통신 인터페이스
  • 채팅: /chat - Arduino와의 대화형 메시지
  • 디지털 핀: /digital-pins - 핀 제어 및 모니터링
  • 웹 슬라이더: /webslider - 이중 아날로그 제어 슬라이더
  • 웹 조이스틱: /webjoystick - 2D 위치 제어 인터페이스

애플리케이션 URL들

각 인터페이스에 직접 접근:

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

창의적인 맞춤화 - 당신의 혁신을 발휘하세요

이 포괄적인 예제는 창의적인 프로젝트의 토대를 제공합니다. 아래 구성을 수정하고 조정하여 고유한 비전에 부합하는 놀라운 IoT 애플리케이션을 구축하세요.

디지털 핀 구성

이 예제는 다양한 용도에 맞춰 특정 핀들을 미리 구성합니다:

출력 핀 (웹에서 제어 가능)

webDigitalPinsPage.enablePin(2, WEB_PIN_OUTPUT); // General purpose output webDigitalPinsPage.enablePin(3, WEB_PIN_OUTPUT); // General purpose output webDigitalPinsPage.enablePin(4, WEB_PIN_OUTPUT); // General purpose output webDigitalPinsPage.enablePin(13, WEB_PIN_OUTPUT); // Built-in LED

입력 핀들 (웹으로 모니터링)

webDigitalPinsPage.enablePin(8, WEB_PIN_INPUT); // Sensor input webDigitalPinsPage.enablePin(9, WEB_PIN_INPUT); // Switch input

조이스틱 구성

// 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);

상태 변수

예제는 모든 인터페이스에 걸쳐 동기화된 상태를 유지합니다:

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)

내장 채팅 명령

채팅 인터페이스에는 미리 프로그래밍된 여러 명령어가 포함되어 있습니다:

기본 명령어

  • hello - 친근한 인사에 대한 응답
  • time - Arduino의 가동 시간을 초 단위로 표시합니다
  • status - Arduino의 상태와 LED 상태를 보고합니다
  • help - 사용 가능한 명령어를 나열합니다

제어 명령

  • LED 켜기 - 내장 LED를 켭니다
  • LED 끄기 - 내장 LED를 끕니다

예시 채팅 세션

User: hello Arduino: Hello! I'm your Arduino. How can I help you? User: led on Arduino: Built-in LED is now ON! User: time Arduino: I've been running for 1245 seconds. User: status Arduino: Status: Running smoothly! LED is ON

프로그래밍 통합 예제

완전한 로봇 제어 시스템

#include <Servo.h> // Hardware definitions const int MOTOR_LEFT_PWM = 9; const int MOTOR_RIGHT_PWM = 10; const int SERVO_PAN = 11; const int SERVO_TILT = 12; const int LED_STRIP_PIN = 6; Servo panServo, tiltServo; void setup() { // Initialize hardware panServo.attach(SERVO_PAN); tiltServo.attach(SERVO_TILT); pinMode(MOTOR_LEFT_PWM, OUTPUT); pinMode(MOTOR_RIGHT_PWM, OUTPUT); // ... WebApp setup code ... setupRobotCallbacks(); } void setupRobotCallbacks() { // Use joystick for robot movement webJoystickPage.onJoystickValueFromWeb([](int x, int y) { // Convert joystick to tank drive int leftSpeed = y + (x / 2); int rightSpeed = y - (x / 2); leftSpeed = constrain(leftSpeed, -100, 100); rightSpeed = constrain(rightSpeed, -100, 100); // Apply speed limits from sliders leftSpeed = map(leftSpeed, -100, 100, -currentSlider1, currentSlider1); rightSpeed = map(rightSpeed, -100, 100, -currentSlider1, currentSlider1); // Control motors analogWrite(MOTOR_LEFT_PWM, abs(leftSpeed)); analogWrite(MOTOR_RIGHT_PWM, abs(rightSpeed)); Serial.println("Robot - Left: " + String(leftSpeed) + ", Right: " + String(rightSpeed)); }); // Use sliders for camera pan/tilt control webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Slider 1 controls maximum speed, Slider 2 controls camera tilt int panAngle = map(currentJoystickX, -100, 100, 0, 180); int tiltAngle = map(slider2, 0, 255, 0, 180); panServo.write(panAngle); tiltServo.write(tiltAngle); Serial.println("Camera - Pan: " + String(panAngle) + "°, Tilt: " + String(tiltAngle) + "°"); }); // Use digital pins for special functions webDigitalPinsPage.onPinWrite([](int pin, int state) { switch (pin) { case 2: // Headlights digitalWrite(pin, state); Serial.println("Headlights " + String(state ? "ON" : "OFF")); break; case 3: // Horn/Buzzer if (state) { // Trigger buzzer sequence digitalWrite(pin, HIGH); delay(200); digitalWrite(pin, LOW); } break; case 4: // Emergency stop if (state) { analogWrite(MOTOR_LEFT_PWM, 0); analogWrite(MOTOR_RIGHT_PWM, 0); Serial.println("EMERGENCY STOP ACTIVATED"); } break; } }); // Enhanced chat commands for robot control chatPage.onChatMessage([](const String& message) { String msg = message; msg.toLowerCase(); if (msg.indexOf("stop") >= 0) { analogWrite(MOTOR_LEFT_PWM, 0); analogWrite(MOTOR_RIGHT_PWM, 0); chatPage.sendToChat("Robot stopped!"); return; } if (msg.indexOf("center camera") >= 0) { panServo.write(90); tiltServo.write(90); chatPage.sendToChat("Camera centered!"); return; } if (msg.indexOf("speed") >= 0) { String response = "Current max speed: " + String(map(currentSlider1, 0, 255, 0, 100)) + "%"; chatPage.sendToChat(response); return; } // Default response for unknown commands chatPage.sendToChat("Robot commands: stop, center camera, speed"); }); }

스마트 홈 제어 시스템

// Home automation pin assignments const int LIVING_ROOM_LIGHTS = 2; const int BEDROOM_LIGHTS = 3; const int KITCHEN_LIGHTS = 4; const int FAN_CONTROL = 9; const int AC_CONTROL = 10; const int MOTION_SENSOR = 8; const int DOOR_SENSOR = 9; void setupHomeAutomation() { // Configure home automation pins pinMode(LIVING_ROOM_LIGHTS, OUTPUT); pinMode(BEDROOM_LIGHTS, OUTPUT); pinMode(KITCHEN_LIGHTS, OUTPUT); pinMode(FAN_CONTROL, OUTPUT); pinMode(AC_CONTROL, OUTPUT); pinMode(MOTION_SENSOR, INPUT); pinMode(DOOR_SENSOR, INPUT_PULLUP); // Digital pins for room lighting control webDigitalPinsPage.onPinWrite([](int pin, int state) { digitalWrite(pin, state); String room; switch (pin) { case 2: room = "Living Room"; break; case 3: room = "Bedroom"; break; case 4: room = "Kitchen"; break; default: room = "Pin " + String(pin); break; } Serial.println(room + " lights " + String(state ? "ON" : "OFF")); // Send notification to chat String message = room + " lights turned " + String(state ? "ON" : "OFF"); chatPage.sendToChat(message); }); // Sliders for fan and AC control webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Slider 1 controls fan speed (0-255) analogWrite(FAN_CONTROL, slider1); // Slider 2 controls AC intensity (0-255) analogWrite(AC_CONTROL, slider2); Serial.println("Fan: " + String(map(slider1, 0, 255, 0, 100)) + "%, " + "AC: " + String(map(slider2, 0, 255, 0, 100)) + "%"); }); // Enhanced chat commands for home control chatPage.onChatMessage([](const String& message) { String msg = message; msg.toLowerCase(); if (msg.indexOf("all lights on") >= 0) { digitalWrite(LIVING_ROOM_LIGHTS, HIGH); digitalWrite(BEDROOM_LIGHTS, HIGH); digitalWrite(KITCHEN_LIGHTS, HIGH); chatPage.sendToChat("All lights turned ON!"); return; } if (msg.indexOf("all lights off") >= 0) { digitalWrite(LIVING_ROOM_LIGHTS, LOW); digitalWrite(BEDROOM_LIGHTS, LOW); digitalWrite(KITCHEN_LIGHTS, LOW); chatPage.sendToChat("All lights turned OFF!"); return; } if (msg.indexOf("temperature") >= 0) { String response = "Fan: " + String(map(currentSlider1, 0, 255, 0, 100)) + "%, " + "AC: " + String(map(currentSlider2, 0, 255, 0, 100)) + "%"; chatPage.sendToChat(response); return; } if (msg.indexOf("security") >= 0) { bool motion = digitalRead(MOTION_SENSOR); bool door = digitalRead(DOOR_SENSOR); String status = "Motion: " + String(motion ? "DETECTED" : "CLEAR") + ", Door: " + String(door ? "CLOSED" : "OPEN"); chatPage.sendToChat(status); return; } // Default home automation help chatPage.sendToChat("Home commands: all lights on/off, temperature, security"); }); } void loop() { server.loop(); // Monitor home security sensors static bool lastMotion = false; static bool lastDoor = false; bool currentMotion = digitalRead(MOTION_SENSOR); bool currentDoor = digitalRead(DOOR_SENSOR); // Send alerts for security events if (currentMotion != lastMotion) { if (currentMotion) { chatPage.sendToChat("🚨 MOTION DETECTED!"); webMonitorPage.sendToWebMonitor("Security Alert: Motion detected"); } lastMotion = currentMotion; } if (currentDoor != lastDoor) { String status = currentDoor ? "CLOSED" : "OPENED"; chatPage.sendToChat("🚪 Door " + status); webMonitorPage.sendToWebMonitor("Security: Door " + status); lastDoor = currentDoor; } delay(10); }

교육용 과학 프로젝트

// Science experiment control system const int HEATING_ELEMENT = 9; const int COOLING_FAN = 10; const int STIRRER_MOTOR = 11; const int TEMP_SENSOR_PIN = A0; const int 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 speed analogWrite(STIRRER_MOTOR, slider2); // Simple temperature control logic int currentTemp = readTemperature(); if (currentTemp < targetTemp) { analogWrite(HEATING_ELEMENT, 200); // Heat on analogWrite(COOLING_FAN, 0); // Fan off } else if (currentTemp > targetTemp + 2) { analogWrite(HEATING_ELEMENT, 0); // Heat off analogWrite(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([](const String& 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 stop analogWrite(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); } }); } int readTemperature() { // Read temperature sensor (example implementation) int sensorValue = analogRead(TEMP_SENSOR_PIN); return map(sensorValue, 0, 1023, 0, 100); // Convert to temperature } float readPH() { // Read pH sensor (example implementation) int sensorValue = analogRead(PH_SENSOR_PIN); return map(sensorValue, 0, 1023, 0, 14) / 10.0; // Convert to pH }

고급 적분 기법

상태 동기화

void synchronizeAllStates() { // Ensure all interfaces show current state webSliderPage.sendToWebSlider(currentSlider1, currentSlider2); webJoystickPage.sendToWebJoystick(currentJoystickX, currentJoystickY); // Update all pin states for (int pin = 0; pin <= 13; pin++) { if (webDigitalPinsPage.isPinEnabled(pin)) { webDigitalPinsPage.updatePinState(pin, pinStates[pin]); } } Serial.println("All interface states synchronized"); }

인터페이스 간 통신

void setupCrossInterfaceCommunication() { // Joystick position affects slider maximum values webJoystickPage.onJoystickValueFromWeb([](int x, int y) { // Calculate distance from center float distance = sqrt(x*x + y*y); // Limit slider maximum based on joystick distance if (distance > 50) { // Reduce maximum slider values when joystick is far from center int 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"); } else if (pin == 2 && state == LOW) { chatPage.sendToChat("📢 System disarmed - limited commands only"); } }); }

문제 해결

일반적인 문제

1. 일부 인터페이스가 로드되지 않음

  • Setup()에서 모든 애플리케이션이 서버에 추가되었는지 확인합니다.
  • 브라우저 콘솔에서 WebSocket 연결을 확인합니다.
  • 모든 인터페이스에 충분한 메모리가 있는지 확인합니다.

2. 인터페이스 간의 불일치를 명시합니다

  • 상태 동기화 콜백을 구현합니다.
  • 상태 추적을 위해 공유 전역 변수를 사용합니다.
  • 주요 상태 변경 후 동기화 함수들을 호출합니다.
  1. 다중 인터페이스의 성능 문제
  • 비핵심 인터페이스의 업데이트 빈도 감소
  • 활성 인터페이스를 기준으로 선별적 업데이트 구현
  • 특정 프로젝트에서 사용하지 않는 인터페이스 비활성화 검토

4. 메모리 제한

  • Serial.print(freeMemory())로 사용 가능한 RAM을 모니터링합니다
  • 메모리가 부족하면 사용하지 않는 인터페이스를 비활성화합니다
  • 메모리 사용량을 최소화하도록 콜백 함수를 최적화합니다

디버깅 전략

void debugSystemState() { Serial.println("=== System State Debug ==="); Serial.println("Free Memory: " + String(freeMemory()) + " bytes"); Serial.println("Digital Pins:"); for (int pin = 0; pin <= 13; pin++) { if (webDigitalPinsPage.isPinEnabled(pin)) { Serial.println(" Pin " + String(pin) + ": " + String(pinStates[pin] ? "HIGH" : "LOW")); } } Serial.println("Sliders: " + String(currentSlider1) + ", " + String(currentSlider2)); Serial.println("Joystick: X=" + String(currentJoystickX) + ", Y=" + String(currentJoystickY)); Serial.println("========================"); }

프로젝트 템플릿

산업 제어 템플릿

  • 기계 제어용 디지털 핀
  • 속도 및 온도 제어용 슬라이더
  • 위치 제어 시스템용 조이스틱
  • 상태 보고 및 명령용 채팅
  • 데이터 로깅용 모니터

교육용 실험실 템플릿

  • 실험 매개변수용 슬라이더
  • 장비 제어용 디지털 핀
  • 학생 상호작용용 채팅
  • 데이터 수집용 모니터
  • 실시간 센서 모니터링

홈 자동화 템플릿

  • 조명/가전 제어를 위한 디지털 핀
  • 디밍 및 기후 제어용 슬라이더
  • 입력 핀을 통한 보안 모니터링
  • 음성 명령과 유사한 채팅
  • 시스템 상태 로깅을 위한 모니터

로봇공학 개발 템플릿

  • 이동 제어용 조이스틱
  • 속도와 서보 위치를 조정하기 위한 슬라이더
  • 센서 입력용 디지털 핀들
  • 명령 인터페이스용 채팅
  • 디버깅 및 텔레메트리를 위한 모니터

성능 최적화

메모리 관리

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 }

업데이트 주기 제어

void controlUpdateFrequency() { static unsigned long lastSlowUpdate = 0; static unsigned long 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(); } }

다음 단계

MultipleWebApps 예제를 숙달한 후:

  1. 프로젝트에 맞게 맞춤화하기: 사용하지 않는 인터페이스를 제거하고 프로젝트 특화 로직을 추가하기
  2. 센서 추가: 입력 모니터링을 위한 실제 센서 데이터를 통합하기
  3. 안전 기능 구현: 비상 정지 및 안전 인터록 추가하기
  4. 맞춤 명령 만들기: 채팅 인터페이스를 프로젝트 전용 명령으로 확장하기
  5. 데이터 로깅 추가: 영구적인 데이터 저장을 위해 웹 모니터를 사용하기
  6. 모바일 최적화: 모바일 기기 사용을 테스트하고 최적화하기

지원

추가 도움이 필요하신 경우:

  • 개별 예제 문서 확인 (Chat_Example.txt, WebMonitor_Example.txt 등)
  • API 레퍼런스 문서 검토
  • DIYables 튜토리얼 방문: https://newbiely.com/tutorials/arduino-uno-r4/arduino-uno-r4-diyables-webapps
  • 아두이노 커뮤니티 포럼

이 포괄적인 예제는 거의 모든 웹으로 제어되는 Arduino 프로젝트의 토대를 제공합니다. 이 템플릿으로 시작하여 귀하의 특정 필요에 맞게 맞춤화하십시오!