아두이노와 ESP8266을 사용하는 Machinechat JEDI One MQTT 브로커 구독 예제

소개

Machinechat의 JEDI One에는 MQTT 브로커가 내장되어 있습니다. 외부 클라이언트 장치는 JEDI One의 토픽(topic)에 발행(publish) 또는 게시(post)할 수 있습니다. 이 게시글에서 아두이노 클라이언트 장치는 JEDI One에서 현재 사용되는 토픽(센서 데이터)을 와이파이를 통해 구독하도록 설정될 것입니다.

배경

MQTT(Message Queuing Telemetry Transport, 메시지 큐 원격 전송)는 장치 간에 메시지를 전송하는 경량형 발행-구독 방식 네트워크 프로토콜을 정의하는 개방형 OASIS 및 ISO 표준으로, 하나의 메시지 브로커와 다수의 클라이언트라는 두 종류의 네트워크 개체를 포함합니다.
Machinechat의 JEDI One IoT 플랫폼에는 MQTT 메시지 브로커로 설정할 수 있는 데이터 수집기가 포함되어 있습니다. JEDI One에 데이터를 발행하거나 토픽을 구독하도록 외부 클라이언트 장치를 설정할 수 있습니다. 토픽에는 MQTT뿐만 아니라 모든 출처에서 JEDI One으로 들어오는 모든 데이터가 포함됩니다. JEDI One에서 발행 메시지는 JSON 페이로드 형식이어야 하며 구독 메시지도 JSON 페이로드 형식으로 제공합니다. 구독할 JEDI One 토픽은 “datacache/Device ID”(예제: “datacache/T960981B2D”) 형식일 것입니다.

구현

이 프로젝트에서는 JEDI One을 설치해 MQTT 데이터 수집기가 활성화 된 라즈베리 파이 4를 사용합니다. 아두이노가 구동되는 ESP8266 보드는 라즈베리 파이에서 구동되는 JEDI One IoT 플랫폼의 센서 데이터 토픽을 구독하는 MQTT 클라이언트로 사용됩니다.

JEDI One 설정

JEDI One에서 MQTT 브로커 데이터 수집기를 아직 설정하지 않은 경우 다음 단계를 수행합니다.
JEDI One의 “Data Collectors” 탭에서 "Add Collector"를 선택하고 설정합니다. "Data Collector"의 이름을 지정하고 "Collector Type"에서 "MQTT Broker"를 선택합니다. MQTT 수집기 설정 스크린샷의 "Listen IP"는 JEDI One 라즈베리 파이의 IP 주소이며 "Listen Port"는 1883입니다. (참고: 아래 예시에서는 암호화되지 않은 설정을 보여주지만 Machinechat의 제품 설명 - How to Generate TLS Certificates and Keys에 설명된 대로 TLS 암호화를 설정할 수 있습니다)

이 예제에서는 라즈베리 파이에서 구동되어 센서 데이터를 수집하고 있는 기존 JEDI One 플랫폼을 사용하여 아두이노가 구독할 수 있는 MQTT 토픽을 제공합니다. 관련 게시글 ESP8266 및 Amphenol T9602 센서를 사용하는 Machinechat에 아래의 센서 데이터를 제공하는 프로젝트가 자세히 나와 있습니다.

아두이노 / ESP8266 예제 코드

이 예제에서 ESP8266는 와이파이 네트워크에 연결하여, JEDI One의 센서 데이터 토픽을 구독하고, JSON 인코딩된 구독 메시지를 디코딩하며, 그리고 디코딩된 타임스탬프와 센서 데이터를 직렬 모니터에 출력하도록 프로그램됩니다. PubSubClient와 ArduinoJson 라이브러리가 예제 코드에 사용되므로 설치해야 합니다.

와이파이 및 일반 설정 코드…

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h" 

// Update these with values suitable for your network.
char ssid[] = SECRET_SSID;     // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
const char* mqttServer = "192.168.1.11";
const int mqttPort = 1883;

StaticJsonDocument<256> doc;

int data1;  //data1 of MQTT json message
int data2;  //data2 of MQTT json message
int data3;  //data3 of MQTT json message
int msg = 0;
const char* timestamp = "dummy data";  //the is the MQTT message timestamp
//const char* current_ts = "blank";
String recv_payload;

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

MQTT 연결 및 구독 코드…

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a unique client ID using the ESP8266 MAC address
    String MACadd = WiFi.macAddress();
    MACadd = "ESP8266cli" + MACadd;  //add "ESP8266cli" to MAC address
    //Serial.println(MACadd);        // debug print
    String clientID = MACadd;

    // Attempt to connect
    if (client.connect(clientID.c_str())) {
      Serial.println("connected");
      // set up MQTT topic subscription
      client.subscribe("datacache/T960981B2D");  // topic needs to be "datacache/" + Device on JEDI One 
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

MQTT 콜백 메시지 및 JSON 디코딩 코드…

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Subscribe topic: ");
  Serial.println(topic);
  Serial.print("Subscribe JSON payload: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);     // print mqtt payload
  }
  Serial.println();

  msg = 1;  //message flag = 1 when new subscribe message received

  deserializeJson(doc, (const byte*)payload, length);   //parse MQTT message
  data1 = doc["data1"];    // data1 is humidity
  data2 = doc["data2"];    // data2 is temp
  data3 = doc["data3"];    // data3 is empty
  timestamp = doc["timestamp"];    //mqtt message timestamp
  //Serial.println(timestamp);     //debug print
  
  recv_payload = String(( char *) payload);  // put payload in string for future use
  //Serial.println("print recv_payload string");   //debug info
  //Serial.println(recv_payload);                  //debug info
}

아두이노 직렬 모니터 출력 데이터 예시…

소프트웨어

하드웨어

라즈베리 파이 (참고: 본 프로젝트에는 라즈베리 파이 4를 사용하지만 아무 라즈베리 파이를 사용해도 됩니다)

ESP8266 보드

아두이노 설정

아두이노에서, “Additional boards manager URLs:” 필드에 다음 링크를 사용하여 ESP8266 지원을 추가합니다.

http://arduino.esp8266.com/stable/package_esp8266com_index.json

아두이노 Library Manager를 통해 다음 라이브러리를 추가합니다:

아두이노 스케치 및 소스 코드는 아래 깃허브 링크에 있습니다.

참고문헌

아두이노 - How to use ArduinoJson with PubSubClient?
Machinechat 제품 설명 - Built In MQTT Broker - Data Collector
Machinechat 제품 설명 - MQTT Broker - Subscribing to a topic
HiveMQ - MQTT Essentials

연락

댓글, 피드백 및 질문은 eewiki@digikey.com로 보내주시면 됩니다.



영문 원본: Machinechat JEDI One MQTT Broker Subscribe Example using Arduino / ESP8266