MQTT 프로토콜 분석과 테스트

주목!! 아래 링크에는 MQTT 를 다양한 플랫폼에 구현해서 테스트 해 볼 수 있는 코드를 안내하고 있습니다. 참고하세요.

홈 오토메이션과 센서 네트웍 관련 자료들을 찾다보니 MQTT 프로토콜이 자주 등장하더군요. 좀 더 세부적으로 살펴보니 여러모로 유용한 것 같아 자료들을 정리해 봤습니다. 실제 테스트도 가능하도록 예제도 첨부했습니다.

MQTT(MQ Telemetry Transport)는 아두이노나 라즈베리파이 같은 임베디드 장치간 통신을 위한 가벼운 메시징 프로토콜입니다. TCP/IP 기반으로 대역폭이 작은 네트워크에서 동작할 수 있도록 설계된 프로토콜입니다. 쉽게 얘기해서 임베디드 장치들을 위한 트위터라고 볼 수 있습니다.

MQTT 자체는 메시지를 어떻게 보낼 것인지를 정의하는 규약일 뿐입니다. 따라서 실제 MQTT 트위터를 동작시키기 위해서는 서버 역할을 해주는 장치(프로그램)가 필요한데 이를 MQTT 브로커(Broker)라고 합니다. MQTT 브로커는 각종 장치들(MQTT Client)이 보내주는 메시지를 수집하고 이걸 다시 필요한 장치들에게 전송해주는 중계서버 역할을 합니다.

MQTT 클라이언트는 브로커에게 메시지를 전달하고 필요한 메시지를 받기만 하면 되고 MQTT 프로토콜의 구조도 간단하기 때문에 처리능력이 낮은 임베디드 장치에 잘 어울립니다. 메시지는 트위터처럼 140자 제한이 없으므로 긴 메시지나 JSON 포맷 또는 파일도 전송이 가능합니다. 이런 특징들 때문에 MQTT 프로토콜은 센서 네트웍을 구성하는데 유용한 도구로 관심을 받고 있습니다.

MQTT 동작 구조 (pub/sub)

트위터 서비스의 동작구조를 떠올려보세요. 트위터에서 사용자는 다른 사용자를 follow 할 수 있습니다. 그럼 다른 사용자가 생성하는 메시지(트윗)를 받아볼 수 있죠. 그리고 스스로 메시지를 생성할 수도 있습니다. 그럼 자신을 follow하는 사용자에게 메시지가 전달되죠.

MQTT도 거의 유사한 동작구조를 갖습니다. MQTT 시스템에 참여하는 MQTT 클라이언트는 메시지 발행(publish, 트윗에 해당), 메시지 구독(subscribe, follow에 해당) 두 가지 동작을 할 수 있습니다. MQTT 클라이언트가 메시지를 특정 채널(Topic, 토픽)에 발행하면 이 채널을 구독한 모든 클라이언트에게 메시지가 전달되는 겁니다. 중간에서 메시지를 수집, 재분해 하는 작업은 MQTT 브로커가 담당합니다.

0912embmqtt01

토픽

메시지를 발행/구독(pub/sub) 하는 행위는 채널 단위로 일어납니다. 이를 MQTT에서는 토픽(Topic)이라고 합니다. 토픽은 슬래시(/)로 구분된 계층구조를 갖습니다.

topic_basics

메시지를 구독/발행 할 때 여러개의 토픽을 한번에 지정할 수 있도록 wild card 문자를 지원합니다. [+] 문자는 단 1개의(1 레벨) 토픽을 임의의 토픽으로 대체하는 와일드카드 문자입니다.

topic_wildcard_plus

