6주차 ‐ ESP32 Web Server 실습 - boguuu/SmartDevice_2025-1 GitHub Wiki
ESP32는 내장 WiFi 기능을 통해 웹서버 기능을 구현 가능.
**STA 모드(Station 모드)**와 **AP 모드(Access Point 모드)**로 구분
- STA 모드: 기존 WiFi 네트워크에 클라이언트로 접속
- AP 모드: ESP32 자체가 WiFi 네트워크 제공 (Soft AP)
✅ 개념
- **ESP32가 Wi-Fi 클라이언트(사용자 기기)**로 동작
- 집이나 회사의 기존 Wi-Fi 공유기에 연결됨
- 연결된 상태에서 인터넷 사용 가능하거나, 다른 장치들과 네트워크 내 통신 가능
✅ 특징
- 일반 스마트폰이나 노트북처럼 기존 Wi-Fi 네트워크에 접속
- 로컬 IP 주소를 공유기로부터 할당받음
- 인터넷과 연결된 웹서버 구축 시 주로 사용
✅ 개념
- ESP32가 Wi-Fi 공유기 역할을 함
- 스마트폰, 태블릿 등 다른 기기가 ESP32에 직접 연결
✅ 특징
- 인터넷 없이도 작동 가능 (로컬 통신 전용)
- SSID 및 비밀번호 직접 설정 가능
- 연결된 장치는 ESP32에서 제공하는 페이지/서비스에 접근 가능
🔁 STA + AP 동시 모드 (혼합 모드) - ESP32는 STA + AP 모드 동시 지원도 가능
#include <WiFi.h> // WiFi 라이브러리를 포함합니다.
#include <WebServer.h> // WebServer 라이브러리를 포함합니다.
const char* ssid = "wifi-SSID"; // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password"; // Wi-Fi의 비밀번호를 입력합니다.
WebServer server(80); // 포트 번호 80을 사용하여 WebServer 객체를 생성합니다.
void handleRoot() {
server.send(200, "text/plain", "Hello from ESP32!"); // "/" 경로에 대한 요청을 처리하는 핸들러 함수입니다.
}
void setup() {
Serial.begin(115200); // 시리얼 통신을 초기화합니다.
WiFi.begin(ssid, password); // Wi-Fi에 연결합니다.
Serial.println("Connected to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
server.on("/", handleRoot); // "/" 경로에 대한 요청을 handleRoot() 함수로 처리합니다.
while (WiFi.status() != WL_CONNECTED) { // Wi-Fi 연결이 완료될 때까지 대기합니다.
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP()); // Wi-Fi의 로컬 IP 주소를 출력합니다.
server.begin(); // 서버를 시작합니다.
}
void loop() {
server.handleClient(); // 클라이언트의 요청을 처리합니다.
}
- ESP32가 지정된 Wi-Fi 네트워크에 연결
- 연결이 성공하면 로컬 IP 주소가 시리얼 모니터에 출력
- 클라이언트가 브라우저에서 ESP32의 IP 주소로 접속하면, 루트 경로(
/
) 요청이 처리되고"Hello from ESP32!"
메시지가 반환
- HTML 파일에
%STATE%
,%BUTTON%
을 사용해 LED 상태 실시간 표시 - 상태에 따라 버튼과 텍스트 자동 갱신
- Async TCP by ESP32Async
- ESP Async WebServer by Esp32Async
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char* ssid = "wifi-SSID";
const char* password = "wifi-Password";
// 현재 출력 상태를 저장하는 보조 변수
String outputState = "off";
// GPIO 핀에 출력 변수 할당
const int output = 2;
// 웹서버 생성(80)
AsyncWebServer server(80);
// HTML 코드
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta charset="utf-8"> // 한글이 깨지지 않도록 문자 인코딩
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<title>ESP 웹서버</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
p {font-size: 3.0rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
.switch {position: relative; display: inline-block; width: 120px; height: 68px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 34px}
.slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; transition: .4s; border-radius: 68px}
input:checked+.slider {background-color: #2196F3}
input:checked+.slider:before {transform: translateX(52px);}
</style>
</head>
<body>
<h2>ESP 웹서버</h2>
%BUTTONPLACEHOLDER%
<script>
function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){ xhr.open("GET", "/update?state=1", true); }
else { xhr.open("GET", "/update?state=0", true); }
xhr.send();
}
setInterval(function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var inputChecked = (this.responseText == "1");
document.getElementById("output").checked = inputChecked;
document.getElementById("outputState").innerHTML = inputChecked ? "On" : "Off";
}
};
xhttp.open("GET", "/state", true);
xhttp.send();
}, 1000);
</script>
</body>
</html>
)rawliteral";
// HTML 내 placeholder를 처리하는 함수
String processor(const String& var){
if(var == "BUTTONPLACEHOLDER"){
String checked = digitalRead(output) ? "checked" : "";
String html = "<h4>GPIO 2 - LED상태 <span id=\"outputState\">";
html += digitalRead(output) ? "On" : "Off";
html += "</span></h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"output\" ";
html += checked + "><span class=\"slider\"></span></label>";
return html;
}
return String();
}
void setup(){
Serial.begin(115200);
// 출력 변수를 출력으로 초기화
pinMode(output, OUTPUT);
// 출력을 LOW로 설정
digitalWrite(output, LOW);
// SSID와 비밀번호로 Wi-Fi 네트워크에 연결
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// 로컬 IP 주소 출력 및 웹 서버 시작
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/on/off
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("state")) {
String state = request->getParam("state")->value();
if (state == "1") {
digitalWrite(output, HIGH);
outputState = "on";
Serial.println("GPIO 2 ON");
} else {
digitalWrite(output, LOW);
outputState = "off";
Serial.println("GPIO 2 OFF");
}
}
request->send(200, "text/plain", "OK");
});
server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request){
int state = digitalRead(output);
request->send(200, "text/plain", String(state));
});
// Start server
server.begin();
}
void loop() {
}
ESP32 웹 서버를 이용해 GPIO 2번 핀을 ON/OFF 제어하는 웹 페이지를 만드는 코드
주요 기능 요약
- ESP32가 Wi-Fi에 연결되고,
- 경로에 접속하면 웹 페이지를 보여줌
- 버튼 클릭으로 GPIO 2번 핀을 ON/OFF 제어 가능 (내장 LED도 해당됨)
- 버튼 상태와 텍스트는 동적으로 바뀜
- **
WiFi.begin(ssid, password)
**를 통해 ESP 장치를 Wi-Fi 네트워크에 연결 - 연결 상태를 **
WiFi.status()
**로 확인하며, 연결이 완료되면 로컬 IP 주소를 출력
-
AsyncWebServer
객체를 생성하여 포트 80에서 동작하는 비동기 웹 서버를 설정 - 주요 라우트:
-
/
: 기본 HTML 페이지 제공. -
/update
: GPIO 상태 업데이트. -
/state
: 현재 GPIO 상태 반환.
-
- GPIO 핀 2(
output
)가 LED 또는 기타 출력 장치로 설정 - 초기화:
- **
pinMode(output, OUTPUT)
**로 출력 모드 설정. - **
digitalWrite(output, LOW)
**로 초기 상태를 꺼짐(Low)으로 설정.
- **
- 상태 변경:
-
/update
요청에서 전달된state
값에 따라 GPIO 핀을 켜거나 끔 - 상태는
outputState
변수에 저장
-
-
HTML:
- 사용자 인터페이스(UI)는 토글 스위치 형태로 구현되어 있으며, **
%BUTTONPLACEHOLDER%
**가 동적으로 대체됩니다.
- 사용자 인터페이스(UI)는 토글 스위치 형태로 구현되어 있으며, **
-
JavaScript:
-
toggleCheckbox(element)
: 사용자가 스위치를 조작할 때/update
경로로 AJAX 요청을 전송하여 GPIO 상태를 변경 -
setInterval
: 매초/state
경로로 AJAX 요청을 보내 현재 GPIO 상태를 확인하고 UI를 업데이트
-
-
processor()
함수:- HTML 템플릿 내 **
%BUTTONPLACEHOLDER%
**를 GPIO 상태에 따라 동적으로 대체 - 현재 GPIO 상태(
On
또는Off
)와 스위치의 초기 상태(checked
)를 설정
- HTML 템플릿 내 **