Chapter 15. [종합] IoT 스마트 보안 시스템

지금까지 배운 모든 기술을 하나로 합칩니다. PIR 센서로 침입을 감지하고, 초음파 센서로 거리를 측정하며, LCD에 상태를 표시하고, 웹 서버를 통해 원격으로 경보를 해제하는 통합 시스템입니다.

Pico 2 W 스마트 보안 시스템 연결도 PIR 센서, 초음파 센서, I2C LCD, 부저, Wi-Fi 대시보드를 Pico 2 W에 연결한 구성도입니다. 입력 센서 제어 보드 출력 / 원격 제어 PIR 움직임 감지 OUT HC-SR04 Trig / Echo 거리 측정 TRIG/ECHO Pico 2 W MicroPython Web Server 센서 감지 + LCD 표시 + 경보 제어 GP18 PIR GP17/16 초음파 GP8/9 I2C GP14 부저 SECURE Dist: 35.2cm LCD 상태 표시 Buzzer 사이렌 Wi-Fi Dashboard ARM / DISARM / RESET 무선 제어 센서 입력 I2C 표시 경보 출력 Wi-Fi 원격 제어

각 선은 실제 GPIO 역할에 맞춰 끝점을 맞췄습니다. 초음파 센서는 GP17(Trig)과 GP16(Echo), LCD는 GP8/GP9 I2C, 부저는 GP14, PIR은 GP18을 사용합니다.

15.1 준비물과 연결 핀

아래 핀맵대로 연결하면 지금까지 배운 센서 입력, 출력 장치, 웹 제어가 한 프로젝트 안에서 함께 동작합니다. 초음파 센서의 Echo가 5V로 출력되는 모듈이라면 Pico 입력 보호를 위해 저항 분압을 사용하세요.

부품 Pico 2 W 핀 역할
PIR 센서 OUT GP18 사람 움직임 감지
초음파 Trig / Echo GP17 / GP16 거리 측정
I2C LCD SDA / SCL GP8 / GP9 상태 메시지 표시
부저 + GP14 침입 감지 시 경보음

15.2 통합 시스템 메인 소스 코드

이 코드는 Ch 5(Web), Ch 7(Sensors), Ch 9(LCD)의 내용을 실제로 합친 예시입니다. 브라우저에서 Pico의 IP 주소로 접속하면 보안 모드 켜기/끄기, 경보 초기화, 현재 거리와 움직임 상태를 확인할 수 있습니다.

import machine
import network
import socket
import time
from pico_i2c_lcd import I2cLcd

# Wi-Fi 설정
SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"

# 보안 기준값
DIST_LIMIT_CM = 20
BUZZER_TIME = 0.25

# 핀 설정
pir = machine.Pin(18, machine.Pin.IN)
trig = machine.Pin(17, machine.Pin.OUT)
echo = machine.Pin(16, machine.Pin.IN)
buzzer = machine.Pin(14, machine.Pin.OUT)

# LCD 설정
i2c = machine.I2C(0, sda=machine.Pin(8), scl=machine.Pin(9))
lcd = I2cLcd(i2c, 0x27, 2, 16)

is_armed = True
alarm_on = False
last_distance = 0
last_motion = 0

def lcd_message(line1, line2=""):
    lcd.clear()
    lcd.move_to(0, 0)
    lcd.putstr(line1[:16])
    lcd.move_to(0, 1)
    lcd.putstr(line2[:16])

def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(SSID, PASSWORD)
    lcd_message("Wi-Fi Connect", "Please wait...")

    for _ in range(20):
        if wlan.isconnected():
            ip = wlan.ifconfig()[0]
            lcd_message("Web Server IP", ip)
            print("Connected:", ip)
            return ip
        time.sleep(0.5)

    lcd_message("Wi-Fi Failed", "Check SSID/PW")
    raise RuntimeError("Wi-Fi connection failed")

def wait_pin_value(pin, target, timeout_us=30000):
    start = time.ticks_us()
    while pin.value() != target:
        if time.ticks_diff(time.ticks_us(), start) > timeout_us:
            return None
    return time.ticks_us()

