10주 차 MQTT를 활용한 초음파 센서 및 능동 부저 제어 - park-02/My_home GitHub Wiki

목차

  • IoT(사물인터넷) 통신 프로토콜 이해
  • IoT(사물인터넷) 통신 프로토콜 유형
  • MQTT
  • 실습[1]
  • 실습[2]
  • 실습[3]
  • 실습[4]

1. IoT(사물인터넷) 통신 프로토콜 이해

1.1 IoT(사물인터넷) 통신 프로토콜 정의

  • IoT 통신 프로토콜은 디바이스 간의 원활한 대화를 가능하게 하는 언어 역할을 합니다. 이러한 프로토콜은 IoT 전체의 기반을 이루며 디바이스 간 데이터 교환의 원활한 흐름을 보장합니다.

1.2 IoT 생태에서의 중요성

  • 효율적인 통신 프로토콜은 연결성과 상호 운용성을 보장하며, 데이터 수집과 분석을 원활하게 합니다. 또한 보안과 개인 정보 보호를 강화하여 시스템의 안전성을 유지하며, 스마트 시티와 산업 자동화와 같은 응용 분야에서 중요한 역할을 합니다.

2 IoT(사물인터넷) 통신 프로토콜 유형

2.1 IoT(사물인터넷) 무선 통신 프로토콜

Zigbee

  • 저전력, 저비용, 짧은 거리 통신을 위한 무선 프로토콜로, 주로 스마트 홈 및 산업 자동화 분야에서 사용됩니다.
  • Mesh 네트워크 구조를 사용하여 확장성과 안정성을 제공합니다.

Bluetooth

  • 근거리 무선 통신 기술로, 저전력 장치 간의 데이터 전송에 주로 사용됩니다.
  • Bluetooth Low Energy(BLE) 버전은 센서 기반 응용 및 웨어러블 디바이스에서 널리 사용됩니다.

Wi-Fi

  • 널리 사용되는 무선 통신 기술로, 고속 데이터 전송이 가능합니다.
  • 주로 스마트 홈 및 비즈니스에서 사용되며 데이터 집약적인 애플리케이션에 견고한 연결을 제공합니다.

LoRaWAN

  • 광역 네트워크에서 저전력 디바이스 간의 통신을 지원하는 무선 프로토콜입니다.
  • 장거리 통신과 저전력 특성을 가지며, 센서 네트워크 및 스마트 시티와 같은 응용 분야에 널리 사용됩니다.

Z-Wave

  • 주로 스마트 홈 응용 분야에서 사용되는 저전력 무선 통신 기술로, Zigbee와 유사한 특성을 가지고 있습니다.
  • Mesh 네트워크를 기반으로 하며, 저전력 소모 및 강력한 보안 기능을 갖추고 있습니다.

2.2 IoT(사물인터넷) 유선 통신 프로토콜

MQTT

  • MQTT(Message Queuing Telemetry Transport)는 경량 메시징 프로토콜로, IoT 환경에서 작은 장치들 간의 효율적인 통신을 지원합니다. 주로 Publish-Subscribe 모델을 사용하며, 클라이언트가 특정 주제(topic)에 메시지를 발행(publish) 하면, 해당 주제를 구독(subscribe) 한 다른 클라이언트가 이를 수신(receive) 합니다.

image

publish/subscribe

  • Pub : 주제(topic)에 발행하는 동작을 나타냅니다.
  • Sub : 관심 주제(topic)를 구독(subscribe) 하여 해당 주제로 발행된 메시지를 수신하는 동작을 나타냅니다.

Broker

  • 클라이언트들은 브로커에 연결하여 메시지를 발행하고 구독하며, 브로커는 이들 간의 통신을 중재합니다. 이를 통해 효율적인 메시지 전달과 관리가 가능해집니다.

다대다(N:N)

  • 통신 지원합니다.

전송 프로토콜

  • TCP, UDP

CoAP

  • CoAP(Constrained Application Protocol)는 제한된 장치와 네트워크 환경에서 동작하는 경량 프로토콜로, 인터넷의 사물인터넷(IoT) 환경에서 효율적인 통신을 위해 설계되었습니다. 주로 장치 간 통신 및 리소스 제어를 위해 사용됩니다.

