149_ESP32_WiFi_웹서버와_원격스마트홈제어 🌐📱

도로시와 지니가 함께하는 ESP32 내장 Wi-Fi 웹 서버 구축과 스마트폰 브라우저 원격 홈 오토메이션

  • 👧 도로시: “지니야! 블루투스는 방을 조금만 벗어나도 연결이 끊기잖아. 학교나 바깥 카페에서도 우리 집 거실 조명과 환풍기를 켜고 끌 순 없을까?”
  • 🐱 지니: “후후, 그게 바로 진짜 사물인터넷(IoT)의 세계란다! 240MHz 듀얼코어와 Wi-Fi를 품은 사물인터넷의 제왕, ESP32 를 사용하면 아두이노가 직접 웹 사이트를 열어 전 세계 어디서든 스마트폰으로 기기를 원격 제어할 수 있지!”
  • 🐶 토토: “바우! 인터넷 신호가 벽을 뚫고 씽씽 날아다닌다 멍!”

  • 🖥️ 강의 슬라이드: slides.md

1. 사물인터넷(IoT)의 심장: ESP32 마이크로컨트롤러란?

Espressif 사의 ESP32는 기존 아두이노 우노(ATmega328P)를 아득히 뛰어넘는 초고성능과 무선 인터넷을 기본 내장한 차세대 IoT 표준 칩셋입니다.

비교 항목 아두이노 우노 (UNO R3) ESP32 NodeMCU 보드
CPU 프로세서 8비트 ATmega328P (1코어) 32비트 Xtensa LX6 (듀얼코어, 2Core)
동작 클록 속도 16 MHz 240 MHz (약 15배 초고속 연산!)
플래시 메모리 / SRAM 32 KB / 2 KB 4 MB (4096KB) / 520 KB
무선 네트워크 통신 없음 (외부 모듈 필요) 2.4GHz Wi-Fi (802.11 b/g/n) + BLE 4.2 내장
동작 전압 (GPIO) 5.0 V 3.3 V (※ 5V 직결 시 파괴 주의!)

2. Wi-Fi의 두 가지 동작 모드: STA vs AP

 [ STA 모드 (Station Mode) ]                     [ AP 모드 (Access Point Mode) ]
 ESP32가 가정용 공유기(AP)에 접속하여            ESP32 자체가 무선 공유기(핫스팟)가 되어
 공유기가 할당해 준 사설 IP 주소로 통신           외부 인터넷 공유기 없이 스마트폰과 1:1 직결
   (스마트폰과 동일 와이파이 망에서 제어)           (야외, 차 안 등 인터넷 없는 곳에서 제어)

     [인터넷 공유기]                                    [ ESP32 ]
     (192.168.0.1)                               (192.168.4.1 핫스팟 생성)
       /        \                                       /         \
   [ESP32]   [스마트폰]                              [노트북]    [스마트폰]
 (192.168.0.45) (192.168.0.22)

3. 회로 결선도 (ESP32 + 릴레이 모듈 + LED)

ESP32는 3.3V 로직 레벨로 동작하므로, 릴레이 모듈의 VCC는 외부 5V 전원에, 신호선(IN)은 GPIO 23번에 연결합니다.

       [ ESP32 NodeMCU ]                   [ 5V 릴레이 모듈 / LED ]
       ────────────────────────────────────────────────────────────
       VIN (또는 외부 5V) ────────────────▶ Relay VCC (+5V)
       GND               ────────────────▶ Relay GND & LED (-)
       GPIO 23           ────────────────▶ Relay IN (조명 제어 신호선)
       GPIO 2 (내장 LED) ────────────────▶ 보드 동작 확인용 블루 LED

4. 실습 1: 공유기(Wi-Fi) 접속 및 할당 IP 확인

아두이노 IDE [보드 매니저]에서 esp32 (Espressif)를 설치하고 보드를 ESP32 Dev Module로 선택합니다.

#include <WiFi.h>

