Arduino Yun과 AWS IoT 2
아두이노 윤으로 AWS IoT와 연결에 대한 두번째 포스팅 입니다. 지난 포스팅에서는 윤의 환경 설정부분과 AWS에서의 설정만을 다루었습니다. 이제 Arduino IDE에서 작업을 진행하여 연결되는 것을 확인 해보고, 이전에 UNO에서 작업하였던 소음 진동 센서를 붙여서, AWS IoT로 메세지를 보내고, AWS에서 제대로 받았는지 확인해 보겠습니다. 지난번과 마찬가지로 본문은 편하게 작성하고자 합니다. 양해 부탁드립니다.
5. Arduino Yun과 AWS IoT 연결 테스트
아래는 내 컴퓨터의 Arduino IDE의 스케치북 폴더의 모습이다. 아래에서 libraries라는 폴더가 라이브러리 폴더이다. libraries 폴더 안에 이전 포스팅에서 언급되었던, "AWS-IoT-Arduino-Yun-Library" 폴더를 통채로 복사 한다. 그리고 Arduino IDE를 실행 시킨 다음 파일>예제>AWS-IoT-Arduino-Yun-Library>BasicPubSub를 클릭한다.
그럼 아래와 같이 예제 샘플 소스가 그대로 뜰 것이다. 나의 경우 소스에서 BasicPubSub의 내용을 변경할 이유가 없었다. 그러나 aws_iot_config.h 파일은 이전 포스팅에서 따로 저장하였던 AWS IoT 연결 설정에서 나왔던 코드로 변경을 하여야 한다.
aws_iot_config.h의 최초 내용이다. 이전 포스팅을 참고하여 내용을 환경에 맞게 변경한다. 복사해서 //==== 두 줄 사이의 코드 내용을 통채로 변경하면 된다. 이제 테스트를 진행 할텐데, 윤보드를 컴퓨터와 연결하고 툴>시리얼 모니터를 클릭하여 시리얼 모니터를 연다. 그리고 좌측 상단의 화살표를 클릭하여, 소스를 빌드하고 배포한다. 소스코드에 Serial.begin(115200);이라 기술 되어 있다. 당연히 시리얼 모니터의 보드레이트는 115200으로 맞쳐야 한다.
별다른 문제없이 빌드되고 배포 되었다면, 아래와 같은 메세지가 나타나야 한다. 만약 뭔가 문제가 있다면 에러와 메세지와 함께 에러 코드가 나타난다. 에러에 대해서 내가 보았던 코드는 -13이었고, 이것의 정의 AWS-IoT-Arduino-Yun-Library/aws_iot_error.h에 CONNECT_CREDENTIAL_NOT_FOUND = -13 이렇게 되어 있었다. 여담이지만, 이게 인증서와 씨름을 하다보니 해결은 되었는데, 구체적으로 어째서 해결이 되었는지 아직도 아리송하다.
이렇게 떠야 정상이다. 그리고 중간에 설명되지 않은 것이 MQTT 프로토콜인데 여기서 설명하자니 너무 내용이 많을 듯하여 대충 설명하고 넘기려 한다. IBM과 Eurotech에 의해 개발된 프로토콜로서 오픈소스로 공개가 되었다. 메세지 발행/구독을 기반으로하는 가벼운 통신 프로토컬이다. Sensor와 통신에서 많이 사용되는 것같다. 그래서 그런지 AWS IoT도 MQTT 기반으로 통신을 하더라.
이제 웹브라우져를 열어 AWS IoT로 이동한 다음, 사이트 우측 상단에 MQTT Client를 클릭한다. 아래와 같은 화면이 뜰 것이다.
Client ID는 아무거나 입력하면 된다. 정말 귀찮다면, Generate client ID버튼을 클릭하면 알아서 입력해준다. 그리고 Connect를 클릭하면 AWS IoT의 MQTT Broker로 연결한다. 화면에 보면 Subscribe to topic라는 항목이 있다. 그것을 클릭하면, 구독을 설정할 수 있는 화면이 나오는데 Subscription topic에서 이전에 Arduino IDE에서 보았던 "topic1"을 입력하고 제일 아래의 Subscribe 버튼을 클릭한다.
위 그림과 같이 좌측에 토픽의 내용을 제대로 받으면 성공이라고 볼 수 있다. 이미 제대로 받는 것은 확인 했지만 이곳에서 메세지를 발행하면 윤이 받는 것도 테스트 해야 되지 않을까? "Pubish to topic" 항목을 클릭하고, Publish topic에 "topic1"이라고 입력한 다음 Payload 항목에 "Hi!"라고 입력한다. 그리고 아래에 Publish 버튼을 클릭한 후 Arduino IDE의 시리얼 모니터를 지켜보자.
저기 빨간색으로 밑줄그은 Hi!가 보인다면, 윤도 제대로 구독을 받는 것이라 생각 할 수 있다. 이제 윤을 이용해서 센서 회로를 구성한 다음 센서의 값을 AWS IoT로 넘겨 주고 제어신호를 받아 LED의 On/Off를 한다면, 윤으로 목표했던 것의 핵심은 다 한 것이라 할 수 있을 것이다.
6. 소음 센서 회로 구성.
아두이노 윤에서 AWS로 뭔가 값을 보내는 것은 AWS IoT SDK의 예제를 통해서 이미 해보았으니, 그 "뭔가"를 해야 한다. 사실 이것은 윤을 작업하기 이전에 벌써 모두 정해진 상태였다. 이미 아두이노 우노와 내부 NodeJS를 이용한 MQTT서버를 이용해서 한번 구현해본 바 있다.
여담이지만, ESP8266을 이용하여 구현했는데 이게 우노보드랑은 궁합이 좋지 못하다는 얘기가 많았다. 전기적인 문제가 있다고 카더라... 게다가 Uno랑 ESP8266은 다루기가 좀 힘들었다. 그래서 잘 동작하는 이넘을 보면서 회사사람들이 "저건 언제 터지니? 저걸 터트려야 윤을 사는데 도움이 되지."라고 하시는 분들이 많았다. 근데 이넘은 장수하고, 첫째 윤이 온날 업그래이드 작업을 하다 맞이 갔으니.......
지난간 일은 잊고, 우노에서는 우여곡절 끝에 ESP8266과 하드웨어 시리얼을 이용하여 통신을 하는 바람에 디버깅을 또는 상태를 위해 시리얼 모니터를 쓸 수가 없었다. 그래서 LCD가 붙어서 이런 기능을 했었는데, 윤은 그럴 필요가 없어 LCD는 빼고, 소음 센서와 LED만을 고대로 옮겨 왔다.(사진을 보면 LED가 13번핀에 연결되어 있다. 13번 핀은 보드에 이미 LED가 붙어 있으나, 일단 가져왔다.)
소음 센서 모듈에서는 아날로그 신호만 A3핀으로 받는다. 구글로 해당 모듈 혹은 소자의 정보를 찾으면 나오니 그걸 확인하고 회로를 구성하면 된다. 여기에 사용한 소자는 D, A, 5V, GND가 있는데, 윤의 GND와 연결하고, 5V는 윤의 5V에 연결 했으며, A가 A3핀에 연결되어 있다. 데이터는 A3에서 받을 것이다.
LED는 저항을 이용해서 전류를 맞추어 주고 (+)는 D13핀에 (-)는 GND에 연결한다. 소음센서와 마찬가지로 회로 구성에 대한 상세설명은 뒤로하고, 13에 연결한 이유는 윤이 MQTT로 신호를 받으면 D13핀에 HIGH를 걸어서 LED 불을 키려는 생각이다.
7. 윤 소스 변경
작업한지 몇일이 되다 보니 기억이 가물가물하다. 소스를 보면서 이 코드를 정말 내가 수정했단 말인가?라는 의문이 든다... 하지만 정황상 나밖에 없으므로, 의심의 여지는 없다.
일단 MQTT의 토픽을 지정한다.
#define mqtt_sensor_value_topic "$aws/things/Corebd_IOT_Sensor/shadow/update"
#define mqtt_sensor_commend_topic "corebd/sensor_control"
#define mqtt_sensor_status_topic "corebd/sensor_status"
아래의 변수를 추가한다.
byte stateState = LOW; // led state
char strOut[64]; // lcd print string
int soundVal = 0;
unsigned long prevMillis = 0;
다음 MQTT 메세지 콜벡 메서드를 아래와 같이 수정한다.
void msg_callback(char* src, int len) {
Serial.println("CALLBACK:");
int i;
for(i = 0; i < len; i++) {
Serial.print(src[i]);
}
byte* p = (byte*)malloc(len);
memcpy(p,src,len);
if (strstr((char*)p, "-1")) {
// 현재 상태에 대한 질의를 받았을 경우.
} else if (strstr((char*)p, "1")) {
stateState = HIGH;
digitalWrite(13, stateState);
} else if (strstr((char*)p, "0")) {
stateState = LOW;
digitalWrite(13,stateState);
}
sprintf(strOut,"{ \"id\":\"%s\" ,\"value\" : \"%d\" }",AWS_IOT_CLIENT_ID , stateState);
if((rc = myClient.publish(mqtt_sensor_status_topic, strOut, strlen(strOut), 1, false)) != 0) {
Serial.println("Publish failed!");
Serial.println(rc);
}
}
그리고 loop의 코드를 다음과 같이 변경한다.
void loop() {
if(success_connect) {
unsigned long currentMillis = millis();
int curSoundVal = analogRead(A3);
if (soundVal < curSoundVal) {
soundVal = curSoundVal;
}
if (currentMillis - prevMillis > 1000)
{
prevMillis = currentMillis;
sprintf(strOut,"{ \"id\":\"%s\", \"value\":\"%d\"}",AWS_IOT_CLIENT_ID , soundVal);
if((rc = myClient.publish(mqtt_sensor_value_topic, strOut, strlen(strOut), 1, false)) != 0) {
Serial.println("Publish failed!");
Serial.println(rc);
} else {
Serial.println(strOut);
}
soundVal=0;
}
if((rc = myClient.yield()) != 0) {
//Serial.println("Yield failed!");
//Serial.println(rc);
}
}
}
그리고
셋업에 아래의 문구를 추가하고
pinMode(13, OUTPUT);
pinMode(A3, INPUT);
myClient.subscribe(... ); 함수를 다음과 같이 변경한다.
myClient.subscribe(mqtt_sensor_commend_topic, 1, msg_callback))
이제 AWS IoT에 연결한 다음, MQTT Client에서 $aws/things/Corebd_IOT_Sensor/shadow/update 토픽을 구독하여 값이 계속 올라오는지를 확인한다. 그 다음 corebd/sensor_control 토픽에 1을 보내고, 0을 보내본다. 각각 LED가 켜지고 꺼져야 정상이다. corebd/sensor_status 토픽을 구독하고, corebd/sensor_control토픽에 -1,0,1을 보내서 corebd/sensor_status가 값을 받으면 정상이다.
이로서 윤보드의 AWS IoT 연결 작업은 일단 끝났다. 이제iPhone 작업을 하여 윤과 통신하게 하고, 각 기능들을 이용해여 간단한 센서 연동 프로그램을 만드는 작업이 남았으나, 포스팅은 여기까지로 하려고 한다.
긴 글 읽어주신 분들 감사합니다.