image

UDP 계층

  • CoAP는 UDP를 사용하여 데이터를 전송하며, UDP 헤더의 포트 번호를 사용하여 통신을 식별합니다.

CoAP Transactions 계층

  • 동기식 또는 비동기식으로 처리되며, 각 트랜잭션에 대해 고유한 ID를 할당하여 중복 패킷을 방지합니다. 이를 통해 요청과 응답 간의 상호 작용을 관리하고, 신뢰성 있는 통신을 지원합니다.

CoAP REST

  • REST 데이터 처리에서는 HTTP의 POST, GET, PUT, DELETE와 같은 메서드를 사용하여 각각 데이터 생성, 조회, 업데이트, 삭제를 수행합니다. 클라이언트는 요청 메서드를 이용하여 서버에 데이터 조작을 요청하고, 서버는 해당 동작을 수행한 후 적절한 응답을 반환합니다.

전송 프로토콜

  • UDP

MQTT CoAP 비교

image

MQTT와 CoAP는 IoT 환경에 적합한 프로토콜이지만, 통신 모델에서의 근본적인 차이점이 있습니다.

MQTT는 중앙 브로커를 통해 Publish-Subscribe, Many-To-Many 통신을 지원하며, 메시지를 발행한 클라이언트와 구독한 클라이언트 간의 효율적인 메시지 전달을 제공합니다. 이는 라이브 데이터를 위한 커뮤니케이션 버스에 적합합니다.

CoAP는 Request-Response, One-To-One 통신 모델을 기반으로 하며, 클라이언트와 서버 간의 상태 정보를 주고받는 데 적합합니다. 또한 REST 기반의 서비스 발견 기능을 제공하여, 클라이언트 연결 시 추가 작업을 최소화할 수 있습니다.

따라서 각 프로토콜은 서로 다른 특성을 가지고 있어서, IoT 서비스 개발 시에는 환경 및 요구사항에 맞게 적절한 프로토콜을 선택하여야 합니다.

NeoIDM은 MQTT와 CoAP를 모두 지원하는 IoT 플랫폼으로, 사용자는 각 디바이스 및 서비스의 특징에 맞게 프로토콜을 선택할 수 있으며, IoT 기술에 대한 관리와 운영은 NeoIDM이 담당하여 사용자는 편리하게 서비스를 운영할 수 있습니다.

MQTT HTTP 비교

프로토콜 특성

  • MQTT: 경량 메시지 프로토콜로, TCP/IP 기반에서 동작하지만 헤더가 작고 메시지 오버헤드가 적다. 따라서 IoT 환경에서 대량의 데이터 전송이 필요한 경우에 유용하다.
  • HTTP: 텍스트 기반의 프로토콜로, HTML 문서, 이미지, 동영상 등 다양한 미디어 자원을 전송할 수 있다. 그러나 상대적으로 무거운 헤더와 상태 관리로 인해 데이터 전송 시 오버헤드가 발생할 수 있다.

장점

  • MQTT 장점 : 낮은 대역폭 요구, 지속적 연결 유지, 경량 프로토콜, 토픽 기반 메시징
  • HTTP 장점 : 범용성, 캐싱 가능, 상태 없는 프로토콜

단점

  • MQTT 단점 : 기본적으로 암호화되지 않음, 메시지 순서 보장 안됨, TLS/SSL 사용으로 보안 강화 가능
  • HTTP 단점 : 기본적으로 암호화되지 않음, 오버헤드 큼, 연결 지속성 낮음(HTTP/1.1 이전).HTTPS를 통해 보안 강화 가능

적합한 사용 사례

  • MQTT : 실시간 기기 모니터링, 홈 자동화, 경량 IoT 통신
  • HTTP : 웹 페이지 요청, 대형 파일 전송, RESTful API 통신

MQTT 추가 설명

MQTT

