NTP ESP32 – Lấy ngày tháng từ Internet cho ESP32 bằng Arduino IDE

Trong bài hướng dẫn này, mình sẽ hướng dẫn bạn cách cập nhật ngày tháng và thời gian hiện tại cho ESP32, sử dụng Arduino IDE và giao thức NTP ESP32.

Ngày tháng và thời gian rất có ích trong việc bạn cần ghi log lại các sự kiện đọc dữ liệu của cảm biến hoặc bật tắt các thiết bị theo giờ cụ thể trong các dự án IoT. Cách thức này đòi hỏi ESP32 phải có kết nối Internet và sẽ lấy ngày tháng, thời gian từ Internet thông qua giao thức NTP (Network Time Protocol). Cách thức này có lợi điểm là chúng ta sẽ không cần thêm phần cứng hỗ trợ nào khác (ví dụ như các module RTC).

NTP ESP32 - Lấy ngày tháng real time từ Internent

Trước khi thực hiện được hướng dẫn này, bạn cần tham khảo bài viết hướng dẫn cài đặt Arduino IDE và add-on hỗ trợ lập trình cho ESP32:

Giao thức NTP (Network Time Protocol)

NTP là viết tắt của từ Network Time Protocol, là giao thức đồng bộ thời gian giữa các thiết bị qua môi trường mạng. Trong một hệ thống mạng, việc đồng bộ thời gian cho tất cả các máy chủ lá rất quan trọng cho công tác quản lý, bảo mật và dễ dàng kiểm tra lại lịch sử các hoạt động trên các máy khi có sự cố xảy ra.

Trên Internet có nhiều server NTP có thể truy cập và lấy thông tin miễn phí như pool.ntp.org. Trong bài hướng dẫn này, bạn sẽ lập trình cho ESP32 đóng vai trò NTP client và gửi request lên NTP server miễn phí này để lấy thời gian ngày tháng hiện tại.

NTP ESP32 - Theo dõi ngày giờ
Giới thiệu về NTP ESP32

Lấy ngày tháng thời gian từ server NTP ESP32

Để ESP32 có thể lấy được ngày tháng và thời gian từ Internet, bạn chỉ cần thêm thư viện time.h trong chương trình là được.

Chương trình Arduino sau sẽ cho ESP32 kết nối WiFi và lấy thời gian từ server NTP ESP32 trên Internet và in ra cửa sổ Serial Monitor của Arduino. Đoạn chương trình này dựa trên ví dụ mẫu của thư viện time.h.

#include <WiFi.h>
#include "time.h"

const char* ssid     = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 25200;
const int   daylightOffset_sec = 0;

void setup(){
  Serial.begin(115200);

  // Connect to Wi-Fi
  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.");
  
  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop(){
  delay(1000);
  printLocalTime();
}

void printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
  Serial.print("Day of week: ");
  Serial.println(&timeinfo, "%A");
  Serial.print("Month: ");
  Serial.println(&timeinfo, "%B");
  Serial.print("Day of Month: ");
  Serial.println(&timeinfo, "%d");
  Serial.print("Year: ");
  Serial.println(&timeinfo, "%Y");
  Serial.print("Hour: ");
  Serial.println(&timeinfo, "%H");
  Serial.print("Hour (12 hour format): ");
  Serial.println(&timeinfo, "%I");
  Serial.print("Minute: ");
  Serial.println(&timeinfo, "%M");
  Serial.print("Second: ");
  Serial.println(&timeinfo, "%S");

  Serial.println("Time variables");
  char timeHour[3];
  strftime(timeHour,3, "%H", &timeinfo);
  Serial.println(timeHour);
  char timeWeekDay[10];
  strftime(timeWeekDay,10, "%A", &timeinfo);
  Serial.println(timeWeekDay);
  Serial.println();
}

Giải thích chương trình

Phần đầu chương trình là khai báo các thư viện để kết nối WiFi và thư viện time.h để làm việc với NTP ESP32.

#include <WiFi.h>
#include "time.h"

Khai báo SSID và Password của mạng WiFi

Để chương trình chạy được, bạn cần thay đổi các thông tin này cho đúng với mạng WiFi mà bạn đang sử dụng để ESP32 có thể kết nối và gửi yêu cầu lên server NTP ESP32 qua Internet.

// Replace with your network credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

Khai báo server NTP và cấu hình thời gian

Bạn có thể thay đổi các thông số về server NTP và múi giờ GMT với 3 biến: ntpServer, gmtOffset_sec and daylightOffset_sec.

Server NTP

Server NTP chúng ta sử dụng là để lấy thời gian là pool.ntp.org.

const char* ntpServer = "pool.ntp.org";

GMT Offset

Biến gmtOffset_sec khai báo múi giờ theo đơn vị là giây. Múi giờ của VN là GMT +7 nên chúng ta khai báo biến này có giá trị là 7 giờ x 60 phút x 60 giây = 25.200 giây

