콘텐츠로 이동

Chapter 18: 2단원 마무리 - 환경 모니터링 스테이션

🎯 이 장에서 배우는 것

  • [ ] 여러 센서를 통합한 환경 모니터링 시스템을 완성할 수 있다
  • [ ] 수집한 데이터를 시각화하고 패턴을 분석할 수 있다
  • [ ] 데이터 기반 인사이트를 도출하고 발표할 수 있다

⏱️ 예상 학습 시간: 2차시 (프로젝트 완성 + 발표)

📚 미리 알아야 할 것

2단원에서 배운 모든 내용이 하나로 합쳐집니다:

flowchart LR A[온습도 센서] --> D[환경 모니터링<br/>스테이션] B[조도 센서] --> D C[데이터 로깅] --> D D --> E[📊 분석 & 발표] style D fill:#e8f5e9,stroke:#388e3c,stroke-width:3px style E fill:#fff3e0,stroke:#f57c00

📚 프로젝트 개요

🏫 "우리 교실 환경 모니터링 스테이션"

flowchart TB subgraph 수집["📥 데이터 수집 (1-2시간)"] A[온도] B[습도] C[조도] end subgraph 저장["💾 데이터 저장"] D[CSV 파일] end subgraph 분석["📊 분석 & 시각화"] E[그래프 생성] F[패턴 발견] end subgraph 발표["🎤 인사이트 공유"] G[결과 발표] end 수집 --> 저장 --> 분석 --> 발표

🔨 따라하기

Step 1: 통합 모니터링 코드 완성

전체 코드 (복사해서 바로 사용하세요):

from machine import Pin, ADC, I2C
import dht
import time

# === 센서 초기화 ===
dht_sensor = dht.DHT11(Pin(15))
light_sensor = ADC(Pin(34))
light_sensor.atten(ADC.ATTN_11DB)

# === 데이터 수집 함수 ===
def read_all_sensors():
    """모든 센서 데이터를 한 번에 읽기"""
    try:
        dht_sensor.measure()
        temp = dht_sensor.temperature()
        humi = dht_sensor.humidity()
    except:
        temp, humi = None, None

    light_raw = light_sensor.read()
    light_percent = round(light_raw / 4095 * 100, 1)

    return {
        'temp': temp,
        'humi': humi,
        'light': light_percent
    }

# === 데이터 저장 함수 ===
def save_to_csv(filename, data, timestamp):
    """CSV 파일에 데이터 추가"""
    with open(filename, 'a') as f:
        line = f"{timestamp},{data['temp']},{data['humi']},{data['light']}\n"
        f.write(line)
        print(f"✅ 저장: {line.strip()}")

# === 메인 모니터링 루프 ===
def start_monitoring(duration_minutes=60, interval_seconds=60):
    """
    환경 모니터링 시작
    - duration_minutes: 총 모니터링 시간(분)
    - interval_seconds: 측정 간격(초)
    """
    filename = "classroom_data.csv"

    # CSV 헤더 작성
    with open(filename, 'w') as f:
        f.write("timestamp,temperature,humidity,light\n")

    print("🏫 교실 환경 모니터링 시작!")
    print(f"📊 {duration_minutes}분간, {interval_seconds}초 간격으로 측정")
    print("-" * 40)

    count = 0
    total_readings = (duration_minutes * 60) // interval_seconds

    while count < total_readings:
        data = read_all_sensors()
        timestamp = count * interval_seconds  # 초 단위 시간

        # 화면에 표시
        print(f"\n{timestamp//60}{timestamp%60}초")
        print(f"   🌡️ 온도: {data['temp']}°C")
        print(f"   💧 습도: {data['humi']}%")
        print(f"   💡 조도: {data['light']}%")

        # 파일에 저장
        save_to_csv(filename, data, timestamp)

        count += 1

        if count < total_readings:
            time.sleep(interval_seconds)

    print("\n" + "=" * 40)
    print("✅ 모니터링 완료!")
    print(f"📁 데이터 저장 위치: {filename}")
    print(f"📊 총 {count}개 데이터 수집")

# === 실행 ===
# 테스트: 5분간 30초 간격으로 측정
start_monitoring(duration_minutes=5, interval_seconds=30)

💡 : 실제 프로젝트에서는 duration_minutes=60으로 1시간 측정하세요!


Step 2: 수집된 데이터 확인

# === 저장된 데이터 읽어보기 ===
def view_data(filename="classroom_data.csv"):
    """저장된 데이터 확인"""
    print("📊 수집된 데이터:")
    print("-" * 50)

    with open(filename, 'r') as f:
        for line in f:
            print(line.strip())

view_data()

예상 출력:

📊 수집된 데이터:
--------------------------------------------------
timestamp,temperature,humidity,light
0,24,55,78.5
30,24,56,75.2
60,25,54,72.1
90,25,55,68.9
...


Step 3: 데이터 분석 (PC에서)

데이터를 PC로 옮긴 후, Python으로 분석합니다:

# PC에서 실행 (pandas, matplotlib 필요)
import pandas as pd
import matplotlib.pyplot as plt

# 데이터 읽기
df = pd.read_csv('classroom_data.csv')