MQTT(Message Queueing Telemetry Transport)는 발행-구독(Publish-Subscribe) 기반의 메시지 송수신 프로토콜로, 2016년 국제 표준화되었습니다. 이는 IoT와 같은 제한된 환경이나 대규모 트래픽 전송에 적합합니다. TCP/IP 위에서 동작하지만 매우 가벼우며, 통신 제약을 효과적으로 해결해 줍니다. 이로 인해 Facebook Messenger와 우아한 형제들(배달의민족 서비스 기업) 등에서도 사용되었습니다. 그러나 가벼운 만큼 메시지 유형이나 서비스 품질(QoS)에는 제약이 있습니다.

MQTT 특징

연결 지향적 (Connection Oriented)

  • 클라이언트가 MQTT 브로커와 연결을 요청하면 TCP/IP 소켓 연결을 맺고, 이 연결은 클라이언트가 명시적으로 연결을 끊거나 네트워크 사정에 의해 끊어질 때까지 상태를 유지합니다. 이를 위해 브로커와의 연결을 유지하기 위해 Live라는 하트비트와 Topic에 발행되는 메시지를 통해 연결을 유지하고 메시지 송수신을 합니다. 연결이 끊어지면 클라이언트는 재접속을 시도할 수 있습니다.

브로커를 통한 통신

  • MQTT의 발행-구독(Publish-Subscribe) 메시징 패턴을 따르며, 이는 오로지 MQTT 브로커를 통해서만 통신할 수 있습니다. 클라이언트가 특정 Topic에 메시지를 발행하면 해당 Topic을 구독하는 다른 클라이언트들에게 메시지가 전달됩니다. 이러한 구조로 인해 일대일, 일대다의 통신이 모두 가능하게 됩니다.

QoS (Quality of Service)

  • QoS 0: 최대 1회 전송됩니다. 메시지의 전송은 Topic을 통해 이루어지지만 보장은 되지 않습니다. 이는 메시지를 보낸 다음에는 해당 메시지에 대해 보장을 하지 않고 잊어버릴 수 있습니다.
  • QoS 1: 최소 1회 전송됩니다. 구독하는 클라이언트가 메시지를 받았는지 불확실할 경우에는 정해진 횟수만큼 메시지를 재전송합니다. 이때 메시지의 핸드셰이킹 과정을 엄밀하게 추적하지 않으므로 중복 전송의 위험이 있습니다.
  • QoS 2: 구독하는 클라이언트가 요구된 메시지를 정확히 한 번 수신할 수 있도록 보장합니다. 메시지의 핸드셰이킹 과정을 추적하며, 이는 가장 높은 품질을 보장하지만 성능을 희생해야 합니다.

QoS 레벨이 낮을수록 메시지 처리에 대한 부하가 줄어들지만 메시지 손실의 위험이 높아지며, 반대로 레벨이 높을수록 메시지 손실의 위험은 줄어들지만 메시지 처리 부하가 늘어납니다. 따라서 일반적으로 0부터 1 정도의 QoS 레벨을 사용하며, 메시지 손실의 위험은 상위 애플리케이션 차원에서 관리하는 방법이 널리 사용됩니다.

메시지 유형

  • 연결하기: 클라이언트는 MQTT 브로커와의 연결을 수립하기 위해 대기하고, 연결이 설정된 후에는 노드 간의 링크를 만듭니다.
  • 연결 끊기: MQTT 클라이언트는 연결이 끊어질 때까지 해야 할 일을 대기하고, 인터넷 프로토콜 스위트 세션의 연결이 끊어지기를 기다립니다.
  • 발행하기: MQTT 클라이언트에 요청이 전달된 직후 애플리케이션 스레드에 즉시 반환됩니다. 이는 메시지를 발행하는 동작을 의미합니다.

다양한 개발 언어의 다양한 클라이언트 지원

  • C/C++/Java/Node.js/Python/Arduino 등 여러 종류로 브로커와 라이브러리가 존재합니다.

토픽(Topic)

Pub와 Sub는 토픽을 기준으로 작동하며, 토픽은 슬래시(/)를 이용하여 계층적으로 구성됩니다. 이를 통해 대량의 센서 기기들을 효율적으로 관리할 수 있습니다. 예를 들어 컴퓨터의 다양한 상태를 측정하는 센서가 있다면 다음과 같이 구성할 수 있습니다

image

메시지 버스

