안녕하세요.
이전 내용에서는 (아두이노 나노 33 IoT로로 작은 웹서버 만들기) 작은 웹 서버를 만들어서 정보를 보여주었습니다.
이번에는 다른 서버에 있는 현재 시간 정보를 가져오는 것을 테스트해 보겠습니다.
NTP(Network Time Protocol) 서버에 접근해서 현재시간을 가져오도록 하겠습니다. 이렇게 하면 RTC(Real Time Clock) 회로를 꾸밀 필요가 없다는 것이 장점이 됩니다. 단, 네트워크가 연결되어야 합니다.
이것을 이용해서 특정 시간에 알람이나 특정 동작을 가능하게 할 수 있습니다.
(이전 웹 서버 만드는 과정을 참고하시면 WiFiNINA 라이브러리 설치하는 방법과 SSID 설정하는 내용이 있습니다.)
1. NTP(Network Time Protocol) 이란?
1) 간략 설명
- 네트워크 상에 분산된 시간 서버들로부터 클라이언트(호스트, 라우터 등)의 시간 동기화
- 표준 시간을 생성하는 장비부터 하위 타임 서버, 호스트 종단 장비까지 각 상하위 서버를 계층화하여 관리
2) NTP 계층
- Stratum 0 (PRC) : 세슘 원자시계, GPS, 표준 주파수 방송국 등 (Primary Reference Clock)
- Stratum 1 : 위 Stratum 0 (PRC)에 동기화시킨 시간 서버(Primary Time Server)
- Stratum 2 ~ 15 : NTP 서버를 경유할 때마다 Stratum이 1씩 증가
3) NTP 메시지 구조
4) NTP Timestamp 형태
- 구조 상세한 내용은 참고 사이트 2번을 참고하시면 됩니다.
5) NTP 서버 리스트
- Worldwide : pool.ntp.org
- Asia : asia.pool.ntp.org
- Europe : europe.pool.ntp.org
- North America : north-america.pool.ntp.org
- Oceania : oceania.pool.ntp.org
- South America : south-america.pool.ntp.org
- KT : ntp.kornet.net
- LG유플러스 : time.bora.net
- 한국 표준 과학연구원(KRISS) : time.kriss.re.kr
- 아이네트호스팅 : time.nuri.net
- NIST : time.nist.gov
- 마이크로소프트 : time.windows.com
- 아마존을 비롯한 여러 곳에서도 운영 중입니다.
2. 소스 확인
- setup() : 시리얼 통신과 WiFi 초기화합니다.
- loop() : NTP 서버에 sendNTPpacket() 함수 호출하고 NTP 서버에서 받은 응답을 파싱 합니다.
epoch time(기원 시간)부터 경과된 시간(Tick 수)을 계산합니다. UTC 시간을 출력합니다.
- sendNTPpacket() : NTP Message 구조에 맞게 데이터 구조를 만듭니다.
그리고 123 포트로 해서 패킷을 전송합니다.
- printWifiStatus() : SSID와 rssi 수신감도를 출력합니다.
/*
Udp NTP Client
Get the time from a Network Time Protocol (NTP) time server
Demonstrates use of UDP sendPacket and ReceivePacket
For more on NTP time servers and the messages needed to communicate with them,
see http://en.wikipedia.org/wiki/Network_Time_Protocol
created 4 Sep 2010
by Michael Margolis
modified 9 Apr 2012
by Tom Igoe
This code is in the public domain.
*/
#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>
int status = WL_IDLE_STATUS;
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key index number (needed only for WEP)
unsigned int localPort = 2390; // local port to listen for UDP packets
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server -> time-a-g.nist.gov
IPAddress timeServer(132, 163, 96, 1); // time-a-b.nist.gov NTP server
const int NTP_PACKET_SIZE = 48; // NTP timestamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to WiFi");
printWifiStatus();
Serial.println("\nStarting connection to server...");
Udp.begin(localPort);
}
void loop() {
sendNTPpacket(timeServer); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);
if (Udp.parsePacket()) {
Serial.println("packet received");
// We've received a packet, read the data from it
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, extract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = ");
Serial.println(secsSince1900);
// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);
// print the hour, minute and second:
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
Serial.print(':');
if (((epoch % 3600) / 60) < 10) {
// In the first 10 minutes of each hour, we'll want a leading '0'
}
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':');
if ((epoch % 60) < 10) {
// In the first 10 seconds of each minute, we'll want a leading '0'
}
Serial.println(epoch % 60); // print the second
}
// wait ten seconds before asking for the time again
delay(10000);
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
- 주석에 time.nist.gov 주소가 129.6.15.28이라고 나와서 그럴 줄 알았는데 그것이 아니라 서버가 여러 개 나누어져 있었습니다. 위의 IP 주소는 time-a-g.nist.gov의 주소입니다.
- 참고 삼아 NTP IP주소 리스트 링크 추가해 두겠습니다.
https://tf.nist.gov/tf-cgi/servers.cgi
3. 동작확인
- 시리얼 모니터를 실행하면 WiFi에 접속해서 NTP 서버에 접속해서 시간을 가져옵니다.
- 타임존(Time Zone)을 보면 한국이 +9시 존(Zone)에 있기 때문에 UTC 시간에 +9를 하면 현재 한국시간과 동일한 것을 확인할 수 있습니다.
- 타임존 원본 사진
https://upload.wikimedia.org/wikipedia/commons/8/88/World_Time_Zones_Map.png
- 정치적인 이야기 하고 싶은 것은 아니지만, 사진을 보면서도 기분이 좋지 않은 것이 wiki 지도에도 Sea of Japan 이라고만 적혀 있는 것이 아쉬울 다름입니다. 국력이 커져서 East of Sea라고 하는 때가 오기를 바라는 마음에 ~~
감사합니다.
<참고사이트>
1. NTP: The Network Time Protocol
2. NTP Network Time Protocol 네트워크 타임 프로토콜
http://www.ktword.co.kr/abbr_view.php?m_temp1=2106
3. 국내 타임 서버 리스트
http://time.ewha.or.kr/domestic.html
4. Network Time Protocol
https://en.wikipedia.org/wiki/Network_Time_Protocol
5. arduino-libraries/WiFiNINA
'Embedded > Arduino' 카테고리의 다른 글
아두이노 나노(Arduino Nano 33 IoT) BLE 사용하기 – 1 (연결하기) (0) | 2024.06.18 |
---|---|
아두이노 나노(Arduino Nano) 33 IoT를 이용한 GY-GPSV3-7M GPS 수신 모듈 테스트(SZH-NT07) (4) | 2024.06.05 |
아두이노 나노(Arduino Nano) 33 IoT로 작은 웹서버 만들기 (0) | 2024.05.31 |
아두이노 나노(NANO) 정품과 아두이노 카피품 비교 및 업로드 차이 (0) | 2024.05.25 |
아두이노 waveshare 1.3인치 OLED에 넣을 BMP 이미지(HEX 값) 만들고 출력하기 (0) | 2024.05.22 |