const char* ssid = "YOUR_WIFI_SSID";         // 공유기 이름
const char* password = "YOUR_WIFI_PASSWORD"; // 공유기 암호

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("
[Wi-Fi 연결 시도 중...]");
  WiFi.begin(ssid, password);

  // 공유기 연결 대기 (점 찍기)
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("
🎉 와이파이 연결 성공!");
  Serial.print("할당받은 IP 주소: http://");
  Serial.println(WiFi.localIP()); // 예: 192.168.0.45
}

void loop() {}

5. 실습 2: 내장 웹 서버 구축 및 스마트폰 반응형 원격 제어

ESP32가 자체 HTML 웹 페이지를 전송하여, 스마트폰 웹 브라우저에서 버튼을 누르면 즉시 릴레이 조명이 켜지고 꺼지는 스마트홈 서버를 완성합니다.

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80); // 80번 표준 HTTP 웹 포트 개방

const int RELAY_PIN = 23;
bool relayState = false;

// 모바일 웹 브라우저에 전송할 반응형 HTML 페이지 생성 함수
String getHTML() {
  String html = "<!DOCTYPE html><html><head><meta charset='UTF-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  html += "<title>도로시의 스마트홈</title>";
  html += "<style>body{font-family:sans-serif;text-align:center;background:#1a1a2e;color:#fff;padding-top:40px;}";
  html += ".card{background:#16213e;padding:30px;border-radius:15px;display:inline-block;box-shadow:0 8px 20px rgba(0,0,0,0.5);}";
  html += ".btn{display:inline-block;padding:15px 40px;font-size:20px;border-radius:50px;text-decoration:none;margin:20px;color:#fff;font-weight:bold;}";
  html += ".on{background:#00b4d8;} .off{background:#e63946;}";
  html += "</style></head><body><div class='card'>";
  html += "<h2>🏡 도로시 & 지니 IoT 스마트홈</h2>";
  html += "<p>현재 조명 상태: <strong>" + String(relayState ? "💡 ON (점등)" : "💤 OFF (소등)") + "</strong></p>";
  
  if (relayState) {
    html += "<a href='/toggle' class='btn off'>조명 끄기 (OFF)</a>";
  } else {
    html += "<a href='/toggle' class='btn on'>조명 켜기 (ON)</a>";
  }
  html += "</div></body></html>";
  return html;
}

// 메인 웹 페이지 접속 핸들러
void handleRoot() {
  server.send(200, "text/html", getHTML());
}

// 토글 버튼 클릭 핸들러
void handleToggle() {
  relayState = !relayState;
  digitalWrite(RELAY_PIN, relayState ? HIGH : LOW);
  server.sendHeader("Location", "/"); // 상태 변경 후 다시 메인으로 리디렉트
  server.send(303);
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("
Wi-Fi Connected!");
  Serial.print("스마트폰으로 접속할 주소: http://");
  Serial.println(WiFi.localIP());

  // URL 라우팅 등록
  server.on("/", handleRoot);
  server.on("/toggle", handleToggle);

  server.begin(); // 웹 서버 시작
  Serial.println("HTTP Web Server Started!");
}

void loop() {
  server.handleClient(); // 들어오는 스마트폰 HTTP 요청을 실시간 처리!
}

🌟 도로시와 지니의 핵심 요약 노트!

  • 👧 도로시: “스마트폰 앱을 따로 설치하지 않아도 크롬이나 사파리 웹 브라우저에서 IP 주소만 치면 예쁜 버튼이 뜨고 진짜 조명이 켜져!”
  • 🐱 지니: “ESP32 내장 WebServer가 마이크로 웹 서버가 되어 반응형 HTML을 뿌려주기 때문이란다! 이제 전 세계 사물인터넷 기기들이 대화하는 언어, ‘150_MQTT_경량IoT메시징’으로 떠나보자!”
  • 🐶 토토: “바우! 초경량 초고속 메시징 우체국이 기다린다 멍!”
서브목차