สร้างระบบตั้งเวลาเปิด-ปิดอุปกรณ์ด้วย ESP32 Web Server

เรียนรู้วิธีสร้างระบบควบคุมพาวเวอร์ไทเมอร์ด้วย ESP32 ที่สามารถตั้งเวลาเปิด-ปิดอุปกรณ์ไฟฟ้าผ่านหน้าเว็บ เหมาะสำหรับโปรเจกต์อัตโนมัติ ระบบรดน้ำ หรือควบคุมไฟในบ้าน

📅 12 มีนาคม 2026⏱️ เวลาอ่าน 15 นาที🎯 ระดับกลาง🛠️ ESP32, Web Server

🎯 ภาพรวมโปรเจกต์

โปรเจกต์นี้จะสอนวิธีสร้าง ระบบตั้งเวลาเปิด-ปิดอุปกรณ์ไฟฟ้า โดยใช้ ESP32 เป็นตัวควบคุม ผ่านหน้าเว็บที่ติดตั้งบนบอร์ดเอง ทำให้สามารถเข้าถึงและควบคุมได้จากอุปกรณ์ที่เชื่อมต่อ WiFi ในเครือข่ายเดียวกัน

✨ จุดเด่นของโปรเจกต์

  • • ควบคุมได้ผ่าน Web Browser ทั้งบนมือถือและคอมพิวเตอร์
  • • ตั้งเวลาเปิด-ปิดได้หลายช่วงเวลา
  • • สถานะปัจจุบันแสดงผลแบบ Real-time
  • • ใช้งานง่าย ไม่ต้องต่อ Internet
  • • ประหยัดพลังงานด้วยการควบคุม Relay

การประยุกต์ใช้งาน

  • ระบบรดน้ำอัตโนมัติ: ตั้งเวลารดน้ำตอนเช้าและเย็น
  • ควบคุมไฟในบ้าน: เปิด-ปิดไฟตามช่วงเวลาที่กำหนด
  • เครื่องใช้ไฟฟ้า: ตั้งเวลาเปิดปั๊มน้ำ, พัดลม, หรืออุปกรณ์อื่นๆ
  • ระบบแจ้งเตือน: ใช้เป็นส่วนหนึ่งของระบบอัตโนมัติภายในบ้านอัจฉริยะ

🔧 อุปกรณ์ที่ต้องใช้

Hardware Components

อุปกรณ์ รายละเอียด ประมาณการ
ESP32 DevKit บอร์ดไมโครคอนโทรลเลอร์ (มี WiFi) ฿100-150
Relay Module 5V 1-channel หรือ 2-channel ฿20-40
LED + Resistor 220Ω สำหรับทดสอบ ฿5
Breadboard + Jumper สายจัมเปอร์และบอร์ดทดลอง ฿30-50
USB Cable Micro USB สำหรับ ESP32 ฿20-30

💡 ข้อควรระวัง

  • • หากต่อกับอุปกรณ์ไฟฟ้า 220V ให้ใช้ Relay ที่รองรับกระแสสูง
  • • ต้องมีความรู้เรื่องไฟฟ้าก่อนต่อกับอุปกรณ์จริง
  • • ใช้หลอด LED ทดสอบก่อนเพื่อความปลอดภัย

⚡ วงจรการต่อใช้งาน

การเชื่อมต่อ Relay Module กับ ESP32

รายการ Pinout:

  • VCC → 3.3V หรือ 5V บน ESP32
  • GND → GND บน ESP32
  • IN1 → GPIO 26 หรือ GPIO ที่ต้องการ
  • IN2 → GPIO 27 (ถ้าใช้ Relay 2-channel)

วงจรทดสอบด้วย LED

การเชื่อมต่อ LED:

  • GPIO 26 → Resistor 220Ω → LED Anode (+)
  • LED Cathode (-) → GND

การเชื่อมต่อ Relay:

  • VCC → 5V
  • GND → GND
  • IN1 → GPIO 26

✅ หมายเหตุ

  • • Relay Module บางรุ่นต้องการกระแสสูง ให้ต่อ VCC เข้ากับ 5V โดยตรง
  • • หลีกเลี่ยงการต่ออุปกรณ์ที่ใช้กระแสสูงกว่า 10A โดยไม่มีการออกแบบวงจรเพิ่มเติม

💻 การเตรียมซอฟต์แวร์

1. ติดตั้ง Arduino IDE

ดาวน์โหลดและติดตั้ง Arduino IDE จาก arduino.cc

2. ติดตั้ง ESP32 Board

  1. เปิด Arduino IDE → File → Preferences
  2. ในช่อง "Additional Board Manager URLs" ใส่:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  1. ไปที่ Tools → Board → Boards Manager
  2. ค้นหา "ESP32" และติดตั้ง

3. เลือกบอร์ดและ Port

  • Tools → Board → ESP32 Arduino → ESP32 Dev Module
  • Tools → Port → เลือก COM port ของ ESP32

📝 โค้ดโปรแกรม

นี่คือโค้ดที่สมบูรณ์สำหรับระบบตั้งเวลาเปิด-ปิดอุปกรณ์:

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

// ==================== การตั้งค่า WiFi ====================
const char* ssid = "YOUR_WIFI_SSID";        // แก้ไขเป็น WiFi ของคุณ
const char* password = "YOUR_WIFI_PASSWORD"; // แก้ไขเป็นรหัสผ่าน WiFi

// ==================== การตั้งค่า Hardware ====================
const int RELAY_PIN = 26;  // GPIO ที่ต่อกับ Relay
const int LED_PIN = 2;     // ในบอร์ด LED (สำหรับทดสอบ)

// ==================== การตั้งค่า Web Server ====================
WebServer server(80);

// ==================== การตั้งค่า Timer ====================
struct Timer {
    int hour;
    int minute;
    bool action;  // true = เปิด, false = ปิด
    bool enabled;
};

#define MAX_TIMERS 8
Timer timers[MAX_TIMERS] = {
    {6, 0, true, true},    // เปิดเวลา 06:00
    {18, 0, false, true},  // ปิดเวลา 18:00
    {7, 30, true, false},  // Timer ที่ 3 (ปิดใช้งาน)
    {0, 0, false, false},
    {0, 0, false, false},
    {0, 0, false, false},
    {0, 0, false, false},
    {0, 0, false, false}
};

bool relayState = false;
bool manualOverride = false;
unsigned long lastCheckTime = 0;
const unsigned long CHECK_INTERVAL = 60000; // ตรวจสอบทุก 1 นาที

// ==================== ฟังก์ชันตั้งค่าเริ่มต้น ====================
void setup() {
    Serial.begin(115200);
    delay(1000);
    
    // ตั้งค่า Pin
    pinMode(RELAY_PIN, OUTPUT);
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, LOW);
    digitalWrite(LED_PIN, LOW);
    
    // เชื่อมต่อ WiFi
    Serial.println("\n\nเชื่อมต่อ WiFi...");
    WiFi.begin(ssid, password);
    
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 20) {
        delay(500);
        Serial.print(".");
        attempts++;
    }
    
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("\n✅ WiFi เชื่อมต่อสำเร็จ!");
        Serial.print("🌐 IP Address: ");
        Serial.println(WiFi.localIP());
        
        // แสดงใน Serial Monitor
        Serial.println("🔗 เปิดหน้าเว็บ: http://" + WiFi.localIP().toString());
    } else {
        Serial.println("\n❌ ไม่สามารถเชื่อมต่อ WiFi ได้");
    }
    
    // ตั้งค่า NTP Time (เวลาอินเทอร์เน็ต)
    configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
    Serial.println("⏰ กำลังตั้งเวลาจากเซิร์ฟเวอร์ NTP...");
    
    // ตั้งค่า Web Server
    setupWebServer();
    
    Serial.println("✅ พร้อมใช้งาน!");
}

