반응형

MQTT(http://mqtt.org/)는 M2M이나 IoT의 접속 프로토콜로 매우 가벼운 Publish/Subscribe 메시지 전송 프로토콜이다. MQTT 는 아주 조그마한 코드로 동작하여야 하고 네트워크 대역폭이 제한적인 환경에서 매우 유용하게 사용 가능하다. IBM에서 설계하였고 Eclipse M2M Industry Working Group에서 활발하게 논의 되고 있다.


MQTT는 따라서 Arduino와 같이 아주 제한적인 디바이스에서 네트워크 접속 프로토콜로 이용 가능한데 arduino용 라이브러리는 다음 사이트에서 얻을 수 있다.


Arduino Client for MQTT - http://knolleary.net/arduino-client-for-mqtt/


근데 WiFly Shield 를 이용하기 위해서는 소스 코드의 수정이 필요하다. 


1) 의존성 문제를 간단히 해결하기 위해서 pubsubclient 폴더에 WiFly폴더에 있는 .cpp 및 .h 파일을 복사해서 넣는다.



2) PubSubClient.h 변경

PubSubClient.h 를 열어서 include 부분을 다음과 같이 변경 한다.


#include "Ethernet.h"

#include "EthernetClient.h"            --> #include "WiFly.h"


class의 private 선언 부분의 EthernetClient _client; 를 Client *_client; 로 변경한다. 그리고  public 메소드로  WiFly 의 begin을 지시하기 위해서 


boolean begin(); 


와 join 환경 설정을 위해서 


boolean join(const char *ssid, const char *passphrase,boolean isWPA); 


를 추가해 준다.


3) PubSubClient.cpp 변경

 PubSubClient.cpp 에서 _client. 으로 되어 있는 코드는 _client-> 로 변경해준다. 예를 들어  _client.available() 은 _client->available() 로 변경해 주면 된다. 

 2)에서 정의했던 함수들을 다음과 같이 추가해 준다.


boolean PubSubClient::begin(){

WiFly.begin();

}

boolean PubSubClient::join(const char *ssid, const char *passphrase,boolean isWPA = true){

return WiFly.join(ssid,passphrase,isWPA);

}


 그리고 PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int)) 및 PubSubClient::PubSubClient(char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int)) 함수 마지막에 다음의 코드를 입력한다.


_client=new Client(domain,port);


4) _client->flush() 추가

 write 이후 flush 하도록 하지 않으면 정상적으로 메시지 송/수신이 되지 않는다. 따라서 _client->write 부분 이후에 _client->flush 코드를 다음의 함수 내에서 추가해준다.


boolean PubSubClient::loop() {

......

 _client->write(MQTTPINGREQ);

 _client->write((uint8_t)0);

_client->flush();

......

 _client->write(MQTTPINGRESP);

_client->write((uint8_t)0);

 _client->flush();

.......

}

boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {

.....

rc = _client->write(header);

rc += _client->write(lenBuf,llen);

rc += _client->write(buf,length);

_client->flush();

.....

}


void PubSubClient::disconnect() {

   _client->write(MQTTDISCONNECT);

   _client->write((uint8_t)0);

   _client->flush();

   _client->stop();

   lastInActivity = millis();

   lastOutActivity = millis();

}


다음은 본 library를 이용 해서 MQTT를 이용해서 deviceid/control/led1 으로 6번 Digital Out을 제어하고 deviceid/control/led2 로 7번 Digital Out을 제어하며 6초마다 DHT22 센서에서 온도와 습도를 deviceid/temperature 및 deviceid/humidity 로 publish해주는 실험을 해보겠다.


다음은 실헙 보드의 구성이다.

다음은 Sketch이다

#include <SPI.h>

#include <PubSubClient.h>

#include <DHT.h>

#define DHTPIN 2

#define DHTTYPE DHT22

DHT dht(DHTPIN,DHTTYPE);

byte server[] = { xxx, xxx, xxx, xxx }; //MQTT Server IP

void callback(char* topic, byte* payload,unsigned int length) {

  // subscribe한 topic 에 메시지가 publish 되면 호출된다.

  // 하나의 주제만 subscribe가 가능하며 하나의 주제 밑에 sub 주제를 이용하여 제어를 분리 가능하다.

  char buffer[4];

  strncpy(buffer,(char*)payload,length);

  if(strcmp(topic,"deviceid/control/led1")){ // sub주제 parsing

    if(strncmp(buffer,"on",2)==0) {

      digitalWrite(6,HIGH);

    } else {

      digitalWrite(6,LOW);

    }

  } else if(strcmp(topic,"deviceid/control/led2")){ // sub주제 parsing

    if(strncmp(buffer,"on",2)==0) {

      digitalWrite(7,HIGH);

    } else {

      digitalWrite(7,LOW);

    }

  }

}

PubSubClient client(server, 1883, callback);

unsigned long timer;

void setup()

{

  Serial.begin(9600);

  client.begin();

  if(!client.join("ssid","passphrase",WEPFLAG)){

    Serial.println("Joining is failed..");

    while(1){}

  }

  Serial.println("Before connect");

  if (client.connect("arduinoClient")) {

    Serial.println("Connected..");

    client.subscribe("deviceid/control");

  }

  timer=millis();

  dht.begin();

  pinMode(6,OUTPUT);

  pinMode(7,OUTPUT);

}

void loop()

{

  client.loop();

  unsigned long time_cmp=millis();

  char buffer[5];

  if(time_cmp-timer>6000){

    timer=time_cmp;

    float h=dht.readHumidity();

    float t=dht.readTemperature();

    int temp=(h-(int)h)*100;

    sprintf(buffer,"%0d.%d",(int)h,temp);

    client.publish("deviceid/humidity",buffer);

    temp=(t-(int)t)*100;

    sprintf(buffer,"%0d.%d",(int)t,temp);

    client.publish("deviceid/temperature",buffer);

  }

}


MQTT 서버는 node.js 의 mqtt.js 를 이용하였고 예제 중 orig.js 를 이용하였다. MQTT의 각 요청에 대해서 console로 출력하도록 수정하였다.

다음은 실행 후 arduino에서 접속하고 publishing 한 서버쪽 메시지 이다.


다음은 deviceid 로 subscription하여 arduino에서 publish 한 데이터를 받는 MQTT 클라이언트 출력 메시지 인다.

DHT22 센서에서 얻어진 온, 습도를 출력해줌을 알 수 있다.


mqtt_pub 프로그램으로 deviceid/control/led1 과 deviceid/control/led2 의 전원을 on/off 할 수 있다.














반응형
Posted by alias
,