MQTT는 메시지 버스 시스템으로 작동합니다. 여기서 MQTT 브로커가 메시지 버스를 형성하고 메시지를 버스를 통해 흘려보냅니다. 버스에 연결된 애플리케이션들은 이 메시지를 읽어갑니다. 메시지 버스에는 다양한 주제(topic)의 메시지들이 흐를 수 있는데, 이를 구분하기 위해 "Topic"이라는 이름의 메시지 채널을 만듭니다. 이를 통해 특정 주제와 관련된 메시지만을 필요에 따라 선택적으로 수신하거나 발행할 수 있습니다.

image

압전소자

압전기(피에조전기 소자)는 일정한 방향에서 압력을 가하면 그에 반응하여 양과 음의 전하가 발생하는 현상입니다. 이러한 현상은 1880년 프랑스의 자크 퀴리와 피에르 퀴리 형제에 의해 처음 발견되었습니다. 압전기의 원리를 이해한 후에는 여러 장의 결정판을 겹쳐 미약한 압력에 대한 반응을 증대시킬 수 있음이 밝혀졌습니다.

결정판에는 고유의 진동이 있으며, 탄성진동과 전기진동이 일치할 때 더욱 강한 진동이 발생한다는 사실도 밝혀졌습니다. 이러한 원리를 이용하여 다양한 발명품이 개발되었습니다. 예를 들어, 마이크로폰, 전화기 및 라디오 스피커, 초음파 탐지기, 수정시계의 진동자, 방송 장비, 원거리 통신 회로 등에서 압전기 및 압전소자가 널리 사용됩니다.

로셸염, 전기석, 타이타늄산바륨 등이 이러한 압전기 및 압전소자로 사용되며, 근래에는 타타르산에틸렌다이아민과 같은 인공 결정도 높은 압전성을 가지고 있음이 확인되었습니다.

실습[1]

실습 내용

이번 실습에서는 ESP32를 사용하여 초음파 센서를 제어하고 거리를 측정하는 실습입니다.

준비물

ESP32, ESP32 확장 실드, 초음파 센서

회로 연결

ESP32와 초음파 센서를 다음과 같이 연결합니다

초음파 센서 VCC 핀 -> ESP32 5V 핀
초음파 센서 Trig 핀 -> ESP32 GPIO 핀 (예: GPIO 12)
초음파 센서 Echo 핀 -> ESP32 GPIO 핀 (예: GPIO 14)
초음파 센서 GND 핀 -> ESP32 GND 핀

소스코드

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 대기
}

동작 원리

  • 핀 설정: trigPin과 echoPin을 각각 12번 핀과 14번 핀으로 설정합니다. 초음파 센서는 trigPin을 통해 초음파를 발사하고, echoPin을 통해 초음파가 되돌아오는 시간을 측정합니다.

  • 변수 설정:

    • duration: 초음파의 왕복 시간을 저장하는 변수입니다.
    • distanceCm: 거리를 센티미터 단위로 저장하는 변수입니다.
    • distanceInch: 거리를 인치 단위로 저장하는 변수입니다.
  • loop() 함수: 다음 작업을 반복합니다.

    • trigPin을 LOW로 설정하여 초음파 송신을 초기화합니다.
    • 2 마이크로초 동안 대기한 후, trigPin을 HIGH로 설정하여 초음파를 발사합니다.
    • 10 마이크로초 동안 초음파를 발사한 후, 다시 trigPin을 LOW로 설정하여 초음파 송신을 종료합니다.
    • pulseIn() 함수를 사용하여 echoPin에서 초음파의 왕복 시간을 측정합니다.
    • 측정된 시간을 이용하여 거리를 계산합니다. 음속이 34cm/ms임을 가정하고, 왕복 시간을 2로 나누어 실제 거리를 구합니다.
    • 계산된 거리를 센티미터와 인치 단위로 변환하여 시리얼 모니터에 출력합니다.
    • 1초 동안 대기한 후 위 과정을 반복합니다.

실행

  • ESP32 보드를 컴퓨터에 연결합니다.
  • Arduino IDE에 소스코드를 컴파일하고 업로드합니다. image

결과

