4단원 마무리 - 나만의 환경 대시보드 완성¶
🎯 이 장에서 배우는 것¶
- [ ] 온습도, 조도 데이터를 표시하는 대시보드를 완성할 수 있다
- [ ] AI에게 추가 기능을 요청하여 개성 있는 대시보드로 발전시킬 수 있다
- [ ] 스마트폰에서 접속하여 시연할 수 있다
⏱️ 예상 학습 시간: 2차시
📚 미리 알아야 할 것¶
지금까지 배운 내용을 총정리해볼게요:
- Flask 웹서버: 피코에서 웹페이지 제공
- 센서 데이터 읽기: 온습도(DHT11), 조도(CDS)
- JSON API:
/api/data로 실시간 데이터 전송 - JavaScript fetch: 자동 갱신으로 화면 업데이트
📚 핵심 개념¶
개념: 대시보드 완성이란?¶
대시보드 완성은 마치 자동차 계기판을 조립하는 것과 같아요.
속도계, 연료계, 경고등을 한곳에 모아 운전자가 한눈에 볼 수 있게 만드는 거죠!
완성된 대시보드의 구성요소:
flowchart TB
subgraph 센서["📡 센서 수집"]
A[🌡️ 온도]
B[💧 습도]
C[☀️ 조도]
end
subgraph 서버["🖥️ 피코 서버"]
D["/api/data"]
end
subgraph 화면["📱 대시보드"]
E[숫자 표시]
F[상태 색상]
G[경고 알림]
end
A --> D
B --> D
C --> D
D --> E
D --> F
D --> G
🔨 따라하기¶
Step 1: 통합 대시보드 코드 완성¶
main.py - 센서 통합 서버:
from machine import Pin, ADC
import dht
import network
import socket
import json
import time
# 센서 설정
dht_sensor = dht.DHT11(Pin(15))
cds = ADC(Pin(26))
# WiFi 연결
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('WiFi이름', '비밀번호')
while not wlan.isconnected():
time.sleep(1)
print(f'접속 주소: http://{wlan.ifconfig()[0]}')
# HTML 페이지
html = """<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🏠 환경 대시보드</title>
<style>
body {
font-family: Arial;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
margin: 0;
padding: 20px;
}
.container {
max-width: 400px;
margin: 0 auto;
}
h1 {
color: white;
text-align: center;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.card {
background: white;
border-radius: 20px;
padding: 25px;
margin: 15px 0;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
text-align: center;
transition: transform 0.3s;
}
.card:hover { transform: scale(1.02); }
.icon { font-size: 50px; }
.value {
font-size: 48px;
font-weight: bold;
margin: 10px 0;
}
.label { color: #666; font-size: 14px; }
.temp { color: #e74c3c; }
.humid { color: #3498db; }
.light { color: #f39c12; }
.status {
padding: 8px 16px;
border-radius: 20px;
color: white;
font-size: 14px;
margin-top: 10px;
display: inline-block;
}
.good { background: #27ae60; }
.warning { background: #f39c12; }
.danger { background: #e74c3c; }
.update-time {
color: rgba(255,255,255,0.8);
text-align: center;
font-size: 12px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>🏠 내 방 환경</h1>
<div class="card">
<div class="icon">🌡️</div>
<div class="value temp" id="temp">--</div>
<div class="label">온도 (°C)</div>
<div class="status" id="temp-status">측정 중...</div>
</div>
<div class="card">
<div class="icon">💧</div>
<div class="value humid" id="humid">--</div>
<div class="label">습도 (%)</div>
<div class="status" id="humid-status">측정 중...</div>
</div>
<div class="card">
<div class="icon">☀️</div>
<div class="value light" id="light">--</div>
<div class="label">밝기 (%)</div>
<div class="status" id="light-status">측정 중...</div>
</div>
<div class="update-time" id="update-time"></div>
</div>
<script>
function getStatus(type, value) {
if (type === 'temp') {
if (value < 18) return ['🥶 추워요', 'warning'];
if (value > 28) return ['🥵 더워요', 'danger'];
return ['😊 쾌적해요', 'good'];
}
if (type === 'humid') {
if (value < 30) return ['건조해요', 'warning'];
if (value > 70) return ['습해요', 'warning'];
return ['적당해요', 'good'];
}
if (type === 'light') {
if (value < 20) return ['🌙 어두워요', 'warning'];
if (value > 80) return ['😎 밝아요', 'good'];
return ['적당해요', 'good'];
}
}
function updateDashboard() {
fetch('/api/data')
.then(response => response.json())
.then(data => {
document.getElementById('temp').textContent = data.temperature;
document.getElementById('humid').textContent = data.humidity;
document.getElementById('light').textContent = data.light;
// 상태 업데이트
let [tempText, tempClass] = getStatus('temp', data.temperature);
let [humidText, humidClass] = getStatus('humid', data.humidity);
let [lightText, lightClass] = getStatus('light', data.light);
document.getElementById('temp-status').textContent = tempText;
document.getElementById('temp-status').className = 'status ' + tempClass;
document.getElementById('humid-status').textContent = humidText;
document.getElementById('humid-status').className = 'status ' + humidClass;
document.getElementById('light-status').textContent = lightText;
document.getElementById('light-status').className = 'status ' + lightClass;
// 시간 표시
let now = new Date();
document.getElementById('update-time').textContent =
'마지막 업데이트: ' + now.toLocaleTimeString();
});
}
updateDashboard();
setInterval(updateDashboard, 3000);
</script>
</body>
</html>"""
def get_sensor_data():
"""모든 센서 데이터 읽기"""
try:
dht_sensor.measure()
temp = dht_sensor.temperature()
humid = dht_sensor.humidity()
except:
temp, humid = 0, 0
# 조도를 퍼센트로 변환 (0~65535 → 0~100)
light_raw = cds.read_u16()
light = int((1 - light_raw / 65535) * 100)
return {"temperature": temp, "humidity": humid, "light": light}
# 웹서버 시작
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(1)
print('대시보드 서버 시작!')
while True:
cl, addr = s.accept()
request = cl.recv(1024).decode()
if 'GET /api/data' in request:
data = get_sensor_data()
response = json.dumps(data)
cl.send('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n')
cl.send(response)
else:
cl.send('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n')
cl.send(html)
cl.close()
Step 2: 스마트폰에서 접속하기¶
flowchart LR
A["📱 스마트폰"] -->|"같은 WiFi"| B["📶 공유기"]
B --> C["🔌 피코 W"]
style A fill:#e8f5e9
style C fill:#fff3e0
접속 방법:
- 스마트폰을 같은 WiFi에 연결
- Thonny 콘솔에 표시된 IP 주소 확인
- 스마트폰 브라우저에서 http://IP주소 입력
✅ 체크포인트: 스마트폰에서 온도, 습도, 조도가 모두 보이면 성공!
🤖 AI와 함께 기능 추가하기¶
이제 AI에게 원하는 기능을 요청해보세요!
요청 예시 1: 그래프 추가¶
"온도 변화를 보여주는 간단한 막대 그래프를 추가하고 싶어요.
최근 10개 데이터를 보여주면 좋겠어요."
요청 예시 2: 알림음 추가¶
"온도가 30도를 넘으면 부저가 울리게 하고 싶어요.
어떻게 코드를 수정하면 될까요?"
요청 예시 3: 디자인 변경¶
"대시보드 배경색을 어두운 테마로 바꾸고 싶어요.
다크모드처럼요!"
💡 팁: AI에게 현재 코드를 보여주고, 원하는 결과를 구체적으로 설명하면 더 정확한 답을 얻을 수 있어요!
📝 전체 시스템 구성¶
flowchart TB
subgraph HW["하드웨어"]
P["Pico W"]
D["DHT11"]
C["CDS 센서"]
end
subgraph SW["소프트웨어"]
S["Flask 서버"]
A["JSON API"]
H["HTML/CSS/JS"]
end
subgraph USER["사용자"]
PC["💻 컴퓨터"]
PH["📱 스마트폰"]
end
D --> P
C --> P
P --> S
S --> A
S --> H
A --> PC
A --> PH
H --> PC
H --> PH
⚠️ 주의할 점¶
1. WiFi 연결 문제¶
증상: 스마트폰에서 접속이 안 돼요
해결: - 피코와 스마트폰이 같은 WiFi인지 확인 - 공유기의 AP 격리(Client Isolation) 기능이 꺼져 있는지 확인
2. 센서 오류¶
증상: 온도가 0으로 표시돼요
해결: - DHT11 연결 핀 번호 확인 (GP15) - 센서 전원(3.3V, GND) 확인