반면 [#] 문자는 여러 레벨의 토픽을 대체할 수 있습니다. [myhome/#] 처럼 사용하면 myhome 의 하위 토픽들 모두를 지칭하게 됩니다. [#] 문자는 토픽 문자열 끝에만 사용할 수 있으며 하위 토픽 모두를 지칭합니다. (2단계 이상 하위 토픽도 포함)

topic_wildcard_hash

[$] 문자로 시작하는 토픽은 시스템에 의해 사용되는 특수한 토픽을 의미합니다. 이 토픽들은 [#] 문자열로 지정해도 포함되지 않는 토픽이 됩니다. 주로 [$SYS/] 로 시작하는 토픽들이 브로커의 내부 메시지를 위해 사용됩니다. (이에 대한 명확한 표준은 없는 상태인듯)

토픽 구조를 구성할 때 몇 가지 주의할 점이 있습니다.

  • 최상위 토픽이 [/] 문자로 시작하지 않도록 합니다. [/home/sensor/humid] 이렇게 사용할 수는 있지만 최상위 토픽이 이름이 없는 토픽이 되므로 사용하지 않는 것을 권장합니다.
  • 토픽 이름에 공백을 사용하지 않습니다.
  • 토픽 이름은 ASCII 문자만 사용합니다. (임베디드 장치와의 호환성을 위해 주의)
  • [#] 를 이용해서 토픽 전체를 구독하지 않도록 합니다. 오버헤드가 심할 경우 브로커/클라이언트 프로세스가 중단될 수 있습니다.

QoS (Quality of Service)

MQTT는 시스템에 참여하는 장치들의 처리 능력, 네트워크 대역폭, 메시지 오버헤드 등 주변상황에 맞게 시스템이 동작할 수 있도록 3단계 QoS(Quality of Service) 를 제공합니다.

  • 0 : 메시지는 한번만 전달하며, 전달여부를 확인하지 않는다. Fire and Forget 타입이다.
  • 1 : 메시지는 반드시 한번 이상 전달된다. 하지만 메시지의 핸드셰이킹 과정을 엄밀하게 추적하지 않기 때문에, 중복전송될 수도 있다.
  • 2 : 메시지는 한번만 전달된다. 메시지의 핸드셰이킹 과정을 추적한다. 높은 품질을 보장하지만 성능의 희생이 따른다.

0에 가까울수록 메시지 처리에 대한 부하가 적은 대신 메시지 손실 위험이 높아집니다. 2에 가까울수록 메시지 손실 위험은 줄어들지만 메시지 처리 부하가 급격히 늘어납니다.

(보통 0~1 정도의 QoS를 사용하면서 메시지 손실등의 위험은 상위 어플리케이션 차원에서 관리하도록 하는듯 합니다.)

MQTT 브로커

MQTT 시스템의 핵심 서버 역할을 하며,  여기에 메시지가 수집되고 다시 재분배 됩니다. 다양한 MQTT 브로커 프로그램들이 개발되어 있는데 ActiveMQ, Apollo, IBM Message Sight, JoramMQ, Mosquitto, RabbitMQ, Solace Message Routers 등이 자주 사용됩니다. 아래 링크에 MQTT 브로커의 특징을 비교한 자료가 있습니다.

여기서는 Mosquitto 브로커를 사용할 것입니다. Mosquitto는 MQTT의 기본 기능을 충실히 지원하는 가벼운 MQTT 브로커 프로그램입니다. Mosquitto 클라이언트 프로그램도 있으므로 여러대의 PC를 이용해서 테스트를 할 수 있습니다.

mosquitto

MQTT 동작 테스트

홈 오토메이션이나 센서 네트워크를 구성하기에는 라즈베리파이같은 손바닥 PC가 제격입니다. 여기서는 MQTT 동작 테스트를 위해 PC와 라즈베리파이에 Mosquitto MQTT 클라이언트, 브로커를 설치할 것입니다.

라즈베리파이에 Mosquitto 브로커를 설치하는 작업부터 시작합니다. Mosquitto 는 apt-get 명령어를 통해 간단히 설치할 수도 있지만 업데이트가 되지 않는 문제점이 보고되고 있습니다. 아래 순서로 설치하길 권장합니다. (최신 소스코드를 다운로드 받아 설치하실땐 링크를 참고하세요.)

  • wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
  • sudo apt-key add mosquitto-repo.gpg.key
  • cd /etc/apt/sources.list.d/
  • sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list
  • sudo apt-get install mosquitto

설치가 완료되면 브로커는 1883 포트를 사용하게 됩니다.

이제 PC와 모바일 폰에 MQTT 클라이언트를 설치해서 연동을 해보겠습니다. PC(Windows, Linux, OS X)에서는 MQTT.fx 클라이언트를 설치하면 됩니다. 아래 링크에서 프로그램을 받을 수 있습니다.

MQTT.fx 클라이언트는 윈도우 64비트만 지원합니다. 이 문제 때문에 설치가 안된다면 크롬 브라우저의 확장 앱으로 설치해서 사용하는 방법도 있습니다. 크롬 브라우저에서 아래 링크를 통해 설치할 수 있습니다.

모바일 폰에서는 앱 스토어에서 MQTT로 검색하시면 됩니다. 다양한 클라이언트가 등록되어 있는데 대부분 비슷하므로 아무거나 사용하셔도 됩니다. 유명한 MQTT 클라이언트들은 링크에서 확인하실 수 있습니다.

설정 방법은 간단합니다. 아래 항목들만 정확히 설정해 주면 됩니다.

  • MQTT 브로커 URL : MQTT 브로커를 설치한 서버의 URL 입니다.
  • Port : 앞서 설치한 Mosquitto 브로커는 기본 1883 포트를 사용합니다.
  • Username / Password : 지금은 설정하지 않아도 됩니다.

테스트를 위해 클라이언트에서 subscribe 버튼을 누르고 토픽에 messagebox를 입력합니다. 그럼 messagebox 토픽이 생성되고 구독이 됩니다. PC, 모바일 등 모든 장치에서 같은 작업을 해줍니다.

이제 PC, 모바일에서 publish 를 합니다. 이때 토픽은 messagebox로 선택합니다. 그럼 입력한 메시지가 브로커로 전달되고 messagebox 토픽을 구독하는 다른 장치들에도 전달되어야 합니다. 제대로 동작하는지 확인해보세요.

MQTT 브로커를 설치한 라즈베리파이에 MQTT 클라이언트를 설치해서 확인할 수도 있습니다.

  • apt-get install mosquitto-clients

아래 명령으로 메시지 발행(pub)을 할 수 있습니다. 다른 기기에도 메시지가 보여야겠죠.

  • mosquitto_pub -d -t messagebox -m “sent from RPi server”

특정 토픽을 구독(sub) 할 수 있습니다. 이 경우 특정 토픽에 메시지가 도착 할 때마다 표시됩니다. Ctrl+c 를 눌러 멈추기 전까지는 메시지 표시하는 상태로 유지됩니다.

  • mosquitto_sub -d -t messagebox

MQTT – IoT 장치 만들기

앞선 MQTT 테스트는 단순한 메시지를 공유하는 일종의 채팅 예제였습니다. 여기서 메시지 내용만 원하는대로 바꿔서 사용하면 센서 네트웍, 홈 오토메이션에도 MQTT가 메시지 전송 프로토콜로 활용될 수 있음을 알 수 있습니다. 여기서는 IoT 장치를 직접 만들기 위해서 마이크로 컨트롤러에 MQTT를 이식하고 메시지를 전달하는 예제를 만들어 보겠습니다.

예제 장치를 만들기 위해 아래와 같은 모듈들이 필요합니다.

  • ESP8266 – NodeMCU (ESP12E 기반) 보드
  • DHT22 (온습도 측정용 센서)
  • I2C 128×64 OLED (옵션, 현재 상태와 송수신 메시지 표시용, 반드시 SSD1306 드라이버 칩을 사용한 모듈 필요)
esp8266_title

ESP8266 – NodeMCU (ESP12E 기반) 보드

가성비와 활용성 면에서 최고의 평가를 받는 ESP8266 WiFi 모듈을 마이크로 컨트롤러로 사용합니다. 여기서는 모듈에 올라갈 펌웨어 작성을 위해서 Sming 개발환경을 사용할 예정인데, ESP8266 Arduino IDE로 작성하는 것도 가능합니다.

먼저 모듈들을 연결을 해줘야겠죠. ESP8266과 DHT22은 아래 순서로 연결합니다.

  • ESP8266 –> DHT22
  • 3V –> VCC
  • GND –> GND
  • D5(GPIO14) –> DAT

ESP8266 에 OLED 디스플레이도 연결합니다.

  • ESP8266 –> OLED
  • 3V –> VCC
  • GND –> GND
  • D3(GPIO0) –> SCL
  • D4(GPIO2) –> SDA

모듈 연결이 끝나면 ESP8266에 올라갈 펌웨어를 만들어야 합니다. Eclipse 기반 Sming 개발환경을 구축하면 MQTT client 예제 파일도 같이 설치됩니다. 이걸 수정해서 DHT22 센서로 온습도를 측정하고 MQTT broker로 전송하도록 만들었습니다. 아래 링크에서 소스코드를 구하실 수 있습니다.

소스에서 몇 가지를 수정해줘야 합니다. 공유기 ID(SSID)와 PASSWORD, 센서값을 전송할 간격, 토픽의 이름(여기서는 messagebox  토픽 사용) 입니다.

......
#ifndef WIFI_SSID
	#define WIFI_SSID "your_ssid" // Put you SSID and Password here
	#define WIFI_PWD "your_password"
#endif
......
MqttClient mqtt("your_mqtt_server.com", 1883, onMessageReceived);
......
	mqtt.publish("your_topic", message); // or publishWithQoS
......
	mqtt.subscribe("your_topic");
......

소스가 수정되면 컴파일을 하고, 생성된 펌웨어를 MSP8266 모듈에 올려 구동하면 정해진 시간 간격마다 MQTT 메시지를 전송합니다. PC, Mobile 폰에서 messagebox 토픽에 해당 메시지가 들어오는지 확인하면 되겠죠.

그리고 반대로 PC, Mobile 폰에서 messagebox 토픽에 메시지를 생성(publish)하면 ESP8266 모듈의 디스플레이에 표시되어야 합니다.

mqtt_exam

메시지가 정상적으로 표시된다면 기본적인 수준의 IoT 장치가 완성된 것입니다!! 이걸 응용하면 IoT 장치를 인터넷 서비스와 연동하는데 사용할 수 있습니다.

Home-Assistant 홈 오토메이션 서버와 연동

MQTT 프로토콜은 단순히 메시지/데이터를 전송하는데 사용되는 규약일 뿐입니다. 대신 MQTT broker/client, 라이브러리를 통해 송수신된 데이터를 처리하는 도구를 풍부하게 제공합니다. MQTT로 전송하는 메시지가 무엇인가는 전혀 관여하지 않습니다. 전송되는 데이터 자체를 어떻게 처리할 것인가는 서비스 개발자의 몫입니다.

따라서 센서 네트웍, 홈 오토메이션에 MQTT 를 사용하더라도 전달되는 데이터를 어떤 형식으로 보낼 것인지는 직접 정의해야 합니다. 이런 작업을 직접 다 하기에는 고려해야 할 점도 많고 구현도 힘들기 때문에 오픈소스로 표준화/공개된 솔루션을 사용할 수 있습니다. 여기서는 Home-assistant 라는 홈 오토메이션 솔루션을 이용해 우리가 만든 IoT 장치를 연동해 보도록 하겠습니다.

홈 어시스턴트 서버를 설치하고 설정하는 방법은 아래 링크에서 다루고 있습니다.

앞서 ESP8266 보드로 만든 장치를 다시 이용하도록 하겠습니다. 대신 소스코드에 약간의 수정이 필요합니다.

void publishMessage() {
	......
	// Make JSON data
	String message = "{\"temp\":";
	message += th.temp;
	message += ", \"humi\":";
	message += th.humid;
	message += "}";

	// publish message
	Serial.println("Let's publish message now!");
	mqtt.publish("home/thirdroom/temp_humi", message, true); // retained message
	......
}

앞서와 다른 점은 데이터를 보낼 때 JSON 형식으로 보낸다는 겁니다. 예를 들어 온도 23.11′, 습도 68.35%를 보낼 때 아래처럼 보냅니다.

{"temp": 23.11, "humi": 68.35}

그리고 이 데이터는 [home/thirdroom/temp_humi] 토픽으로 전송합니다. 마지막에 true 파라미터가 붙은건 마지막 데이터를 저장했다가 새로 구독(subscribe)하는 기기가 있으면 보내주기 위한 retained message 기능입니다.

홈 어시스턴트 서버에서는 [home/thirdroom/temp_humi] 토픽을 구독하면서 새로운 업데이트가 생겼을 때 JSON 데이터를 파싱하면 됩니다. 홈 어시스턴트 설정파일인 [configuration.yaml] 파일에서 아래와 같이 설정해주면 됩니다.

sensor 3:
  platform: mqtt
  state_topic: "home/thirdroom/temp_humi"
  name: "Thirdroom Humidity"
  qos: 0
  unit_of_measurement: "%"
  value_template: '{{ value_json.humi }}'

sensor 4:
  platform: mqtt
  state_topic: "home/thirdroom/temp_humi"
  name: "Thirdroom Temperature"
  qos: 0
  unit_of_measurement: "°C"
  value_template: '{{ value_json.temp }}'

[home/thirdroom/temp_humi] 토픽을 구독하면서 데이터가 도착하면 humi, temp 변수를 찾아 그 안에 할당된 값을 추출합니다. 정상적으로 동작하면 홈 어시스턴트 웹 페이지에서 아래처럼 보이게 됩니다.

ha_mqtt_device

openHAB 홈 오토메이션 서버와 연동

openHAB 도 홈 어시스턴트와 같은 컨셉을 가진 홈 오토메이션 서버입니다. 아래에 설명하는 과정은 openHAB 홈 오토메이션 서버MQTT 브로커를 연동해서 센서값을 보여주는 방법입니다. 여기서는 이미 openHAB이 설치된 리눅스 서버가 있다는 가정하에 진행하겠습니다. 라즈베리파이에 openHAB 서버 설치는 링크의 내용을 참고하세요.

openHAB 서버가 MQTT 브로커와 연결되기 위해서는 전용 add-on 을 설치해야 합니다.

  • sudo apt-get install openhab-addon-binding-mqtt
  • sudo chown -R openhab:openhab /usr/share/openhab

openHAB 설정 파일을 수정해줍니다.

  • sudo nano /usr/share/openhab/configurations/openhab.cfg

아래 내용을 추가

mqtt:broker.url=tcp://localhost:1883
mqtt:broker.clientId=openhab

openHAB 재실행

  • sudo service openhab restart

MQTT 로 들어온 메시지가 연결될 Number item 추가 작업

(이하 내용 작성 중…)

참고 링크

참고자료

아두이노와 Ethernet 모듈을 이용한 센서 장치 만들기

You may also like...