위의 실행 결과는 시리얼 모니터에 표시된 센서로부터의 측정값입니다. 이는 초음파 센서가 성공적으로 거리를 측정하고, ESP32가 이를 시리얼 모니터에 출력합니다.


실습[2]

실습 내용

이번 실습에서는 초음파 센서 데이터를 발행하는 Publisher를 만드는 실습입니다. (원래 "MQTT Dashboard"앱으로 실습해야 하는데 사라져서 "IoT MQTT Panel"에서 실습을 진행해 보겠습니다.)

준비물

ESP32, ESP32 확장 실드, 초음파 센서

  • 초음파 센서는 음파 파동을 사용하여 거리를 측정해주는 센서입니다.

회로 연결

ESP32와 초음파 센서를 다음과 같이 연결합니다

초음파 센서 VCC 핀 -> ESP32 5V 핀
초음파 센서 Trig 핀 -> ESP32 GPIO 핀 (예: GPIO 12)
초음파 센서 Echo 핀 -> ESP32 GPIO 핀 (예: GPIO 14)
초음파 센서 GND 핀 -> ESP32 GND 핀

소스코드

#include <WiFi.h>          //Wi-Fi 연결 관련 라이브러리
#include <PubSubClient.h>  //MQTT 프로토콜을 사용하기 위한 라이브러리

const char* ssid = "..";          // 사용하는 WiFi 네트워크 이름 (SSID)
const char* password = "123456799";  // 사용하는 WiFi 네트워크 비밀번호

const int trigPin = 12;  // 초음파 센서의 트리거 
const int echoPin = 14;  // 초음파 센서의 에코 

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("user/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;
}

소스코드 보충 설명

1.

  • WiFiClient espClient : ESP32에서 Wi-Fi 통신을 수행하기 위해 사용되는 WiFiClient 객체를 생성합니다. 이 객체는 Wi-Fi 연결을 관리하고 TCP/IP 통신을 처리합니다.
  • PubSubClient client(espClient): MQTT 통신을 위한 PubSubClient 객체를 생성합니다. PubSubClient는 MQTT 프로토콜을 사용하여 MQTT 브로커와 통신하기 위한 라이브러리입니다.

2.

11111111111

