ในโปรเจคนี้เราจะมาควบคุมอุปกรณ์อิเล็กทรอนิกส์ของเราด้วยมือถือกันดีกว่า! เราจะใช้ NodeMCU ESP8266 ทำเป็น Web Server แล้วสร้างหน้าเว็บที่ใช้ AJAX เพื่อให้หน้าเว็บตอบสนองได้ลื่นไหล ไม่ต้องรอรีเฟรชหน้าทุกที จัดไปวัยรุ่น!
วิธีนี้จะช่วยกำจัดปัญหาหน้าจอกระพริบและความจำเป็นต้องรีโหลดหน้าเว็บใหม่ทั้งหมด โดยใช้ XMLHttpRequest กับ Javascript แทน
มาดูตัวอย่างการทำงานกันหน่อย
รุ่นพี่ได้เขียนขั้นตอนการทำโปรเจคนี้ไว้แบบละเอียดยิบเลย (แต่ลิงค์ขอไม่แปะนะ เดี๋ยวโดนหาว่าโปรโมท) ใครอยากรู้รายละเอียดลึกๆ ว่าตั้งแต่เริ่มจนจบทำยังไง ค่อยไปหาอ่านเพิ่มเติมกันเองนะน้อง
โค้ดทั้งหมดรุ่นพี่อัพไว้ให้แล้วใน GitHub ตามลิงค์ด้านล่างนี้ (อันนี้แปะได้) ห้ามช็อตนะตัวนี้
เราใช้ Arduino IDE ในการโปรแกรม NodeMCU ESP8266 Web Server นี้ โดยต้องติดตั้ง ESP8266 Core Addon ให้เรียบร้อยก่อน
Asynchronous Telemetry: The ESP8266 AJAX Web Server
เว็บเซิร์ฟเวอร์แบบ Arduino ทั่วไปมันจะบังคับให้รีโหลดหน้าเว็บทั้งหน้าใหม่ทุกครั้งที่เราต้องการเช็คสถานะปุ่มหรือข้อมูล ESP8266 AJAX Web Server แก้ปัญหานี้ด้วยการใช้ Asynchronous JavaScript and XML (AJAX) พอเราเปิดหน้าเว็บ มันจะโหลดมาแค่ครั้งเดียว จากนั้น Javascript ที่รันอยู่ในเบราว์เซอร์ของเราจะสามารถส่งคำขอไปหา ESP8266 ในพื้นหลังเพื่ออัปเดตข้อมูลหรือส่งคำสั่งได้ โดยไม่ต้องรีโหลดหน้าเว็บทั้งหน้าอีกเลย ทำให้ประสบการณ์ผู้ใช้ลื่นไหล ตอบสนองดี และดูโมเดิร์นขึ้นมาก
การจัดโครงสร้างระบบไฟล์ด้วย SPIFFS
การเขียนโค้ด HTML, CSS และ JavaScript เป็นร้อยๆ บรรทัดลงในตัวแปร String ของ Arduino โดยตรงนี่มันไม่เวิร์กเลยสักนิด นี่คือจุดที่ ESP8266 SPIFFS (SPI Flash File System) เข้ามาช่วย SPIFFS อนุญาตให้เราเก็บไฟล์หน้าเว็บ (เช่น index.html, style.css, script.js) ลงในหน่วยความจำแฟลชของ ESP8266 โดยตรง แยกออกจากโค้ดโปรแกรม
- เราสร้างไฟล์
index.htmlของเราขึ้นมา พร้อมกับ HTML, CSS และ JavaScript ทั้งหมด - JavaScript จะใช้ออบเจ็กต์
XMLHttpRequestเพื่อสื่อสารกับเซิร์ฟเวอร์แบบ asynchronous (ไม่ต้องรอ)
ตัวอย่างเช่น JavaScript snippet ต่อไปนี้จะส่งคำขอไปหาเซิร์ฟเวอร์ทุกๆ 2 วินาทีเพื่อดึงค่าจากเซนเซอร์:
setInterval(function() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// อัปเดตองค์ประกอบบนหน้าเว็บด้วยข้อมูลใหม่
document.getElementById("temperature").innerHTML = this.responseText;
}
};
// ส่งคำขอ GET ไปยัง endpoint '/readTemp' บน ESP8266
xhttp.open("GET", "/readTemp", true);
xhttp.send();
}, 2000); // ส่งคำขอทุกๆ 2000 มิลลิวินาที
วิเคราะห์ GET Request แบบเป๊ะๆ
ฝั่ง Arduino (C++) นะน้อง ตัวโค้ดจะตั้งเซิร์ฟเวอร์เว็บขึ้นมาเพื่อรอรับคำขอแบบนี้โดยเฉพาะ ไลบรารีสำคัญที่ต้องมีคือ:
#include <ESP8266WiFi.h>สำหรับเชื่อมต่อเน็ต#include <ESP8266WebServer.h>สำหรับจัดการ HTTP requests
จากนั้นเราก็ต้องกำหนดฟังก์ชัน handler สำหรับแต่ละ endpoint ของ URL ตามตัวอย่าง JavaScript ข้างบน เราก็จะสร้าง handler สำหรับพาธ /readTemp แบบนี้:
server.on("/readTemp", [](){
int sensorValue = analogRead(A0); // อ่านค่าจากเซนเซอร์
server.send(200, "text/plain", String(sensorValue));
});
ฟังก์ชันนี้จะถูกเรียกใช้งานทันทีที่ ESP8266 ได้รับ GET request ไปที่ /readTemp มันจะอ่านค่าจากเซนเซอร์ แปลงค่าเป็น String แล้วส่งกลับมาเป็น plain text response ซึ่งฝั่ง JavaScript XMLHttpRequest object ก็จะรับค่ากลับไปใช้งานต่อนั่นเอง
อุปกรณ์และสกิลที่ต้องมี
- NodeMCU ESP8266 หรือ ESP32 (ไมโครคอนโทรลเลอร์เจ้าบ้านที่รันเว็บเซิร์ฟเวอร์)
- ความชำนาญด้าน Frontend (HTML, CSS, JS) (เพื่อออกแบบ UI ที่สวยงามและ responsive ในบราวเซอร์)
- เซนเซอร์พื้นฐานอย่าง DHT11 / โพเทนชิโอมิเตอร์ (ตัวอย่างอุปกรณ์สำหรับควบคุมหรืออ่านข้อมูล)