#include <WiFi.h>
const char* ssid = "dinmin-iPhone"; // 雙引號內,修改為你要 ESP32 連上的 WiFi 網路名稱 SSID
const char* password = "11111111"; // 雙引號內,鍵入此網路的密碼
WiFiServer server(80); //設定網路伺服器 port number 為 80
// 用於存儲 HTTP 請求的變數
String header;
String output15State = "off"; //設定字串變數 output15State,顯示 GPIO15 狀態。如果您要增加可控制的 GPIO 數目,請在這裡增加
String output16State = "off";
String output2State = "off"; //設定字串變數 output2State,顯示 GPIO15 狀態。如果您要增加可控制的 GPIO 數目,請在這裡增加
String output4State = "off";
// 將輸出變量分配給 GPIO 引腳
const int output15 = 15;
const int output16 = 16;
const int output2 = 2;
const int output4 = 4;
// 當前時間
unsigned long currentTime = millis();
unsigned long previousTime = 0; // Previous time
const long timeoutTime = 2000; //以毫秒為單位定義超時時間(example: 2000ms = 2s)
void setup() {
Serial.begin(115200); //設定序列埠螢幕顯示的 baud rate 為 115200
// 設定output15、output16狀態為輸出模式
pinMode(output15, OUTPUT);
pinMode(output16, OUTPUT);
pinMode(output2, OUTPUT);
pinMode(output4, OUTPUT);
// 數位輸出output15、output16為LOW
digitalWrite(output15, LOW);
digitalWrite(output16, LOW);
digitalWrite(output2, LOW);
digitalWrite(output4, LOW);
Serial.print("Connecting to "); // 連上你所指定的Wi-Fi,並在序列埠螢幕中,印出 ESP32 web server 的 IP address
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// 在監控視窗顯示IP並啟動Web服務器
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop(){
WiFiClient client = server.available(); // 看有沒有外部裝置 client (如手機),藉著瀏覽器 browser 連上 ESP32 web server
if (client) { // 如果有新客戶端連接
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // 在序列埠中打印一條消息
String currentLine = ""; // 製作一個字符串來保存來自客戶端的傳入數據
while (client.connected() && currentTime - previousTime <= timeoutTime) { // 客戶端連接時循環
currentTime = millis();
if (client.available()) { // 如果有字節要從客戶端讀取
char c = client.read(); // 讀取一個字節
Serial.write(c); // 然後將其打印出序列埠監視器
header += c;
if (c == '\n') { // 如果字節是換行符號
// 如果當前行為空白,則連續有兩個換行符。
// 這是客戶端 HTTP 請求的結束,所以發送一個回應
if (currentLine.length() == 0) {
// HTTP 標頭始終以響應代碼開頭 (例如 HTTP/1.1 200 OK) 和一個內容類型,以便客戶端知道接下來會發生什麼,然後是一個空行
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// 接收 client 的指令,點亮或關閉 連上 GPIO 的 LED。瀏覽器上,不同的按鈕,會發出不同的指令 (URLs requests)
if (header.indexOf("GET /15/on") >= 0) {
Serial.println("GPIO 15 on");
output15State = "on";
digitalWrite(output15, HIGH);
} else if (header.indexOf("GET /15/off") >= 0) {
Serial.println("GPIO 15 off");
output15State = "off";
digitalWrite(output15, LOW);
} else if (header.indexOf("GET /16/on") >= 0) {
Serial.println("GPIO 16 on");
output16State = "on";
digitalWrite(output16, HIGH);
} else if (header.indexOf("GET /16/off") >= 0) {
Serial.println("GPIO 16 off");
output16State = "off";
digitalWrite(output16, LOW);
} else if (header.indexOf("GET /2/off") >= 0) {
Serial.println("GPIO 2 off");
output2State = "off";
digitalWrite(output2, LOW);
} else if (header.indexOf("GET /2/on") >= 0) {
Serial.println("GPIO 2 on");
output2State = "on";
digitalWrite(output2, HIGH);
} else if (header.indexOf("GET /4/on") >= 0) {
Serial.println("GPIO 4 on");
output4State = "on";
digitalWrite(output4, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
Serial.println("GPIO 4 off");
output4State = "off";
digitalWrite(output4, LOW);
}
// 設計 client 上的瀏覽器網頁格式,包括顏色、字型大小、有無邊框、字元等,這一部分是用 HTML 的語言寫成的
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS 來設置開/關按鈕的樣式
// 可隨意更改背景顏色和字體大小屬性
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #ff0000; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;}</style></head>");
// 網頁標題
client.println("<body><h1>ESP32 Web Server</h1>");
// 顯示當前狀態,以及GPIO 15的開關按鈕
client.println("<p>GPIO 15 - State " + output15State + "</p>");
//如果 output15State 為 off,則顯示 ON 按鈕
if (output15State=="off") {
client.println("<p><a href=\"/15/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/15/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// 顯示當前狀態,以及GPIO 16的開關按鈕
client.println("<p>GPIO 16 - State " + output16State + "</p>");
// 如果 output16State 為 off,則顯示 ON 按鈕
if (output16State=="off") {
client.println("<p><a href=\"/16/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/16/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// 顯示當前狀態,以及GPIO 2的開關按鈕
client.println("<p>GPIO 2 - State " + output2State + "</p>");
//如果 output2State 為 off,則顯示 ON 按鈕
if (output2State=="off") {
client.println("<p><a href=\"/2/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/2/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// 顯示當前狀態,以及GPIO 4的開關按鈕
client.println("<p>GPIO 4 - State " + output16State + "</p>");
// 如果 output4State 為 off,則顯示 ON 按鈕
if (output4State=="off") {
client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
}
client.println("</body></html>");
// HTTP 回應以另一個空行結尾
client.println();
// 跳出while循環
break;
} else { // 如果有換行符,則清除當前行
currentLine = "";
}
} else if (c != '\r') { // 如果除了return之外還有其他內容,請添加到當前行的末尾
currentLine += c;
}
}
}
//清除開頭變數
header = "";
// 關閉連接
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}