2017년 5월 11일 목요일

라즈베리 파이에서 MQTT를 이용해 ESP8266 제어하기

여기서는 라즈베리 파이, ESP8266(또는 와이파이 쉴드를 붙인 아두이노), PC를 MQTT로 연결해 보도록 하겠다.

이번에 하고자 하는 것은 라즈베리파이가 python을 사용해 PC에 있는 MQTT 브로커에 메시지를 보내면 그 메시지가 ESP8266으로 전달되어 거기에 있는 LED를 제어하는 것이다.

MQTT for PC


MQTT server(브로커)로 사용할 수 있는 옵션이 몇가지 있다. Amazon의 AWS IoT나 AdafruitIO 같은 서비스들은 클라우드 기반의 브로커이다. 각 서비스는 여러가지 장점이 있다. 프로젝트의 필요성에 따라 클라우드 기반 서비스를 사용할 필요가 있을수도 있다.

Mosquitto


자신의 호스트에 브로커를 실행하고 싶으면 오픈소스인 moqsuitto가 훌륭한 옵션이다. 이 브로커는 MQTT를 완전히 지원할 뿐 아니라 pub/sub를 위한 커맨드라인 유틸리티까지 제공한다.

윈도우를 사용하면 mosquitto.org에서 바이너리 인스톨러를 받을 수 있다. 리눅스의 경우 패키지 매니져에서 'mosquitto' 또는 'mosquitto-mqtt'를 찾으면 된다. 맥에서는 homebrew를 사용해 mosquitto를 설치할 수 있다.

* 맥에서 설치한 경우 '/usr/local/sbin'을 PATH에 넣어줘야 한다.

Running Mosquitto


Mosquitto는 디폴트로 1883번 포트를 사용하고 보안기능은 다 꺼져 있다. 처음 시작할 때는 이것으로 충분하지만 결국에는 보안기능을 추가해 줄 필요가 있다.

Mosquitto를 verbose 모드로 실행하길 권장한다. 그러면 출력을 보고 어떤 일이 일어나는지에 대한 아이디어를 얻을 수 있을 것이다.

MacMan:~ james$ mosquitto -v 
1456272937: mosquitto version 1.4.5 (build date 2015-11-09 14:23:46-0800) starting 1456272937: Using default config. 
1456272937: Opening ipv4 listen socket on port 1883. 
1456272937: Opening ipv6 listen socket on port 1883.

Testing Mosquitto


서버 코드를 verbose 모드에서 실행시키고, 추가로 두개의 명령어 프롬프트를 열어준다. 각각의 명령어 프롬프트에서 메시지 전송 테스트를 위해 mosquitto_pub와 mosquitto_sub를 사용할 것이다.

Subscribing to MQTT Topic with Mosquitto


먼저 클라이언트가"debug"라는 토픽을 subscribe하게 해 준다. 첫번째 명령어 프롬프트에서 아래 명령을 입력해 주면 된다.

$ mosquitto_sub -h 127.0.0.1 -i testSub -t debug

* -h : host flag는 mosquitto가 실행되고 있는 서버를 지정. 여기서는 localhost
* -i : identity flag 는 옵션이다. Client ID가 지정되지 않으면 mosquitto_sub가 임의로 만듬
* -t : topic flag 는 subscribe 하려고 하는 topic을 지정. 여기서는 "debug"

서버에서는 topic을 만들지 않았다는걸 주목해라. Topic은 subscriber나 publisher가 처음 지정할 때 만들어진다.

Publish to MQTT Topic with Mosquitto


이제 topic을 기다리는 클라이언트를 가지고 있으므로, 다른 클라이언트가 그 topic을 publish하게 해 본다.

$ mosquitto_pub -h 127.0.0.1 -i testPublish -t debug -m 'Hello World'


이제 첫번째 명령어 프롬프트 화면을 보면 publish된 메시지가 와 있는것을 확인할 수 있다. mosquitto_pub와 mosquitto_sub 명렁 모두 --help 플래그로 확인 해 봐라. 매우 여러가지 유용한 옵션들을 찾아볼 수 있을 것이다.

이제 mosquitto 브로커가 정상 동작하고 있는것이 확인되었으므로 디바이스와 통신을 하게 해 보자.

MQTT for Raspberry Pi (Python)


라즈베리 파이에서 MQTT 메지시를 보내고 받을 수 있는 옵션으로는 mosquitto를 설치하는 것이다. 그러면 라즈베리 파이에서도 동일하게 mosquitto_pub와 mosquitto_sub 명령어를 사용할 수 있다.

다른 방법으로는 자신이 선호하는 언어용 MQTT 라이브러리를 사용하는 것이다. 여기서는 파이선을 사용한다.

Install MQTT for Python


여기서 사용할 MQTT library는 Paho Python Client이다. 오픈소스로 가장 최신의 MQTT를 지원한다.

