ESP32 NTP: Đồng bộ ngày và giờ với mô hình Client Server

Trong bài hướng dẫn này, chúng ta sẽ cùng tìm hiểu về chủ đề ESP32 NTP – Làm máy chủ NTP dựa trên Arduino IDE, để lấy thông tin ngày và giờ đồng bộ. Đây là yếu tố quan trọng trong các dự án cần ghi dữ liệu theo từng mốc thời gian.

Để lấy thông tin ngày giờ từ NTP Server, ESP32 cần phải có kết nối Internet và bạn không cần dùng thêm các phần cứng bổ sung khác như đồng hồ RTC.

Giới thiệu NTP (Network Time Protocol)

NTP (Network Time Protocol) là giao thức mạng giúp đồng bộ hóa thời gian giữa các hệ thống máy tính trong mạng.

Một trong các NTP Server phổ biến là pool.ntp.org, bất kỳ ai cũng có thể yêu cầu thời gian từ Server này với tư cách là Client. Trong bài hướng dẫn này, IoTZone sẽ sử dụng ESP32 NTP như một máy khách để yêu cầu thời gian từ NTP Server này.

Giới thiệu về ESP32 NTP

Chương trình code lấy thời gian cho ESP32 NTP

Để lấy thời gian đồng bộ từ NTP Server, bạn chỉ cần thêm dòng time.h trong code chứ không cần cài bất kỳ thư viện nào khác.

Dưới đây là đoạn code mẫu để ESP32 NTP lấy thông tin ngày và giờ từ NTP Server và in kết quả ra màn hình Serial Monitor:

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

const char* ssid = "THAY_THE_BANG_TEN_WIFI_CUA_BAN";
const char* password = "THAY_THE_BANG_MAT_KHAU_CUA_BAN";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 7;
const int   daylightOffset_sec = 3600;

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

  // Kết nối WiFi
  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.");
  
  // Lấy thông tin thời gian
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //Ngắt kết nối WiFi khi không cần dùng đến
  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

Khai báo thư viện để ESP32 kết nối với WiFi và có thể lấy thời gian:

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

Đặt thông tin cho mạng WiFi (gồm tên và mật khẩu WiFi):

const char* ssid = "THAY_THE_BANG_TEN_WIFI_CUA_BAN";
const char* password = "THAY_THE_BANG_MAT_KHAU_CUA_BAN";

Ngoài ra, bạn cũng có thể dùng SmartConfig để ESP32 dễ dàng kết nối với mạng WiFi mới.

Cài đặt thời gian và NTP Server

Bạn cần cấu hình các thông tin sau để lấy được thời gian đúng từ máy chủ NTP về cho ESP32:

1. NTP Server

Như đã nói, ESP32 sẽ yêu cầu thời gian từ máy chủ Server có tên là pool.ntp.org. Đây là một máy chủ về thời gian mà bất kỳ ai cũng có thể yêu cầu thời gian từ nó:

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

2. Chọn GMT

Xác định múi giờ của mình, như ở Việt Nam thì múi giờ là 7:

const long gmtOffset_sec = 7;

3. Chọn độ lệch Daylight Off

Đây là độ lệch tính bằng giây, nói chung là 1 giờ tương ứng với 3600 giây:

const int daylightOffset_sec = 3600;

Setting()

Đầu tiên, bạn tạo giao tiếp nối tiếp ở tốc độ 115200. Chúng ta sẽ dùng chúng để in kết quả ngày và giờ đọc được từ mô hình Client Server:

Serial.begin(115200);

Kết nối ESP32 với bộ định tuyến:

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.");

Xác định cấu hình thời gian với các thông tin bạn đã chọn trước đó:

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

In thời gian

Sau khi cấu hình thời gian, bạn hãy gọi hàm printLocalTime() để in thời gian vào trong Serial Monitor.

Trong đó, hãy tạo cấu trúc thời gian (struct tm) có tên là timeinfo để chứa các thông tin chi tiết liên quan đến thời gian như giờ, phút,…

struct tm timeinfo;

Cấu trúc trên chứa thông tin về ngày và giờ, được chia thành các thành phần như sau:

  • tm_sec: giây sau phút;
  • tm_min: phút sau giờ;
  • tm_hour: giờ tính từ nửa đêm;
  • tm_mday: Ngày trong tháng;
  • tm_năm: Năm kể từ năm 1900;
  • tm_wday: Số ngày kể từ Chủ nhật;
  • tm_yday: Số ngày kể từ ngày 1 tháng 1;
  • tm_isdst: Cờ Daylight Saving Time;

Bạn lập trình ESP32 nhận tất cả các thông tin trên và lưu chúng vào cấu trúc timeinfo đã tạo:

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

In tất cả các thông tin trên ra màn hình 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");

Để vào xem các thành phần của cấu trúc ngày và giờ, bạn sử dụng cách xác định sau:

%ANgày trong tuần – tên đầy đủ
%BTên đầy đủ của tháng
%dNgày trong tháng
%YNăm
%HGiờ ở định dạng 24h
%IGiờ ở định dạng 12h
%MPhút
%SGiây

Ngoài ra, khi làm dự án ESP32 NTP thì bạn sẽ bắt gặp nhiều công cụ khác, để bạn lấy những thông tin khác, chẳng hạn như:

  • %b: Tên tháng viết tắt
  • %a: Tên ngày viết tắt
  • %U: Số tuần có chủ nhật đầu tiên là ngày 1 tháng 1….

Ngoài ra, bạn cũng có thể lưu thông tin về thời gian dưới dạng biến. Ví dụ, bạn lưu giờ vào một biến tên là timeHour, tạo một biến char với độ dài 3 ký tự (phải lưu ký tự giờ cộng với ký tự kết thúc). Sau đs, bạn sao chép thông tin đó trên cấu trúc TimeInfo vào TimeHour bằng cách sử dụng chức năng strftime():

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

Để lấy các biến khác, hãy dùng quy trình tương tự.

Ví dụ, đối với ngày trong tuần, bạn cần tạo biến char có độ dài là 10 ký tự, vì ngày dài nhất có đến 9 ký tự rồi (Saturday)

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

Demo

Sau khi chèn thông tin mạng WiFi của bạn và sửa đổi các cấu hình thông tin thời gian như múi giờ,… bạn có thể nạp code vào ESP32 và kiểm tra.

Sau khi Upload code vào ESP32, bạn hãy nhấn nút RST trên ESP32. Khi đó, trên màn hình Serial Monitor sẽ hiển thị thời gian ngày và giờ nhận được sau mỗi giây như hình:

Demo dự án ESP32 NTP trên Serial Monitor
Demo dự án ESP32 NTP trên Serial Monitor

Lời kết

Trong hướng dẫn này, IoTZone đã hướng dẫn bạn cách lấy thời gian ngày và giờ từ NTP Server và hiển thị chúng lên Serial Monitor (Arduino IDE) thông qua ESP32. Chúc bạn thành công với dự án ESP32 NTP này!

Phương pháp trên chỉ hoạt động được khi ESP32 được kết nối với Internet. Nếu mạch của bạn không có khả năng kết nối WiFi, bạn cần dùng thêm các module bên ngoài khác như RTC hoặc DS1307.

Chúc các bạn thành công! Đừng quên xem qua một số hướng dẫn về ESP32 khác của IoTZone:

IoTZone – Chuyên cung cấp thiết bị điện tử & tài liệu cho Makers

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 *