// ==================== ฟังก์ชันหลัก ====================
void loop() {
    server.handleClient();
    
    // ตรวจสอบ Timer ทุก 1 นาที
    unsigned long currentTime = millis();
    if (currentTime - lastCheckTime >= CHECK_INTERVAL) {
        lastCheckTime = currentTime;
        checkTimers();
    }
    
    delay(10);
}

// ==================== ฟังก์ชันตรวจสอบ Timer ====================
void checkTimers() {
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo)) {
        Serial.println("❌ ไม่สามารถรับเวลาได้");
        return;
    }
    
    int currentHour = timeinfo.tm_hour;
    int currentMinute = timeinfo.tm_min;
    
    // ตรวจสอบทุก Timer
    for (int i = 0; i < MAX_TIMERS; i++) {
        if (timers[i].enabled && 
            timers[i].hour == currentHour && 
            timers[i].minute == currentMinute) {
            
            // ทำการเปิด/ปิด Relay
            setRelay(timers[i].action);
            Serial.printf("⏰ Timer %d: %s\n", i + 1, timers[i].action ? "เปิด" : "ปิด");
        }
    }
}

// ==================== ฟังก์ชันควบคุม Relay ====================
void setRelay(bool state) {
    relayState = state;
    digitalWrite(RELAY_PIN, state ? HIGH : LOW);
    digitalWrite(LED_PIN, state ? HIGH : LOW);
    manualOverride = true;
}

// ==================== ฟังก์ชันตั้งค่า Web Server ====================
void setupWebServer() {
    // หน้าหลัก
    server.on("/", []() {
        String html = generateWebPage();
        server.send(200, "text/html", html);
    });
    
    // API: อัปเดต Timer
    server.on("/api/timer", HTTP_POST, []() {
        if (server.hasArg("index") && server.hasArg("hour") && 
            server.hasArg("minute") && server.hasArg("action")) {
            
            int index = server.arg("index").toInt();
            timers[index].hour = server.arg("hour").toInt();
            timers[index].minute = server.arg("minute").toInt();
            timers[index].action = server.arg("action") == "1";
            timers[index].enabled = server.hasArg("enabled") ? 
                server.arg("enabled") == "1" : true;
            
            server.send(200, "application/json", "{\"status\":\"ok\"}");
        } else {
            server.send(400, "application/json", "{\"status\":\"error\"}");
        }
    });
    
    // API: เปิด/ปิด Relay แบบ Manual
    server.on("/api/relay", HTTP_POST, []() {
        bool state = server.arg("state") == "1";
        setRelay(state);
        server.send(200, "application/json", "{\"status\":\"ok\"}");
    });
    
    // API: ดึงสถานะ
    server.on("/api/status", HTTP_GET, []() {
        struct tm timeinfo;
        getLocalTime(&timeinfo);
        
        String json = "{";
        json += "\"relay\":" + String(relayState ? "true" : "false") + ",";
        json += "\"hour\":" + String(timeinfo.tm_hour) + ",";
        json += "\"minute\":" + String(timeinfo.tm_min) + ",";
        json += "\"second\":" + String(timeinfo.tm_sec) + ",";
        json += "\"timers\":[";
        
        for (int i = 0; i < MAX_TIMERS; i++) {
            if (i > 0) json += ",";
            json += "{";
            json += "\"hour\":" + String(timers[i].hour) + ",";
            json += "\"minute\":" + String(timers[i].minute) + ",";
            json += "\"action\":" + String(timers[i].action ? "true" : "false") + ",";
            json += "\"enabled\":" + String(timers[i].enabled ? "true" : "false");
            json += "}";
        }
        json += "]}";
        
        server.send(200, "application/json", json);
    });
    
    server.begin();
    Serial.println("🌐 Web Server เริ่มทำงานแล้ว");
}

