12주차_아두이노 클라우드와 NTP 서버 활용 - sookite22/SmartDivice_24 GitHub Wiki

목차

  • 아두이노 클라우드
  • NTP
    • NTP 서버
  • 실습
    • 아두이노 IOT 클라우드 활용
    • OLED 디스플레이
      • NTP 서버 활용
  • 후기

1. 아두이노 클라우드(Arduino Cloud)란?

Arduino에서 제공하는 IoT 플랫폼 으로, 개발자가 인터넷에 연결된 장치를 쉽게 관리하고 모니터링할 수 있도록 해 준다. 이를 통해 하드웨어, 소프트웨어, 클라우드 서비스를 통합하여 IoT 프로젝트를 간편하게 구축하고 운영할 수 있다.

Arduino 자체는 오픈 소스 전자 플랫폼으로, 전자 제품을 만들고 프로그래밍하는 데 사용되는 간단한 하드웨어와 소프트웨어를 제공한다. 2005년, 이탈리아의 Ivrea Interaction Design Institute에서 학생들이 쉽고 저렴하게 프로그래밍 가능한 전자 제품을 만들 수 있도록 하기 위한 프로젝트로 시작되었다. Arduino의 성공 비결 중 하나는 오픈 소스 하드웨어소프트웨어 철학 으로, 모든 설계 파일과 소스 코드는 누구나 자유롭게 수정하고 배포할 수 있도록 공개되었고 그 이후로 전 세계적으로 인기를 얻게 되었다.

1. Arduino IoT Cloud

  • 장치 관리: 여러 IoT 장치를 한 곳에서 쉽게 관리할 수 있다. 각 장치는 고유한 보안 인증서를 통해 인증되며, 클라우드에서 상태를 모니터링하고 업데이트할 수 있다.
  • 데이터 대시보드: 실시간으로 데이터를 시각화하고 모니터링할 수 있는 대시보드를 제공한다.
  • 자동화 및 규칙 설정: 특정 조건이 충족될 때 자동으로 동작하는 규칙을 설정할 수 있다. 예를 들어, 특정 온도에 도달하면 알림을 보내거나 장치를 켜거나 끌 수 있다.

2. Arduino Create

  • Arduino Web Editor: 웹 기반 코드 편집기다. 인터넷 연결이 가능한 어디서든 프로젝트를 개발하고 테스트할 수 있다. 다양한 보드와 라이브러리를 지원한다.
  • Arduino CLI: 명령 줄 인터페이스 도구다. 개발자가 터미널을 통해 프로젝트를 빌드하고 배포할 수 있다.

3. 통합 및 확장성

  • 통합 기능: 외부 서비스와의 통합을 위한 API와 Webhook을 제공한다. 이를 통해 다른 웹 서비스와 데이터를 주고받을 수 있다.
  • 연동 기능: 스마트 홈 기기와의 통합을 지원하여, 음성 명령이나 스마트폰 앱을 통해 장치를 제어할 수 있다. ex) 삼성 SmartThings, Alexa 등

2. NTP(Network Time Protocol)란?

인터넷이나 로컬 네트워크 상에서 컴퓨터 시스템 간의 시간을 동기화하는 프로토콜이다. 1980년대에 개발되었으며, 오늘날 인터넷과 로컬 네트워크에서 널리 사용되고 있다.

NTP는 인터넷 상의 공용 서버와 로컬 네트워크 서버를 모두 사용할 수 있으며, 높은 정확성안정성 을 제공한다.

예를 들어, 네트워크 보안 에서 로그와 이벤트 시간의 정확성 보장하고, 금융 거래 에서 거래 시간의 정확성을 보장하고, 분산 시스템 에서 시스템 간의 동기화를 유지하는 등 다양한 분야에서 중요한 부분을 차지한다.

