스마트 디바이스 9주차 MQTT 초음파센서 실습 - yubiine/25-1_smartdevice GitHub Wiki
- MQTT를 활용한 IoT 서비스 구현
-
MQTT(Message Queuing Telemetry Transport) 는 경량 메시지 통신 프로토콜로,
제한된 네트워크 환경에서도 빠르고 안정적인 통신이 가능한 방식입니다. 주로 IoT(사물인터넷) 장치 간 통신에 사용됩니다. - 1999년 IBM에서 처음 개발되었으며,
낮은 대역폭, 높은 신뢰성, 적은 전력 소비가 필요한 환경에 최적화되어 있습니다.
MQTT는 전통적인 클라이언트-서버 방식이 아니라 메시지를 발행하고 구독하는 구조입니다.
[Publisher] → [Broker] → [Subscriber]
-
Publisher (발행자): 특정 주제(topic)에 메시지를 보냅니다.
-
Subscriber (구독자): 특정 topic을 구독하고, 그에 대한 메시지를 받습니다.
-
Broker (중개자): Publisher가 보낸 메시지를 받아서 해당 topic을 구독 중인 Subscriber들에게 전달합니다.

이 구조는 여러 장치 간의 효율적이고 유연한 통신을 가능하게 합니다.
MQTT에서는 메시지가 string 형식의 토픽에 따라 전송됩니다.
예: "sensor/room1/temperature"
Subscriber는 해당 토픽을 구독하면 해당 토픽으로 발행된 메시지를 수신합니다.
토픽은 디렉토리 구조처럼 구분("/")되고, 와일드카드(+, #)도 사용 가능합니다.
Broker는 핵심 중개자입니다. MQTT 장치들(Publisher/Subscribers)은 서로 직접 통신하지 않고, Broker를 통해서만 통신합니다.
대표적인 MQTT Broker:
- Mosquitto (오픈소스)
- HiveMQ (상업용 및 무료)
- AWS IoT Core, Google Cloud IoT 등 클라우드 서비스
MQTT는 전송 신뢰도를 3단계로 설정할 수 있습니다.
QoS 수준 | 설명 |
---|---|
0 (At most once) | 최대 한 번 전송, 손실될 수 있음. 가장 빠름. |
1 (At least once) | 한 번 이상 전달, 중복 가능성 있음. |
2 (Exactly once) | 정확히 한 번만 전달, 가장 신뢰성 높지만 느림. |
네트워크 품질이나 데이터 중요도에 따라 QoS를 선택할 수 있습니다.
특징 | 설명 |
---|---|
경량성 (Lightweight) | 매우 작은 헤더(2바이트), 텍스트 기반 프로토콜 아님. 저사양, 배터리 기반 장치에서도 적합. |
낮은 대역폭 사용 | 텍스트가 아니라 이진 메시지를 사용. 네트워크가 느려도 효과적으로 작동. |
유지 연결 (Persistent Connection) | MQTT는 연결을 계속 유지하며 메시지를 지속적으로 수신하거나 발행함. |
Last Will and Testament (LWT) | 클라이언트가 비정상 종료되었을 때, 미리 정의한 메시지를 Broker가 대신 발행하여 상태 알림. |
Retained Messages | 가장 최근 메시지를 Broker가 저장해두고, 새로 연결한 Subscriber에게 즉시 전달. |
Session 유지 | 클라이언트는 재연결 시에도 이전의 구독 상태를 유지할 수 있음. (Clean Session = false 일 때) |
보안 (Security) | 기본적으로 암호화 없음. 하지만 TLS/SSL을 추가하거나 인증 토큰 사용 가능. |
확장성 | 수천 개의 장치를 동시에 관리할 수 있으며, 클러스터링도 가능함. |
항목 | MQTT | HTTP |
---|---|---|
프로토콜 방식 | 메시지 기반, 발행/구독(Pub/Sub) | 요청/응답(Request/Response) 기반 |
연결 상태 | 지속 연결 (Keep-Alive) | 매 요청마다 연결 |
메시지 크기 | 작음 (2바이트 헤더) | 큼 (헤더 + 본문 포함) |
통신 방향 | 양방향 (Broker를 통한 Push 지원) | 단방향 (클라이언트가 요청 시에만) |
신뢰성(QoS) | QoS 0, 1, 2 지원 (메시지 전송 보장) | 기본 보장 없음 (애플리케이션 레벨 처리) |
실시간성 | 매우 우수 (즉시 전송) | 낮음 (주기적 요청 필요) |
배터리 효율 | 높음 (지속 연결 유지, 오버헤드 적음) | 낮음 (자주 연결하고 끊어야 함) |
데이터 전송 빈도 | 빈번한 전송에 적합 | 느린 빈도에 적합 |
보안 | TLS/SSL 적용 가능 | HTTPS (TLS 기반) 기본 적용 |
서버 | MQTT Broker 필요 | 일반 웹서버 가능 |
따라서 MQTT는 센서, 홈 IoT, 스마트팩토리, 모바일 디바이스에 특히 적합합니다.
상황 | 이유 |
---|---|
🔁 지속적인 데이터 송수신 필요 | 센서에서 실시간으로 데이터를 보내야 할 때 (ex. 온도, 거리, GPS 등) |
📡 IoT 장치가 자주 메시지를 주고받는 환경 | Pub/Sub 구조로 효율적이며, Broker가 중개하여 분산에 강함 |
🔌 네트워크가 불안정하거나 제한된 환경 | 메시지 유실 방지(QoS), 재전송, 저전력 통신 |
🔋 배터리로 동작하는 저전력 장치 | 낮은 오버헤드, 연결 유지 비용 적음 |
🔒 비정상 종료 감지 필요 | LWT(Last Will) 기능으로 장애 탐지 가능 |
📊 데이터 수집이 잦은 스마트 팩토리, 홈 IoT | 수백 대 장치를 효율적으로 관리 가능 |
예: 스마트홈, 공장 자동화, 드론 통신, 환경 모니터링 센서, 웨어러블 기기
상황 | 이유 |
---|---|
🌐 웹 기반 애플리케이션 | 브라우저에서 HTTP/HTTPS 요청이 기본 |
📄 대량의 정적/동적 데이터 요청 | 이미지, 문서, JSON API 등에 적합 |
⏳ 간헐적인 데이터 통신 | 매번 새로 요청할 때 유리 (예: 하루에 한 번, 버튼 클릭 시 등) |
🔒 표준 보안 요구가 명확한 시스템 | HTTPS는 이미 대부분 보안이 내장됨 |
🧩 REST API 설계 및 문서화가 중요한 경우 | Swagger, Postman 등 도구와 호환성 우수 |
📡 서버 주도적 구조 (서버에서 응답 위주) | 클라이언트가 요청할 때만 응답하면 되는 구조에 적합 |
예: 사용자 로그인, 데이터베이스 질의, 웹페이지 요청, RESTful API 통신

- Trig 핀: 초음파 신호 송신 (Output)
- Echo 핀: 반사된 초음파 수신 (Input)
- 거리 계산: Echo 핀으로 들어오는 신호 시간을 측정하여 거리 계산
const int trigPin = 12; // 초음파 센서의 트리거 핀
const int echoPin = 14; // 초음파 센서의 에코 핀
long duration; // 음파의 왕복 시간(마이크로초)
float distanceCm; // 거리(cm)
float distanceInch; // 거리(인치)
void setup() {
Serial.begin(115200); // 시리얼 통신 시작 (통신 속도: 115200bps)
pinMode(trigPin, OUTPUT); // 트리거 핀을 출력으로 설정
pinMode(echoPin, INPUT); // 에코 핀을 입력으로 설정
}
void loop() {
digitalWrite(trigPin, LOW); // 트리거 핀 LOW로 초기화
delayMicroseconds(2); // 2 마이크로초 대기
digitalWrite(trigPin, HIGH); // 트리거 핀 HIGH로 설정하여 초음파 송신
delayMicroseconds(10); // 10 마이크로초 동안
digitalWrite(trigPin, LOW); // 초음파 송신 종료
duration = pulseIn(echoPin, HIGH); // 에코 핀에서 초음파의 왕복 시간 측정
distanceCm = duration * 0.034/2; // 거리 계산
distanceInch = distanceCm * 0.393701; // 인치로 변환
Serial.print("Distance: ");
Serial.print(distanceCm); // 거리 (cm)
Serial.print("(cm) ");
Serial.print(distanceInch); // 거리 (인치)
Serial.println("(inch)");
delay(1000); // 1초 대기
}

- 라이브러리 설치

- https://mqtt-explorer.com/ 접속하여 다운로드

- host에 코드에 설정한
test.mosquitto.org
입력

- 검색 창에 user1/esp32/ultra을 입력하여 경로 지정 후 확인

#include <WiFi.h> //Wi-Fi 연결 관련 라이브러리
#include <PubSubClient.h> //MQTT 프로토콜을 사용하기 위한 라이브러리
// 다음 변수들을 당신의 SSID와 비밀번호로 대체하세요.
const char* ssid = "wifi-SSID"; // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password"; // Wi-Fi의 비밀번호를 입력합니다.
const int trigPin = 12; // 초음파 센서의 트리거 핀
const int echoPin = 14; // 초음파 센서의 에코 핀
// MQTT 브로커 IP 주소를 여기에 입력하세요 (예: "192.168.1.144")
const char* mqtt_server = "test.mosquitto.org";
const int mqttPort = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsgTime = 0;
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqttPort);
pinMode(echoPin, INPUT); // 에코 핀을 입력으로 설정
// 트리거 핀 초기화
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
}
void setup_wifi() {
delay(10);
// Wi-Fi 네트워크에 연결 시작
Serial.println();
Serial.print("연결 중인 Wi-Fi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Wi-Fi 연결됨");
Serial.println("IP 주소: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
// 연결이 될 때까지 반복
while (!client.connected()) {
Serial.print("MQTT 연결 시도 중...");
// 랜덤 클라이언트 ID 생성
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
Serial.print("클라이언트 ID: ");
Serial.println(clientId);
// 연결 시도
if (client.connect(clientId.c_str())) {
Serial.println("연결됨");
} else {
Serial.print("실패, rc=");
Serial.print(client.state());
Serial.println(" 5초 후 다시 시도");
// 5초 대기 후 다시 시도
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
// 클라이언트가 메시지를 처리하고 서버와 연결 유지
client.loop();
long now = millis();
if (now - lastMsgTime > 1000) { //1초 간격
lastMsgTime = now;
// 초음파 센서 값을 읽어옵니다.
float sensorValue = readUltrasonicSensor();
char sensorString[8];
dtostrf(sensorValue, 1, 2, sensorString);
client.publish("user1/esp32/ultra", sensorString);
}
}
float readUltrasonicSensor() {
// 트리거 핀을 10 마이크로초 동안 HIGH로 설정하여 초음파를 발사합니다.
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 에코 핀에서 펄스의 지속 시간을 측정합니다.
pinMode(echoPin, INPUT);
float duration = pulseIn(echoPin, HIGH);
// 소리의 속도를 기준으로 거리를 계산합니다.(343m/s로 가정)
float distance = duration * 0.0343 / 2.0;
return distance;
}
IMG_7331.MOV
const int buzzerPin = 2; //led 핀 번호 설절
void setup (){
pinMode (buzzerPin,OUTPUT );//buzzerPin 을 출력으로 설정
}
void loop (){
digitalWrite (buzzerPin, HIGH ); //buzzerPin 에 HIGH 값 쓰기
delay (500 ); // 0.5 초 기다리기
digitalWrite (buzzerPin, LOW ); //buzzerPin 에 LOW 값 쓰기
delay (1000 ); // 1 초 기다리기
}
IMG_7332.MOV
- host에 코드에 설정한
test.mosquitto.org
입력 -
user1/esp32/buzzer
토픽 사용


#include <WiFi.h>
#include <PubSubClient.h>
// 다음 변수들을 당신의 SSID와 비밀번호로 대체하세요.
const char* ssid = "wifi-SSID"; // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password"; // Wi-Fi의 비밀번호를 입력합니다.
// MQTT 브로커 IP 주소를 여기에 입력하세요 (예: "192.168.1.144")
const char* mqtt_server = "test.mosquitto.org";
const int mqttPort = 1883 ;
const char * mqttTopic = "user1/esp32/buzzer"; // 사용자에 맞게 변경
const int buzzerPin = 2 ; // 부저에 연결된 GPIO 핀 번호
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
// Wi-Fi 네트워크에 연결 시작
Serial.println();
Serial.print("연결 중인 Wi-Fi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Wi-Fi 연결됨");
Serial.println("IP 주소: ");
Serial.println(WiFi.localIP());
}
void setup(){
// 시리얼 통신 초기화
Serial.begin(115200);
// Wi-Fi 연결 설정
setup_wifi();
client.setServer(mqtt_server, mqttPort);
client.setCallback(callback);
// 부저 핀을 출력 모드로 설정
pinMode(buzzerPin,OUTPUT);
}
void loop(){
if(!client.connected()){
reconnect();
}
client.loop();//MQTT 클라이언트를 유지하기 위해 호출
}
void callback(char*topic , byte *payload , unsigned int length){
Serial.print("Receivedmessage: ");
Serial.print(topic);
Serial.print(" ");
for(int i = 0 ; i <length;i++){
Serial.print((char)payload[i]);
}
Serial.println();
if(strcmp(topic, mqttTopic)== 0){
if(payload[0] == '1'){
// 부저를 켜는 코드 작성
digitalWrite(buzzerPin, HIGH);
}else if(payload[0] == '0'){
// 부저를 끄는 코드 작성
digitalWrite(buzzerPin, LOW);
}
}
}
void reconnect(){
while(!client.connected()){
Serial.print("Connectingto MQTT Broker...");
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
if(client.connect(clientId.c_str())){
Serial.println("Connected to MQTT Broker");
client.subscribe(mqttTopic);
}else {
Serial.print("Failed, rc=");
Serial.print(client.state());
Serial.println("Retrying in 5 seconds...");
delay(5000);
}
}
}
- 0 입력시 정지
- 1 입력시 재생
default.MOV
✅ 주의!!
- MQTT Explorer를 사용할때 맥은 앱스토어에서 다운로드함
- MQTT Explorer에서 연결한 후 검색에 입력하지 않으면 프로그램이 버벅댐 (윈도우와 차이가 있을 수 있음)