Currency :
Login Register

Login to your account

Username
Password *
Remember Me

Create an account

Fields marked with an asterisk (*) are required.
Name
Username
Password *
Verify password *
Email *
Verify email *
Captcha *
Real time web analytics, Heat map tracking

Search

Your Cart

ไม่มีสินค้าในตะกร้า

new customer 200p

EduBanner20160216

Preorder Logo

Free Shipping 200x200

Promotion

Our Products

  • Long Live The King
หน้าแรกบทความและวิกิApplications of Productsบทความการใช้งานเริ่มต้น ESP8266 NodeMCU และการใช้งาน Application ต่างๆ ตอนที่ 5 Web Server

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

ตอนที่ 5 Web Server

 01

 

>>> Download Example Code <<<

         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)

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

45

         ที่ 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 แล้ว

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

47

#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

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

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

50

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

         เพิ่ม 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
         ต่อวงจรดังนี้

52
         ก่อนจะเขียนโปรแกรมเราลองมาดู 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>

53         

         ใน 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  
  if(sw_input==1)
  {
    web += "<div class=\"circle-gray\"></div>\r\n";	//ถ้าเป็น 1 ให้แสดงวงกลมสีเทา
    web += "<p>SW = 1</p>\r\n";
  }
  else
  {
    web += "<div class=\"circle-yellow\"></div>\r\n";	//ถ้าเป็น 0 ให้แสดงวงกลมสีเหลือง
    web += "<p>SW = 0</p>\r\n";
  }
  web += "</p>\r\n";
  web += "</body>\r\n";
  web += "</html>\r\n";
  client.print(web);					//ส่ง HTML ไปยัง Client
}

ทดลอง Run Program
         เปิด Web Browser แล้วเรียกหน้า Page ไปยัง IP ของ Node MCU

54
         ทดลองกด Switch

55
ตัวอย่าง Web Server โดยใช้ Ajax
         ในตัวอย่างก่อนหน้านี้ การ update สถานะของการกด Button จะใช้การ refresh หน้า web ทั้งหน้าทุกๆ 1 วินาที ทำให้ทั้งหน้ากระพริบ และ เป็นการรับ/ส่ง Data ที่ค่อนข้างสิ้นเปลือง เนื่องจากในบางส่วนไม่ได้มีการเปลี่ยนแปลงแต่เราต้อง update ทั้งหน้า ในการทดลองนี้เราได้นำเอา Ajax เข้ามาช่วยให้สามารถ update ข้อมูลมาแสดงเฉพาะส่วนที่มีการเปลี่ยนแปลง ทำให้ไม่ต้อง refresh ทั้งหน้า และลดภาระของ Webserver ให้ทำงานน้อยลง
         ต่อวงจรดังนี้

56
Code HTML

<html>
<head>
<!--กำหนด style ของ button-->
<style>
	.button-red,.button-blue 
	{	
		color: white;
		border-radius: 9px;
		font-family:Arial;
		font-size:25px;
		padding:50px 80px;
	}
	.button-red:hover:active,.button-blue:hover:active 
	{	
		position:relative;top:3px;color: yellow;
	}
	.button-red 
	{
		background: rgb(202, 60, 60);
	}
	.button-blue 
	{
		background: rgb(100,116,255);
	}
	h1
	{
		color:black;font-family:Arial;
		font-size:40px;
		text-align:center;
	}	      
</style>

<script>
var ajax = null;
<!--เงื่อนไขเลือกสร้าง Object Ajax เพื่อให้รองรับกับ Browser ต่างๆ-->
if (window.XMLHttpRequest)
{
	ajax =new XMLHttpRequest();
}
else
{
	ajax=new ActiveXObject("Microsoft.XMLHTTP");
}
<!—function Load-->
function ajaxLoad(method ,URL,displayElementId,sendData)
{
	if(!ajax)
	{
		alert("not support");
return;}
	ajax.open(method,URL,true);    <!--เปิดการเชื่อมต่อ-->
	ajax.on-readystatechange = function()<!--เรียกใช้ Functionให้ทำงาน-->
	{
		if(ajax.readyState == 4 && ajax.status==200) <!—ตรวจสอบสถานะของ page
ที่เปิด (4= complete,200=OK)-->
	{
		var ajax_result = ajax.responseText; <!--อ่านค่าป็น text mode-->
		<!--elementสำหรับสแดงผล-->
		var el = document.getElementById(displayElementId);
		el.innerHTML = ajax_result;
	}
}	
	ajax.send(sendData);
}
<!—function สำหรับ update ค่า temp,Humidity-->
function update_temp_humi() 
{
	var URL = "/Temp_Humi.html";
	ajaxLoad("GET",URL,'temp_humi',null);
}
</script>
</head>
<body>
<h1>Demo Web Server Ajax </h1> 
<h2>Temp and Humidity</h2>
<div id="temp_humi">
	<h3>Temp = xx C</h3> 
	<h3>Humidity = xx %</h3>