// ==================== สร้างหน้าเว็บ ====================
String generateWebPage() {
    struct tm timeinfo;
    getLocalTime(&timeinfo);
    
    String html = "<!DOCTYPE html>";
    html += "<html lang='th'>";
    html += "<head>";
    html += "<meta charset='UTF-8'>";
    html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
    html += "<title>ESP32 Power Timer</title>";
    html += "<style>";
    html += "body{font-family:sarabun,sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh;margin:0;padding:20px}";
    html += ".container{max-width:800px;margin:0 auto;background:white;border-radius:20px;box-shadow:0 20px 60px rgba(0,0,0,0.3);padding:30px}";
    html += "h1{text-align:center;color:#333;margin-bottom:10px}";
    html += ".status{text-align:center;font-size:24px;margin-bottom:30px;padding:15px;border-radius:10px}";
    html += ".status.on{background:#4ade80;color:white}";
    html += ".status.off{background:#f87171;color:white}";
    html += ".time{text-align:center;font-size:18px;color:#666;margin-bottom:20px}";
    html += ".timer{background:#f9fafb;padding:15px;border-radius:10px;margin-bottom:10px;border-left:4px solid #667eea}";
    html += ".timer h3{margin:0 0 10px 0;color:#333}";
    html += ".timer-controls{display:flex;gap:10px;align-items:center}";
    html += "input[type='number']{width:60px;padding:8px;border:1px solid #ddd;border-radius:5px}";
    html += "button{padding:10px 20px;border:none;border-radius:5px;cursor:pointer;font-weight:bold;transition:all 0.3s}";
    html += ".btn-primary{background:#667eea;color:white}";
    html += ".btn-primary:hover{background:#5568d3}";
    html += ".btn-danger{background:#f87171;color:white}";
    html += ".btn-success{background:#4ade80;color:white}";
    html += ".toggle{position:relative;display:inline-block;width:50px;height:26px}";
    html += ".toggle input{opacity:0;width:0;height:0}";
    html += ".slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:.4s;border-radius:26px}";
    html += ".slider:before{position:absolute;content:'';height:20px;width:20px;left:3px;bottom:3px;background-color:white;transition:.4s;border-radius:50%}";
    html += "input:checked+.slider{background-color:#667eea}";
    html += "input:checked+.slider:before{transform:translateX(24px)}";
    html += "</style>";
    html += "</head>";
    html += "<body>";
    html += "<div class='container'>";
    html += "<h1>⏰ ระบบตั้งเวลา ESP32</h1>";
    
    // สถานะ Relay
    html += "<div class='status " + String(relayState ? "on" : "off") + "'>";
    html += relayState ? "🔌 สถานะ: เปิดอยู่" : "🔌 สถานะ: ปิดอยู่";
    html += "</div>";
    
    // เวลาปัจจุบัน
    html += "<div class='time'>";
    html += "🕐 เวลา: " + String(timeinfo.tm_hour) + ":" + 
            String(timeinfo.tm_min) + ":" + String(timeinfo.tm_sec);
    html += "</div>";
    
    // ปุ่มเปิด/ปิด Manual
    html += "<div style='text-align:center;margin-bottom:30px'>";
    html += "<button class='btn-primary' onclick='toggleRelay()'>เปิด/ปิด แบบ Manual</button>";
    html += "</div>";
    
    // รายการ Timer
    html += "<h2 style='color:#333;margin-bottom:20px'>📋 รายการ Timer</h2>";
    
    for (int i = 0; i < MAX_TIMERS; i++) {
        html += "<div class='timer'>";
        html += "<h3>Timer " + String(i + 1) + "</h3>";
        html += "<div class='timer-controls'>";
        html += "<input type='number' id='hour" + String(i) + "' value='" + 
                String(timers[i].hour) + "' min='0' max='23' placeholder='ชม.'>";
        html += "<span>:</span>";
        html += "<input type='number' id='minute" + String(i) + "' value='" + 
                String(timers[i].minute) + "' min='0' max='59' placeholder='นาที'>";
        html += "<label class='toggle'>";
        html += "<input type='checkbox' id='enabled" + String(i) + "' " + 
                String(timers[i].enabled ? "checked" : "") + " onchange='toggleTimer(" + String(i) + ")'>";
        html += "<span class='slider'></span>";
        html += "</label>";
        html += "<button class='btn-success' onclick='saveTimer(" + String(i) + ")'>บันทึก</button>";
        html += "</div>";
        html += "</div>";
    }
    
    html += "</div>";
    html += "<script>";
    html += "function toggleRelay(){";
    html += "  fetch('/api/relay', {method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: 'state=' + (relayState ? '0' : '1')}).then(()=>location.reload());";
    html += "}";
    html += "function saveTimer(index){";
    html += "  const hour = document.getElementById('hour' + index).value;";
    html += "  const minute = document.getElementById('minute' + index).value;";
    html += "  const enabled = document.getElementById('enabled' + index).checked;";
    html += "  fetch('/api/timer', {method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: 'index=' + index + '&hour=' + hour + '&minute=' + minute + '&action=1&enabled=' + (enabled ? '1' : '0')}).then(()=>location.reload());";
    html += "}";
    html += "setInterval(()=>location.reload(), 60000);"; // รีโหลดทุก 1 นาที
    html += "</script>";
    html += "</body>";
    html += "</html>";
    
    return html;
}