주요 특징

  1. 시간 동기화: 시간 정보를 제공하여 네트워크 상의 모든 장치가 정확한 시간으로 동기화 되게 한다. 이는 로그 파일의 타임스탬프, 일정 관리, 데이터베이스 트랜잭션 등 시간에 의존하는 많은 시스템에서 매우 중요하다.

  2. 정확성: 인터넷을 통해 공인된 시간 서버에 연결될 경우 밀리초 단위의 정밀도를 제공한다. 로컬 네트워크 환경에서는 수십 밀리초의 정밀도를 제공할 수도 있다.

  3. 계층 구조: 계층적인 시간 서버 구조 를 사용한다. 각 계층은 Stratum으로 불린다. 가장 상위에 있는 서버들은 주로 원자 시계, GPS 시간 정보 등 매우 정확한 시간 소스를 사용하며, 하위 계층의 서버들은 상위 서버들과 동기화하여 시간을 제공한다. 최종적으로 클라이언트 장치들이 이 서버들과 동기화된다.

  4. 시간 소스: NTP 서버는 다양한 시간 소스를 사용하여 정확한 시간 을 제공한다. 이는 GPS, 원자 시계, 라디오 시계 신호 등 매우 정밀한 시간 소스를 포함한다.

동작 원리

1. 클라이언트-서버 모델: 클라이언트는 NTP 서버에 요청을 보내고, 서버는 클라이언트에게 현재 시간을 응답한다. 클라이언트는 이 응답을 바탕으로 자신의 시간을 조정한다. 서버와 클라이언트 간의 시간 정보를 주고받아 시간을 동기화한다.

2. 시간 요청과 응답: 클라이언트는 NTP 서버에 패킷을 보내 시간을 요청한다. 이 패킷에는 요청이 발송된 시간 정보가 포함된다. 서버는 요청을 받은 시간을 기록하고, 서버의 현재 시간을 패킷에 포함하여 클라이언트에게 응답한다. 클라이언트는 이 응답을 수신한 시간을 기록하고, 서버의 시간 정보와 네트워크 지연 시간을 계산하여 자신의 시간을 조정한다. 클라이언트는 주기적으로 NTP 서버에 접속하여 시간 정보를 갱신한다.

3. 시간 보정 알고리즘: NTP는 단순히 시간을 설정하는 것이 아니라 시간이 조금씩 조정되도록 보정 알고리즘 을 사용한다. 이를 통해 시간 설정 시 발생할 수 있는 갑작스러운 시간 변화로 인한 문제를 방지할 수 있다. 정밀한 원자 시계 또는 GPS를 통해 정확한 시간을 유지한다.

2.1. NTP 서버

네트워크 상의 컴퓨터들이 정확한 시간을 동기화할 수 있도록 하는 프로토콜을 제공하는 서버이다. 이를 통해 네트워크 상의 모든 장치가 동일한 시간 기준을 유지할 수 있다.

NTP 서버는 네트워크 상의 컴퓨터들이 정확하고 일관된 시간을 유지할 수 있도록 하는 중요한 역할을 한다. 이를 통해 시간에 민감한 많은 시스템들이 신뢰성 있게 동작할 수 있게 되었다.

주요 NTP 서버 예시

  • 'pool.ntp.org': 전 세계적으로 분산된 NTP 서버 풀. 각 지역에 따라 여러 서버로 구성되며, 사용자가 가장 가까운 서버와 자동으로 동기화된다.
  • NIST (National Institute of Standards and Technology) ('time.nist.gov'): 미국 국립표준기술연구소(NIST)에서 운영하는 서버.
  • Microsoft NTP ('time.windows.com'): 마이크로소프트에서 제공하는 NTP 서버.
  • US Naval Observatory(USNO) ('tick.usno.navy.mil'): 미국 해군 천문대에서 운영하는 NTP 서버. 정확한 원자 시계 시간 정보를 제공한다.
  • Google NTP ('time.google.com'): 구글의 NTP 서버. 전 세계적으로 사용된다.
  • Apple NTP ('time.apple.com'): Apple의 NTP 서버. 주로 Apple 장치와의 동기화에 사용된다.

3. 실습

3.1. 아두이노 IOT 클라우드 활용 - 온도, 습도 데이터를 모니터링하고 LED 제어하기

