ESP32 MQTT 기반 OTA 구현 방법
ESP32에서 MQTT를 제어 채널로 사용해 펌웨어를 배포하고 HTTP로 바이너리를 받아 업데이트하는 절차와 코드 예제 설명
목차
개요
이 글은 ESP32에 MQTT를 활용한 OTA(Over-The-Air) 업데이트 흐름을 설명한다. MQTT는 기기 제어와 알림에 적합하며, 펌웨어 바이너리 자체는 HTTP 서버에 두고 MQTT는 업데이트 명령을 전달하는 방식으로 안정성을 높인다. 초보자도 이해할 수 있도록 단계별로 구성하며 esp32 ota mqtt 예제 코드를 포함한다.
필요 조건
- ESP32 개발보드
- Arduino 환경 또는 ESP-IDF 환경 (여기서는 Arduino 스타일 예제 사용)
- MQTT 브로커 (예: Mosquitto)
- HTTP 서버에 올린 펌웨어 바이너리 파일
구성 개요
구성은 간단하다. MQTT는 업데이트 명령(버전, 바이너리 URL)을 기기로 전달한다. ESP32는 메시지를 받고 현재 버전과 비교한 뒤 HTTP로 바이너리를 내려받아 Update API로 펌웨어를 적용한다. 이 패턴이 mqtt 기반 ota 구현의 핵심이다.
절차 요약
- 1) 빌드: 새로운 펌웨어를 컴파일하고 firmware.bin 생성
- 2) 배포: HTTP 서버(또는 CDN)에 firmware.bin 업로드
- 3) 알림: MQTT로 topic(예: ota/esp32/command)에 URL과 버전 전송
- 4) 수신: ESP32가 메시지 수신, 버전 확인 후 다운로드 시작
- 5) 업데이트: HTTP로 받은 바이너리를 Update API로 플래시 후 재부팅
MQTT 메시지 포맷
간단한 CSV 형식으로 예시를 든다. 실무에서는 JSON 또는 서명된 메시지 사용을 권장한다.
- 토픽: ota/esp32/command
- 페이로드 예: http://server/firmware.bin,1.2.0
ESP32 예제 코드 (Arduino)
아래 코드는 기본적인 mqtt 기반 ota 구현 예제다. MQTT로 URL과 버전을 받아 HTTP로 바이너리를 받아 업데이트한다. 실제 배포 전에는 TLS와 서명 검증을 추가해야 안전하다.
#include <WiFi.h>
#include <HTTPClient.h>
#include <Update.h>
#include <PubSubClient.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "YOUR_MQTT_BROKER_IP";
WiFiClient espClient;
PubSubClient client(espClient);
String currentVersion = "1.0.0"; // 기기에 내장된 현재 버전
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
// 페이로드 형식: url,version
int comma = msg.indexOf(',');
if (comma == -1) return;
String url = msg.substring(0, comma);
String ver = msg.substring(comma + 1);
if (ver != currentVersion) {
Serial.println("New version available: " + ver);
performOTA(url);
} else {
Serial.println("Already latest version");
}
}
void reconnect() {
while (!client.connected()) {
if (client.connect("esp32-client")) {
client.subscribe("ota/esp32/command");
} else {
delay(2000);
}
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
}
void performOTA(const String &url) {
HTTPClient http;
http.begin(url);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
int contentLength = http.getSize();
bool canBegin = Update.begin(contentLength);
if (canBegin) {
WiFiClient *stream = http.getStreamPtr();
size_t written = Update.writeStream(*stream);
if (written == (size_t)contentLength) {
if (Update.end(true)) {
Serial.println("Update OK, rebooting...");
ESP.restart();
}
}
}
}
http.end();
}
브로커에서 업데이트 알림 전송 예
Mosquitto가 설치된 서버에서 터미널로 간단히 전송할 수 있다.
mosquitto_pub -h broker.example.com -t ota/esp32/command -m "http://example.com/firmware.bin,1.2.0"
보안 및 안정성 고려사항
- MQTT와 HTTP는 가능하면 TLS를 사용해 중간자 공격을 방지한다.
- 업데이트 파일에 서명 또는 해시를 제공해 무결성을 검증한다.
- 부분 다운로드나 네트워크 실패를 고려해 재시도 로직을 구현한다.
- 배터리 전원 환경에서는 업데이트 도중 전원 차단을 방지하는 전략 필요
문제 해결 팁
- Update.begin 실패: contentLength가 정확한지 확인
- 다운로드 중 끊김: HTTPClient의 버퍼 크기와 재시도 로직 확인
- 기기가 재시작 후 동일 버전 유지: 버전 문자열 저장 위치 확인
마무리
MQTT를 제어 채널로 사용하고 HTTP로 바이너리를 전달하는 방식은 구현이 단순하면서도 확장성 있다. 위 예제는 esp32 펌웨어 업데이트 mqtt 환경에서 바로 적용 가능한 기본 흐름을 제공하며, 실제 서비스에서는 보안 강화와 무결성 검증을 추가해 운영 품질을 높인다. 추가로 심층 구현을 원하면 서명 검증과 TLS 설정을 검토할 것.