📌 คำอธิบายโค้ด

  • • โค้ดใช้ WebServer library สร้างหน้าเว็บแบบง่าย
  • • มีการตั้งค่า Timer ได้สูงสุด 8 ช่วงเวลา
  • • รับเวลาจาก NTP Server เพื่อความแม่นยำ
  • • หน้าเว็บมีการตกแต่งและใช้งานง่าย
  • • รองรับการควบคุม Manual ผ่านปุ่มบนหน้าเว็บ

🧪 การทดสอบระบบ

ขั้นตอนการทดสอบ

  1. อัปโหลดโค้ด: กดปุ่ม Upload ใน Arduino IDE รอจนกว่าจะขึ้น "Done uploading"
  2. เปิด Serial Monitor: กด Ctrl+Shift+M ตั้ง baud rate เป็น 115200
  3. ตรวจสอบ IP Address: ดูใน Serial Monitor จะขึ้น IP เช่น "192.168.1.100"
  4. เปิดหน้าเว็บ: พิมพ์ IP address ใน Web Browser บนมือถือหรือคอมพิวเตอร์
  5. ทดสอบ Relay: กดปุ่ม "เปิด/ปิด แบบ Manual" ควรได้ยินเสียงคลิ๊กจาก Relay
  6. ตั้งเวลา: ตั้ง Timer 1-2 ช่วงเวลา บันทึกและรอดูผล

✅ ผลลัพธ์ที่คาดหวัง

  • • เห็นหน้าเว็บสีม่วงสวยงามพร้อมปุ่มควบคุม
  • • กดปุ่ม Manual แล้ว Relay ทำงาน (LED ติด/ดับ)
  • • ตั้งเวลาแล้ว Relay เปิด/ปิดตามเวลาที่กำหนด
  • • หน้าเว็บรีโหลดอัตโนมัติทุก 1 นาที

🔧 การแก้ปัญหา

ปัญหา: ESP32 เชื่อมต่อ WiFi ไม่ได้

  • • ตรวจสอบชื่อและรหัสผ่าน WiFi ในโค้ด
  • • ลองรีเซ็ต ESP32 แล้วอัปโหลดใหม่
  • • ตรวจสอบว่า Router ไม่ได้บล็อกอุปกรณ์
  • • ลองเปลี่ยนช่องสัญญาณ WiFi (channel) เป็น 1, 6 หรือ 11

ปัญหา: Relay ไม่ทำงาน

  • • ตรวจสอบการเชื่อมต่อสาย VCC, GND, IN1
  • • ทดสอบด้วย LED ก่อนเพื่อให้แน่ใจว่าโค้ดทำงาน
  • • บาง Relay Module ต้องใช้ 5V ไม่ใช่ 3.3V
  • • ลองเปลี่ยน Pin GPIO เป็นตัวเลขอื่น