회로 연결

  • 준비물 : ESP32, ESP32 확장 실드, DH11 온습도 센서, LED 모듈

KakaoTalk_20240522_150657694

아두이노 클라우드 설정

  1. https://cloud.arduino.cc/ 에 Sign In 한 후, 오른쪽 상단 메뉴를 통해 Arduino Cloud 사이트로 이동한다.

스크린샷 2024-05-22 143933 스크린샷 2024-05-22 144259

  1. Thing tab에서 “CREATE THING” 버튼을 클릭한다.

스크린샷 2024-05-22 144501

  1. 프로젝트의 이름을 입력하고 “ADD VARIABLE” 버튼을 클릭한다.

스크린샷 2024-05-22 144648

  1. LED 상태를 제어하기 위한 led_state 변수를 추가한다.

스크린샷 2024-05-22 144907

  1. LED 상태를 제어하기 위한 led_state 변수를 추가한다.

스크린샷 2024-05-22 145109

장치 설정

  1. “Associated Device” 섹션에서 “Select Device” 버튼을 클릭한다.

스크린샷 2024-05-22 145221

  1. “SET UP NEW DEVICE”를 선택한 뒤, “Set up a 3rd Party device”를 클릭한다.

스크린샷 2024-05-22 145314

  1. ESP32를 선택하고 드롭다운 메뉴에서 “DOIT ESP32 DEVKIT V1”을 선택한 후, Device의 이름을 정하고 다음으로 진행한다.

스크린샷 2024-05-22 145428

  1. “Device ID”와 “Security Key”를 받게 된다. “Security Key”는 이 화면에서만 조회할 수 있으므로 반드시 메모해두어야 한다.

스크린샷 2024-05-22 145805(1)

네트워크 설정

  1. Network” 섹션에서 “Configure”버튼을 클릭한다.

스크린샷 2024-05-22 150301

  1. 네트워크 이름, 네트워크 암호 및 “Security Key”를 입력한 후, 완료되면 “저장”을 클릭한다.

스크린샷 2024-05-22 151821

보드 프로그래밍

  • “Sketch” 탭에서는 자동으로 생성된 스케치 파일을 볼 수 있다.

스크린샷 2024-05-22 152151

일반적인 “.ino” 파일과 구조가 같다. 그러나 네트워크 및 클라우드에 연결하기 위한 몇 가지 추가 코드가 존재한다. 예를 들어, 읽기 권한을 가진 클라우드 변수를 사용하여 저장하는 코드이다. 스케치가 업로드되면 일반 스케치로 작동하지만 동시에 클라우드 변수도 업데이트된다. 또한, 읽기 및 쓰기 권한이 활성화된 변수를 생성하면 스케치 파일 하단에 함수도 생성된다. 이는 이 변수가 변경될 때마다 실행되는 함수이다. 계속 실행돼야 하는 코드는 기존 아두이노 코드와 같이 loop() 함수에 작성하면 된다.

코드 작성

#include "thingProperties.h"
#include "DHT.h"

int led_pin = 23;
int dh11_pin = 13;

DHT dht(dh11_pin, DHT11);

void setup() {
  pinMode(led_pin, OUTPUT);
  dht.begin();
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500);

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
  */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
}

void loop() {
  ArduinoCloud.update();
  // Your code here
  // Read temperature as Celsius (the default)
  temperature = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(temperature)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  
  Serial.print(F("Temperature: "));
  Serial.println(temperature);
  
  delay(1000);
}

/*
  Since LedState is READ_WRITE variable, onLedStateChange() is
  executed every time a new value is received from IoT Cloud.
*/
void onLedStateChange()  {
  // Add your code here to act upon LedState change
  Serial.print("LED state is changed : ");
  Serial.println(led_state);
  if (led_state) {
    digitalWrite(led_pin, HIGH);
  }
  else {
    digitalWrite(led_pin, LOW);
  }
}

스케치 업로드

프로그램을 보드에 업로드하려면 “업로드” 버튼을 클릭한다.

