스마트디바이스실습 ‐ 9주차 - jiho0419/SmartDevice_2025-1 GitHub Wiki

1️⃣ MQTT (Message Queuing Telemetry Transport)

*️⃣ 정의

💠 MQTT(Message Queuing Telemetry Transport) 는 경량의 메시지 기반 통신 프로토콜로, 제한된 자원과 불안정한 네트워크 환경에서도 효율적으로 동작하도록 설계되어있다.
💠 주로 사물인터넷(IoT) 시스템에서 사용되며, Publisher / Subscriber 기반 메시징 프로토콜이며 TCP/IP 위에서 동작한다.

*️⃣ 특징

특징 설명
경량 프로토콜 헤더가 작아 데이터 사용량이 적음
지속 연결 유지 서버와 클라이언트가 연결된 상태를 유지 (세션 기반)
Pub/Sub 구조 발행자(Publisher)가 메시지를 보내고, 구독자(Subscriber)가 해당 주제를 구독
QoS (품질 보장) 0, 1, 2단계의 메시지 전송 보장 수준
낮은 전력 소모 소형 디바이스에 적합

*️⃣ 기본 구조

💠 핵심 개념

구성 요소 설명
Broker 중앙 서버로, 모든 메시지는 브로커를 통해 전달됨
Client Publisher 또는 Subscriber 역할을 하는 IoT 디바이스, 앱 등
Topic 메시지를 구분하는 문자열 기반 경로 (예: home/livingroom/temp)
Message 실제로 전달되는 데이터 내용

💠 통신 흐름

🔸 클라이언트가 브로커에 연결함 (Connect)
🔸 클라이언트가 topic을 구독(subscribe) 하거나 발행(publish)
🔸 브로커는 발행된 메시지를 해당 topic을 구독한 클라이언트에게 전달

*️⃣ 장 / 단점

💠 장점

🔸 가볍고 빠름 (헤더가 2바이트)
🔸 낮은 대역폭 에서도 통신 가능
🔸 QoS지속 연결 유지
🔸 Pub/Sub 구조로 유연함

💠 단점

🔸 브라우저와 직접 통신 불가 (WebSocket 브리지 필요)
🔸 보안 설정을 따로 해야 함
🔸 복잡한 메시지 구조나 대규모 데이터 전송엔 적합하지 않음

2️⃣ HTTP (HyperText Transfer Protocol)

*️⃣ 정의

💠 HTTP (HyperText Transfer Protocol)웹 상에서 클라이언트와 서버 간 데이터(문서, 이미지, JSON 등)를 주고받는 통신 프로토콜 을 말한다.
💠 웹 브라우저와 서버, 앱과 서버가 통신할 때 가장 일반적으로 사용하는 프로토콜이며 기본적으로 텍스트 기반의 요청/응답(Request/Response) 방식으로 작동한다.

*️⃣ 사용 분야

분야 설명
웹 브라우징 HTML 페이지 요청 및 응답
REST API 통신 클라이언트-서버 간 JSON 기반 API
모바일 앱 백엔드 서버와 데이터 주고받기
크롤링, 스크래핑 웹 페이지 데이터 수집

*️⃣ 특징

항목 설명
통신 방식 요청/응답 기반 (Stateless)
보안 HTTPS 사용 시 안전
표준화 전 세계 웹 시스템의 핵심
확장성 REST, GraphQL 등 다양한 방식과 연계

*️⃣ 장 / 단점

💠 장점

🔸 전 세계 표준 프로토콜 (웹 기반 서비스 대부분이 사용)
🔸 보안성 높음 (HTTPS 사용 시)
🔸 인프라가 잘 갖춰짐 (방화벽, 로드 밸런서 등과 호환)

💠 단점

🔸 지속 연결 어려움 (연결 유지하려면 polling, long-polling, WebSocket 필요)
🔸 IoT 기기처럼 빈번한 데이터 전송 에는 비효율적
🔸 데이터 오버헤드가 큼 (헤더가 큼)

*️⃣ MQTT vs HTTP

💠 비교 요약

항목 MQTT HTTP
구조 Pub/Sub Request/Response
통신 방식 지속 연결 비연결 (Stateless)
효율성 매우 효율적 (저전력/저대역폭) 상대적으로 무거움
용도 IoT, 센서 네트워크 웹, 모바일 앱, API 서버
메시지 보장 QoS 지원 (0, 1, 2) 보장 없음 (응답 실패 시 클라이언트 재시도 필요)
보안 TLS 사용 가능 (설정 필요) HTTPS로 보안 보장
브라우저 사용 WebSocket 통해 가능 기본 지원

💠 적합한 상황

💠 MQTT가 적합한 경우

🔸 센서, IoT 디바이스가 자주 작은 데이터를 보내는 경우
🔸 네트워크가 불안정하거나 전력 제약이 있는 환경
🔸 실시간성이 중요한 경우 (예: 홈 자동화)

💠 HTTP가 적합한 경우

🔸 웹사이트, 앱, 서버 간 통신 등 일반적인 웹 환경
🔸 파일 전송, 폼 제출 등 데이터 양이 많은 통신
🔸 RESTful API 기반의 서비스 개발