const long gmtOffset_sec = 25200;

Daylight Offset

Biến này khai báo múi giờ Daylight Saving Time thường được sử dụng ở các nước phương Tây. Ở VN chúng ta không sử dụng nên trong chương trình biến này có giá trị bằng 0.

const int daylightOffset_sec = 0;

setup()

Trong hàm setup(), chương trình khởi tạo chức năng Serial với baud rate là 115200 để in ra kết quả đọc được từ NTP server:

Serial.begin(115200);

Sau đó cho ESP32 kết nối với WiFi được khai báo.

// Connect to Wi-Fi
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.");

Cấu hình về server NTP ESP32 và múi giờ như các biến đã khai báo ở trên:

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

printLocalTime()

Sau khi cấu hình, hàm printLocalTime() sẽ in ra thời gian ở cửa sổ Serial Monitor.

Trong hàm này, một biến dạng cấu trúc struct tm tên là timeinfo được dùng để chứa thông tin về ngày tháng và thời gian lấy được từ server NTP (giờ, phút, giây…).

struct tm timeinfo;

struct loại tm bao gồm các thông tin sau:

  • tm_sec: seconds after the minute;
  • tm_min: minutes after the hour;
  • tm_hour: hours since midnight;
  • tm_mday: day of the month;
  • tm_year: years since 1900;
  • tm_wday: days since Sunday;
  • tm_yday: days since January 1;
  • tm_isdst: Daylight Saving Time flag;
  • Tham khao thêm tài liệu về tm structure ở đây.

Lấy toàn bộ thông tin về ngày tháng và thời gian vào biến timeinfo.

if(!getLocalTime(&timeinfo)){
  Serial.println("Failed to obtain time");
  return;
}

Và in ra cửa sổ Serial Monitor.

Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
Serial.print("Day of week: ");
Serial.println(&timeinfo, "%A");
Serial.print("Month: ");
Serial.println(&timeinfo, "%B");
Serial.print("Day of Month: ");
Serial.println(&timeinfo, "%d");
Serial.print("Year: ");
Serial.println(&timeinfo, "%Y");
Serial.print("Hour: ");
Serial.println(&timeinfo, "%H");
Serial.print("Hour (12 hour format): ");
Serial.println(&timeinfo, "%I");
Serial.print("Minute: ");
Serial.println(&timeinfo, "%M");
Serial.print("Second: ");
Serial.println(&timeinfo, "%S");

Để đọc các thông tin trong struct loại tm, bạn có thể sử dụng các khai báo định dạng hiển thị sau:

%ATên ngày trong tuần
%BTên tháng
%dSố ngày trong tháng
%YNăm
%HGiờ theo format 24h
%IGiờ theo format 12h
%MPhút
%SGiây

Một số khai báo định dạng khác mà bạn có thể sử dụng như: tên tháng viết tắt (%b), tên tuần viết tắt (%a), số tuần trong năm (%U), và một số khác tham khảo ở đây .

Trong chương trình trên, bạn cũng thấy được cách lưu một thông tin cụ thể nào đó vào biến để có thể xử lý riêng thay vì chỉ in ra màn hình Serial Monitor. Ví dụ, nếu bạn muốn lưu giờ hiện tại vào biến tên là timeHour, bạn sẽ tạo ra một biến chuỗi ký tự có chiều dài 3 ký tự (dữ liệu và thêm ký tự kết thúc chuỗi) và copy giá trị hour trong timeinfo vào bằng hàm strftime().

Serial.println("Time variables");
char timeHour[3];
strftime(timeHour,3, "%H", &timeinfo);
Serial.println(timeHour);

Chúng ta làm tương tự cho tên ngày trong tuần với một chuỗi có tối đa 9 ký tự (tên ngày trong tuần dài nhất là saturday).

char timeWeekDay[10];
strftime(timeWeekDay,10, "%A", &timeinfo);
Serial.println(timeWeekDay);
Serial.println();

Kết quả khi chạy

Sau khi đã khai báo chính xác các thông tin trong chương trình, bạn nạp code và quan sát kết quả đọc được trên cửa sổ Serial Monitor và sẽ thấy thời gian được in ra như hình bên dưới.

NTP ESP32 - Theo dõi ngày giờ

Lời kết

Trong bài hướng dẫn này, bạn đã biết cách viết chương trình đọc thời gian và ngày tháng từ Internet cho ESP32 qua giao thức NTP trên Arduino IDE. Bạn có thể ứng dụng trong các chương trình cần đọc các chỉ số cảm biến và lưu lại thời gian khi đọc.

Nhược điểm của phương pháp này là ESP32 cần phải kết nối với Internet. Nếu dự án bạn không thể truy cập Internet thì bạn cần phải sử dụng có module phần cứng hỗ trợ như các module RTC DS1307.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *