ESP32

ESP32 NTP 클라이언트-서버: 날짜 및 시간 가져오기(Arduino IDE)

기하 2021. 8. 16. 05:35

Arduino IDE와 함께 ESP32를 사용하여

NTP서버에서 날짜와 시간을 요청하는 방법을 알아봅니다. 

 

날짜와 시간을 가져오는 것은

데이터 로깅 프로젝트에서 판독값을 타임스탬프하는 데 유용합니다. 

NTP 서버에서 시간을 얻으려면 

ESP32 가 인터넷에 연결되어 있어야 하며

추가 하드웨어(예: RTC 시계)가 필요하지 않습니다.

NTP(네트워크 시간 프로토콜)

NTP는 Network Time Protocol의 약자로 컴퓨터 시스템 간의

시계 동기화를 위한 네트워킹 프로토콜입니다. 

즉, 네트워크에서 컴퓨터 시계 시간을 동기화하는 데 사용됩니다.

 

pool.ntp.org 와 같은 NTP 서버가 있어 누구나 클라이언트로 시간을 요청할 수 있습니다. 

이 경우 ESP32는 NTP 서버( kr.pool.ntp.org ) 에서 시간을 요청하는 NTP 클라이언트입니다 .

 

NTP 서버에서 날짜 및 시간 가져오기

ESP32로 날짜와 시간을 얻으려면 라이브러리를 설치할 필요가 없습니다. 

당신의 코드에  time.h 라이브러리.만 포함하면 됩니다.

 

다음 코드는 NTP 서버에서 날짜와 시간을 가져와 직렬 모니터에 결과를 인쇄합니다. 

time.h 라이브러리에서 제공하는 샘플 코드입니다

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-date-time-ntp-client-server-arduino/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

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

const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const char* ntpServer = "kr.pool.ntp.org";
//3200초는 1시간. 우리나라는 GMT+9 이므로 3600x9=32400
const long  gmtOffset_sec = 32400;

//섬머타임 적용시 3600(시간을 1시간빠르게함)
//우리나라는 시행 않함으로 0
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();
}

 

#include <WiFi.h>
#include "time.h"
 
const char* ssid       = "ssid"; //와이파이 SSID
const char* password   = "password";  //와이파이 패스워드
 
const char* ntpServer = "kr.pool.ntp.org";
 
//3200초는 1시간, 우리나라는 GMT+9 이므로 3600초x9 = 32400 해 줌
const long  gmtOffset_sec = 32400; 
 
//섬머타임 적용 시 3600 (시간을 1시간 빠르게 함)
//우리나라는 시행 안하므로 0
const int   daylightOffset_sec = 0; 
 
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");
}
 
void setup()
{
  Serial.begin(115200);
  
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" 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();
}


출처: https://deneb21.tistory.com/594 [Do It Yourself!]

코드 작동 방식

코드가 어떻게 작동하는지 간단히 살펴보겠습니다. 

먼저 Wi-Fi에 연결하고 시간을 확보할 라이브러리를 포함합니다.

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

SSID 및 비밀번호 설정

ESP32가 인터넷 연결을 설정하고 NTP 서버에서 날짜와 시간을 가져올 수 있도록

다음 변수에 네트워크 자격 증명을 입력합니다.

const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

NTP 서버 및 시간 설정

그런 다음 NTP 서버에서 시간을 구성하고 가져오려면 다음 변수를 정의해야 합니다. 

 

ntpServer, gmtOffset_sec and daylightOffset_sec.

 

NTP Server

우리의 시간을 요청해야합니다. 

pool.ntp.org 사람이 시간을 요청하는 데 사용할 수있는 시간 서버의 클러스터입니다.

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

GMT Offset

gmtOffset_sec변수는 시간대와 GMT 사이의 오프셋을 초 단위로 정의합니다. 

gmtOffset_sec 를 자신의 시간대와 일치시켜야 합니다.

const long gmtOffset_sec = 32400; // GMT+9 - 3600*9 = 32400

Daylight Offset

daylightOffset_sec변수는 섬머타임 시간의 오프셋을 초 단위로 정의합니다. 

일반적으로 3600초에 해당하는 1시간입니다.

const int daylightOffset_sec = 0;

setup() 함수

setup() 에서 결과를 인쇄하기 위해 전송 속도 115200에서 직렬 통신을 초기화합니다.

Serial.begin(115200);

다음 줄은 ESP32를 Wifi에 연결합니다.

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

이전에 정의한 설정으로 시간을 구성합니다.

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

printLocalTime()

 

시간을 설정한 후, printLocalTime() 는 시리얼 모니터에서 시간을 출력하는 기능입니다.

해당 함수에서 timeinfo 라고 불리는 시간구조( struct tm) 를 만들며  

여기에는 시간(분, 초, 시간 등)에 대한 모든 세부 정보를 포함합니다.

struct tm timeinfo;

tm 구조체에는 구성 요소로 분류된 달력 날짜 및 시간이 포함됩니다.

  • tm_sec: 분 후 초
  • tm_min: 시간 후 분;
  • tm_hour: 자정 이후 시간;
  • tm_mday: 그 달의 일;
  • tm_year: 1900년 이후 몇 년;
  • tm_wday: 일요일 이후의 일;
  • tm_yday: 1월 1일 이후의 일;
  • tm_isdst: 일광 절약 시간 플래그;
  • 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");

 

날짜 및 시간 구조의 멤버에 액세스하려면 다음 지정자를 사용할 수 있습니다.

%A 전체 요일 이름
%B 전체 월 이름
%d 달의 날
%Y 년도
%H 24시간 형식의 시간
%l 12시간 형식의 시간
%M
%S

다른 형식으로 정보를 가져오는 데 사용할 수 있는 다른 지정자가 있습니다.

예: 축약된 월 이름(%b), 축약된 요일 이름(%a),

첫 번째 일요일이 첫 번째 주의 첫 번째 날인 주 번호(%U) 및 기타( 더 읽기 ).

 

또한 시간에 대한 정보를 변수에 저장하려는 경우 예를 보여줍니다. 

예를 들어 시간을 timeHour변수에 저장하려는 경우 길이가 3자인 char 변수를 만듭니다

(시간 문자와 종료 문자를 저장해야 함). 그런 다음 에 있는 시간에 대한 정보를 복사합니다.

strftime() 함수를 사용하여 timeinfo 구조체에 있는 시간정보를 timeHour 변수에 복사합니다.

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

다른 변수를 얻으려면 유사한 프로세스를 사용하십시오. 

예를 들어, 요일의 경우 한 주의 가장 긴 요일이 9자(토요일)를 포함하기 때문에

길이가 10자인 char 변수를 생성해야 합니다.

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

데모

네트워크 자격 증명을 삽입하고 변수를 수정하여

시간대 및 일광 절약 시간제를 변경한 후 예제를 테스트할 수 있습니다.

ESP32 보드에 코드를 업로드하십시오. 올바른 보드와 COM 포트를 선택했는지 확인하십시오. 

코드를 업로드한 후 ESP32 "Enable" 버튼을 누르면 다음 그림과 같이 1초마다 날짜와 시간이 표시됩니다.

 

마무리

이 튜토리얼에서는 Arduino IDE로 프로그래밍된 ESP32를 사용하여

NTP 서버에서 날짜와 시간을 가져오는 방법을 배웠습니다. 

이제 여기에서 배운 내용을 사용하여 자신의 프로젝트에서

센서 판독값을 타임스탬프로 지정할 수 있습니다.

 

이 방법은 ESP32가 인터넷에 연결된 경우에만 작동합니다. 

프로젝트에서 인터넷에 액세스할 수 없는 경우 다른 방법을 사용해야 합니다.