บทความนี้เป็นตัวอย่างการใช้ไลบรารี NTP และ TimeLib ของเฟรมเวิร์ก Arduino กับ ESP-01s (ดังภาพที่ 1) หรือ esp8266 เพื่อรายงานเวลาปัจจุบันผ่านทางเว็บที่ให้บริการโดยไมโครคอนโทรลเลอร์ esp8266 ซึ่งในตัวอย่างนี้มีการเรียกใช้ไลบรารี NTPClient และ TimeLib โดยต้องมีการเชื่อมต่อเข้ากับเครือข่ายอินเทอร์เน็ตในการอ่านวันที่และเวลาจากเครื่องให้บริการ NTP เช่น time.nist.gov เป็นต้น
อุปกรณ์
อุปกรณ์สำหรับการทดลองในครั้งนี้ คือ โมดูล ESP-01s หรือ ESP-01 พร้อมชุดโปรแกรมชิพและใช้งานชิพ โดยพวกเราใช้บอร์ด dCore-0 รุ่น 0.7 ที่พัฒนาขึ้น หรือ บอร์ด NodeMCU
NTPClient
การเรียกใช้บริการ NTP หรือ Network Time Protocol ซึ่งเป็นโพรโทคอลสำหรับอ่านค่าวันที่และเวลาบทเครือข่ายทำให้เครื่องในเครือข่ายนั้นตั้งเวลาได้ตรงกันหรือคลาดเคลื่อนน้อยที่สุด นอกจากนี้ด้วยการที่เป็นโพรโทคอลที่ทำงานแบบ UDP จึงมีความรวดเร็วในการสื่อสาร ดังนั้น การเรียกใช้ไลบรารี NTPClient ขึงต้องเรียกใช้ไฟล์ส่วนหัวดังนี้
#include <NTPClient.h>
#include <WiFiUdp.h>
การสร้างวัตถุประเภท NTP เพื่อใช้สำหรับเป็นตัวอ้างอิงการทำงานทำดังนี้
WiFiUdp ชื่อวัตถุยูดีพี;
NTPClient ชื่อวัตถุ( ชื่อวัตถุยูดีพี, “ชื่อเครื่องให้บริการntp”, ค่าช่วงเวลา, time_interval )
ซึ่งค่าชื่อเครื่องให้บริการntp ที่เป็นแหล่งหลัก คือ time.nist.gov และค่าช่วงเวลาเป็นค่าระบุจำนวนวินาทีจากเวลาของกรีนิช ดังนั้น เมื่อใช้กับประเทศไทยจึงเป็นค่า 7*3600 หรือ GMT+7 โดยรายชื่อเครื่องให้บริการ NTP ภายในประเทศไทยได้แก่
- 1.th.pool.ntp.org
- asia.pool.ntp.org
- 1.asia.pool.ntp.org
- time.navy.mi.th (เวลามาตรฐานประเทศไทย โดย กรมอุทกศาสตร์ กองทัพเรือ)
- time2.navy.mi.th (เวลามาตรฐานประเทศไทย โดย กรมอุทกศาสตร์ กองทัพเรือ)
คำสั่งที่สามารถใช้งานได้เป็นดังนี้
- ชื่อวัตถุ.begin() เริ่มต้นการทำงานของ NTPClient
- ชื่อวัตถุ.update() สั่งซิงค์ข้อมูล
- ตัวแปร = ชื่อวัตถุ.getEpochTime() สำหรับอ่านค่าวันที่และเวลาในรูปแบบ UNIX ไปเก็บไว้ในตัวแปร
TimeLib
ทางเราเลือกใช้ไลบรารี Time หรือ TimeLib.h ของ Paul Stoffregen บน github เป็นไลบรารีช่วยจัดการแปลงข้อมูลวันที่และเวลาที่อยู่ในรูปแบบของ NTPClient โดยต้องดาวน์โหลดจาก github และคัดลอกไปไว้ในโฟลเดอร์ libraries ของ Arduino หลังจากนั้นเรียกใช้ด้วยการนำเข้าไฟล์ TimeLib.h ดังนี้
#include <TimeLib.h>
คำสั่งใช้งานมีดังนี้
- hour() สำหรับอ่านข้อมูลค่าชั่วโมง ซึ่งมีช่วงค่า 0 ถึง 23
- minute() สำหรับอ่านข้อมูลค่านาที ซึ่งมีช่วงค่า 0 ถึง 59
- second() สำหรับอ่านข้อมูลค่าวินาที ซึ่งมีช่วงค่า 0 ถึง 59
- day() สำหรับอ่านข้อมูลค่าวัน ซึ่งมีช่วงค่า 1 ถึง 31
- weekday() สำหรับอ่านข้อมูลค่าวันในสัปดาห์ มีช่วงค่า 1 ถึง 7
- month() สำหรับอ่านข้อมูลค่าเดือน มีช่วงค่า 1 ถึง 12
- year() สำหรับอ่านข้อมูลค่าปีแบบ ค.ศ.
- hourFormat12() สำหรับตั้งการทำงานของรูปแบบชั่วโมงเป็น 12 ชั่วโมง
- isAM() สำหรับตรวจสอบค่าชั่วโมงที่อ่านได้นั้นเป็นหลังเที่ยงคืนและก่อนเที่ยงวัน
- isPM() สำหรับตรวจสอบค่าชั่วโมงที่อ่านได้นั้นเป็นหลังเที่ยงวันและก่อนเที่ยงคืน
- now() สำหรับอ่านข้อมูลค่าเวลาปัจจุบัน
- setTime() สำหรับตั้งค่าวันที่และเวลาจากค่า time_t
- adjustTime() สำหรับตั้งค่าวันที่และเวลา
- timeStatus() สำหรับอ่านข้อมูลค่าสถานะของการซิงค์เวลา ซึ่งคืนค่าเป็น
- timeNotSet หมายถึงวันที่และเวลานั้นไม่เคยถูกตั้งค่า
- timeNeedsSync หมายถึงต้องดำเนินการซิงค์ค่าวันที่และเวลา
- timeSet หมายถึงวันที่และเวลาถูกตั้งค่าและซิงค์แล้ว
- setSyncProvider() สำหรับกำหนดตัวให้ค่าวันที่และเวลาจากภายนอก
- setSyncInterval() สำหรับกำหนดระยะเวลาของการซิงค์วันที่และเวลา
ตัวอย่างโปรแกรม
ตัวอย่างโปรแกรมสำหรับเชื่อมต่อและอ่านค่าวันที่/เวลาจาก time.nist.gov และเก็บสตริงวันที่และเวลาในตัวแปร dateMsg และ timeMsg เป็นดังนี้
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <TimeLib.h>
const char *ssid = "ชื่อap";
const char *password = "รหัสของap";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "time.nist.gov", 7 * 3600, 60000);
unsigned long unix_epoch;
char dateMsg[64];
char timeMsg[64];
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(".");
}
timeClient.begin();
}
void showRTC() {
char dow_matrix[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
byte x_pos[7] = {29, 29, 23, 11, 17, 29, 17};
static byte previous_dow = 0;
if ( previous_dow != weekday(unix_epoch) ) {
previous_dow = weekday(unix_epoch);
}
sprintf( dateMsg, "%02u-%02u-%04u", day(unix_epoch), month(unix_epoch), year(unix_epoch) );
sprintf( timeMsg, "%02u:%02u:%02u", hour(unix_epoch), minute(unix_epoch), second(unix_epoch) );
Serial.println(dateMsg);
Serial.println(timeMsg);
}
void loop() {
timeClient.update();
unix_epoch = timeClient.getEpochTime(); // get UNIX Epoch time
showRTC();
delay(500);
}
เมื่อนำไปประยุกต์เข้ากับการให้ไมโครคอนโทรลเลอร์ esp8266 เป็นตัวให้บริการ AP และเมื่อเข้าเว็บของชิพจะรายงานวันที่และเวลาดังตัวอย่างภาพที่ 2
สรุป
จากบทความนี้จะพบว่า ไมโครคอนโทรลเลอร์ esp8266 หรือโมดูลตระกูล ESP-01/ESP-01s ทำให้สามารถเข้าใช้บริการ NTP ได้อย่างสะดวก ดังนั้น เมื่อพัฒนาระบบที่เกี่ยวข้องกับวันที่และเวลาจึงสามารถเข้าใช้ค่าที่ตรงกับประเทศที่กำหนดได้ ซึ่งสามารถนำไปประยุกต์เข้ากับการทำ data logger ที่เก็บค่าจากเซ็นเซอร์และบันทึกค่าตามวันที่และเวลาที่กำหนด โดยไม่ต้องติดตั้งวงจรของชุด RTC เพิ่มเติม สุดท้ายนี้ขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ
แหล่งอ้างอิง
- Paul Stoffregen : Time
- ThaiCERT : NTP Reflection DDoS attack
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-08-29, 2021-11-26