บทความการใช้งานเริ่มต้น ESP8266 NodeMCU และการใช้งาน Application ต่างๆ
ตอนที่ 5 Web Server

Web Server คือ Server ที่ให้บริการเว็บไซต์แก่ Client ที่เข้ามาเรียกขอหน้าเว็บโดยใช้ Hypertext Transfer Protocol (HTTP)
ถ้าหากเราลองมองรูปแบบการทำงานของ Web Server แบบง่ายๆ Web Server ก็คือ TCP Server ที่เปิด Port 80 เอาไว้เพื่อคอยทำหน้าที่รอรับ การร้องขอข้อมูลจาก Client ซึ่งในที่นี้คือ Web browser โดยใช้ Protocol แบบ HTTP เมื่อ Web Server ได้รับการร้องขอก็จะส่งข้อมูลที่ถูกร้องขอกลับไปยัง Client เพื่อนำไปแสดงผลนั่นเอง
ทดลองทำ Web Server จากโปรแกรม Hercules
จากการทดลองในเรื่อง TCP ในบทความก่อนหน้านี้ ได้แนะนำโปรแกรม Hercules ที่ใช้ช่วยในการทดสอบการทำงานของ TCP ไปแล้วนั้น จะเห็นได้ว่าโปรแกรม Hercules สามารถใช้งานได้ทั้งในโหมด TCP Client และ TCP Server ในตอนต้น ผมได้กล่าวไปแล้วว่า Web Server นั้นทำงานอยู่บนพื้นฐานของ TCP Server ในการทดลองนี้ ผมจะทดลองใช้โปรแกรม Hercules เป็น TCP Server เพื่อดูว่าเมื่อ Web browser เรียกขอหน้าเว็บไซต์ไปยัง Server นั้น ที่ Server จะได้ข้อมูลอะไรมาบ้างและจะทดลองส่ง Code HTML ง่ายๆ กลับไปแสดงผลยัง Web browser
ขั้นตอนแรก เปิดโปรแกรม Hercules ขึ้นมาแล้วไปที่ Tab TCP Server กำหนดใช้ Port 8000 (โดยปกติการใช้งานเว็บไซต์จะใช้ที่ Port 80)

จากนั้นเปิด Web browser ขึ้นมาแล้วเรียกเปิดเว็บไปที่ IP ของเครื่องเราเองที่ Port 8000 ซึ่งในที่นี้เครื่องของผมใช้หมายเลข IP 192.168.1.36 จึงเรียกหน้า web ไปที่ http://192.168.1.36:8000

ที่ TCP Server ที่เราเปิด Port รอรับเอาไว้จะมีข้อมูลเข้ามา ซึ่งเป็นข้อมูลการเรียกขอหน้าเว็บไซต์จาก Web browser ให้สังเกตที่ GET / HTTP/1.1 หมายถึงต้องการเรียกขอ File ที่อยู่ใน root ซึ่งโดยปรกติแล้วการ / (root) จะหมายถึงการเรียกหน้า Home page ของเรานั่นคือ index.html นั่นเอง
GET / HTTP/1.1 Host: 192.168.1.36:8000 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: th-TH,th;q=0.8
จากนั้น ทดลองส่ง HTML Code ตอบกลับไปดังนี้?
<html> <body> <h1>My First Web</h1> <p>Test Simple Web Server</p> </body> </html>
จะพบว่า HTM Code ของเราที่ส่งกลับไปได้ขึ้นไปแสดงที่ Web browser แล้ว

สามารถอ่านข้อมูลเพิ่มเติมเรื่องของ Hypertext Transfer Protocol เพิ่มเติมได้ที่ http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
ทดลองสร้าง Web Server อย่างง่ายบน Node MCU
การทดลองนี้เป็นการนำเอา ESP8266 มาสร้างเป็น Web Server โดยลอกเลียนแบบกระบวนการทำงานของ TCP Server บนโปรแกรม Hercules แบบการทดลองก่อนหน้า และนำการร้องขอหน้าเว็บไซต์มาเป็นตัวกำหนดให้หลอด LED ติดดับ
ต่อวงจรดังนี้