def get_distance():
    trig.low()
    time.sleep_us(2)
    trig.high()
    time.sleep_us(10)
    trig.low()

    start = wait_pin_value(echo, 1)
    if start is None:
        return 999

    end = wait_pin_value(echo, 0)
    if end is None:
        return 999

    return (time.ticks_diff(end, start) * 0.0343) / 2

def beep(count=1):
    for _ in range(count):
        buzzer.high()
        time.sleep(BUZZER_TIME)
        buzzer.low()
        time.sleep(0.08)

def render_page():
    armed_text = "ON" if is_armed else "OFF"
    alarm_text = "DETECTED" if alarm_on else "CLEAR"
    motion_text = "YES" if last_motion else "NO"

    return f"""<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pico Security</title>
    <style>
        body {{ font-family: Arial, sans-serif; max-width: 560px; margin: 40px auto; color: #0f172a; }}
        .box {{ border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; }}
        .danger {{ color: #dc2626; font-weight: bold; }}
        .ok {{ color: #16a34a; font-weight: bold; }}
        a {{ display: inline-block; margin: 6px; padding: 10px 14px; border-radius: 8px; background: #0ea5e9; color: white; text-decoration: none; }}
        a.warn {{ background: #f97316; }}
    </style>
</head>
<body>
    <h1>Pico 2 W Security</h1>
    <div class="box">
        <p>보안 모드: <strong>{armed_text}</strong></p>
        <p>경보 상태: <span class="{'danger' if alarm_on else 'ok'}">{alarm_text}</span></p>
        <p>움직임 감지: {motion_text}</p>
        <p>거리: {last_distance:.1f} cm</p>
        <a href="/arm">ARM</a>
        <a href="/disarm" class="warn">DISARM</a>
        <a href="/reset">RESET</a>
    </div>
</body>
</html>"""

def handle_request(request):
    global is_armed, alarm_on

    if "GET /arm" in request:
        is_armed = True
        lcd_message("Security Mode", "ARMED")
    elif "GET /disarm" in request:
        is_armed = False
        alarm_on = False
        buzzer.low()
        lcd_message("Security Mode", "DISARMED")
    elif "GET /reset" in request:
        alarm_on = False
        buzzer.low()
        lcd_message("Alarm Reset", "Monitoring...")

def start_server(ip):
    addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1]
    server = socket.socket()
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(addr)
    server.listen(1)
    server.settimeout(0.05)
    print("Open browser: http://" + ip)
    return server

ip = connect_wifi()
server = start_server(ip)
lcd_message("System Ready", ip)

while True:
    last_motion = pir.value()
    last_distance = get_distance()

    if is_armed:
        if last_motion == 1 or last_distance < DIST_LIMIT_CM:
            alarm_on = True
            lcd_message("!! WARNING !!", "INTRUDER")
            beep(2)
        else:
            lcd.move_to(0,0)
            lcd.putstr("Status: Secure  ")
            lcd.move_to(0,1)
            lcd.putstr(f"Dist:{last_distance:5.1f}cm ")

    try:
        client, addr = server.accept()
        request = client.recv(1024).decode()
        handle_request(request)
        response = render_page()
        client.send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
        client.send(response)
        client.close()
    except OSError:
        pass

    time.sleep(0.1)

💡 테스트 순서

먼저 SSIDPASSWORD를 수정한 뒤 실행하세요. LCD에 표시된 IP 주소를 같은 Wi-Fi에 연결된 컴퓨터나 스마트폰 브라우저에 입력하면 제어 화면이 열립니다.

15.3 동작 흐름

시스템은 0.1초 간격으로 PIR과 초음파 센서를 읽습니다. 보안 모드가 켜져 있고 움직임이 감지되거나 거리가 20cm보다 가까워지면 LCD에 경고를 띄우고 부저를 울립니다. 웹 대시보드에서 DISARM을 누르면 감지를 잠시 끄고, ARM을 누르면 다시 감시를 시작합니다.

🏁 완강을 축하드립니다!

이제 여러분은 하드웨어 제어, 통신, 클라우드 연동까지 가능한 Pico 2 마스터가 되었습니다. 이 가이드북의 기초를 바탕으로 여러분만의 더 멋진 발명품을 만들어보세요!