# 시간을 분 단위로 변환
df['minutes'] = df['timestamp'] / 60

# === 그래프 그리기 ===
fig, axes = plt.subplots(3, 1, figsize=(10, 8))

# 온도 그래프
axes[0].plot(df['minutes'], df['temperature'], 'r-', linewidth=2)
axes[0].set_ylabel('온도 (°C)')
axes[0].set_title('🌡️ 온도 변화')
axes[0].grid(True)

# 습도 그래프
axes[1].plot(df['minutes'], df['humidity'], 'b-', linewidth=2)
axes[1].set_ylabel('습도 (%)')
axes[1].set_title('💧 습도 변화')
axes[1].grid(True)

# 조도 그래프
axes[2].plot(df['minutes'], df['light'], 'orange', linewidth=2)
axes[2].set_ylabel('조도 (%)')
axes[2].set_xlabel('시간 (분)')
axes[2].set_title('💡 조도 변화')
axes[2].grid(True)

plt.tight_layout()
plt.savefig('classroom_environment.png')
plt.show()

print("📈 그래프 저장 완료: classroom_environment.png")

📊 데이터 분석 가이드

찾아볼 패턴들

flowchart TB subgraph 질문["🤔 분석 질문"] Q1[온도가 가장 높은 시간은?] Q2[습도와 온도의 관계는?] Q3[조도 변화의 원인은?] end subgraph 발견["💡 인사이트 예시"] A1[점심시간에 온도 상승] A2[온도↑ = 습도↓ 경향] A3[구름/커튼으로 조도 급감] end Q1 --> A1 Q2 --> A2 Q3 --> A3

통계 요약 코드

# 기본 통계 확인
print("📊 데이터 요약")
print("=" * 40)
print(f"🌡️ 온도: 평균 {df['temperature'].mean():.1f}°C")
print(f"        최저 {df['temperature'].min()}°C ~ 최고 {df['temperature'].max()}°C")
print()
print(f"💧 습도: 평균 {df['humidity'].mean():.1f}%")
print(f"        최저 {df['humidity'].min()}% ~ 최고 {df['humidity'].max()}%")
print()
print(f"💡 조도: 평균 {df['light'].mean():.1f}%")
print(f"        최저 {df['light'].min():.1f}% ~ 최고 {df['light'].max():.1f}%")

🎤 발표 준비

발표 구성 (5분)

flowchart LR A[1. 프로젝트 소개<br/>30초] --> B[2. 데이터 수집 과정<br/>1분] B --> C[3. 그래프 & 분석<br/>2분] C --> D[4. 인사이트 & 제안<br/>1분] D --> E[5. 마무리<br/>30초]

발표 템플릿

1. 프로젝트 소개 "저희 모둠은 ○○교실의 환경을 ○○분간 모니터링했습니다."

2. 데이터 수집 "총 ○○개의 데이터를 ○○초 간격으로 수집했습니다."

3. 주요 발견 "그래프를 보시면 ○○시에 온도가 급격히 ○○하는 것을 알 수 있습니다."

4. 인사이트 "이를 통해 알 수 있는 것은... / 개선 제안은..."

5. 마무리 "데이터를 통해 ○○을 직접 확인할 수 있었습니다."


⚠️ 주의할 점

1. 센서 위치 선정

✅ 좋은 위치:
- 책상 위, 사람에게서 떨어진 곳
- 에어컨/히터 바람이 직접 닿지 않는 곳

❌ 피할 위치:
- 창문 바로 옆 (직사광선)
- 컴퓨터 뒤 (열기)

2. 데이터 손실 방지

# 중간 저장 확인
import os
if 'classroom_data.csv' in os.listdir():
    print("✅ 데이터 파일 존재")
else:
    print("⚠️ 파일 없음 - 모니터링 시작 필요")

✅ 2단원 최종 점검

🎯 센서 통합 역량

  1. DHT11로 온습도를 측정할 수 있나요?
확인 ✅ `dht_sensor.temperature()`, `dht_sensor.humidity()` 사용
  1. 조도 센서 값을 퍼센트로 변환할 수 있나요?
확인 ✅ `light_raw / 4095 * 100`으로 0~100% 변환
  1. 데이터를 CSV 파일에 저장할 수 있나요?
확인 ✅ `open(filename, 'a')`로 추가 모드 열기, `f.write()`로 저장

🏆 2단원 완료!

🎉 축하합니다!

여러분은 이제 진짜 데이터 과학자처럼 일할 수 있어요!

배운 것들: - ✅ 온습도 센서로 환경 측정 - ✅ 조도 센서로 빛 측정
- ✅ 데이터 저장 & 로깅 - ✅ 데이터 분석 & 시각화 - ✅ 인사이트 도출 & 발표

```mermaid flowchart LR subgraph 완료["✅ Part 2 완료"] A[센서로 세상을
측정하기] end

subgraph 다음["🚀 Part 3 예고"]
    B[모터로 세상을<br/>움직이기]
end

완료 --> 다음

style 완료 fill:#c8e6c9,stroke:#388e3c,stroke-width:2px
style 다음 fill:#bbdefb,stroke:#1976d2,