설치는 간단하다. 먼저 'pip'를 설치하고 나서 아래 명령을 실행한다.

$ pip install paho-mqtt

* 만일 python3를 사용한다면 'pip' 대신 'pip3'를 사용해야 하는걸 잊지 마라.

Example MQTT Python Code for Raspberry Pi


Paho는 MQTT 서버와 통신을 매우 쉽게 만들어 준다.

import paho.mqtt.publish as publish
import time
print ("Sending 0...")
publish.single("ledStatus", "0", hostname="macman")
time.sleep(1)
print ("Sending 1...")
publish.single("ledStatus", "1", hostname="macman")

진짜 간단하다. 스크립트에 서버가 실행되고 있는 호스트 이름(여기서는 'macman'), Topic (여기서는 'ledStatus'), 메시지(여기서는 '0' 또는 '1')만 알려주면 된다.

이 MQTT 튜토리얼 예제에서는 '0'을 보내고 1초 기다린 후에 '1'을 보낸다. 이 동작은 ESP8266에 있는 LED가 잠깐동안 꺼졌다 다시 켜지게 만든다.


이제 RPi가 MQTT 메시지를 보내게 만들었으니 그 메시지를 받도록 만들어 보자. 다음 섹션은 ESP8266이 topic "ledStatus"의 메시지를 받아 실제로 LED를 깜빡이게 만들 것이다.

MQTT for ESP8266


PubSubClient는 아두이노 기반의 MQTT 클라이언트이다. 단지 몇 줄의 코드만으로 매우 쉽게 topic을 subscribe하거나 새로운 topic을 publish할 수 있다.

여기서는 ESP8266을 프로그래밍 하기 위해 아두이노 IDE를 사용했다.

Installing MQTT for Arduino IDE


아두이노 IDE에 PubSubClient를 설치하는건 간단하다. Github에서 수동으로 설치하거나 또는 Arduino Package Installer를 사용할 수 있다.


Arduino ESP8266 and Uno Note


Ethernet 쉴드가 장착된 Uno와 ESP8266간에 스위칭에는 별도의 추가적인 노력이 필요 없다. 라이브러리는 양쪽 모두 잘 동작한다.

Code Example for Arduino MQTT


PubSubCilent에 포함되어 있는 예제는 매우 훌륭하다. 예제에는 특히 MQTT에 대한 ESP8266 코드도 들어있다. 처음 시작할 때 그것들도 꼭 확인해 보기 바란다.

아래는 WiFi에 연결하고 "ledStatus" topic을 subscribe하는 코드이다. ESP8266이 메시지를 받으면 그에 따라 ledPin을 on/off한다.

#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_INA219.h>

// Connect to the WiFi
const char* ssid = "Dear John";
const char* password = "password123";
const char* mqtt_server = "macman";

WiFiClient espClient;
PubSubClient client(espClient);

const byte ledPin = 0; // Pin with LED on Adafruit Huzzah

void callback(char* topic, byte* payload, unsigned int length) {
 Serial.print("Message arrived [");
 Serial.print(topic);
 Serial.print("] ");
 for (int i=0;i<length;i++) {
  char receivedChar = (char)payload[i];
  Serial.print(receivedChar);
  if (receivedChar == '0')
  // ESP8266 Huzzah outputs are "reversed"
  digitalWrite(ledPin, HIGH);
  if (receivedChar == '1')
   digitalWrite(ledPin, LOW);
  }
  Serial.println();
}


void reconnect() {
 // Loop until we're reconnected
 while (!client.connected()) {
 Serial.print("Attempting MQTT connection...");
 // Attempt to connect
 if (client.connect("ESP8266 Client")) {
  Serial.println("connected");
  // ... and subscribe to topic
  client.subscribe("ledStatus");
 } else {
  Serial.print("failed, rc=");
  Serial.print(client.state());
  Serial.println(" try again in 5 seconds");
  // Wait 5 seconds before retrying
  delay(5000);
  }
 }
}

void setup()
{
 Serial.begin(115200);

 client.setServer(mqtt_server, 1883);
 client.setCallback(callback);

 pinMode(ledPin, OUTPUT);
}

void loop()
{
 if (!client.connected()) {
  reconnect();
 }
 client.loop();
}


모든 마법은 "callback" 함수 안에서 일어난다. 실제 코드에서는 받은 메시지를 처리하는 함수를 작성하고 싶을 것이다. 여기서는 topic에 대해 한글자 메시지만을 보내기 때문에 이 간단한 코드로 충분하다.

Conclusion


이 MQTT 튜토리얼은 매우 기초적이다. 하지만 라즈베리 파이, ESP8266을 MQTT 브로커가 실행되고 있는 PC에 연결하는데 필요한 최소한의 것을 보여준다.

다음에는 MQTT를 통해 어떻게 더 복잡한 메시지를 보낼 수 있는가를 설명하겠다.




댓글 없음:

댓글 쓰기