บทความนี้เป็นตัวอย่างการใช้ไลบรารี NTP และ TimeLib ของเฟรมเวิร์ก Arduino กับ ESP-01s (ดังภาพที่ 1) หรือ esp8266 เพื่อรายงานเวลาปัจจุบันผ่านทางเว็บที่ให้บริการโดยไมโครคอนโทรลเลอร์ esp8266 ซึ่งในตัวอย่างนี้มีการเรียกใช้ไลบรารี NTPClient และ TimeLib โดยต้องมีการเชื่อมต่อเข้ากับเครือข่ายอินเทอร์เน็ตในการอ่านวันที่และเวลาจากเครื่องให้บริการ NTP เช่น time.nist.gov เป็นต้น

ภาพที่ 1 โมดูล ESP-01s บนบอร์ด dCore-0 รุ่น 0.7

อุปกรณ์

อุปกรณ์สำหรับการทดลองในครั้งนี้ คือ โมดูล 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. 1.th.pool.ntp.org
  2. asia.pool.ntp.org
  3. 1.asia.pool.ntp.org
  4. time.navy.mi.th (เวลามาตรฐานประเทศไทย โดย กรมอุทกศาสตร์ กองทัพเรือ)
  5. time2.navy.mi.th (เวลามาตรฐานประเทศไทย โดย กรมอุทกศาสตร์ กองทัพเรือ)

คำสั่งที่สามารถใช้งานได้เป็นดังนี้

  1. ชื่อวัตถุ.begin() เริ่มต้นการทำงานของ NTPClient
  2. ชื่อวัตถุ.update() สั่งซิงค์ข้อมูล
  3. ตัวแปร = ชื่อวัตถุ.getEpochTime() สำหรับอ่านค่าวันที่และเวลาในรูปแบบ UNIX ไปเก็บไว้ในตัวแปร

TimeLib

ทางเราเลือกใช้ไลบรารี Time หรือ TimeLib.h ของ Paul Stoffregen บน github เป็นไลบรารีช่วยจัดการแปลงข้อมูลวันที่และเวลาที่อยู่ในรูปแบบของ NTPClient โดยต้องดาวน์โหลดจาก github และคัดลอกไปไว้ในโฟลเดอร์ libraries ของ Arduino หลังจากนั้นเรียกใช้ด้วยการนำเข้าไฟล์ TimeLib.h ดังนี้

#include <TimeLib.h>

คำสั่งใช้งานมีดังนี้

  1. hour() สำหรับอ่านข้อมูลค่าชั่วโมง ซึ่งมีช่วงค่า 0 ถึง 23
  2. minute() สำหรับอ่านข้อมูลค่านาที ซึ่งมีช่วงค่า 0 ถึง 59
  3. second() สำหรับอ่านข้อมูลค่าวินาที ซึ่งมีช่วงค่า 0 ถึง 59
  4. day() สำหรับอ่านข้อมูลค่าวัน ซึ่งมีช่วงค่า 1 ถึง 31
  5. weekday() สำหรับอ่านข้อมูลค่าวันในสัปดาห์ มีช่วงค่า 1 ถึง 7
  6. month() สำหรับอ่านข้อมูลค่าเดือน มีช่วงค่า 1 ถึง 12
  7. year() สำหรับอ่านข้อมูลค่าปีแบบ ค.ศ.
  8. hourFormat12() สำหรับตั้งการทำงานของรูปแบบชั่วโมงเป็น 12 ชั่วโมง
  9. isAM() สำหรับตรวจสอบค่าชั่วโมงที่อ่านได้นั้นเป็นหลังเที่ยงคืนและก่อนเที่ยงวัน
  10. isPM() สำหรับตรวจสอบค่าชั่วโมงที่อ่านได้นั้นเป็นหลังเที่ยงวันและก่อนเที่ยงคืน
  11. now() สำหรับอ่านข้อมูลค่าเวลาปัจจุบัน
  12. setTime() สำหรับตั้งค่าวันที่และเวลาจากค่า time_t
  13. adjustTime() สำหรับตั้งค่าวันที่และเวลา
  14. timeStatus() สำหรับอ่านข้อมูลค่าสถานะของการซิงค์เวลา ซึ่งคืนค่าเป็น
    1. timeNotSet หมายถึงวันที่และเวลานั้นไม่เคยถูกตั้งค่า
    2. timeNeedsSync หมายถึงต้องดำเนินการซิงค์ค่าวันที่และเวลา
    3. timeSet หมายถึงวันที่และเวลาถูกตั้งค่าและซิงค์แล้ว
  15. setSyncProvider() สำหรับกำหนดตัวให้ค่าวันที่และเวลาจากภายนอก
  16. 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

ภาพที่ 2 ตัวอย่างผลลัพธ์เมื่อนำไปประยุกต์กับการเป็น AP และให้บริการเว็บ

สรุป

จากบทความนี้จะพบว่า ไมโครคอนโทรลเลอร์ esp8266 หรือโมดูลตระกูล ESP-01/ESP-01s ทำให้สามารถเข้าใช้บริการ NTP ได้อย่างสะดวก ดังนั้น เมื่อพัฒนาระบบที่เกี่ยวข้องกับวันที่และเวลาจึงสามารถเข้าใช้ค่าที่ตรงกับประเทศที่กำหนดได้ ซึ่งสามารถนำไปประยุกต์เข้ากับการทำ data logger ที่เก็บค่าจากเซ็นเซอร์และบันทึกค่าตามวันที่และเวลาที่กำหนด โดยไม่ต้องติดตั้งวงจรของชุด RTC เพิ่มเติม สุดท้ายนี้ขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ

แหล่งอ้างอิง

  1. Paul Stoffregen : Time
  2. ThaiCERT : NTP Reflection DDoS attack

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ

ปรับปรุงเมื่อ 2021-08-29, 2021-11-26