</div>
<div>
	<p>
	<input class="button-red" type="button" value="Relay 1 On" on-click="Relay('r1on')">
	<input class="button-blue" type="button" value="Relay 1 Off" on-click="Relay('r1off')">
	</P>
	<p>
	<input class="button-red" type="button" value="Relay 2 On" on-click="Relay('r2on')">
	<input class="button-blue" type="button" value="Relay 2 Off" on-click="Relay('r2off')">
	</P>
</div>

<!— สำหรับเรียก update ค่า temp,Humidity ทุกๆ 2 วินาที-->
<script>
	function Relay(state){ajaxLoad("GET",state+'.html',null,null);}	
	setInterval("update_temp_humi()",2000);
</script>
</body>
</html>

Code Program

#include <ESP8266WiFi.h>
#include "DHT.h"

const char* ssid = "stk";
const char* password = "stk123456";
#define Relay1 D1
#define Relay2 D2
#define DHTPIN D3
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE,15);
WiFiServer server(80);
void setup() {
  Serial.begin(115200);
  delay(10);
  dht.begin();
  pinMode(Relay1, OUTPUT);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Relay1,LOW);
  digitalWrite(Relay2,LOW);
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");
  Serial.println(WiFi.localIP());
}

void loop() {
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  if (req.indexOf("/r1off.html") != -1)
  {
    digitalWrite(Relay1,LOW);
     
  }
  else if (req.indexOf("/r1on.html") != -1)
  {
    digitalWrite(Relay1,HIGH);
  }
   else if (req.indexOf("/r2on.html") != -1)
  {
    digitalWrite(Relay2,HIGH);
  }
   else if (req.indexOf("/r2off.html") != -1)
  {
    digitalWrite(Relay2,LOW);
  }
  else if(req.indexOf("/Temp_.html") != -1)
  {
     float h = dht.readHumidity();
     float t = dht.readTemperature();
    client.flush();
    String humi="<h3>Temp = ";
    humi += String(t)+" C</h3>\r\n";
    humi += "<h3>Humidity = ";
    humi += String(h)+" %</h3>\r\n";
    client.print(humi);
  }
  else if(req.indexOf("/") != -1)
  {
    client.flush();
    String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
    web += "<html>\r\n";
    web += "<head>\r\n";
    web += "<style>\r\n";
    web += ".button-red,.button-blue\r\n"; 
    web += "{color: white;\r\n";
    web += "border-radius: 9px;\r\n";
    web += "font-family:Arial;\r\n";
    web += "font-size:25px;\r\n";
    web += "padding:50px 80px;\r\n";
    web += "}\r\n";
    web += ".button-red:hover:active,.button-blue:hover:active\r\n"; 
    web += "{position:relative;top:3px;color: yellow;}\r\n";
    web += ".button-red {background: rgb(202, 60, 60);}\r\n";
    web += ".button-blue {background: rgb(100,116,255);}\r\n";
    web += "h1{color:black;font-family:Arial;font-size:40px;text-align:center;}\r\n";	      
    web += "</style>\r\n";
    web += "<script>\r\n";
    web += "var ajax = null;\r\n";
    web += "if (window.XMLHttpRequest)\r\n";
    web += "{ajax =new XMLHttpRequest();}\r\n";
    web += "else\r\n";
    web += "{ajax=new ActiveXObject(\"Microsoft.XMLHTTP\");}\r\n";
    web += "function ajaxLoad(method ,URL,displayElementId,sendData)\r\n";
    web += "{\r\n";
    web += "if(!ajax){alert(\"not support\");return;}\r\n";
    web += "ajax.open(method,URL,true);\r\n";
    web += "ajax.on-readystatechange = function()\r\n";
    web += "{\r\n";
    web += "if(ajax.readyState == 4 && ajax.status==200)\r\n";
    web += "{\r\n";
    web += "var ajax_result = ajax.responseText;\r\n";
    web += "var el = document.getElementById(displayElementId);\r\n";
    web += "el.innerHTML = ajax_result;\r\n";
    web += "}\r\n";
    web += "}\r\n";	
    web += "ajax.send(sendData);\r\n";
    web += "}\r\n";
    web += "function update_temp_humi()\r\n"; 
    web += "{\r\n";
    web += "var URL = \"/Temp_.html\";\r\n";
    web += "ajaxLoad(\"GET\",URL,\'temp_humi\',null);\r\n";
    web += "}\r\n";
    web += "</script>\r\n";
    web += "</head>";
    web += "<body>";
    web += "<h1>Demo Web Server Ajax</h1>"; 
    web += "<h2>Temp and Humidity</h2>";
    web += "<div id=\"temp_humi\">";
    web += "<h3>Temp = xx C</h3>"; 
    web += "<h3>Humidity = xx %</h3>";
    web += "</div>";
    web += "<p><div><input class=\"button-red\" type=\"button\" value=\"Relay 1 On\" on-click=\"Relay(\'r1on\')\">";
    web += "<input class=\"button-blue\" type=\"button\" value=\"Relay 1 Off\" on-click=\"Relay(\'r1off\')\"></P>";
    web += "<p><input class=\"button-red\" type=\"button\" value=\"Relay 2 On\" on-click=\"Relay(\'r2on\')\">";
    web += "<input class=\"button-blue\" type=\"button\" value=\"Relay 2 Off\" on-click=\"Relay(\'r2off\')\"></P>";
    web += "<script>";
    web += "function Relay(state){ajaxLoad(\"GET\",state+\'.html\',null,null);}";	
    web += "setInterval(\"update_temp_humi()\",2000);";
    web += "</script>";
    web += "</body>";
    web += "</html>";
     client.print(web);

    return;
  }
}

ทดลอง Run Program 

         เปิด Web Browser แล้วเรียกหน้า Page ไปยัง IP ของ Node MCU

57
ตัวอย่าง Web Server กับ SD Card
         จากตัวอย่างทั้งหมดที่กล่าวมาในข้างต้น จะเห็นว่าเราได้นำเอา HTML Code เข้าไปเป็นส่วนหนึ่งของ Code ภาษา C ทั้งหมด ซึ่งก็ถือว่าการใช้งานจะค่อนข้างลำบาก เนื่องจากต้องนำเอา HTML มาเก็บในตัวแปรประเภท String และด้วยข้อกำหนดในภาษา C เรื่องการเก็บข้อมูลเป็น String อาจทำให้เกิดความยุ่งยากและไม่สะดวกกับการแก้ไข HTML Code มากนัก เพราะต้องโปรแกรม Code ลงไปใหม่ทั้งหมด รวมถึงพื้นที่ในการเก็บข้อมูลภายใน ESP8266 ก็ถือว่ายังไม่มาก (ใน NodeMCU V2 ใช้ ESP8266 -12E มี Flash Memory ถึง 4MB) การใช้ ESP8266 เชื่อมต่อกับ SD Card ก็ถือเป็นอีกวิธีที่จะช่วยให้การใช้งานได้สะดวกมากขึ้น ทั้งการแก้ไข HTML และการเก็บ Log ที่ใช้ FAT File System ทำให้สามารถนำไปเปิดและแก้ไขในเครื่องคอมพิวเตอร์ได้ แต่ก็มีข้อเสียคือ เราต้องเสียขา I/O ไปบางส่วน
         ก่อนใช้งาน SD Card ผมขออธิบายและทำความเข้าใจเรื่องของ FAT File System ที่ใช้กับ ESP8266 ซึ่งมากับ Arduino IDE ในเชิงการใช้งานก่อนนะครับ เนื่องจาก FAT File System เป็นตัวที่ทำมาให้ใช้กับ Microcontroller ขนาดเล็ก จึงมีการตัดเอา Function บางส่วนออกไปบ้าง เช่นเรื่องของ LFN (Long File Name) ทำให้ไม่สามารถใช้งาน หรืออ้างถึงชื่อ File แบบเต็มๆตามที่เราตั้งได้แต่ FAT File System จะบังคับให้เราใช้ชื่อ แบบย่อ หรือ 8.3 Filename คือ สามารถแสดงตัวอักษรหน้า ‘.’ ก็คือชื่อ File ได้ 8 ตัวอักษร และตัวอักษรหลังจุด (นามสกุล) ได้ 3 ตัวอักษร ถ้าหากมีการตั้งชื่อ File ที่ยาวกว่า 8 ตัวอักษร FAT File System ก็จะมีการปรับแต่งชื่อ File ของเราใหม่ รวมถึงนามสกุลของ File ก็เช่นกันหากยาวเกินกว่า 3 ตัวอักษรจะตัดเหลือ 3 ตัวอักษร และมีการใส่สัญลักษณ์ลงไปแทนในชื่อไฟล์ด้วย ตัว FAT File System จะมองตัวอักษรทั้งหมดเป็นตัวใหญ่ (upper case) เพราะฉะนั้น abcd.txt กับ ABCD.txt จึงถูกมองเป็น File เดียวกัน
เช่น ถ้าหากเราตั้งชื่อ File เป็น
         index.html จะถูกเปลี่ยนเป็น INDEX~1.HTM หมายเหตุ นามสกุลยาวกว่า 3 ตัว
         index.htm จะไม่ถูกเปลี่ยนแปลง(INDEX.HTM)
         my.html จะถูกเปลี่ยนเป็น MY3237.HTM หมายเหตุ นามสกุลยาวกว่า 3 ตัว
         my.htm จะไม่ถูกเปลี่ยนแปลง(MY.HTM)
         abcdefgh.htm จะไม่ถูกเปลี่ยนแปลง(ABCDEFGH.HTM)
         abcdefghijk.htm จะถูกเปลี่ยนเป็น ABCDEF~4.HTM หมายเหตุ ชื่อยาวกว่า 8 ตัว
         เพื่อลดความยุ่งยากในการใช้งาน จึงแนะนำให้ไม่ควรตั้งชื่อ File เกิน 8 ตัวอักษร และนามสกุลไม่เกินกว่า 3 ตัวอักษร
หรืออาจใช้วิธีรับชื่อ File แบบเต็มๆ แล้วเขียนโปรแกรมแปลงชื่อ File เป็น 8.3 ก็ได้เช่นกัน โดยสามารถศึกษาเพิ่มเติมได้ที่
http://en.wikipedia.org/wiki/8.3_filename
วิธีการต่อใช้งาน Module SD Card กับ NodeMCU

58

ทดลองใช้งาน Example Code CardInfo
         ไปที่ เมนู File >> Example >> SD >> CardInfo

59

ทดลองโปรแกรม และ Run

60

         หากต่อวงจรถูกต้อง โปรแกรมจะสามารถแสดงรายละเอียดเกี่ยวกับ SD Card และ List รายชื่อ File ใน Card ออกมาแสดงได้
ทดลองสร้าง Webserver โดยเก็บหน้าเว็บ และรูปภาพใน SD Card

         ภาพการต่อวงจร

61

Code Program