USB 포트를 통해 스케치를 업로드하려면 Create Agent가 필요하다. 스케치 탭에 진입했을 때 아래 메시지 창이 뜬다면 Create Agent가 설치되어 있지 않은 것이다.

스크린샷 2024-05-22 165419

“Learn More”를 누르면 download 링크를 확인할 수 있다.

스크린샷 2024-05-22 165534

Create Agent를 다운 받는다.

그러면 실행이 되는 것을 확인할 수 있다.

스크린샷 2024-05-22 170139

대시 보드 설정

대시 보드는 클라우드를 통해 보드와 상호작용하기 위한 시각적 사용자 인터페이스다. 이는 IoT 프로젝트에 요구 사항 따라 다양한 설정을 할 수 있다.

Arduino Cloud 홈 페이지에서 “Dashboard” 메뉴를 클릭하여 대시 보드에 액세스할 수 있다.

스크린샷 2024-05-22 170337

위젯 추가

위젯은 우리가 만드는 변수의 시각적 표현이다.

위젯을 만들어 보자.

스크린샷 2024-05-22 170614

led_state 변수를 제어할 switch 위젯을 선택한다. 위젯의 이름을 정한 후, “Link Variable” 버튼을 클릭하 디바이스(ESP32)와 변수(led_state)를 선택하여 위젯에 연결한다. 스크린샷 2024-05-22 170755 스크린샷 2024-05-22 170909

temperature를 모니터링할 Chart 위젯을 추가한다.

스크린샷 2024-05-22 171038

디바이스(ESP32)와 변수(temperature)를 선택하여 연결한다.

스크린샷 2024-05-22 171124 스크린샷 2024-05-22 171200

  • 위젯 크기를 수정하거나 스마트폰 어플의 화면도 편집 가능하다. 스크린샷 2024-05-22 171507

결과 확인

KakaoTalk_20240523_131543908.mp4
  • 위젯을 연결하고 조작하면 LED가 ON/OFF되고, 실시간으로 온도 값이 업데이트되는 것을 확인할 수 있다.

3.2-1. OLED 디스플레이

회로 연결

  • 준비물 : ESP32, ESP32 확장 실드, OLED 디스플레이

스크린샷 2024-05-22 173741

라이브러리 설치

"Adafruit_SSD1306" 라이브러리와 "Adafruit_GFX" 라이브러리 두 가지 라이브러리를 설치한다.

스크린샷 2024-05-22 173954 스크린샷 2024-05-22 174120

코드 작성

  • 먼저 OLED에 문자를 Display되는 것을 확인해 보자.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

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

  // OLED 디스플레이 초기화
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 오류");
    while (true);
  }

  // OLED 디스플레이 클리어
  display.clearDisplay();
}

void loop() {
  // "Hello, World!"를 크기가 다른 세 개의 텍스트로 표시
  display.clearDisplay();
  
  // 크기 6의 폰트로 텍스트 표시
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("Hello, World!");

  // 크기 8의 폰트로 텍스트 표시
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 15);
  display.println("Hello, World");

  display.display();
  delay(2000);
}

결과 확인

KakaoTalk_20240522_175450910

  • OLED에 문자가 Display되는 것을 확인할 수 있다.

3.2-2. NTP 서버 활용 - NTP 서버에서 시간을 가져와 OLED 디스플레이에 표시하는 디지털 시계 만들기

NTP 정보를 활용하여 ESP32에서 시간 동기화를 수행하거나 시간 기반 작업을 수행할 수 있다. 현재 시간을 NTP서버에서 받아와 OLED에 표시하는 디지털 시계를 구현해 보자.

코드 작성

#include <WiFi.h>  // WiFi 통신을 위한 라이브러리
#include <time.h>  // 시간과 관련된 함수를 위한 라이브러리

#include <Adafruit_GFX.h>      // 디스플레이를 위한 그래픽 라이브러리
#include <Adafruit_SSD1306.h>  // SSD1306 OLED 디스플레이를 위한 라이브러리
// SSD1306 디스플레이 객체 초기화
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire, -1);