#include <ESP8266WiFi.h> #define LED D1 //กำหนดขาที่ต่อ LED เป็นขา D1 const char* ssid = "stk"; //กำหนด SSID (อย่าลืมแก้เป็นของตัวเอง) const char* password = "stk123456"; //กำหนด Password(อย่าลืมแก้เป็นของตัวเอง) unsigned char status_led=0; //กำหนดตัวแปร ที่เก็บค่าสถานะของ LED WiFiServer server(80); //กำหนดใช้งาน TCP Server ที่ Port 80 void setup() { Serial.begin(115200); //เปิดใช้ Serial pinMode(LED, OUTPUT); //กำหนด Pin ที่ต่อกับ LED เป็น Output Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); //เชื่อมต่อกับ AP while (WiFi.status() != WL_CONNECTED) //รอการเชื่อมต่อ { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); //แสดงข้อความเชื่อมต่อสำเร็จ server.begin(); //เปิด TCP Server Serial.println("Server started"); Serial.println(WiFi.localIP()); // แสดงหมายเลข IP ของ Server } void loop() { WiFiClient client = server.available(); //รอรับ การเชื่อมต่อจาก Client if (!client) { //ถ้าไม่มี Client เข้ามาให้เริ่มกับไปวน loop รอรับใหม่ return; } Serial.println("new client"); while(!client.available()) { delay(1); } String req = client.readStringUntil('\r'); //อ่านค่าที่ได้รับจากclient จากข้อมูลแรกถึง '\r' Serial.println(req); //แสดงค่าที่ได้รับทาง Serial client.flush(); if (req.indexOf("/ledoff") != -1) //ตรวจสอบว่า data ที่เข้ามามีข้อความ"/ledoff" หรือไม่ { status_led=0; //ถ้ามีให้กำหนดค่า ในตัวแปรใน status_led=0 digitalWrite(LED,LOW); //ให้ LED ดับ Serial.println("LED OFF"); } else if(req.indexOf("/ledon") != -1) //ตรวจสอบว่า data ที่เข้ามามีข้อความ"/ledon" หรือไม่ { status_led=1; //ถ้ามีให้กำหนดค่า ในตัวแปรใน status_led=1 digitalWrite(LED,HIGH); //ให้ LED ติด Serial.println("LED ON"); } //เก็บ Code HTML ลงในตัวแปรสตริง web String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; web += "<html>\r\n"; web += "<body>\r\n"; web += "<h1>LED Status</h1>\r\n"; web += "<p>\r\n"; if(status_led==1) // ตรวจเช็คสถานะของ LED ว่า On หรือ Off web += "LED On\r\n"; else web += "LED Off\r\n"; web += "</p>\r\n"; web += "</body>\r\n"; web += "</html>\r\n"; client.print(web); //ส่ง HTML Code ไปยัง client }
ทดลอง Run Program
เปิด Web Browser แล้วกำหนด url ไปที่ IP ของ NodeMCU

เรียกหน้าเว็บไปที่ xxx.xxx.xxx.xxx/ledon สังเกต >> หลอด LED จะติด

เรียกหน้าเว็บไปที่ xxx.xxx.xxx.xxx/ledoff สังเกต >> หลอด LED จะดับ

ตัวอย่างทดลองใช้ Button เปิด/ปิด LED แทนการเรียกผ่าน URL

เพิ่ม Code HTML สร้าง Button LED On และ LED Off ลงไป
<html> <body> <h1>LED Status</h1> <p> LED Off </p> <p> <a href="/ledon"> <button>LED On</button> </a> </p> <a href="/ledoff"> <button>LED Off</button> </a> </body> </html>
แก้ไข Code ในส่วนเก็บ Code HTML ลงในตัวแปรสตริง web
String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; web += "<html>\r\n"; web += "<body>\r\n"; web += "<h1>LED Status</h1>\r\n"; web += "<p>\r\n"; if(status_led==1) web += "LED On\r\n"; else web += "LED Off\r\n"; web += "</p>\r\n"; web += "<p>\r\n"; web += "<a href=\"/ledon\">\r\n"; web += "<button>LED On</button>\r\n"; web += "</a>\r\n"; web += "</p>\r\n"; web += "<a href=\"/ledoff\">\r\n"; web += "<button>LED Off</button>\r\n"; web += "</a>\r\n"; web += "</body>\r\n"; web += "</html>\r\n"; client.print(web);
ตัวอย่าง Web Server and Digital Input
ต่อวงจรดังนี้

