Chapter 11. MQTT와 Adafruit IO 클라우드 연동
IoT의 핵심 프로토콜인 MQTT를 학습합니다. 내 방의 센서 데이터를 전 세계 어디서든 스마트폰 대시보드로 모니터링할 수 있는 시스템을 구축합니다.
📡 MQTT란 무엇인가요?
MQTT(Message Queuing Telemetry Transport)는 IoT 기기처럼 배터리와 데이터 사용량이 제한된 장치를 위해 설계된 초경량 통신 프로토콜입니다. 웹사이트가 쓰는 HTTP보다 훨씬 가볍고, 실시간으로 값이 바뀔 때마다 즉시 전달할 수 있어 센서 데이터 전송에 매우 적합합니다.
MQTT 통신에는 3개의 역할이 있습니다.
- Publisher(발행자) — 데이터를 보내는 쪽. 예) Pico가 측정한 온습도 값
- Broker(브로커) — 메시지를 중계하는 서버. 이 챕터에서는
Adafruit IO가 브로커 역할을 합니다 - Subscriber(구독자) — 데이터를 받는 쪽. 예) 스마트폰 대시보드, 혹은 명령을 받는 Pico 자신
중요한 점은 Publisher와 Subscriber가 서로의 IP 주소나 위치를 몰라도 된다는 것입니다. 모두가 브로커의 Topic(토픽)이라는 "채널"만 바라보고 통신하기 때문에, Pico 한 대가 데이터를 발행(publish)하면서 동시에 다른 토픽을 구독(subscribe)하는 양방향 통신도 자연스럽게 가능합니다.
11.1 Adafruit IO 설정 및 연결 구성
Adafruit IO는 무료로 사용할 수 있는 MQTT 브로커 겸 클라우드 대시보드 서비스입니다. 센서 데이터를 받아 그래프로 보여주고, 버튼이나 스위치 위젯으로 다시 기기에 명령을 내려보낼 수 있습니다. Adafruit IO에서는 각 데이터 채널을 Feed(피드)라고 부르며, MQTT 토픽 이름은 항상 사용자이름/feeds/피드이름 형식을 따릅니다.
1. Adafruit IO에 가입하여 AIO Key를 복사해 두세요.
2. Thonny의 [Tools] -> [Manage Packages]에서 umqtt.simple을 검색해 설치해야 합니다.
| 항목 | 설정값 | 역할 |
|---|---|---|
| DHT11 Data | GP15 | 온습도 측정 |
| 상태 LED | LED | 클라우드 명령 확인 |
| MQTT Feed | temperature, humidity, led-cmd | 데이터 전송과 원격 제어 |
11.2 MQTT 발행과 구독 소스 코드
import time
import machine
import network
import dht
from umqtt.simple import MQTTClient
# Wi-Fi & Adafruit IO 설정
WIFI_SSID = "your_wifi_name"
WIFI_PASS = "your_wifi_password"
AIO_USER = "your_username"
AIO_KEY = "your_aio_key"
BROKER = "io.adafruit.com"
CLIENT_ID = "pico2-weather-node"
TEMP_FEED = AIO_USER + "/feeds/temperature"
HUM_FEED = AIO_USER + "/feeds/humidity"
LED_CMD_FEED = AIO_USER + "/feeds/led-cmd"
sensor = dht.DHT11(machine.Pin(15))
led = machine.Pin("LED", machine.Pin.OUT)
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASS)
print("Wi-Fi 연결 중...")
for _ in range(20):
if wlan.isconnected():
print("Wi-Fi Connected:", wlan.ifconfig()[0])
return
time.sleep(0.5)
raise RuntimeError("Wi-Fi connection failed")
def on_message(topic, msg):
command = msg.decode().strip().lower()
print("수신:", topic.decode(), command)
if command in ("on", "1", "true"):
led.on()
elif command in ("off", "0", "false"):
led.off()
def connect_mqtt():
client = MQTTClient(CLIENT_ID, BROKER, user=AIO_USER, password=AIO_KEY)
client.set_callback(on_message)
client.connect()
client.subscribe(LED_CMD_FEED)
print("MQTT Connected and subscribed:", LED_CMD_FEED)
return client
connect_wifi()
client = connect_mqtt()
last_publish = time.ticks_ms()
while True:
try:
# 구독한 led-cmd feed에 새 명령이 있는지 확인합니다.
client.check_msg()
if time.ticks_diff(time.ticks_ms(), last_publish) >= 10000:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
client.publish(TEMP_FEED, str(temp))
client.publish(HUM_FEED, str(hum))
print(f"Published: {temp}C, {hum}%")
last_publish = time.ticks_ms()
time.sleep(0.1)
except OSError as e:
print("MQTT 오류, 재연결 시도:", e)
time.sleep(3)
connect_wifi()
client = connect_mqtt()
💡 Feed 이름 확인
Adafruit IO에서 temperature, humidity, led-cmd feed를 먼저 만들어 두세요. 대시보드 버튼에서 led-cmd에 on 또는 off를 보내면 Pico의 내장 LED가 반응합니다.
11.3 동작 흐름
Pico는 10초마다 DHT11 값을 읽어 온도와 습도 feed로 발행합니다. 동시에 led-cmd feed를 구독하고 있다가 클라우드 대시보드에서 명령이 들어오면 내장 LED를 켜거나 끕니다. 이 구조가 IoT에서 가장 기본적인 양방향 통신 패턴입니다.
🏆 과제 해결해보기!
과제 1. 발행 주기 단축하고 새 Feed 추가하기
현재 코드는 10초마다 temperature, humidity 두 개의 feed만 발행합니다. 발행 주기를 5초로 줄이고, DHT11의 습도값이 70% 이상일 때 alert라는 이름의 새 feed에 문자열 "HIGH_HUMIDITY"를 추가로 발행하도록 코드를 수정해 보세요.
과제 2. 여러 개의 명령어로 LED 밝기 제어하기
현재 led-cmd feed는 on/off 두 가지 명령만 처리합니다. PWM을 이용해 0~100 사이의 숫자 문자열을 받으면 LED 밝기를 그 값에 비례하도록 조절하는 on_message 콜백을 작성해 보세요. (힌트: machine.PWM과 duty_u16()을 사용합니다.)
11.4 Wokwi 시뮬레이션으로 실습하기
Chapter 1(1.8)에서 소개한 Wokwi 온라인 시뮬레이터로 이 챕터의 코드 일부를 미리 테스트해볼 수 있습니다.
⚠️ Wokwi에서는 실제 MQTT 통신을 테스트할 수 없어요
Wokwi의 무료 시뮬레이션 Pico 보드는 기본적으로 실제 인터넷에 연결되지 않습니다. 따라서 network.WLAN으로 Wi-Fi에 접속하거나 umqtt.simple로 Adafruit IO 브로커에 실제로 연결하는 부분은 시뮬레이터에서 동작하지 않습니다.
대신 아래처럼 나누어 연습하는 것을 권장합니다.
- Wokwi에서 연습: DHT11 센서를 읽어 온도/습도 값을 출력하는 부분(
sensor.measure(),sensor.temperature(),sensor.humidity())만 따로 떼어 로컬 동작을 확인합니다. - 실제 하드웨어에서 확인: Wi-Fi 연결과
client.publish(),client.subscribe()등 실제 MQTT 송수신은 반드시 진짜 Pico 2 W 보드와 실제 Wi-Fi 환경에서 테스트하세요.
💡 Tip: 아래는 DHT11 센서 읽기 로직만 검증할 수 있는 최소 diagram.json 예시입니다. Wokwi 화면에서 [+ New Project] → [MicroPython] 선택 후, 아래 diagram.json 내용을 프로젝트의 diagram 편집기에 붙여넣고, main.py에는 DHT11을 읽어 print()로 출력하는 부분만 넣어 초록색 ▶️ 재생 버튼을 눌러 실행하세요.
{
"version": 1,
"author": "Pico 2 Guide",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-pi-pico", "id": "pico", "top": 0, "left": 0, "attrs": { "env": "micropython-20231005-v1.21.0" } },
{ "type": "wokwi-dht22", "id": "dht1", "top": -40, "left": 100, "attrs": { "temperature": "24", "humidity": "55" } }
],
"connections": [
[ "pico:GP15", "dht1:SDA", "green", [] ],
[ "dht1:VCC", "pico:3V3", "red", [] ],
[ "dht1:GND", "pico:GND", "black", [] ]
]
}
💡 참고: Wokwi 부품 라이브러리에는 DHT11 전용 부품이 없어 wokwi-dht22 부품으로 대체했습니다(코드에서 dht.DHT11 대신 dht.DHT22를 사용하면 됩니다). 정확한 부품 이름은 Wokwi 편집기 좌측의 부품 검색창에서 다시 한번 확인하는 것을 권장합니다.