#include <ESP8266WiFi.h>
#include "DHT.h"				
#include <SPI.h>
#include <SD.h>
File myFile;
const char* ssid = "stk";				//กำหนด SSID (อย่าลืมเปลี่ยนเป็นของตัวเอง)
const char* password = "stk123456";		//กำหนด password (อย่าลืมเปลี่ยนเป็นของตัวเอง)
#define LED_R D0				//กำหนดให้ LED สีแดงใช้ขา D0
#define LED_G D1				//กำหนดให้ LED สีเขียวใช้ขา D1
#define LED_B D2				//กำหนดให้ LED สีน้ำเงินใช้ขา D2
#define BUZZ  D4				//กำหนดให้ buzzer ใช้ขา D4
#define DHTPIN D3				//กำหนดให้ DHT22 ใช้ขา D3
#define DHTTYPE DHT22			//กำหนดใช้ DHT22
DHT dht(DHTPIN, DHTTYPE,15);			//ตั้งค่ากำหนดใช้งาน DHT 
WiFiServer server(80);				//ประกาศใช้ TCP Server ที่ port 80
void setup() {
  Serial.begin(115200);
  delay(10);
  dht.begin();
  pinMode(LED_R, OUTPUT);			//กำหนดขา RGB LED และ Buzzer เป็น output
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);
  pinMode(BUZZ, OUTPUT);
  
  digitalWrite(LED_R,HIGH);			//กำหนดขา RGB LED และ Buzzer เป็น High	
  digitalWrite(LED_G,HIGH);
  digitalWrite(LED_B,HIGH);
  digitalWrite(BUZZ,HIGH);
  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();					//เปิดใช้งาน Server
  Serial.println("Server started");
  Serial.println(WiFi.localIP());			//แสดง IP
  Serial.print("Initializing SD card...");

  if (!SD.begin()) {				//เริ่มต้นใช้งาน SD Card
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}
void loop() {
  WiFiClient client = server.available();		//รอการเชื่อมต่อจาก Client
  if (!client) {				
    return;					//หากไม่มีการเชื่อมต่อให้เริ่ม loop ใหม่
  }
  
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  String req = client.readStringUntil('\r');		//อ่านค่าที่ได้รับจากclient จากข้อมูลแรกถึง ‘\r’
  Serial.println(req);
  client.flush();
  if (req.indexOf("/red.html") != -1)		//ตรวจสอบว่ามีการร้องขอ File red.html หรือไม่
      control_led(LED_R);				//ถ้ามีให้เปลี่ยนสถานะ LEDสีแดง
  else if (req.indexOf("/green.html") != -1)    //ตรวจสอบว่ามีการร้องขอ File green.html หรือไม่
      control_led(LED_G);				//ถ้ามีให้เปลี่ยนสถานะ LEDสีเขียว
   else if (req.indexOf("/blue.html") != -1) //ตรวจสอบว่ามีการร้องขอ File blue.html หรือไม่
      control_led(LED_B);			//ถ้ามีให้เปลี่ยนสถานะ LEDน้ำเงิน
   else if(req.indexOf("/Temp_Humi.html") != -1) /*ตรวจสอบว่ามีการเรียกขอ File      
                                                                                      Temp_Humi.html หรือไม่*/ 
    {
      float h = dht.readHumidity();			//อ่านค่า Humidity
      float t = dht.readTemperature();		//อ่านค่า Temp
      String humi="<h3>\r\n";			//เก็บ Code HTML ลงตัวแปร String
	     humi+="<center>\r\n";
/*แปลงค่า Temp และ Humidity เป็น String และ รวมเข้าไปใน HTML*/
	     humi+="Temp = "+ String(t) +"C &nbsp;&nbsp; Humidity ="+ String(h)+"%\r\n"; 
             humi+="</center>\r\n";
             humi+="</h3>\r\n";
      client.print(humi);		//ส่งข้อมูลไปยัง Client
  }
  else if(req.indexOf("/temp.jpg") != -1)	//ตรวจสอบว่ามีการร้องขอ temp.jpg หรือไม่
    open_and_send_file(client,"temp.jpg"); // ถ้ามีให้อ่านFile ใน SD แล้วส่งกลับไปให้ Client 
  else if(req.indexOf("/humi.jpg") != -1) //ตรวจสอบว่ามีการร้องขอ humi.jpg หรือไม่
    open_and_send_file(client,"humi.jpg"); // ถ้ามีให้อ่านFile ใน SD แล้วส่งกลับให้ Client
  else if(req.indexOf("/") != -1)		//ตรวจสอบว่ามีการร้องขอ file root (index.htm) หรือไม่
  {
    client.flush();
    String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
    client.print(web);
    open_and_send_file(client,"index.htm");	//อ่านFile แล้วส่งกลับไปให้ Client
  }
}

void open_and_send_file(WiFiClient client_in,const char* path) /*functionอ่าน File แล้วส่งไปให้ Client*/
{
    myFile = SD.open(path);	//เปิด File
    size_t totalSize = myFile.size(); 	//อ่านขนาด File 
    if (client_in.write(myFile, 2000) != totalSize)  //อ่าน File แล้วส่งออกไปให้ Client 
    {
        Serial.println("Sent less data than expected!");
    }
    myFile.close();	//ปิด File 
}
void control_led(int pin) //function เปลี่ยนสถานะ LED 
{
     unsigned char state = digitalRead(pin);  // อ่านสถานะของ Pin
     digitalWrite(pin,!state);	//กำหนดสถานะของ Pin ให้ตรงข้ามกับค่าปัจจุบัน
     digitalWrite(BUZZ,LOW);	//ให้ Buzzerทำงาน
     delay(200);			//หน่วงเวลา
     digitalWrite(BUZZ,HIGH);	//ให้ Buzzer หยุดทำงาน
}

ทดลอง Run Program

         - ให้ Copy File index.htm, temp.jpg, humi.jpg ลงใน root ของ SD Card แล้วใส่ SD Card ลงใน Module SD Card
         - Compile และ Run Program
         - เปิด Web browser ไปยัง IP ของ NodeMCU

62

 

 

<< ย้อนกลับหน้าสารบัญ

Newsletter

Follow Us