reconnect() 함수는 MQTT 브로커와의 연결이 끊어졌을 때 다시 연결하는 함수입니다.
while (!client.connected()) : MQTT가 연결되지 않는 동안에는 반복문이 실행됩니다.   
Serial.print("MQTT 연결 시도 중..."); : 시리얼 모니터에 "MQTT 연결 시도 중이라는 메시지를 출력합니다.   
String clientId = "ESP32Client-"; : 문자열을 초기화합니다.   
clientId += String(random(0xffff), HEX); : 16진수로 표현된 랜덤한 숫자를 생성하여 클라이언트 ID 문자열에 추가합니다.   
Serial.print("클라이언트 ID: "); : 시리얼 모니터에 생성된 클라이언트 ID를 출력합니다.   
if (client.connect(clientId.c_str())) { : MQTT 브로커에 재연결을 시도합니다. 연결에 성공하면 client.connected()는 true를 반환하고, if 문이 실행됩니다.   
Serial.println("연결됨"); : 시리얼 모니터에 "연결됨" 메시지를 출력합니다.   
} else { : 연결에 실패한 경우
Serial.print("실패, rc="); : 시리얼 모니터에 "실패, rc="메시지와 'client.stata()'의 반환값을 출력합니다.   
Serial.println(" 5초 후 다시 시도"); 시리얼 모니터에 "5초 후 다시 시도" 메시지를 출력합니다.   
delay(5000); : 5초 동안 대기합니다.  

3.

11111111111

long now = millis(); : 현재 시간을 밀리초 단위로 합니다.   
if (now - lastMsgTime > 1000) { : 마지막 메시지가 전송된 이후 1초가 지났는지 확인합니다.   
lastMsgTime = now; : 현재 시간을 lastMsgTime 변수에 저장합니다. 이렇게 함으로써 다음 메시지 전송 시간을 설정합니다.   
float sensorValue = readUltrasonicSensor(); : 초음파 센서 값을 읽어옵니다.   
char sensorString[8]; : 초음파 센서 값을 문자열로 변환하여 저장할 문자열 배열을 선언합니다. 최대 7자리의 숫자가 저장될 수 있도록 크기를 설정합니다.   
dtostrf(sensorValue, 1, 2, sensorString); : sensorValue 값을 문자열로 변환하여 sensorString 배열에 저장합니다. 소수점 아래 2자리까지 표시하도록 설정합니다.   
client.publish("user1/esp32/ultra", sensorString); : MQTT 브로커에 "user1/esp32/ultra" 토픽으로 센서 값을 발행합니다. 발행된 메시지는 문자열 형태로 변환된 sensorString 값이 됩니다.   

4.

11111111111

if (now - lastMsgTime > 1000) { : now가 마지막 메시지가 전송된 시간을 lastMsgTimeㄹ로 비교하여, 1초가 지났는지 확인합니다.    
lastMsgTime = now; : 현재 시간을 lastMsgTime 변수에 저장하여 다음 메시지 전송 시간을 설정합니다.   
float sensorValue = readUltrasonicSensor(); : 초음파 센서로부터 값을 읽어옵니다.   
char sensorString[8]; : 초음파 센서 값을 문자열로 변환하여 저장할 문자열 배열을 선언합니다. 최대 7자리의 숫자가 저장될 수 있도록 크기를 설정합니다.    
dtostrf(sensorValue, 1, 2, sensorString); : sensorValue 값을 문자열로 변환하여 sensorString 배열에 저장합니다. 소수점 아래 2자리까지 표시하도록 설정합니다.   
client.publish("user1/esp32/ultra", sensorString); : MQTT 브로커에 "user1/esp32/ultra" 토픽으로 센서 값을 발행합니다. 발행된 메시지는 문자열 형태로 변환된 sensorString 값이 됩니다. 

라이브러리 설치

  • “PubSubClient by Nick O’Leary”를 검색하고 설치합니다.

123

"IoT MQTT Panel"

  • Play Store에서 검색하여 IoT MQTT Panel 앱을 찾습니다. 앱을 설치하고 실행하여 MQTT에 연결할 수 있습니다.
  • 앱을 열면 MQTT 브로커 연결 설정을 먼저 해야 합니다.
  • ‘ADD PANNEL’을 눌러 ‘Text Log’을 추가해 줍니다.
  • PANNEL 이름, 구독할 Topic 이름 정보 등을 설정하고 ‘CREATE’버튼을 클릭해 줍니다.

실행

  • ESP32 보드를 컴퓨터에 연결합니다.
  • Arduino IDE에 소스코드를 컴파일하고 업로드합니다.

KakaoTalk_20240513_223405470

KakaoTalk_20240513_232126509.mp4

결과

  • 초음파 센서 거리 값 변화를 "IoT MQTT Panel" 앱에서 확인할 수 있습니다.

실습[3]

실습 내용

이번 실습에서는 ESP32를 사용하여 초음파 센서를 제어하고 거리를 측정하는 실습입니다.

준비물

ESP32, ESP32 확장 실드, 능동 부저

  • 능동 부저는 전기 신호를 가지고 소리를 내는 부저입니다.

회로 연결

ESP32와 능동부저를 다음과 같이 연결합니다

능동부저 S 핀 -> D2 S
능동부저 V(+) 핀 -> D2 V(+)
능동부저 G(-) 핀 -> D2 G(-)

소스코드

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  기다리기
}
digitalWrite(buzzerPin, HIGH); : buzzerPin에 HIGH(전압이 가해진 상태)를 설정하여 부저를 켭니다.   
delay(500);: 0.5초 동안 기다립니다.   
digitalWrite(buzzerPin, LOW); : buzzerPin에 LOW(전압이 가해지지 않은 상태)를 설정하여 부저를 끕니다.   
delay(1000); : 1초 동안 기다립니다.   

실행

  • ESP32 보드를 컴퓨터에 연결합니다.
  • Arduino IDE에 소스코드를 컴파일하고 업로드합니다.
KakaoTalk_20240509_012503273.mp4

결과

ESP32 보드에서 부저 소리가 들릴 것입니다. 부저가 1초 간격으로 켜지고 꺼지는 것을 확인할 수 있습니다.


실습[4]

실습 내용

이번 실습에서는 능동 부저 제어 실습입니다.

준비물

ESP32, ESP32 확장 실드, 능동부저

회로 연결

ESP32와 능동부저를 다음과 같이 연결합니다

능동부저 S 핀 -> D2 S
능동부저 V(+) 핀 -> D2 V(+)
능동부저 G(-) 핀 -> D2 G(-)

소스코드

#include <WiFi.h>
#include <PubSubClient.h>
 
const char* ssid = "..";
const char* password = "123456799";

const char* mqtt_server = "test.mosquitto.org";
const int mqttPort = 1883 ;
const char * mqttTopic = "user/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);
    }
  }
}

