시간 동기화 - 정확한 시계¶
🎯 이 장에서 배우는 것¶
- [ ] NTP 프로토콜이 무엇인지 설명할 수 있다
- [ ] 인터넷에서 현재 시간을 받아올 수 있다
- [ ] 한국 시간대(UTC+9)를 설정할 수 있다
- [ ] OLED에 실시간 디지털 시계를 표시할 수 있다
💡 왜 이걸 배우나요?¶
피코는 시간을 기억하지 못해. 전원을 끄면 시간 정보가 사라지고, 다시 켜면 1970년 1월 1일부터 시작해. 마치 정전 후 깜빡이는 전자레인지 시계처럼!
이런 문제가 생겨: - 센서 데이터를 기록할 때 "언제" 측정했는지 모름 - 알람 시계를 만들어도 시간이 엉망 - IoT 기기들끼리 시간이 안 맞아서 혼란
해결책: 인터넷에 있는 시간 서버에게 물어보는 거야!
🕐 "지금 몇 시야?"
피코 ──────────────► 시간 서버 (NTP)
◄──────────────
"2024년 12월 15일 14:30:25야!"
스마트폰, 컴퓨터, 인터넷 공유기 모두 이 방식으로 정확한 시간을 유지해. 오늘 이걸 직접 구현해볼 거야!
📚 핵심 개념¶
개념 1: NTP (Network Time Protocol)¶
-
비유로 시작: "NTP는 마치 114 시간 안내 서비스와 같아요. 전화해서 '지금 몇 시야?'라고 물으면 정확한 시간을 알려주는 것처럼, 피코가 인터넷으로 시간 서버에 물어보는 거예요."
-
정확한 정의: "NTP(Network Time Protocol)는 컴퓨터와 기기들이 인터넷을 통해 정확한 시간을 동기화하는 표준 프로토콜입니다. 전 세계에 수천 개의 NTP 서버가 있어요."
-
예시로 확인: "예를 들어,
pool.ntp.org라는 서버에 요청하면 현재 UTC 시간을 밀리초 단위로 정확하게 알려줘요."
쉽게 말하면: 인터넷에 있는 "공식 시계"에서 시간을 가져오는 방법이야!
개념 2: UTC와 시간대¶
-
비유로 시작: "UTC는 마치 세계 공용어인 영어와 같아요. 모든 나라가 영어로 소통하면 혼란이 없듯이, 모든 컴퓨터는 UTC라는 '세계 표준 시간'으로 먼저 소통해요."
-
정확한 정의: "UTC(Coordinated Universal Time)는 영국 그리니치 천문대를 기준으로 하는 세계 표준시예요. 한국은 UTC보다 9시간 빠른 UTC+9를 사용합니다."
-
예시로 확인:
UTC 시간: 05:00 (새벽 5시) 한국 시간: 14:00 (오후 2시) ← UTC + 9시간
쉽게 말하면: NTP가 알려주는 시간에 9시간을 더하면 한국 시간이야!
개념 3: RTC (Real Time Clock)¶
-
비유로 시작: "RTC는 피코 내부의 작은 손목시계와 같아요. 한 번 맞춰놓으면 계속 시간을 세고 있지만, 전원이 꺼지면 멈춰요."
-
정확한 정의: "RTC(Real Time Clock)는 마이크로컨트롤러 내부에서 시간을 추적하는 하드웨어입니다. 피코의 RTC는 전원이 켜져 있는 동안 1초씩 시간을 증가시켜요."
-
예시로 확인: "NTP로 시간을 한 번 맞추면, RTC가 이후 시간을 자동으로 계산해줘서 매초 NTP 서버에 물어볼 필요가 없어요."
쉽게 말하면: 처음에 한 번만 시간을 맞추면, 피코가 알아서 시계처럼 돌아가!
🔨 따라하기¶
Step 1: WiFi 연결 함수 준비¶
목표: 이전 장에서 배운 WiFi 연결 코드를 함수로 정리해서 재사용하기
코드:
# === WHAT: WiFi 연결을 위한 기본 설정 ===
# NTP 시간을 받으려면 먼저 인터넷에 연결해야 해요
# --- WHY: 이전 장의 코드를 함수로 정리 ---
# 매번 긴 코드를 쓰지 않고, connect_wifi() 한 줄로 연결!
# HOW: 어떻게 동작하는지
import network # WiFi 연결 기능
import time # 대기 시간 처리
# ⚠️ 여기에 실제 WiFi 정보를 입력하세요!
WIFI_SSID = "your_wifi_name" # WiFi 이름
WIFI_PASSWORD = "your_password" # WiFi 비밀번호
def connect_wifi():
"""WiFi에 연결하는 함수"""
wlan = network.WLAN(network.STA_IF) # WiFi 클라이언트 모드
wlan.active(True) # WiFi 켜기
if wlan.isconnected():
print("✅ 이미 WiFi에 연결됨!")
return wlan
print(f"📡 '{WIFI_SSID}'에 연결 중...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
# 최대 10초 대기
timeout = 10
while timeout > 0:
if wlan.isconnected():
print("✅ WiFi 연결 성공!")
print(f"📍 IP 주소: {wlan.ifconfig()[0]}")
return wlan
time.sleep(1)
timeout -= 1
print(f" 대기 중... {timeout}초")
print("❌ WiFi 연결 실패!")
return None
# 테스트
wifi = connect_wifi()
실행 결과:
📡 'your_wifi_name'에 연결 중...
대기 중... 9초
대기 중... 8초
✅ WiFi 연결 성공!
📍 IP 주소: 192.168.0.15
여기서 잠깐! 🤔 WiFi 이름과 비밀번호는 큰따옴표 안에 정확히 입력해야 해! 대소문자도 구분하니까 주의하자.
Step 2: NTP로 시간 받아오기¶
목표: ntptime 라이브러리로 인터넷에서 정확한 시간 받아오기
코드:
# === WHAT: NTP 서버에서 현재 시간 받아오기 ===
# 인터넷 시간 서버에 "지금 몇 시야?" 물어보는 코드
# --- WHY: 피코는 전원을 끄면 시간을 잊어버려요 ---
# NTP로 정확한 시간을 받아와서 내부 시계를 맞춰요
# HOW: 어떻게 동작하는지
import network
import ntptime # NTP 시간 동기화 라이브러리
import time
# WiFi 설정 (위에서 복사)
WIFI_SSID = "your_wifi_name"
WIFI_PASSWORD = "your_password"
def connect_wifi():
"""WiFi에 연결하는 함수"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if wlan.isconnected():
return wlan
print(f"📡 '{WIFI_SSID}'에 연결 중...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 10
while timeout > 0:
if wlan.isconnected():
print("✅ WiFi 연결 성공!")
return wlan
time.sleep(1)
timeout -= 1
return None
def sync_time_ntp():
"""NTP 서버에서 시간을 받아와 동기화"""
print("\n⏰ NTP 서버에서 시간 받아오는 중...")
try:
# NTP 서버 설정 (한국에서 가까운 서버)
ntptime.host = "pool.ntp.org"
# 시간 동기화 실행!
ntptime.settime()
print("✅ 시간 동기화 성공!")
return True
except Exception as e:
print(f"❌ 시간 동기화 실패: {e}")
return False
# === 메인 실행 ===
# 1. WiFi 연결
wifi = connect_wifi()
if wifi:
# 2. NTP 동기화
if sync_time_ntp():
# 3. 현재 시간 확인 (UTC 시간)
current = time.localtime()
print(f"\n🌍 UTC 시간: {current[0]}년 {current[1]}월 {current[2]}일")
print(f" {current[3]:02d}:{current[4]:02d}:{current[5]:02d}")
실행 결과:
📡 'your_wifi_name'에 연결 중...
✅ WiFi 연결 성공!
⏰ NTP 서버에서 시간 받아오는 중...
✅ 시간 동기화 성공!
🌍 UTC 시간: 2024년 12월 15일
05:30:25
여기서 잠깐! 🤔 출력된 시간이 현재 한국 시간보다 9시간 느린 게 정상이야! UTC는 세계 표준시니까. 다음 단계에서 한국 시간으로 바꿔볼 거야.
Step 3: 한국 시간으로 변환하기¶
목표: UTC 시간에 9시간을 더해서 한국 시간(KST)으로 변환
코드:
# === WHAT: UTC를 한국 시간(KST)으로 변환 ===
# NTP가 알려주는 UTC 시간에 9시간을 더해요
# --- WHY: 한국은 UTC+9 시간대 ---
# UTC 05:00 = 한국 14:00
# HOW: 어떻게 동작하는지
import network
import ntptime
import time
WIFI_SSID = "your_wifi_name"
WIFI_PASSWORD = "your_password"
KST_OFFSET = 9 * 3600 # 9시간을 초 단위로 (9 * 60 * 60)
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if wlan.isconnected():
return wlan
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 10
while timeout > 0:
if wlan.isconnected():
return wlan
time.sleep(1)
timeout -= 1
return None
def sync_time_ntp():
try:
ntptime.host = "pool.ntp.org"
ntptime.settime()
return True
except:
return False
def get_korea_time():
"""현재 한국 시간을 반환"""
# UTC 타임스탬프 (1970년부터 지금까지 초)
utc_timestamp = time.time()
# 한국 시간으로 변환 (+9시간)
kst_timestamp = utc_timestamp + KST_OFFSET
# 읽기 좋은 형태로 변환
kst_time = time.localtime(kst_timestamp)
return kst_time
def format_time(t):
"""시간을 보기 좋게 포맷팅"""
# t = (년, 월, 일, 시, 분, 초, 요일, ...)
year = t[0]
month = t[1]
day = t[2]
hour = t[3]
minute = t[4]
second = t[5]
weekday = t[6] # 0=월요일, 6=일요일
days = ["월", "화", "수", "목", "금", "토", "일"]
day_name = days[weekday]
return f"{year}년 {month}월 {day}일 ({day_name}) {hour:02d}:{minute:02d}:{second:02d}"
# === 메인 실행 ===
wifi = connect_wifi()
if wifi and sync_time_ntp():
print("\n" + "="*40)
# UTC 시간
utc = time.localtime()
print(f"🌍 UTC 시간: {format_time(utc)}")
# 한국 시간
kst = get_korea_time()
print(f"🇰🇷 한국 시간: {format_time(kst)}")
print("="*40)
실행 결과:
========================================
🌍 UTC 시간: 2024년 12월 15일 (일) 05:30:25
🇰🇷 한국 시간: 2024년 12월 15일 (일) 14:30:25
========================================
여기서 잠깐! 🤔
time.time()은 1970년 1월 1일부터 지금까지 흐른 초를 반환해. 여기에 32400초(9시간×60분×60초)를 더하면 한국 시간이 되는 거야!
Step 4: OLED에 디지털 시계 표시하기¶
목표: OLED 화면에 예쁜 디지털 시계 만들기
코드:
# === WHAT: OLED 디지털 시계 만들기 ===
# 실시간으로 시간이 바뀌는 멋진 시계!
# --- WHY: 눈에 보이는 결과물이 있어야 재미있잖아! ---
# LED로 숫자를 표시하는 것보다 OLED가 훨씬 멋져요
# HOW: 어떻게 동작하는지
import network
import ntptime
import time
from machine import Pin, I2C
import ssd1306
# === 설정 값 ===
WIFI_SSID = "your_wifi_name"
WIFI_PASSWORD = "your_password"
KST_OFFSET = 9 * 3600
# === OLED 초기화 ===
i2c = I2C(0, sda=Pin(4), scl=Pin(5))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# OLED에 연결 중 표시
oled.fill(0)
oled.text("WiFi", 45, 20)
oled.text("Connecting...", 20, 35)
oled.show()
if wlan.isconnected():
return wlan
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 10
while timeout > 0:
if wlan.isconnected():
return wlan
time.sleep(1)
timeout -= 1
return None
def sync_time_ntp():
oled.fill(0)
oled.text("NTP Sync...", 25, 28)
oled.show()
try:
ntptime.host = "pool.ntp.org"
ntptime.settime()
return True
except:
return False
def get_korea_time():
utc_timestamp = time.time()
kst_timestamp = utc_timestamp + KST_OFFSET
return time.localtime(kst_timestamp)
def display_clock(t):
"""OLED에 시계 표시"""
# t = (년, 월, 일, 시, 분, 초, 요일, ...)
year = t[0]
month = t[1]
day = t[2]
hour = t[3]
minute = t[4]
second = t[5]
weekday = t[6]
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
day_name = days[weekday]
# 화면 지우기
oled.fill(0)
# 날짜 (위쪽)
date_str = f"{year}.{month:02d}.{day:02d} {day_name}"
oled.text(date_str, 15, 5)
# 구분선
oled.hline(0, 18, 128, 1)
# 시간 (크게 - 중앙)
time_str = f"{hour:02d}:{minute:02d}:{second:02d}"
# 큰 글씨 효과 (같은 텍스트를 약간 겹쳐서)
oled.text(time_str, 28, 28)
oled.text(time_str, 29, 28)
oled.text(time_str, 28, 29)
# 한국 시간 표시
oled.text("KST (UTC+9)", 28, 50)
# 화면에 표시
oled.show()
# === 메인 실행 ===
print("🕐 OLED 디지털 시계 시작!")
# 1. WiFi 연결
wifi = connect_wifi()
if not wifi:
oled.fill(0)
oled.text("WiFi Failed!", 20, 28)
oled.show()
print("❌ WiFi 연결 실패")
else:
print("✅ WiFi 연결 성공")
# 2. NTP 동기화
if sync_time_ntp():
print("✅ 시간 동기화 성공")
# 3. 시계 표시 시작 (무한 루프)
print("⏰ 시계 작동 중... (Ctrl+C로 중지)")
while True:
kst = get_korea_time()
display_clock(kst)
time.sleep(1) # 1초마다 갱신
else:
oled.fill(0)
oled.text("NTP Failed!", 20, 28)
oled.show()
print("❌ NTP 동기화 실패")
실행 결과:
🕐 OLED 디지털 시계 시작!
✅ WiFi 연결 성공
✅ 시간 동기화 성공
⏰ 시계 작동 중... (Ctrl+C로 중지)
OLED 화면:
┌────────────────────────┐
│ 2024.12.15 SUN │
│────────────────────────│
│ │
│ 14:30:25 │
│ │
│ KST (UTC+9) │
└────────────────────────┘
여기서 잠깐! 🤔
while True:는 무한 루프야. 프로그램을 멈추려면 Thonny에서 Ctrl+C를 누르거나, Stop 버튼을 클릭해!
📝 전체 코드¶
# === OLED 디지털 시계 (NTP 동기화) ===
# 인터넷에서 정확한 시간을 받아와 OLED에 표시
# 작성일: 2024
import network
import ntptime
import time
from machine import Pin, I2C
import ssd1306
# ========================================
# 설정 - 여기만 수정하세요!
# ========================================
WIFI_SSID = "your_wifi_name" # 👈 WiFi 이름
WIFI_PASSWORD = "your_password" # 👈 WiFi 비밀번호
KST_OFFSET = 9 * 3600 # 한국 시간대 (UTC+9)
# ========================================
# OLED 초기화
# ========================================
i2c = I2C(0, sda=Pin(4), scl=Pin(5))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# ========================================
# 함수 정의
# ========================================
def connect_wifi():
"""WiFi에 연결"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
oled.fill(0)
oled.text("WiFi", 45, 20)
oled.text("Connecting...", 20, 35)
oled.show()
if wlan.isconnected():
return wlan
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 15
while timeout > 0:
if wlan.isconnected():
return wlan
time.sleep(1)
timeout -= 1
oled.fill(0)
oled.text("WiFi", 45, 20)
oled.text(f"Waiting... {timeout}s", 15, 35)
oled.show()
return None
def sync_time_ntp():
"""NTP 서버와 시간 동기화"""
oled.fill(0)
oled.text("NTP Sync...", 25, 28)
oled.show()
try:
ntptime.host = "pool.ntp.org"
ntptime.settime()
time.sleep(0.5)
return True
except Exception as e:
print(f"NTP 오류: {e}")
return False
def get_korea_time():
"""한국 시간 반환"""
utc_timestamp = time.time()
kst_timestamp = utc_timestamp + KST_OFFSET
return time.localtime(kst_timestamp)
def display_clock(t):
"""OLED에 시계 표시"""
year = t[0]
month = t[1]
day = t[2]
hour = t[3]
minute = t[4]
second = t[5]
weekday = t[6]
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
day_name = days[weekday]
oled.fill(0)
# 날짜
date_str = f"{year}.{month:02d}.{day:02d} {day_name}"
oled.text(date_str, 15, 5)
# 구분선
oled.hline(0, 18, 128, 1)
# 시간 (굵게 표시)
time_str = f"{hour:02d}:{minute:02d}:{second:02d}"
oled.text(time_str, 28, 28)
oled.text(time_str, 29, 28)
oled.text(time_str, 28, 29)
# 시간대 표시
oled.text("KST (UTC+9)", 28, 50)
oled.show()
def show_error(message):
"""에러 메시지 표시"""
oled.fill(0)
oled.text("ERROR", 45, 20)
oled.text(message, 10, 35)
oled.show()
# ========================================
# 메인 실행
# ========================================
print("="*40)
print("🕐 OLED 디지털 시계")
print("="*40)
# 1. WiFi 연결
print("\n1️⃣ WiFi 연결 중...")
wifi = connect_wifi()
if not wifi:
show_error("WiFi Failed!")
print("❌ WiFi 연결 실패 - SSID와 비밀번호를 확인하세요")
else:
print(f"✅ WiFi 연결 성공!")
# 2. NTP 시간 동기화
print("\n2️⃣ NTP 동기화 중...")
if sync_time_ntp():
print("✅ 시간 동기화 성공!")
# 3. 시계 시작
print("\n3️⃣ 시계 작동 시작!")
print(" Ctrl+C 로 중지\n")
try:
while True:
kst = get_korea_time()
display_clock(kst)
# 터미널에도 시간 출력 (10초마다)
if kst[5] % 10 == 0:
print(f" {kst[3]:02d}:{kst[4]:02d}:{kst[5]:02d}")
time.sleep(1)
except KeyboardInterrupt:
print("\n\n⏹️ 시계 중지됨")
oled.fill(0)
oled.text("Clock Stopped", 15, 28)
oled.show()
else:
show_error("NTP Failed!")
print("❌ NTP 동기화 실패 - 인터넷 연결을 확인하세요")
⚠️ 자주 하는 실수¶
실수 1: WiFi 정보를 그대로 두고 실행¶
증상: WiFi 연결 실패 또는 무한 대기
원인: "your_wifi_name"을 실제 WiFi 이름으로 바꾸지 않음
해결:
# 잘못된 코드
WIFI_SSID = "your_wifi_name" # ❌ 예시 그대로
WIFI_PASSWORD = "your_password" # ❌ 예시 그대로
# 올바른 코드
WIFI_SSID = "우리집WiFi" # ✅ 실제 WiFi 이름
WIFI_PASSWORD = "wifi12345" # ✅ 실제 비밀번호
실수 2: 시간대 계산을 안 해서 9시간 느린 시간 표시¶
증상: OLED에 새벽 5시로 나오는데, 실제는 오후 2시
원인: time.localtime()은 UTC를 반환하는데, 그대로 표시함
해결:
# 잘못된 코드 - UTC 시간 그대로 표시
current = time.localtime() # ❌ UTC 시간
# 올바른 코드 - 한국 시간으로 변환
KST_OFFSET = 9 * 3600
utc_timestamp = time.time()
kst_timestamp = utc_timestamp + KST_OFFSET
current = time.localtime(kst_timestamp) # ✅ 한국 시간
실수 3: NTP 동기화를 WiFi 연결 전에 시도¶
증상: OSError: [Errno -2] ENOENT 또는 유사한 네트워크 에러
원인: 인터넷에 연결되지 않은 상태에서 NTP 서버에 접속 시도
해결:
# 잘못된 코드 - 순서가 틀림
ntptime.settime() # ❌ WiFi 연결 전에 실행
connect_wifi()
# 올바른 코드 - 순서 지키기
wifi = connect_wifi() # ✅ 1. 먼저 WiFi 연결
if wifi:
ntptime.settime() # ✅ 2. 그 다음 NTP 동기화
실수 4: OLED 라이브러리 없음¶
증상: ImportError: no module named 'ssd1306'
원인: ssd1306 라이브러리가 피코에 설치되지 않음
해결:
1. Thonny 메뉴에서 도구 → 패키지 관리
2. ssd1306 검색
3. micropython-ssd1306 설치
4. 다시 코드 실행
실수 5: while 루프에서 time.sleep() 빼먹음¶
증상: OLED 화면이 깜빡거리거나, 피코가 과열됨
원인: 루프가 초당 수천 번 실행되면서 과부하
해결:
# 잘못된 코드 - sleep 없음
while True:
display_clock(kst) # ❌ 초당 수천 번 실행!
# 올바른 코드 - 1초 대기 추가
while True:
display_clock(kst)
time.sleep(1) # ✅ 1초에 한 번만 실행
✅ 스스로 점검하기¶
-
NTP가 뭔지 한 문장으로 설명할 수 있어?
-
한국 시간은 UTC보다 몇 시간 빠를까? 그래서 코드에서 어떻게 처리했어?
-
왜 WiFi 연결을 NTP 동기화보다 먼저 해야 할까?
-
time.sleep(1)을time.sleep(0.1)로 바꾸면 어떻게 될까? -
피코 전원을 껐다 켜면 시간이 어떻게 될까? 왜 그럴까?
정답 확인
1. **NTP**: 인터넷에 있는 시간 서버에서 정확한 시간을 받아오는 프로토콜이야. 2. **9시간 빠름**. `KST_OFFSET = 9 * 3600`으로 9시간(32400초)을 UTC에 더해서 한국 시간을 계산해. 3. NTP 서버는 **인터넷에 있기 때문**에, WiFi로 인터넷에 먼저 연결해야 서버에 접속할 수 있어. 4. 화면이 **0.1초마다 갱신**돼. 보기엔 차이 없지만, 피코가 10배 더 일하게 되어 전력 소모가 늘어나. 5. **시간이 1970년 1월 1일로 초기화**돼. 피코는 배터리가 없어서 전원이 꺼지면 RTC가 멈추고, 시간 정보를 잃어버려. 그래서 매번 켤 때마다 NTP로 다시 동기화해야 해.🚀 더 해보기¶
도전 1: AM/PM 형식으로 바꾸기 ⭐¶
24시간 형식(14:30) 대신 12시간 형식(02:30 PM)으로 표시해봐!
힌트:
hour_12 = hour if hour <= 12 else hour - 12
period = "AM" if hour < 12 else "PM"
도전 2: 초침 애니메이션 추가하기 ⭐⭐¶
OLED 화면 아래쪽에 초를 나타내는 진행 바를 그려봐!
힌트:
# 60초를 128픽셀로 변환
bar_width = int(second * 128 / 60)
oled.fill_rect(0, 60, bar_width, 4, 1)
도전 3: 알람 기능 추가하기 ⭐⭐⭐¶
특정 시간이 되면 부저가 울리는 알람 시계를 만들어봐!
힌트:
ALARM_HOUR = 7
ALARM_MINUTE = 30
if hour == ALARM_HOUR and minute == ALARM_MINUTE:
# 부저 울리기!
buzzer.on()
🔗 다음 장으로¶
축하해! 🎉 이제 피코가 정확한 시간을 알게 됐어!
이번 장에서 배운 것: - NTP로 인터넷에서 시간 받아오기 - UTC를 한국 시간(UTC+9)으로 변환 - OLED에 실시간 디지털 시계 표시
다음 장에서는 웹 API를 배워볼 거야. 시간뿐만 아니라 날씨 정보도 인터넷에서 받아올 수 있어. 현재 기온, 날씨 상태, 심지어 내일 날씨까지! 시계에 날씨 정보를 추가하면 진짜 스마트 시계가 완성돼 🌤️