const char* ssid = "Your_SSID";          // 여기에 사용하는 WiFi 네트워크 이름 (SSID)을 입력하세요
const char* password = "Your_Password";  // 여기에 사용하는 WiFi 네트워크 비밀번호를 입력하세요

int GMTOffset = 60 * 60 * 9;  // 시간 오프셋 설정, 한국은 UTC/GMT +9입니다.
int daylightOffset = 0;       // 국가에서 서머타임을 사용하는 경우 오프셋 값을 설정하세요.

const String weekDays[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };  // 요일 이름 배열

void setup() {
  Serial.begin(115200);  // 디버깅을 위한 시리얼 통신 시작

  // SSD1306 디스플레이 초기화
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 초기화 실패"));
    while (1)
      ;  // 디스플레이 초기화에 실패하면 프로그램 실행 중지
  }

  delay(2000);                  // 2초 동안 대기
  display.clearDisplay();       // 디스플레이 지우기
  display.setTextSize(1);       // 텍스트 크기를 1로 설정
  display.setCursor(0, 0);      // 커서 위치를 디스플레이 왼쪽 위 모서리로 설정
  display.setTextColor(WHITE);  // 텍스트 색상을 흰색으로 설정

  WiFi.begin(ssid, password);  // 제공된 SSID와 비밀번호를 사용하여 WiFi 네트워크에 연결
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }

  Serial.println("Connected to Wi-Fi!");
  // 시간 설정을 위한 NTP 서버 설정
  configTime(GMTOffset, daylightOffset, "pool.ntp.org", "time.nist.gov");
}

void loop() {

  // 현재 시간 가져오기
  time_t rawtime = time(nullptr);
  struct tm* timeinfo = localtime(&rawtime);

  // 시리얼 모니터에 날짜 출력
  Serial.print(timeinfo->tm_mday);
  Serial.print("/");
  Serial.print(timeinfo->tm_mon + 1);
  Serial.print("/");
  Serial.print(timeinfo->tm_year + 1900);

  Serial.print(" ");

  // 시리얼 모니터에 시간 출력
  Serial.print("Time: ");
  Serial.print(timeinfo->tm_hour);
  Serial.print(":");
  Serial.print(timeinfo->tm_min);
  Serial.print(":");
  Serial.println(timeinfo->tm_sec);

  // OLED 디스플레이 초기화
  display.clearDisplay();
  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);

  // 시간 출력
  if (timeinfo->tm_hour < 10)
    display.print("0");
  display.print(timeinfo->tm_hour);

  display.print(":");

  if (timeinfo->tm_min < 10)
    display.print("0");
  display.print(timeinfo->tm_min);

  display.print(":");

  // 초 출력
  display.setTextSize(2);
  display.setCursor(102, 5);

  if (timeinfo->tm_sec < 10)
    display.print("0");
  display.print(timeinfo->tm_sec);

  // 날짜 출력
  display.setTextSize(1);
  display.setCursor(0, 25);
  display.print(timeinfo->tm_mday);
  display.print("/");
  display.print(timeinfo->tm_mon + 1);
  display.print("/");
  display.print(timeinfo->tm_year + 1900);

  display.print(" ");
  display.print(weekDays[timeinfo->tm_wday]);

  // 디스플레이에 표시
  display.display();

  delay(1000);
}

결과 확인

KakaoTalk_20240523_124754352

  • 상단에 시간을 표시하고 하단에 날짜와 요일을 표시하는 시계로 동작하는 것을 확인할 수 있다.

4. 후기

아두이노 클라우드를 직접 사용해보니 간단하고 어렵지 않게 위젯을 직접 구성하여 쉽게 관리하고 모니터링할 수 있다는 것을 체감할 수 있었고, 매우 매력적인 플랫폼이라고 느낀다. NTP 서버는 네트워크 상의 컴퓨터들이 정확하고 일관된 시간을 유지할 수 있도록 하는 중요한 역할을 한다는 것을 배웠다. 이 NTP를 이용하여 직접 OLED 모듈로 시계를 만들어서 직관적이고 흥미로웠다.

⚠️ **GitHub.com Fallback** ⚠️