ก่อนจะเขียนโปรแกรมเราลองมาดู Code HTML ที่ใช้ในการทดลองนี้กันก่อนนะครับ
<html> <body> <head>Read Switch <style> .circle-gray,.circle-yellow //กำหนดขนาด และ เส้นขอบของวงกลม { width: 100px; height: 100px; border-radius: 50%; } .circle-gray //กำหนดสี พื้นหลังของวงกลมเป็นสีเทา { background-color: gray } .circle-yellow //กำหนดสี พื้นหลังของวงกลมเป็นสีเหลือง { background-color: yellow } </style> </head> <meta http-equiv="refresh" content="1"> //สั่งให้ Refresh หน้าpage ทุกๆ 1 วินาที <p> <div class="circle-gray"></div> //แสดงวงกลมสีเทา <p>SW = 1</p> //แสดงข้อความ "SW=1" </p> </body> </html>

ใน Code HTML นี้ใช้ CSS สร้างวงกลม โดยมีวงกลม 2 ชื่อได้แก่ circle-gray และ circle-yellow โดยทั้ง 2 มีขนาดเท่ากัน แตกต่างกันเพียงสีพื้นหลังและสามารถเรียกใช้งานได้เช่นนี้
<div class=”circle-gray”></div> => แสดงวงกลมสีเทา
<div class=”circle-yellow”></div> => แสดงวงกลมสีเหลือง
และ Code HTML อีกส่วนที่น่าสนใจคือ <meta http-equiv=”refresh” content=”1″> เป็นคำสั่งที่ใช้สำหรับสั่งให้หน้าเว็บ refresh ซึ่งสามารถกำหนดความถี่ในการ refresh ได้ โดยกำหนดค่า content ดังในตัวอย่าง เป็นการกำหนดให้ refresh ทุกๆ 1 วินาที
Code Program
#include <ESP8266WiFi.h> #define SW D2 //กำหนดรับ input จาก Switch ที่ Pin D2 const char* ssid = "stk"; //กำหนด SSID (อย่าลืมเปลี่ยนเป็นของตัวเอง) const char* password = "stk123456"; //กำหนด password (อย่าลืมเปลี่ยนเป็นของตัวเอง) WiFiServer server(80); //กำหนดใช้งาน TCP Server ที่ Port 80 void setup() { Serial.begin(115200); pinMode(SW,INPUT); //กำหนดให้ pin D2 เป็น input Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); // เชื่อมต่อกับ AP while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); server.begin(); //เริ่มใช้งาน TCP Server Serial.println("Server started"); Serial.println(WiFi.localIP()); //แสดง IP } void loop() { WiFiClient client = server.available(); //รอรับ การเชื่อมต่อจาก Client if (!client) { //ถ้าไม่มี Client เข้ามาให้เริ่มกับไปวน loop รอรับใหม่ return; } Serial.println("new client"); while(!client.available()) { delay(1); } String req = client.readStringUntil('\r'); //อ่านค่าที่ได้รับจากclient จากข้อมูลแรกถึง '\r' Serial.println(req); client.flush(); // เก็บ HTML Code ลงในตัวแปร String web String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; web += "<html>\r\n"; web += "<body>\r\n"; web += "<head>Read Switch\r\n"; web += "<style>\r\n"; web += ".circle-gray,.circle-yellow\r\n"; web += "{width: 100px;\r\n"; web += "height: 100px;\r\n"; web += "border-radius: 50%;}\r\n"; web += ".circle-gray\r\n"; web += "{background-color: gray}\r\n"; web += ".circle-yellow\r\n"; web += "{background-color: yellow}\r\n"; web += "</style>\r\n"; web += "</head>\r\n"; web += "<meta http-equiv=\"refresh\" content=\"1\">"; web += "<p>\r\n"; unsigned char sw_input = digitalRead(SW); //อ่านค่าจาก Switch