고급⏱ 예상 시간: 60분📝 7단계
ESP32 스마트 조명
ESP32 웹서버로 네오픽셀 LED의 색상, 밝기, 패턴을 스마트폰에서 원격 제어하는 스마트 조명을 만듭니다.
🧩 필요한 모듈
브레드보드
ESP32
점퍼 와이어
네오픽셀 LED 스트립 (WS2812B)
저항 (220Ω / 10kΩ)
📖 단계별 설명서
1단계준비물 확인
다음 부품들을 준비해주세요:
- ESP32 보드 1개
- 브레드보드 1개
- 점퍼 와이어 5개
- 네오픽셀 LED 스트립 (WS2812B) 1개 (8개 이상 권장)
- 470Ω 저항 1개 (데이터 핀 보호용)
💡 팁: 네오픽셀 LED가 많을수록 전력 소모가 큽니다. 8개 이하라면 ESP32의 5V로 충분하지만, 그 이상이면 외부 전원을 사용하세요.
2단계회로 연결하기
- 네오픽셀 데이터 핀을 470Ω 저항을 통해 ESP32 GPIO 5에 연결합니다.
- 네오픽셀 VCC를 5V에, GND를 GND에 연결합니다.
- ESP32와 네오픽셀의 GND를 반드시 공유합니다.
📐 회로도
회로도 이미지
/images/projects/esp32-smart-light-circuit.png
3단계라이브러리 설치
아두이노 IDE에서:
- 보드 매니저에서
ESP32보드를 설치합니다. - 라이브러리 관리에서
Adafruit NeoPixel을 설치합니다.
4단계코드 작성하기
code.ino
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_NeoPixel.h>
#define LED_PIN 5
#define LED_COUNT 8
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
WebServer server(80);
int r = 255, g = 100, b = 0;
int brightness = 128;
int pattern = 0; // 0: solid, 1: rainbow, 2: breathe
const char HTML[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Smart Light</title>
<style>
body{font-family:sans-serif;text-align:center;padding:20px;background:#1a1a2e;color:#fff}
h1{color:#e94560}
.slider{width:80%;margin:10px auto}
input[type=range]{width:100%;accent-color:#e94560}
.btn{padding:12px 24px;margin:5px;border:none;border-radius:8px;font-size:16px;cursor:pointer}
.btn-pattern{background:#0f3460;color:#fff}
.btn-pattern.active{background:#e94560}
label{display:block;margin-top:15px;font-size:14px}
</style>
</head>
<body>
<h1>Smart Light</h1>
<div id="preview" style="width:100px;height:100px;border-radius:50%;margin:10px auto;border:3px solid #333"></div>
<label>R: <span id="rv">255</span></label>
<div class="slider"><input type="range" id="r" min="0" max="255" value="255" oninput="update()"></div>
<label>G: <span id="gv">100</span></label>
<div class="slider"><input type="range" id="g" min="0" max="255" value="100" oninput="update()"></div>
<label>B: <span id="bv">0</span></label>
<div class="slider"><input type="range" id="b" min="0" max="255" value="0" oninput="update()"></div>
<label>Brightness: <span id="brv">128</span></label>
<div class="slider"><input type="range" id="br" min="0" max="255" value="128" oninput="update()"></div>
<div style="margin-top:15px">
<button class="btn btn-pattern active" onclick="setPattern(0)">Solid</button>
<button class="btn btn-pattern" onclick="setPattern(1)">Rainbow</button>
<button class="btn btn-pattern" onclick="setPattern(2)">Breathe</button>
</div>
<script>
function update(){
var rv=document.getElementById('r').value;
var gv=document.getElementById('g').value;
var bv=document.getElementById('b').value;
var br=document.getElementById('br').value;
document.getElementById('rv').innerText=rv;
document.getElementById('gv').innerText=gv;
document.getElementById('bv').innerText=bv;
document.getElementById('brv').innerText=br;
document.getElementById('preview').style.background='rgb('+rv+','+gv+','+bv+')';
fetch('/set?r='+rv+'&g='+gv+'&b='+bv+'&br='+br);
}
function setPattern(p){
fetch('/pattern?p='+p);
document.querySelectorAll('.btn-pattern').forEach((b,i)=>b.classList.toggle('active',i==p));
}
update();
</script>
</body>
</html>
)rawliteral";
void handleRoot() {
server.send(200, "text/html", HTML);
}
void handleSet() {
r = server.arg("r").toInt();
g = server.arg("g").toInt();
b = server.arg("b").toInt();
brightness = server.arg("br").toInt();
pattern = 0;
server.send(200, "text/plain", "OK");
}
void handlePattern() {
pattern = server.arg("p").toInt();
server.send(200, "text/plain", "OK");
}
void setup() {
Serial.begin(115200);
strip.begin();
strip.setBrightness(brightness);
strip.show();
WiFi.begin(ssid, password);
Serial.print("Connecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("IP: ");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.on("/set", handleSet);
server.on("/pattern", handlePattern);
server.begin();
}
void loop() {
server.handleClient();
strip.setBrightness(brightness);
if (pattern == 0) {
// Solid color
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
} else if (pattern == 1) {
// Rainbow
static uint16_t hue = 0;
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.gamma32(
strip.ColorHSV(hue + (i * 65536L / LED_COUNT))));
}
hue += 256;
} else if (pattern == 2) {
// Breathe
static int breathVal = 0;
static int breathDir = 5;
breathVal += breathDir;
if (breathVal >= 255 || breathVal <= 0) breathDir = -breathDir;
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.Color(
r * breathVal / 255,
g * breathVal / 255,
b * breathVal / 255));
}
}
strip.show();
delay(20);
}+129 줄 더 보기
5단계Wi-Fi 설정 변경
코드에서 YOUR_WIFI_SSID와 YOUR_WIFI_PASSWORD를 실제 Wi-Fi 정보로 변경합니다.
6단계업로드 및 테스트
- ESP32 보드를 선택하고 코드를 업로드합니다.
- 시리얼 모니터를 열어 ESP32가 받은 IP 주소를 확인합니다.
- 같은 Wi-Fi에 연결된 스마트폰 브라우저에서 해당 IP를 입력합니다.
- 슬라이더로 색상과 밝기를 조절하고, 패턴 버튼으로 효과를 변경합니다.
💡 팁: IP 주소를 매번 확인하기 번거롭다면 mDNS를 설정하여 http://smartlight.local로 접속할 수도 있습니다.
7단계심화 — 시간 기반 자동 모드
NTP 시간 동기화를 추가하면 시간대별로 자동으로 색상과 밝기가 변하는 기능을 구현할 수 있습니다.