3️⃣ 실습

*️⃣ 초음파 센서를 이용한 거리 측정

💠 1초 간격으로 물체와 초음파 센서 사이의 거리가 출력하는 실습 진행

💠 준비물

🔸 ESP32
🔸 ESP32 확장 쉴드
🔸 초음파 센서


💠 회로 연결

ESP32 핀 초음파 센서 핀
D12 Trig (S)
D14 Echo (S)
5V Vcc
GND GND

💠 동작 설명

🔸 Trig 핀 : 초음파 신호 송신 (Output)
🔸 Echo 핀 : 반사된 초음파 수신 (Input)
🔸 거리 계산 : Echo 핀으로 들어오는 신호 시간을 측정하여 거리 계산


💠 코드

const int trigPin = 12;  // 초음파 센서의 트리거 핀
const int echoPin = 14;  // 초음파 센서의 에코 핀
long duration;          // 초음파가 물체에 반사되어 돌아오는 데 걸린 시간 (단위: 마이크로초)
float distanceCm;       // 측정된 거리 (단위: 센티미터)
float distanceInch;     // 측정된 거리 (단위: 인치)

void setup() {
  Serial.begin(115200); // 시리얼 통신 시작 (컴퓨터와 ESP32 간의 통신속도 설정)
  pinMode(trigPin, OUTPUT);  // 트리거 핀을 출력 모드로 설정
  pinMode(echoPin, INPUT);   // 에코 핀을 입력 모드로 설정
}
void loop() {
  digitalWrite(trigPin, LOW);           // 먼저 트리거 핀을 LOW로 초기화
  delayMicroseconds(2);                 // 2마이크로초 동안 대기
  digitalWrite(trigPin, HIGH);          // 트리거 핀을 HIGH로 설정하여 초음파 발사
  delayMicroseconds(10);                // HIGH 상태를 10마이크로초 동안 유지
  digitalWrite(trigPin, LOW);           // 초음파 발사를 마치고 다시 LOW로 설정

  duration = pulseIn(echoPin, HIGH);     // echo 핀에서 HIGH 신호가 유지되는 시간 측정
  distanceCm = duration * 0.034/2; 
  distanceInch = distanceCm * 0.393701; 

  Serial.print("Distance: ");
  Serial.print(distanceCm);
  Serial.print("(cm)  ");
  Serial.print(distanceInch);
  Serial.println("(inch)");

  delay(1000);
}

💠 실습 결과

🔸시리얼 모니터에서 초음파 센서 거리에 따라 출력되는 값이 변하는 것을 확인

*️⃣ 초음파 센서 Publish

💠 주요 설정

🔸 WiFi 정보 설정: SSID, PASSWORD 수정
🔸 MQTT 서버 주소 설정
🔸 MQTT Client 객체 생성
🔸 고유한 Client ID 생성 후 서버 연결


💠 코드

#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;
}

💠 실행 방법

🔸라이브러리 매니저에서 Pubsubclient를 설치


🔸 MQTT Explorer 설정을 위해 https://mqtt-explorer.com/ 접속
🔸 자신에 맞는 운영체제를 다운로드 ( window를 사용해서 window용으로 다운)


🔸 MQTT Explorer을 킨 후 밑에 사진과 변경
🔸 Name은 실습의 내용을 적고 Host에는 코드에 설정한 test.mosquitto.org을 입력
🔸 Port는 1883으로 설정 후 CONNECT 클릭


🔸 검색 창에 user1/esp32/ultra을 입력하여 경로 지정
🔸 지정 후 초음파 센서가 정상적으로 작동하는 지 확인

💠 실행 결과

🔸 손에 의해서 초음파 센서가 정상적으로 작동하는 것을 확인

3.mp4

*️⃣ 능동 부저 제어

💠 부저가 0.5초 울리고 1초동안 꺼진 상태를 유지하는 실습 진행

💠 준비물

🔸 ESP32
🔸 ESP32 확장 쉴드
🔸 능동 부저


💠 회로 연결

ESP32 핀 능동 부저 핀
D2 S
D14 Echo (S)
5V Vcc
GND GND

💠 코드

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 초 기다리기
}
}

💠 실습 결과

🔸부저가 0.5초 울리고 1초동안 꺼진 상태를 유지되는 것을 확인

2.mp4

*️⃣ 능동 부저 Subscriber

💠 MQTT Explorer을 이용하여 부저를 제어하는 실습 진행


💠 코드

#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);
    }
  }
}

💠 실행 방법

🔸 MQTT Explorer을 킨 후 밑에 사진과 변경
🔸 Name은 실습의 내용을 적고 Host에는 코드에 설정한 test.mosquitto.org을 입력
🔸 Port는 1883으로 설정 후 CONNECT 클릭


🔸 Publish에 user1/esp32/buzzer을 입력하여 경로 지정
🔸 지정 후 0 또는 1을 입력 후 PUBLISH 을 클릭하여 버저 확인


💠 실습 결과

🔸1이 수신되면 버저에서 계속 소리가 나고 0을 입력되면 버저가 멈추는 것을 확인

1.mp4
⚠️ **GitHub.com Fallback** ⚠️