요즘에는 많은 IOT 기기들과 작업하고 있어요. 많은 기기들을 다루는 데 큰 어려움이 있어요. 운영, 데이터 수집, 유지관리 등을 모두 집중적으로 하기가 어려워요.
리얼타임 기기들이 클라우드와 어떻게 소통할 수 있는 가장 좋은 방법은 무엇인가요?
MQTT 프로토콜에 대해 알아봐요!!!!!!!!
이 글에서는 다음의 내용을 다룹니다.
- MQTT 브로커와의 ESP8266 연결
- MQTT 브로커와의 Flutter 연결
가이드를 두 부분으로 나눴어요.
첫 번째 파트에서는 우리의 브로커와 Esp8266을 구성하는 방법에 대해 다룹니다.
두 번째 파트에서는 어플리케이션에서 데이터를 읽고 쓰는 방법에 대해 다룹니다.
MQTT 브로커란 무엇인가요?
아키텍처 사이에서 중개자 역할을 한다고 생각해보세요. Esp8266 장치는 데이터를 브로커로 보내고, 거기서 데이터가 저장됩니다. 그런 후 어플리케이션은 MQTT 브로커에 연결하여 데이터에 접근할 수 있습니다.
참고: 대부분의 경우, 데이터를 처리하기 위해 백엔드가 필요하고 응용 프로그램이 이에 액세스하지만, MQTT를 사용하여 연결하고 데이터를 보내는 방법을 알고 나면 쉽다는 것을 이 문서에서 다루지는 않습니다. 나중에 전체 IOT 인프라를 보여주는 글을 쓸 수도 있습니다.
준비물
- MQTT의 이해
- 발행/구독 아키텍처의 기본 이해
- ESP8266 Node MCU 모듈
- Flutter 또는 다른 기본 프레임워크에 대한 이해
파트 1: 설정
전체 아키텍처를 구현하려면 먼저 MQTT 브로커가 필요합니다. HiveMQ와 EMQX와 같은 많은 무료 브로커들이 있으며 Mosquitto를 사용하여 로컬 브로커를 만들 수도 있습니다.
EMQX에 계정을 등록하고 브로커를 생성했습니다.
그런 다음 브로커에 액세스하는 데 사용될 몇 가지 사용자 계정을 만듭니다.
Part 2: ESP8266 펌웨어
펌웨어 작업을 시작하기 전에 몇 가지 알아야 할 사항이 있습니다.
웹에서 MQTT 브로커에 액세스할 때 TLS를 사용하거나 사용하지 않을 수 있습니다. 제 경험상 TLS를 사용하지 않고 브로커에 연결하려고 시도하면 Esp8266에서 작동하지 않습니다. 모든 연결 요청이 거부됩니다. 따라서 저는 연결을 가장 안전하게 만드는 방법을 보여드리겠습니다.
- 브로커에서 인증서를 다운로드하십시오 (나중에 필요할 것입니다)
- Arduino IDE를 열고 Esp8266을 설정합니다.
Esp8266을 사용해본 적이 없다면, 이 가이드를 따를 수 있습니다.
우선 라이브러리를 가져오겠습니다.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// 이 부분은 선택 사항입니다. 센서 데이터로 보낼 무작위 숫자를 생성하기 위해 사용했습니다.
#include <ESP8266TrueRandom.h>
// 인터넷과의 시간 동기화에 사용됩니다.
#include <time.h>
이제 자격 증명을 정의해 봅시다.
const char *ntp_server = "0.pool.ntp.org"; // 기본 NTP 서버
const long gmt_offset_sec = 0; // GMT 오프셋(시간대에 맞게 조정)
const int daylight_offset_sec = 0; // 일광 절약 시간 오프셋(초)
const char* SSID = "************";
const char* PASSWORD = "************";
const char* MQTT_HOST = "************"; // 브로커 대시보드에서 가져오세요
const int MQTT_PORT = 8883; // 기본 MQTT TCP TLS 포트
const char* MQTT_USERNAME = "";
const char* MQTT_PASSWORD = "";
const char* MQTT_TOPIC = "test";
char payload[10] = "";
BearSSL::WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);
이제 다운로드한 인증서 데이터를 입력해 봅시다. 텍스트 편집기로 해당 파일을 열어 내용을 복사하세요.
다음은 Markdown 형식으로 table 태그를 변경해주세요.
static const char ca_cert[] = R"EOF(
|-----BEGIN CERTIFICATE-----|
|---MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh---|
|---MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3---|
|---d3cuZGlnaWNlcnQuYa9tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD---|
|-----END CERTIFICATE-----|
)EOF";
먼저, WiFi에 연결해야 합니다.
void connectToWiFi() {
WiFi.begin(SSID, PASSWORD);
Serial.print("WiFi에 연결 중");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 네트워크에 연결되었습니다");
}
우리의 Esp8266과 시간을 동기화하기 위해 NTP(Network Time Protocol) 서버를 사용합니다.
void syncTime() {
configTime(gmt_offset_sec, daylight_offset_sec, ntp_server);
Serial.print("NTP 시간 동기화를 기다리는 중: ");
while (time(nullptr) < 8 * 3600 * 2) {
delay(1000);
Serial.print(".");
}
Serial.println("시간이 동기화되었습니다.");
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
Serial.print("현재 시간: ");
Serial.println(asctime(&timeinfo));
} else {
Serial.println("로컬 시간을 가져오지 못했습니다.");
}
}
브로커에 연결하려면 다음 함수를 사용할 것입니다.
void connectToMQTTBroker() {
// 우리의 인증서를 사용하여 신뢰할 수 있는 연결 요청을 수행합니다
BearSSL::X509List serverTrustedCA(ca_cert);
espClient.setTrustAnchors(&serverTrustedCA);
while (!mqtt_client.connected()) {
String client_id = "esp8266-client-" + String(WiFi.macAddress());
Serial.printf("%s로 MQTT 브로커에 연결 중.....\n", client_id.c_str());
if (mqtt_client.connect(client_id.c_str(), MQTT_USERNAME, MQTT_PASSWORD)) {
Serial.println("MQTT 브로커에 연결되었습니다.");
} else {
char err_buf[128];
espClient.getLastSSLError(err_buf, sizeof(err_buf));
Serial.print("MQTT 브로커에 연결에 실패했습니다. rc=");
Serial.println(mqtt_client.state());
Serial.print("SSL 오류: ");
Serial.println(err_buf);
delay(5000);
}
}
}
해당 함수를 사용하여 주제에 대한 데이터를 게시합니다.
void publishData(int data){
// Int 데이터를 String으로 변환합니다.
itoa(data, payload, 10);
// 주제 "test"에 데이터를 게시합니다.
mqtt_client.publish(MQTT_TOPIC, payload);
}
이벤트에 구독하려면 다음과 같이 작성합니다.
void subscribeToTopic(char* topic){
mqtt_client.subscribe(topic);
Serial.print("주제에 구독함: ");
Serial.println(topic);
}
구독한 주제를 듣습니다.
void mqttCallback(char *topic, byte *payload, unsigned int length) {
Serial.print("주제에서 메시지 받음: ");
Serial.println(topic);
Serial.print("메시지:");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
마지막으로 전체 펌웨어 코드를 작성해 봅시다.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266TrueRandom.h>
#include <time.h>
// NTP 서버 설정
const char *ntp_server = "0.pool.ntp.org"; // 기본 NTP 서버
const long gmt_offset_sec = 0; // GMT 오프셋(시간대에 따라 조정)
const int daylight_offset_sec = 0; // 일광 절약 시간 오프셋(초)
const char* SSID = "본인의 와이파이를 사용해주세요";
const char* PASSWORD = "패스워드";
const char* MQTT_HOST = "f4b0e072.ala.asia-southeast1.emqxsl.com";
const int MQTT_PORT = 8883;
const char* MQTT_USERNAME = "test2";
const char* MQTT_PASSWORD = "testpass123A";
const char* MQTT_TOPIC = "test";
char payload[10] = "";
static const char ca_cert[] = R"EOF(
-----BEGIN CERTIFICATE-----
여기에 인증서 내용을 복사하세요
-----END CERTIFICATE-----
)EOF";
BearSSL::WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);
void subscribeToTopic(char* topic){
mqtt_client.subscribe(topic);
Serial.print("주제에 구독 완료: ");
Serial.println(topic);
}
void mqttCallback(char *topic, byte *payload, unsigned int length) {
Serial.print("주제에서 받은 메시지: ");
Serial.println(topic);
Serial.print("메시지:");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void connectToMQTTBroker() {
// 인증서를 사용하여 신뢰할 수 있는 연결 요청을 수행합니다
BearSSL::X509List serverTrustedCA(ca_cert);
espClient.setTrustAnchors(&serverTrustedCA);
while (!mqtt_client.connected()) {
String client_id = "esp8266-client-" + String(WiFi.macAddress());
Serial.printf("%s로 MQTT 브로커에 연결 중.....\n", client_id.c_str());
if (mqtt_client.connect(client_id.c_str(), MQTT_USERNAME, MQTT_PASSWORD)) {
Serial.println("MQTT 브로커에 연결됨");
subscribeToTopic("test");
} else {
char err_buf[128];
espClient.getLastSSLError(err_buf, sizeof(err_buf));
Serial.print("MQTT 브로커에 연결 실패, 상태=");
Serial.println(mqtt_client.state());
Serial.print("SSL 오류: ");
Serial.println(err_buf);
delay(5000);
}
}
}
void syncTime() {
configTime(gmt_offset_sec, daylight_offset_sec, ntp_server);
Serial.print("NTP 시간 동기화 대기 중: ");
while (time(nullptr) < 8 * 3600 * 2) {
delay(1000);
Serial.print(".");
}
Serial.println("시간 동기화 완료");
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
Serial.print("현재 시간: ");
Serial.println(asctime(&timeinfo));
} else {
Serial.println("로컬 시간 획득 실패");
}
}
void publishData(int data){
// 정수 데이터를 문자열로 변환합니다
itoa(data,payload,10);
// "test" 주제에 데이터를 발행합니다
mqtt_client.publish(MQTT_TOPIC,payload);
}
void connectToWiFi() {
WiFi.begin(SSID, PASSWORD);
Serial.print("WiFi에 연결 중");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 네트워크에 연결됨");
}
void setup() {
Serial.begin(115200);
connectToWiFi();
syncTime();
mqtt_client.setServer(MQTT_HOST,MQTT_PORT);
connectToMQTTBroker();
}
void loop() {
if (!mqtt_client.connected()) {
connectToMQTTBroker();
}
mqtt_client.loop();
// 3초마다 무작위 숫자를 보냅니다. 여러분은 센서 데이터를 전송할 수 있습니다.
publishData(ESP8266TrueRandom.random(1,500));
delay(3000);
}
마침내, 코드를 Esp8266에 업로드하세요.
mqtt-cli를 설치하고 컴퓨터 터미널에서 실행하여 데이터가 발행되는지 확인하세요.
설치 후, 다음 명령어를 실행하세요
mqtt sub -h <호스트> -p <포트> -s -u <사용자이름> -pw <비밀번호> -t <토픽>
우리 경우에는 "test" 주제입니다.
다음 출력을 볼 수 있습니다.

이것은 우리의 Esp8266이 데이터를 MQTT 브로커로 보내고, 우리 컴퓨터에서 실행되는 CLI 도구를 사용하여 해당 데이터를 구독한다는 것을 보여줍니다.
마지막으로
MQTT를 Esp8266 및 Flutter와 함께 사용하는 방법에 대한 두 부분 가이드의 첫 번째 부분이 끝났습니다.
소중한 시간 내주셔서 감사합니다. 이에 대한 생각을 알려주세요!
도움이 되었다면 LinkedIn에서 제 소식을 지켜보실 수도 있습니다.