"IoT MQTT Panel"

  • 점 세 개 클릭하여 “Add new dashboard”를 선택해 줍니다.
  • 대시보드 이름 입력하고 ‘CREATE’버튼을 클릭해 줍니다.
  • ‘Add Panel’을 클릭하고 ‘Switch’를 추가하여 줍니다.
  • “Topic”값을 “user1/esp32/buzzer”로 합니다.

실행

  • ESP32 보드를 컴퓨터에 연결합니다.
  • Arduino IDE에 소스코드를 컴파일하고 업로드합니다.
KakaoTalk_20240513_232128271.mp4

결과

  • on 하면 “user1/esp32/buzzer 1” 메시지가 전달되고 부저가 울립니다. off 하면 “user1/esp32/buzzer 0” 메시지가 전달되고 부저가 꺼집니다.

image

동작 원리

1. ESP32 보드가 Wi-Fi 네트워크에 연결됩니다.
2. Wi-Fi 연결 후, ESP32 보드는 MQTT 브로커에 접속합니다.
3. 접속이 완료되면, ESP32 보드는 특정 토픽을 구독합니다.
4. MQTT 메시지가 도착하면, 지정된 콜백 함수가 호출됩니다.
5. 콜백 함수는 메시지의 페이로드를 확인하여 부저를 켜거나 끕니다.
6. MQTT 연결이 끊어질 경우, 자동 재연결 함수가 실행됩니다.
7. 메인 루프는 지속적으로 MQTT 연결 상태를 유지하며, 수신된 메시지를 처리합니다.

콜백 함수

callback() 함수: 이 함수는 MQTT 메시지를 수신할 때 자동으로 호출됩니다. 세 개의 매개변수를 받습니다.
topic 매개변수는 수신된 메시지의 토픽 이름을 나타냅니다. payload 매개변수는 메시지의 내용(페이로드)을 나타내며, length 매개변수는 페이로드의 길이를 나타냅니다.
콜백 함수는 수신된 토픽이 구독된 토픽과 일치하는지 확인합니다.
만약 일치한다면, 페이로드를 검사합니다. 페이로드가 '1'이면 부저를 켜고, '0'이면 부저를 끕니다.

후기

실습을 통해 ESP32를 사용하여 초음파 센서를 제어하고 거리를 측정하는 방법을 배웠습니다. 또한, MQTT를 활용하여 초음파 센서 데이터를 발행하는 Publisher를 만드는 실습을 진행했습니다. 실습에서는 "IoT MQTT Panel" 앱을 활용하여 MQTT 브로커에 연결하고 데이터를 발행하는 과정을 진행했습니다.

부저를 활용하여 실습의 진행 상태를 알려주는 것도 흥미로웠습니다. 부저가 1초 간격으로 켜지고 꺼지는 것을 확인하며, 데이터의 전송과 부저의 동작이 시각적으로 표현되어 실습을 진행하는 데 도움이 되었습니다.

실습을 통해 IoT 기기와 MQTT 프로토콜을 활용하여 센서 데이터를 전송하는 방법을 배우고, 이를 실제 애플리케이션에 적용하는 과정을 경험할 수 있어서 유익했습니다. 다음에는 더 많은 기능을 추가하여 더 다양한 IoT 프로젝트를 시도해 보고 싶습니다.

⚠️ **GitHub.com Fallback** ⚠️