09주차 ‐ MQTT 초음파센서 실습 - movie-01/SmartDevice GitHub Wiki

09주차 ‐ MQTT 초음파센서 실습


개요

  • 통신 프로토콜
  • MQTT
  • 능동 부저

📡 통신 프로토콜 (Communication Protocol)

통신 프로토콜은 서로 다른 장치 간에 데이터를 교환할 수 있도록 정해진 규칙이야. 이 규칙은 데이터의 형식, 전송 방식, 오류 검출, 동기화 방식 등을 포함하며, 네트워크의 신뢰성과 효율성을 보장하기 위한 핵심 요소로 작용해.

🧱 주요 구성 요소

  • 구문(Syntax): 데이터의 구조와 형식 (예: 비트 수, 바이트 순서 등)
  • 의미(Semantics): 각 비트/바이트의 의미와 역할 (예: 시작 비트, 오류 체크 등)
  • 타이밍(Timing): 데이터 전송 타이밍과 속도 조절

🌐 분류

계층 프로토콜 예시 역할
응용 계층 HTTP, MQTT, FTP 사용자와 가장 가까운 데이터 전송 방식
전송 계층 TCP, UDP 송수신 간 연결 및 신뢰성 관리
인터넷 계층 IP, ICMP 주소 지정 및 라우팅
네트워크 인터페이스 계층 Ethernet, Wi-Fi 실제 물리적 전송 수행

📎 특징

  • 프로토콜은 표준화되어 있어 다양한 제조사 기기 간의 호환성을 보장함
  • IoT 분야에선 경량화된 프로토콜이 선호됨 (ex. MQTT, CoAP)

📶 MQTT (Message Queuing Telemetry Transport)

MQTT는 경량 메시지 기반 퍼블리시/서브스크라이브(Pub/Sub) 통신 프로토콜로, 저전력 장치와 불안정한 네트워크 환경에서 효율적으로 데이터를 전송할 수 있도록 설계되었어. IBM이 개발했고, 현재는 OASIS에서 표준화되어 있어.

🧱 핵심 구성 요소

  • Publisher: 메시지를 발행하는 클라이언트
  • Broker: 모든 메시지를 중계하는 중앙 서버 (Ex: Mosquitto)
  • Subscriber: 특정 주제를 구독하는 클라이언트

예: 온도 센서(Publisher)가 home/temperature 주제로 값을 전송하면, 구독자(Subscriber)가 해당 주제를 받아보기만 하면 됨

🔗 주요 기능

  • 주제 기반 라우팅 (Topic Routing): /sensor/temperature, /device/led 등

  • QoS 레벨 (Quality of Service):

    • 0: 한번만 전송 (최소 보장)
    • 1: 적어도 한번 전송
    • 2: 정확히 한번 전송 (가장 안정적)
  • 지속 세션(Persistent Session): 장치가 잠시 오프라인이어도 메시지를 저장해둠

🧠 사용 시 장점

  • 저전력, 저용량 시스템에서 동작 가능
  • TCP 위에서 작동하여 신뢰성 보장
  • 브로커 구조 덕분에 클라이언트 간 복잡도 감소

실습

1.초음파 센서를 이용한 거리 측정

준비물

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

image

코드작성

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

결과

image


준비사항

  • 라이브러리 설치: [PubSubClient by Nick O’Leary] 설치

주요 설정

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

데이터 Publish

  • 초음파 센서 값을 "user1/esp32/ultra" 토픽으로 Publish

"PubSubClient by Nick O’Leary" 라이브러리 설치

image


코드작성

#include <WiFi.h>          // Wi-Fi 연결용 라이브러리
#include <PubSubClient.h>  // MQTT 통신용 라이브러리

const char* ssid = "Your_SSID";          // 연결할 Wi-Fi SSID (이름)
const char* password = "Your_Password";  // Wi-Fi 비밀번호

const int trigPin = 12;  // 초음파 센서 트리거 핀 (ESP32의 D12)
const int echoPin = 14;  // 초음파 센서 에코 핀 (ESP32의 D14)

const char* mqtt_server = "test.mosquitto.org"; // MQTT 브로커 서버 주소
const int mqttPort = 1883; // MQTT 기본 포트 (1883)

WiFiClient espClient;
PubSubClient client(espClient);

long lastMsgTime = 0;

void setup() {
  Serial.begin(115200);         // 시리얼 통신 시작
  setup_wifi();                 // Wi-Fi 연결 시도
  client.setServer(mqtt_server, mqttPort); // MQTT 브로커 정보 설정

  pinMode(echoPin, INPUT);       // 에코 핀 입력 설정
  pinMode(trigPin, OUTPUT);      // 트리거 핀 출력 설정
  digitalWrite(trigPin, LOW);    // 트리거 핀 초기화 (LOW)
  delayMicroseconds(2);          // 약간의 대기
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("연결 중인 Wi-Fi: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password); // Wi-Fi 연결 시작

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);               // 0.5초마다 상태 확인
    Serial.print(".");         // 연결 진행 표시
  }

  Serial.println("");
  Serial.println("Wi-Fi 연결됨");
  Serial.print("IP 주소: ");
  Serial.println(WiFi.localIP()); // 할당된 IP 주소 출력
}

