12주 차 아두이노 클라우드와 NTP - park-02/2024-1_Smart-Devices GitHub Wiki
- AWS (Amazon Web Services)란?
- 클라우드 컴퓨팅
- NTP
- 실습[1]
- 실습[2]
- 실습[3]
- 후기
- AWS는 아마존닷컴에서 개발한 클라우드 컴퓨팅 플랫폼입니다.
- 이 플랫폼은 가상 컴퓨터, 스토리지, 네트워크 인프라 등 다양한 클라우드 서비스를 제공하며, 네트워킹을 기반으로 합니다.
- 비즈니스와 개발자가 확장 가능하고 정교한 애플리케이션을 구축하도록 지원합니다.
- 현재 소규모 법인부터 개인 사용자, 거대 기업까지 다양한 사용자들이 AWS의 클라우드 컴퓨팅 장점을 활용하고 있습니다.
- 자동 확장 기능과 글로벌 인프라 제공으로 필요에 따라 자원을 손쉽게 조절할 수 있습니다.
- 종량제 요금제로 사용한 만큼만 지불하며, 비용 최적화 도구를 통해 비용 관리가 용이합니다.
- 종합적인 보안 기능과 데이터 암호화 지원으로 높은 수준의 보안을 제공합니다.
- 클라우드 컴퓨팅은 기존의 물리적인 컴퓨팅 리소스를 네트워크 기반 서비스 형태로 제공하는 것을 의미합니다.
- 이는 사용자가 네트워크 상에서 클라우드 서비스의 자원을 사용하는 것을 가능하게 합니다.
- IaaS (Infrastructure as a Service): 서버, 스토리지, 네트워크 등 기본 인프라 자원을 제공합니다.
- PaaS (Platform as a Service): 애플리케이션 개발에 필요한 플랫폼과 환경을 제공합니다.
- SaaS (Software as a Service): 소프트웨어 애플리케이션을 서비스 형태로 제공합니다.
- Network Time Protocol(NTP)은 네트워크로 구성된 환경에서 시스템들의 시간을 동기화하기 위한 프로토콜입니다. 동기화는 서버와 클라이언트 간의 시간 차이로 인해 발생할 수 있는 프로그램 및 프로세스의 오류를 방지하기 위해 필요합니다. 예를 들어, 서버에서 20분에 실행 지시를 했는데 클라이언트가 30분으로 받아들이면 10분의 지연이 발생하여 오류가 생길 수 있습니다. 또한, 네트워크 보안을 위해 시간 서버를 이용해 시간이 서버와 다르면 접근을 거부하여 해커와 악성 소프트웨어의 접근을 방지합니다.
- Stratum은 NTP에서 시간을 전송하는 장비들을 계층화하여 나타내는데 사용되는 용어입니다. 이 중에서도 Stratum 0은 GPS나 세슘 원자 시계 등의 정확한 시간을 제공하는 기기를 가리키며, Stratum 1은 Stratum 0 기기와 직접 연결되어 시간을 동기화하는 서버를 의미합니다. 그 이후로는 트리 구조를 형성하며, Stratum 2, 3 등은 상위 Stratum의 서버로부터 동기화된 시간을 받아오고 다시 이를 하위 Stratum의 서버로 전파합니다. 이렇게 함으로써 Stratum 1 서버에 대한 접근 부하를 줄일 수 있습니다. 이러한 구조는 네트워크의 안정성과 성능을 향상시키는 데 도움이 됩니다.
- 데이터 손실을 방지합니다.
- 로그에 대한 분석이 용이합니다.
- 예약된 작업을 정상적으로 가능하게 합니다.
- 외부 서버를 통해서 시간을 동기화하는 부분으로 인해 보안상의 취약하다.
- 이번 실습은 아두이노에서 제공하는 IOT 클라우드를 사용해서 온도, 습도 데이터를 모니터링하고 LED를 제어하는 실습입니다.
- ESP32, ESP32 확장 실드, DH11 온습도 센서, LED 모듈
- https://cloud.arduino.cc/에 Sign In 한 후에 오른쪽 상단의 메뉴를 통해 Arduino Cloud 사이트로 이동합니다.
- Things 탭에서 “CREATE THING” 버튼을 클릭합니다.
- 프로젝트의 이름을 입력하고, “ADD VARIABLE” 버튼을 클릭합니다.
- LED 상태를 제어하기 위한 led_state 변수 추가합니다.
- 온습도 센서를 모니터링하기 위한 temperature 변수 추가합니다.
- “Associated Device” 섹션에서 “Select Device” 버튼을 클릭합니다.
- “SET UP NEW DEVICE”를 선택한 뒤, “Third party device”를 클릭합니다
- ESP32를 선택하고 드롭다운 메뉴에서 “DOIT ESP32 DEVKIT V1”을 선택합니다. Device의 이름을 정하고 다음으로 진행합니다.
- “Device ID”와 “Security Key”를 받게 됩니다. “Security Key”는 이 화면에서만 조회할 수 있으므로 반드시 메모해야 합니다.
- Network” 섹션에서 “Configure”버튼을 클릭합니다.
- 네트워크 이름, 네트워크 암호 및 “Security Key”를 입력합니다. 완료되면 “저장”을 클릭합니다.
- “Sketch” 탭에서는 자동으로 생성된 스케치 파일을 볼 수 있습니다.
- 일반적인 ".ino" 파일과 구조가 같습니다. 다만, 네트워크 및 클라우드에 연결하기 위한 몇 가지 추가 코드가 있습니다. 예를 들어, 읽기 권한을 가진 클라우드 변수를 사용하여 데이터를 저장하는 코드입니다. 스케치가 업로드되면 일반 스케치로 작동하지만, 동시에 클라우드 변수도 업데이트됩니다. 또한, 읽기 및 쓰기 권한이 활성화된 변수를 생성하면 스케치 파일 하단에 해당 변수가 변경될 때마다 실행되는 함수도 생성됩니다. 계속 실행돼야 하는 코드는 기존 아두이노 코드와 같이 loop() 함수에 작성하면 됩니다.
USB 포트를 통해 스케치를 업로드하려면 Creat Agent가 필요합니다.
스케치 탭에 진입했을 때 아래 메시지 창이 뜬다면 Create Agent가 설치되어 있지 않은 것입니다.
"LEARN MORE”를 눌러 다운로드합니다.
#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);
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}
void loop() {
ArduinoCloud.update();
temperature = dht.readTemperature();
if (isnan(temperature)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("Temperature: "));
Serial.println(temperature);
delay(1000);
}
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);
}
}
코드는 DHT11 온습도 센서를 사용하여 온도를 읽고, Arduino IoT Cloud를 통해 LED를 제어합니다.
setup() 함수에서는 센서 초기화와 IoT Cloud 연결 설정을 수행합니다.
loop() 함수는 주기적으로 온도를 측정하고, IoT Cloud와의 통신을 처리합니다.
onLedStateChange() 함수는 IoT Cloud에서 LED 상태 변경 시 호출되어 LED를 제어합니다.
프로그램은 센서 데이터 수집과 외부 제어를 통합하여 IoT 기기의 기본 기능을 구현합니다.
- 대시보드는 클라우드를 통해 보드와 상호작용하기 위한 시각적인 사용자 인터페이스입니다. Arduino Cloud 홈페이지에서“Dashboard” 메뉴를 클릭하여 대시보드에 액세스할 수 있습니다.
- 위젯을 만들어 줍니다.
- led_start 변수를 제어할 switch 위젯을 선택합니다. 위젯의 이름을 정한 뒤 Link Variable 버튼을 클릭하고 디바이스(ESP32)와 변수(led_state)를 선택해 연결합니다.
- temperature를 모니터링할 Chart 위젯을 추가합니다. 디바이스(ESP32)와 변수(temperature)를 선택하여 연결합니다.
- 위젯 크기를 수정하거나 스마트폰 어플로 화면을 편집할 수 있습니다.
- 위젯을 연결하여 실시간으로 온도 값이 업데이트되고 Switch를 OFF 했을 때 LED가 꺼지고 ON을 하면 LED가 켜지는 것을 확인할 수 있습니다.
- 이번 실습은 OLED 디스플레이에 텍스트를 출력하는 실습입니다.
- ESP32, ESP32 확장 실드, OLED 디스플레이
- "Adafruit_SSD1306" 라이브러리와 "Adafruit_GFX" 라이브러리를 설치합니다.
#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("Park SH");
// 크기 8의 폰트로 텍스트 표시
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0, 15);
display.println("202110097");
display.display();
delay(2000);
}
- OLED 디스플레이를 초기화하고 설정합니다.
- 루프에서 디스플레이를 지운 후, 텍스트 크기와 위치를 설정하고 문자열을 출력합니다.
- 2초 동안 대기한 후, 화면을 업데이트합니다.
- ESP32 보드를 컴퓨터에 연결합니다.
- Arduino IDE에 소스코드를 컴파일하고 업로드합니다.
- OLED 디스플레이에 1 크기의 폰트로 "Park SH"가 표시됩니다.
- 2 크기의 폰트로 "202110097"가 표시됩니다.
- 이번 실습은 현재 시간을 NTP서버에서 받아와 OLED에 표시하는 디지털시계를 구현하는 실습입니다.
- ESP32, ESP32 확장실드, 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 = ".."; // 여기에 사용하는 WiFi 네트워크 이름 (SSID)을 입력하세요
const char* password = "123456799"; // 여기에 사용하는 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);
}
- ESP32가 WiFi에 연결하고 NTP 서버를 통해 현재 시간을 동기화합니다. 이 시간을 SSD1306 OLED 디스플레이에 실시간으로 표시하여 시:분:초와 날짜를 보여줍니다. setup() 함수에서 WiFi와 NTP 설정을 완료하고, loop() 함수에서 반복적으로 시간을 갱신하고 출력합니다.
- WiFi, time, Adafruit_GFX, Adafruit_SSD1306 라이브러리를 포함하여 디스플레이 객체를 초기화합니다.
- WiFi 네트워크 이름(SSID)과 비밀번호를 설정하고, 한국 시간대(GMT+9)를 적용합니다.
- setup() 함수에서 WiFi 네트워크에 연결하고, configTime() 함수를 사용하여 NTP 서버를 통해 시간 동기화를 설정합니다.
- loop() 함수에서 현재 시간을 가져와 시리얼 모니터와 OLED 디스플레이에 실시간으로 표시합니다.
- 디스플레이에 시간(시:분:초)과 날짜(일/월/연도)를 포맷에 맞게 출력합니다
- ESP32 보드를 컴퓨터에 연결합니다.
- Arduino IDE에 소스코드를 컴파일하고 업로드합니다.
- 상단에 시간을 표시하고 하단에 날짜와 요일을 표시하는 시계로 동작하게 됩니다.
- 이번 실습을 통해 아두이노에서 제공하는 IoT 클라우드를 활용하여 온도와 습도 데이터를 모니터링하고, 이를 통해 LED를 제어하는 방법을 배웠습니다. 또한, OLED 디스플레이에 텍스트를 출력하는 실습을 통해 간단한 그래픽 디스플레이 장치를 다루는 방법을 익혔습니다. 마지막으로, NTP 서버에서 현재 시간을 받아와 OLED에 표시하는 디지털시계를 구현하는 실습을 통해 시간 동기화의 중요성을 알았습니다. ESP32와 NTP 서버를 연동하여 실시간으로 시간을 받아와 표시하는 과정을 통해 실시간 데이터 처리와 디스플레이 출력에 대한 이해를 높일 수 있었습니다.