#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
// WiFi Setting
const char* WIFI_NAME = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// กำหนดขาแยกตามบอร์ด
#if defined(ESP32)
const int GPIO_PIN_NUMBER_2 = 2; // LED1
const int GPIO_PIN_NUMBER_3 = 32; // LED2
#elif defined(ESP8266)
const int GPIO_PIN_NUMBER_2 = 2; // LED1 (D4)
const int GPIO_PIN_NUMBER_3 = 0; // LED2 (D3)
#endif
WiFiServer server(80);
String header;
String LED_ONE_STATE = "off";
String LED_TWO_STATE = "off";
void setup() {
Serial.begin(115200);
pinMode(GPIO_PIN_NUMBER_2, OUTPUT);
pinMode(GPIO_PIN_NUMBER_3, OUTPUT);
digitalWrite(GPIO_PIN_NUMBER_2, LOW);
digitalWrite(GPIO_PIN_NUMBER_3, LOW);
Serial.print("Connecting to ");
Serial.println(WIFI_NAME);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ Successfully connected to WiFi");
Serial.print("🌐 IP Address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
Serial.println("🔔 New Client connected");
String current_data_line = "";
while (client.connected()) {
if (client.available()) {
char new_byte = client.read();
header += new_byte;
if (new_byte == '\n') {
if (current_data_line.length() == 0) {
// HEADER
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// LED1 Control
if (header.indexOf("LED1=ON") != -1) {
LED_ONE_STATE = "on";
digitalWrite(GPIO_PIN_NUMBER_2, HIGH);
}
if (header.indexOf("LED1=OFF") != -1) {
LED_ONE_STATE = "off";
digitalWrite(GPIO_PIN_NUMBER_2, LOW);
}
// LED2 Control
if (header.indexOf("LED2=ON") != -1) {
LED_TWO_STATE = "on";
digitalWrite(GPIO_PIN_NUMBER_3, HIGH);
}
if (header.indexOf("LED2=OFF") != -1) {
LED_TWO_STATE = "off";
digitalWrite(GPIO_PIN_NUMBER_3, LOW);
}
// Web Page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<style>html{font-family:Helvetica;text-align:center;} ");
client.println(".button{background:#4CAF50;color:white;padding:15px 32px;border:none;border-radius:8px;cursor:pointer;}");
client.println("</style></head>");
client.println("<body><h1>ESP Web Server LED Control</h1>");
client.println("<p>LED1 is <b>" + LED_ONE_STATE + "</b></p>");
client.println("<button class=\"button\" onclick=\"location.href='/?LED1=ON'\">LED1 ON</button>");
client.println("<button class=\"button\" onclick=\"location.href='/?LED1=OFF'\">LED1 OFF</button><br><br>");
client.println("<p>LED2 is <b>" + LED_TWO_STATE + "</b></p>");
client.println("<button class=\"button\" onclick=\"location.href='/?LED2=ON'\">LED2 ON</button>");
client.println("<button class=\"button\" onclick=\"location.href='/?LED2=OFF'\">LED2 OFF</button><br><br>");
client.println("</body></html>");
client.println();
break;
} else {
current_data_line = "";
}
} else if (new_byte != '\r') {
current_data_line += new_byte;
}
}
}
header = "";
client.stop();
Serial.println("❌ Client disconnected\n");
}
}
/*
#include <WiFi.h> // รวมไลบรารีสำหรับจัดการการเชื่อมต่อ Wi-Fi และฟังก์ชันเซิร์ฟเวอร์บน ESP32
// ตั้งค่า WiFi
const char* WIFI_NAME = "Wokwi-GUEST"; // กำหนดชื่อเครือข่าย Wi-Fi (SSID) ที่จะเชื่อมต่อ
const char* WIFI_PASSWORD = ""; // กำหนดรหัสผ่านของเครือข่าย Wi-Fi (ในกรณีนี้คือไม่มีรหัสผ่าน)
WiFiServer server(80); // สร้างอ็อบเจกต์เซิร์ฟเวอร์ Wi-Fi บนพอร์ต 80 ซึ่งเป็นพอร์ตมาตรฐานสำหรับ HTTP
String header; // ตัวแปร String ใช้เก็บข้อมูล HTTP Header ที่ได้รับจากไคลเอ็นต์ (เบราว์เซอร์)
String LED_ONE_STATE = "off"; // ตัวแปร String เก็บสถานะปัจจุบันของ LED 1 (เริ่มต้นเป็น "off")
String LED_TWO_STATE = "off"; // ตัวแปร String เก็บสถานะปัจจุบันของ LED 2 (เริ่มต้นเป็น "off")
const int GPIO_PIN_NUMBER_2 = 2; // กำหนดหมายเลขขา GPIO ของ ESP32 สำหรับ LED 1 (ขา 2)
const int GPIO_PIN_NUMBER_3 = 32; // กำหนดหมายเลขขา GPIO ของ ESP32 สำหรับ LED 2 (ขา 32)
void setup() { // ฟังก์ชันที่ทำงานเพียงครั้งเดียวเมื่อเริ่มต้น (Start up)
Serial.begin(115200); // เริ่มการสื่อสารแบบอนุกรม (Serial) ที่อัตราบอด 115200 เพื่อแสดงข้อความ Debug ใน Serial Monitor
pinMode(GPIO_PIN_NUMBER_2, OUTPUT); // ตั้งค่าขา GPIO 2 เป็นโหมด Output สำหรับควบคุม LED 1
pinMode(GPIO_PIN_NUMBER_3, OUTPUT); // ตั้งค่าขา GPIO 32 เป็นโหมด Output สำหรับควบคุม LED 2
digitalWrite(GPIO_PIN_NUMBER_2, LOW); // ตั้งค่าเริ่มต้นให้ LED 1 ปิด (LOW = 0V)
digitalWrite(GPIO_PIN_NUMBER_3, LOW); // ตั้งค่าเริ่มต้นให้ LED 2 ปิด (LOW = 0V)
Serial.print("Connecting to "); // แสดงข้อความใน Serial Monitor
Serial.println(WIFI_NAME); // แสดงชื่อ Wi-Fi ที่กำลังเชื่อมต่อ
WiFi.begin(WIFI_NAME, WIFI_PASSWORD); // พยายามเชื่อมต่อ ESP32 เข้ากับเครือข่าย Wi-Fi
while (WiFi.status() != WL_CONNECTED) { // วนลูปจนกว่าจะเชื่อมต่อ Wi-Fi สำเร็จ
delay(1000); // หน่วงเวลา 1 วินาที
Serial.print("."); // แสดงจุดใน Serial Monitor ขณะรอการเชื่อมต่อ
}
Serial.println(""); // ขึ้นบรรทัดใหม่
Serial.println("✅ Successfully connected to WiFi"); // แสดงข้อความเมื่อเชื่อมต่อสำเร็จ
Serial.print("🌐 IP Address: "); // แสดงข้อความ
Serial.println(WiFi.localIP()); // แสดงที่อยู่ IP ที่ ESP32 ได้รับ
server.begin(); // เริ่มต้นการทำงานของเซิร์ฟเวอร์ HTTP และเริ่มรอการเชื่อมต่อจากไคลเอ็นต์
}
void loop() { // ฟังก์ชันหลักที่ทำงานซ้ำไปเรื่อย ๆ อย่างต่อเนื่อง
WiFiClient client = server.available(); // ตรวจสอบว่ามีไคลเอ็นต์ใหม่เชื่อมต่อเข้ามาที่เซิร์ฟเวอร์หรือไม่
if (client) { // ถ้ามีไคลเอ็นต์เชื่อมต่อเข้ามา
Serial.println("🔔 New Client connected"); // แสดงข้อความแจ้งเตือนใน Serial Monitor
String current_data_line = ""; // ตัวแปร String ใช้เก็บข้อมูลในแต่ละบรรทัดของ HTTP Request
while (client.connected()) { // วนลูปตราบเท่าที่ไคลเอ็นต์ยังคงเชื่อมต่ออยู่
if (client.available()) { // ตรวจสอบว่ามีข้อมูลจากไคลเอ็นต์พร้อมให้อ่านหรือไม่
char new_byte = client.read(); // อ่านข้อมูลมาทีละ 1 ไบต์ (ตัวอักษร)
header += new_byte; // เพิ่มไบต์ที่อ่านได้เข้าในตัวแปร header เพื่อเก็บ HTTP Header ทั้งหมด
if (new_byte == '\n') { // ตรวจสอบว่าอ่านถึงอักขระขึ้นบรรทัดใหม่ (End of Line) หรือไม่
if (current_data_line.length() == 0) { // ถ้าบรรทัดที่อ่านได้มีความยาวเป็น 0 แสดงว่าอ่านถึงส่วนท้ายของ HTTP Header (บรรทัดว่างเปล่า)
// HTTP header
client.println("HTTP/1.1 200 OK"); // ส่ง HTTP Response Status Line กลับไปยังไคลเอ็นต์ (สถานะสำเร็จ)
client.println("Content-type:text/html"); // กำหนดชนิดของข้อมูลที่ส่งกลับเป็น HTML
client.println("Connection: close"); // บอกไคลเอ็นต์ว่าเซิร์ฟเวอร์จะปิดการเชื่อมต่อหลังจากส่งข้อมูลเสร็จ
client.println(); // ส่งบรรทัดว่างเปล่าเพื่อสิ้นสุดส่วน HTTP Header และเริ่มต้นส่วนเนื้อหา (Body)
////////////////////////////////////
if (header.indexOf("LED1=ON") != -1) { // ตรวจสอบว่ามีข้อความ "LED1=ON" อยู่ใน HTTP Header หรือไม่ (จากการคลิกปุ่ม)
Serial.println("👉 GPIO2 LED is ON"); // แสดงข้อความใน Serial Monitor
LED_ONE_STATE = "on"; // อัพเดตสถานะของ LED 1 เป็น "on"
digitalWrite(GPIO_PIN_NUMBER_2, HIGH); // สั่งให้ขา GPIO 2 เป็น HIGH (เปิด LED 1)
}
if (header.indexOf("LED1=OFF") != -1) { // ตรวจสอบว่ามีข้อความ "LED1=OFF" อยู่ใน HTTP Header หรือไม่
Serial.println("👉 GPIO2 LED is OFF"); // แสดงข้อความ
LED_ONE_STATE = "off"; // อัพเดตสถานะของ LED 1 เป็น "off"
digitalWrite(GPIO_PIN_NUMBER_2, LOW); // สั่งให้ขา GPIO 2 เป็น LOW (ปิด LED 1)
}
/////////////////////////////////////
if (header.indexOf("LED2=ON") != -1) { // ตรวจสอบว่ามีข้อความ "LED2=ON" อยู่ใน HTTP Header หรือไม่
Serial.println("👉 GPIO32 LED is ON"); // แสดงข้อความ
LED_TWO_STATE = "on"; // อัพเดตสถานะของ LED 2 เป็น "on"
digitalWrite(GPIO_PIN_NUMBER_3, HIGH); // สั่งให้ขา GPIO 32 เป็น HIGH (เปิด LED 2)
}
if (header.indexOf("LED2=OFF") != -1) { // ตรวจสอบว่ามีข้อความ "LED2=OFF" อยู่ใน HTTP Header หรือไม่
Serial.println("👉 GPIO32 LED is OFF"); // แสดงข้อความ
LED_TWO_STATE = "off"; // อัพเดตสถานะของ LED 2 เป็น "off"
digitalWrite(GPIO_PIN_NUMBER_3, LOW); // สั่งให้ขา GPIO 32 เป็น LOW (ปิด LED 2)
}
/////////////////////////////////////
// สร้าง Web Page
client.println("<!DOCTYPE html><html>"); // เริ่มต้นเอกสาร HTML
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); // ตั้งค่า Viewport สำหรับการแสดงผลบนอุปกรณ์มือถือ
client.println("<link rel=\"icon\" href=\"data:,\">"); // ป้องกันการร้องขอ favicon
client.println("<style>"); // เริ่มต้น CSS
client.println("html { font-family: Helvetica; text-align: center; }"); // กำหนดฟอนต์และจัดข้อความให้อยู่กึ่งกลาง
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 15px 32px;"); // กำหนดสไตล์ปุ่ม
client.println("text-align: center; text-decoration: none; display: inline-block;"); // สไตล์ปุ่มต่อ
client.println("font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 8px; }"); // สไตล์ปุ่มต่อ
client.println("</style></head>"); // สิ้นสุด CSS และส่วน Head
client.println("<body><h1>ESP32 Web Server LED Control</h1>"); // เริ่มต้นส่วน Body และหัวข้อ
/////////////////////////////////////////////////////
client.println("<p>LED1 is <b>" + LED_ONE_STATE + "</b></p>"); // แสดงสถานะปัจจุบันของ LED 1
// สร้างปุ่ม LED1 ON: เมื่อคลิกจะเปลี่ยน URL เป็น /?LED1=ON ซึ่งจะถูกประมวลผลในโค้ดด้านบน
client.println("<button class=\"button\" name=\"LED1\" value=\"ON\" type=\"submit\" onclick=\"location.href='/?LED1=ON'\">LED1 ON</button>");
// สร้างปุ่ม LED1 OFF
client.println("<button class=\"button\" name=\"LED1\" value=\"OFF\" type=\"submit\" onclick=\"location.href='/?LED1=OFF'\">LED1 OFF</button><br><br>");
/////////////////////////////////////////////////////
client.println("<p>LED2 is <b>" + LED_TWO_STATE + "</b></p>"); // แสดงสถานะปัจจุบันของ LED 2
// สร้างปุ่ม LED2 ON
client.println("<button class=\"button\" name=\"LED2\" value=\"ON\" type=\"submit\" onclick=\"location.href='/?LED2=ON'\">LED2 ON</button>");
// สร้างปุ่ม LED2 OFF
client.println("<button class=\"button\" name=\"LED2\" value=\"OFF\" type=\"submit\" onclick=\"location.href='/?LED2=OFF'\">LED2 OFF</button><br><br>");
/////////////////////////////////////////////////////
client.println("</body></html>"); // สิ้นสุดส่วน Body และเอกสาร HTML
client.println(); // ส่งบรรทัดว่างเปล่าเพิ่มเติม
break; // ออกจากลูป while (client.connected()) เพื่อหยุดอ่านข้อมูลจากไคลเอ็นต์
} else {
current_data_line = ""; // ถ้าไม่ใช่บรรทัดว่างเปล่า (หมายถึงเป็นบรรทัดของ HTTP Header ที่มีข้อมูล) ให้ล้าง current_data_line เพื่อเริ่มต้นบรรทัดใหม่
}
} else if (new_byte != '\r') { // ถ้าไม่ใช่ '\n' (ขึ้นบรรทัดใหม่) และไม่ใช่ '\r' (Carriage Return)
current_data_line += new_byte; // เพิ่มไบต์ที่อ่านได้เข้าใน current_data_line เพื่อสร้างบรรทัดปัจจุบัน
}
}
}
// Clear the header variable
header = ""; // ล้างตัวแปร header สำหรับการเชื่อมต่อครั้งถัดไป
// Close the connection
client.stop(); // ปิดการเชื่อมต่อกับไคลเอ็นต์
Serial.println("❌ Client disconnected\n"); // แสดงข้อความเมื่อไคลเอ็นต์ตัดการเชื่อมต่อ
}
}
*/