ปัญหา: หน้าเว็บเปิดไม่ได้

  • • ตรวจสอบว่าอุปกรณ์เชื่อมต่อ WiFi อยู่ในเครือข่ายเดียวกัน
  • • รอสักครู่ NTP Server อาจใช้เวลาในการซิงค์เวลา
  • • ลองพิมพ์ IP address ใน Browser อื่น
  • • เปิด Serial Monitor ดูว่ามีข้อผิดพลาดหรือไม่

ปัญหา: Timer ทำงานไม่ตรงเวลา

  • • ตรวจสอบว่าได้ตั้งค่า timezone ถูกต้อง (บรรทัด configTime)
  • • NTP Server อาจล่าช้า ให้รอ 2-3 นาทีหลังเปิดเครื่อง
  • • ตรวจสอบว่าเวลาบนหน้าเว็บถูกต้องหรือไม่

🚀 ขยายความสามารถ

ไอเดียต่อยอด

  • เพิ่มช่อง Relay: ใช้ Relay 2-channel 4-channel หรือ 8-channel เพื่อควบคุมหลายอุปกรณ์พร้อมกัน
  • เชื่อมต่อ CynoIoT: ส่งข้อมูลเข้าสู่ CynoIoT Platform เพื่อบันทึกประวัติและควบคุมระยะไกลผ่าน Cloud
  • เพิ่ม Sensor: ต่อเซ็นเซอร์วัดอุณหภูมิ ความชื้น DHT11/DHT22 เพื่อตั้งเวลาตามสภาพอากาศ
  • ประหยัดพลังงาน: ใช้ Deep Sleep Mode เพื่อประหยัดแบตเตอรี่ในโปรเจกต์พกพา
  • ระบบแจ้งเตือน: เพิ่ม Module Line Notify หรือ Telegram Bot เพื่อแจ้งเตือนเมื่อ Timer ทำงาน
  • หน้าจอแสดงผล: เพิ่ม OLED LCD หรือ 7-segment display เพื่อแสดงสถานะโดยไม่ต้องเปิดเว็บ

💡 Tip: การเชื่อมต่อ CynoIoT

คุณสามารถใช้ CynoIoT SDK เพื่อส่งข้อมูลการเปิด-ปิด Relay เข้าสู่ระบบ Cloud ทำให้สามารถควบคุมและดูประวัติได้จากทุกที่ ไม่จำกัดอยู่ในเครือข่ายเดียวกัน

📝 สรุป

ในบทความนี้ คุณได้เรียนรู้วิธีสร้าง ระบบตั้งเวลาเปิด-ปิดอุปกรณ์ไฟฟ้า ด้วย ESP32 และ Web Server ที่สามารถควบคุมผ่านหน้าเว็บได้ง่ายๆ โปรเจกต์นี้เหมาะสำหรับการนำไปประยุกต์ใช้กับระบบอัตโนมัติภายในบ้าน การรดน้ำ หรือโปรเจกต์ IoT อื่นๆ

สิ่งที่คุณได้เรียนรู้

  • ✅ การเชื่อมต่อ Relay Module กับ ESP32
  • ✅ การสร้าง Web Server บน ESP32
  • ✅ การใช้ NTP เพื่อรับเวลาจากอินเทอร์เน็ต
  • ✅ การตั้งเวลาอัตโนมัติด้วย Timer
  • ✅ การสร้างหน้าเว็บสวยงามและใช้งานง่าย

ถัดไป

CynoIoT LogoCynoIoT

แพลตฟอร์ม IoT ที่ง่ายที่สุด สำหรับการสร้างโปรเจกต์อัจฉริยะ และระบบอัตโนมัติภายในบ้าน

© 2026 CynoIoT. All rights reserved.