void reconnect() {
  while (!client.connected()) {        // MQTT 연결이 안 되어 있으면
    Serial.print("MQTT 연결 시도 중...");
    String clientId = "ESP32Client-";   // 클라이언트 ID를 랜덤 생성
    clientId += String(random(0xffff), HEX);

    if (client.connect(clientId.c_str())) {  // 연결 시도
      Serial.println("연결됨");
    } else {
      Serial.print("실패, rc=");
      Serial.print(client.state());     // 실패 상태 코드 출력
      Serial.println(" 5초 후 다시 시도");
      delay(5000);                      // 5초 후 재시도
    }
  }
}

void loop() {
  if (!client.connected()) {  // MQTT 연결이 끊어졌으면
    reconnect();              // 재연결
  }
  client.loop();              // 클라이언트 통신 유지 (수신 등 처리)

  long now = millis();        // 현재 시간(밀리초) 읽기
  if (now - lastMsgTime > 1000) {  // 1초 경과했으면
    lastMsgTime = now;
    
    float sensorValue = readUltrasonicSensor();  // 초음파 센서 읽기
    char sensorString[8];                        // 문자열 버퍼
    dtostrf(sensorValue, 1, 2, sensorString);     // float 값을 문자열로 변환 (소수점 2자리)
    
    client.publish("user1/esp32/ultra", sensorString); // "user1/esp32/ultra" 토픽으로 Publish
  }
}

float readUltrasonicSensor() {
  digitalWrite(trigPin, HIGH);  // 트리거 핀 HIGH
  delayMicroseconds(10);        // 10μs 동안 유지
  digitalWrite(trigPin, LOW);   // 트리거 핀 LOW로 끄기

  pinMode(echoPin, INPUT);      // 에코 핀 입력모드
  float duration = pulseIn(echoPin, HIGH);  // echo 핀 HIGH 지속시간 측정

  float distance = duration * 0.0343 / 2.0;  // 거리(cm) 계산
  return distance;
}

MQTT PC 클라이언트 설치

구글에 "mqtt explorer" 입력

image

MQTT Explorer설정

  • CONNECT후 "user1/esp32/ultra" 등으로 검색 image

  • 하지만 ultra 탭이 안 나오는 경우가 생긴다. image

  • 이후 advance에 들어가서 본인 아이디와 경로 설정 했으나 안 됐다.


🔔 능동 부저 (Active Buzzer)

**능동 부저(Active Buzzer)**는 내부에 발진 회로가 내장된 전자 부품이다. 별도로 주파수 신호를 인가하지 않아도 단순한 HIGH/LOW 전압으로 작동 가능함.

준비물

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

image


코드 작성

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

🧱 내부 구조 및 원리

  • 내부에 발진 회로가 내장되어 있어 전류만 흐르면 일정 주파수의 소리를 냄
  • 단순 ON/OFF 제어만으로 소리 발생 (PWM 제어 불필요)
  • DC 전압만 인가해도 작동함

수동 부저는 주파수를 조절해야 하므로 코드 제어가 필요하지만, 능동 부저는 아두이노나 라즈베리파이에서 간단하게 디지털 핀으로 제어 가능

결과

default.mp4

🛠️ 사용 예시

  • 문 열림 알림음
  • 센서 경고 시스템
  • 사용자 피드백 (버튼 입력 등)

✅ 장점 vs 수동 부저

항목 능동 부저 수동 부저
제어 방식 ON/OFF PWM 필요
회로 구성 간단 복잡
소리 제어 일정 자유로움
사용 편의성 높음 낮음

능동 부저

image

코드 작성

#include <WiFi.h>
#include <PubSubClient.h>

const char* ssid = "your_wifi";
const char* password = "your_pw";

const char* mqtt_server = "test.mosquitto.org";
const int mqttPort = 1883;
const char* mqttTopic = "user1/esp32/buzzer";

const int buzzerPin = 2;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(115200);
  
  pinMode(buzzerPin, OUTPUT); // 부저 핀 설정

  setup_wifi();
  client.setServer(mqtt_server, mqttPort);
  client.setCallback(callback);
}

void setup_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Wi-Fi 연결됨");
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("MQTT 연결 중...");
    String clientId = "ESP32Client-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println("연결 성공");
      client.subscribe(mqttTopic);  
    } else {
      Serial.print("연결 실패, rc=");
      Serial.print(client.state());
      Serial.println(" 다시 시도 중...");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  if (strcmp(topic, mqttTopic) == 0) {
    if (length > 0 && payload[0] == '1') {
      digitalWrite(buzzerPin, HIGH); // 부저 켜기
    } else if (length > 0 && payload[0] == '0') {
      digitalWrite(buzzerPin, LOW);  // 부저 끄기
    }
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();  // MQTT 통신 유지
}
⚠️ **GitHub.com Fallback** ⚠️