아두이노 MultipleWebApps 예제 완전한 IoT 대시보드 튜토리얼
개요
이 예제는 DIYables WebApps 라이브러리를 사용하여 여러 웹 애플리케이션을 동시에 사용하는 방법을 보여줍니다. 또한 모니터링, 제어 및 통신과 같은 여러 대화형 웹 인터페이스를 단일 프로젝트 내에서 통합하는 것을 시연합니다. Arduino Uno R4 WiFi 및 DIYables STEM V4 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 버튼을 클릭합니다.

- 다른 라이브러리 의존성 설치를 요청받게 됩니다.
- 모든 라이브러리 의존성을 설치하려면 Install All 버튼을 클릭하세요.

- 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
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
Clear output
9600 baud
Newline
- 아무 것도 보이지 않는 경우 Arduino 보드를 재부팅하십시오.
- 표시된 IP 주소를 메모하고, 이 주소를 스마트폰이나 PC의 웹 브라우저의 주소 표시줄에 입력하십시오.
- 예: http://192.168.0.2
- 아래 그림과 같이 모든 웹 애플리케이션이 포함된 홈 페이지가 표시됩니다.

- 어떤 웹 애플리케이션 링크(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. 인터페이스 간의 불일치를 명시합니다
- 상태 동기화 콜백을 구현합니다.
- 상태 추적을 위해 공유 전역 변수를 사용합니다.
- 주요 상태 변경 후 동기화 함수들을 호출합니다.
- 다중 인터페이스의 성능 문제
- 비핵심 인터페이스의 업데이트 빈도 감소
- 활성 인터페이스를 기준으로 선별적 업데이트 구현
- 특정 프로젝트에서 사용하지 않는 인터페이스 비활성화 검토
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 예제를 숙달한 후:
- 프로젝트에 맞게 맞춤화하기: 사용하지 않는 인터페이스를 제거하고 프로젝트 특화 로직을 추가하기
- 센서 추가: 입력 모니터링을 위한 실제 센서 데이터를 통합하기
- 안전 기능 구현: 비상 정지 및 안전 인터록 추가하기
- 맞춤 명령 만들기: 채팅 인터페이스를 프로젝트 전용 명령으로 확장하기
- 데이터 로깅 추가: 영구적인 데이터 저장을 위해 웹 모니터를 사용하기
- 모바일 최적화: 모바일 기기 사용을 테스트하고 최적화하기
지원
추가 도움이 필요하신 경우:
- 개별 예제 문서 확인 (Chat_Example.txt, WebMonitor_Example.txt 등)
- API 레퍼런스 문서 검토
- DIYables 튜토리얼 방문: https://newbiely.com/tutorials/arduino-uno-r4/arduino-uno-r4-diyables-webapps
- 아두이노 커뮤니티 포럼
이 포괄적인 예제는 거의 모든 웹으로 제어되는 Arduino 프로젝트의 토대를 제공합니다. 이 템플릿으로 시작하여 귀하의 특정 필요에 맞게 맞춤화하십시오!