09주차 ‐ MQTT 초음파센서 실습 - movie-01/SmartDevice GitHub Wiki
- 통신 프로토콜
- MQTT
- 능동 부저
통신 프로토콜은 서로 다른 장치 간에 데이터를 교환할 수 있도록 정해진 규칙이야. 이 규칙은 데이터의 형식, 전송 방식, 오류 검출, 동기화 방식 등을 포함하며, 네트워크의 신뢰성과 효율성을 보장하기 위한 핵심 요소로 작용해.
- 구문(Syntax): 데이터의 구조와 형식 (예: 비트 수, 바이트 순서 등)
- 의미(Semantics): 각 비트/바이트의 의미와 역할 (예: 시작 비트, 오류 체크 등)
- 타이밍(Timing): 데이터 전송 타이밍과 속도 조절
계층 | 프로토콜 예시 | 역할 |
---|---|---|
응용 계층 | HTTP, MQTT, FTP | 사용자와 가장 가까운 데이터 전송 방식 |
전송 계층 | TCP, UDP | 송수신 간 연결 및 신뢰성 관리 |
인터넷 계층 | IP, ICMP | 주소 지정 및 라우팅 |
네트워크 인터페이스 계층 | Ethernet, Wi-Fi | 실제 물리적 전송 수행 |
- 프로토콜은 표준화되어 있어 다양한 제조사 기기 간의 호환성을 보장함
- IoT 분야에선 경량화된 프로토콜이 선호됨 (ex. MQTT, CoAP)
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 위에서 작동하여 신뢰성 보장
- 브로커 구조 덕분에 클라이언트 간 복잡도 감소
- ESP32
- ESP32 확장 쉴드
- 초음파 센서
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);
}
- 라이브러리 설치: [PubSubClient by Nick O’Leary] 설치
- WiFi 정보 설정: SSID, PASSWORD 수정
- MQTT 서버 주소 설정
- MQTT Client 객체 생성
- 고유한 Client ID 생성 후 서버 연결
- 초음파 센서 값을 "user1/esp32/ultra" 토픽으로 Publish
#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 explorer" 입력
-
CONNECT후 "user1/esp32/ultra" 등으로 검색
-
하지만 ultra 탭이 안 나오는 경우가 생긴다.
-
이후 advance에 들어가서 본인 아이디와 경로 설정 했으나 안 됐다.
**능동 부저(Active Buzzer)**는 내부에 발진 회로가 내장된 전자 부품이다. 별도로 주파수 신호를 인가하지 않아도 단순한 HIGH/LOW 전압으로 작동 가능함.
- ESP32
- ESP32 확장 쉴드
- 능동 부저
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
- 문 열림 알림음
- 센서 경고 시스템
- 사용자 피드백 (버튼 입력 등)
항목 | 능동 부저 | 수동 부저 |
---|---|---|
제어 방식 | ON/OFF | PWM 필요 |
회로 구성 | 간단 | 복잡 |
소리 제어 | 일정 | 자유로움 |
사용 편의성 | 높음 | 낮음 |
#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 통신 유지
}