Aug 18, 2014

[IBM IoT Foundation Bootcamp @Korea] 6. Node-RED Flow Design

[Hands-on Lab]
Bluemix 상에서 Node-RED UI를 구동하고 Node-RED를 활용하여 Galileo 보드에서 수집하여 보내는 CPU 온도 값만 추출하여 출력하는 flow를 만들어 보자.

Step 1. "2. Device Recipe"에서 실습한 과정을 반복하여 Galileo 보드가 IoT Cloud에 접속하고 CPU 온도 측정값을 송신하게 한다.

Step 2. "4. IBM PaaS -- Bluemix"에서 실습한 과정을 반복하여 IoT application이 정상적으로 running하게 한다.

Step 3. 아래 예시처럼 dashboard에서 "Routes:" 이후에 있는 hyperlink를 클릭하거나 web browser의 주소창에 직접 <app-name>.mybluemix.net을 입력한다.

Step 4. Node-RED의 welcome page에서 "Go to your Node-RED flow editor" 버튼을 클릭하여 바로 flow editor 화면으로 이동한다.
Welcome Page
Flow Editor
Step 5. Node-RED의 flow editor 화면에서 가장 먼저 작업할 것은 Galileo 보드에서 보내는 데이터를 수신할 수 있는 인스턴스를 하나 생성해 보는 것이다. 아래 예시의 순서를 따라 작업해보도록 하자.
1) "inputs" 카테고리에서 mqtt 수신 노드를 선택하여 Sheet로 drag-and-drop
2) mqtt 수신 노드를 더블클릭하면 아래 그림과 같이 속성 편집 팝업이 뜨는데 여기에서 해당 topic을 입력하고 -- topic 설정 방법은 "3. MQTT Based Messaging" 참조 -- broker 연결 설정 정보 편집을 위해 버튼을 실행
Topic  설정
3) MQTT Broker 연결을 위한 설정 정보까지 입력하고 우측 상단 Deploy 버튼 실행
  • Broker - <org-id>.messaging.internetofthings.ibmcloud.com
  • Port - 1883
  • Client ID - a:<org-id>:<device-id>
  • Username - API Key의 key 파트
  • Password - API Key의 auth-token 파트
Broker 설정
4)  선택된 mqtt 수신 노드의 상태를 확인하기 위하여 "Node Status" 클릭
Node Status 확인 활성화
5) IoT Cloud에 연결 상태 정보 확인 (green: connected)
Connected 상태 확인

Step 6. mqtt 수신 노드의 output은 JSON String 형태이므로 JSON Object로 변경해 주어야 논리적 조작이 가능하다. 이를 위하여 mqtt 수신 노드에 json 변환 노드를 연결하도록 하자.


Step 7. 이제 JSON Object 형태로 데이터가 변환되었으니 CPU 온도값에 액세스하여 그 값만 추출할 수 있게 되었다. 이러한 논리적인 조작은 function 노드를 이용하여 가능하다. 아래 예시를 참조하여 구현해 보자.


Step 8. 마지막으로 값을 출력하기 위하여 debug 노드를 이용한다. 디버그 데이터 출력은 Node-RED flow editor에 있는 debug 탭과 server console 상에 가능하며 여기서는 debug 탭만 선택하여 출력해 보기로 한다.

Deploy 버튼을 실행하면 debug 탭에 CPU 온도 값만 출력되는 것을 확인할 수 있을 것이다.


[Hands-on Lab]
Galileo 보드가 주기적으로 수집하여 보내는 CPU 온도가 특정 값이하이면 송신중단 명령 처리를 하는 Node-RED flow를 구현해 보자.
Step 1. 앞의 Hands-on Lab에서 작성한 flow에서 mqtt 수신 노드와 json 변환 노드는 재사용하되 mqtt 수신 노드의 Client ID만 아래와 같이 변경한다.
  • Client ID - a:<org-id>:<device-id>:evt
  • 위와 같이 변경하는 이유는 동일한 MQTT broker에 mqtt 수신 노드와 송신 노드를 모두 연결하여 양방향 메시징이 되게 하려면 각 노드의 Client ID를 다르게 하여 식별 가능하게 해야 하기 때문이다. 



Step 2. 이제 특정 온도이하이면 상태정보 전송을 중단하라는 명령 메시지를 만드는 기능을 구현해 보자. 여기서는 CPU 온도가 67도이하이면 상태보고를 중단하도록 하였다. "3. MQTT Based Messaging"에서 같이 살펴 보았듯이 Galileo에서 command를 수신하면 payload에 포함된 JSON 객체에 "send-status" 프로퍼티가 포함되어 있는지 확인하여 그 값이 true일 경우는 상태정보를 보내고 false일 때는 상태 정보 송신을 중단하도록 구현되어 있다. 이에 착안하여 CPU 온도가 67도 이하임을 detect하면 바로 "send-status" 프로퍼티를 false로 설정한 메시지를 다음 단계로 넘기는 로직을 작성한다.


Step 3. 앞 단계에서 작성한 function 노드의 output은 2개로 설정하였고 그 중 하나는 debug 탭에 Galileo로부터 수신한 데이터를 출력하게 한다.

Step 4. 나머지 하나의 output은 mqtt 송신 노드에 연결하여 해당 온도 조건을 만족하면 Galileo로 MQTT publish하게 한다. Step 1에서 강조하였듯이 Client ID를 mqtt 수신 노드와 다르게 설정하여함에 유의한다. 나머지는 mqtt 수신 노드와 동일하게 설정한다.
  • Client ID - a:<org-id>:<device-id>:cmd



Step 5. Command 송신을 위한 topic을 다음과 같이 설정한다.
  • iot-2/type/<type-id>/id/<device-id>/cmd/<cmd-id>/fmt/json


Step 6. 완성된 flow는 아래 그림과 같으며, Deploy를 실행한다. 성공적으로 deploy되고 나면 설정에서 "Node Status"를 체크하여 mqtt 수신/송신 노드의 connection 상태를 확인한다.
Deploy 이전
Deploy 완료 후 Node Status 체크

Step 7. 터미널 상에서 SSH로 Galileo에 접속하여 ibm-iot-quickstart를 실행시킨다. Console log 정보를 보면 CPU 온도가 71도에서 시작하였는데 팬을 이용하여 강제로 CPU 외부 온도를 낮추어 주었고 이로 인하여 CPU 온도가 점차 내려갔음을 확인할 수 있다. CPU 온도가 66도가 된 순간 IoT Cloud로부터 stop command를 수신하였고 Galileo가 해당 command를 정상적으로 수행함으로써 주기적으로(1초 단위로 주기 설정) 송신하던 것을 중단하였음을 확인할 수 있다.


Step 8. Node-RED 상의 debug 탭 결과도 확인해보니 66도로 온도가 낮추어진 이후에 MQTT 메시지 수신도 중단되었음을 확인할 수 있다.

[IBM IoT Foundation Bootcamp @Korea] 5. Visual Tool for Wiring the IoT -- Node-RED

Flow-based Programming
Node-RED는 Flow-based Programming 개념을 따르는 전형적인 개발 방법론을 제시하고 있다. 주요 특징은 다음과 같다.
  • Node-RED Node라는 Things와 Logic의 단위를 만들고 이를 message passing 방식의 Node 간의 연결을 flow라는 형태로 2차 저작이 가능한 구조: Flow Library를 통한 industry scenario를 반영한 2차 저작물의 공유, 생산성 향상
  • Web Browser 방식의 UI를 통한 event flow 설계 지원
  • Edge-of-Network 환경과 Cloud 환경에서 실행하기에 적합한 light-weight runtime
User Interface
사용자 인테페이스는 아래와 같이 6개의 핵심 컴포넌트로 구성되어 있으며, 직관적이며 단순한 화면 구조이다.


1. Node palette
2. Canvas
3. Info Tab
4. Debug Tab
5. Deploy
6. Options Menu

Function Nodes
Function 노드는 JavaScript로 작성된 임의의 로직을 수행할 수 있게 한다. JavaScript의 function scope을 이용하여 모듈화하는 개발 방법론을 기반으로 하고 있다.
  • Input: msg라는 이름을 가진 JSON 객체
    • 일반적으로 msg는 payload라는 property를 갖고, 이는 message body에 해당
    • msg가 topic이라는 property를 갖는 경우도 있다.
  • Output
    • Single output인 경우는 단일 JSON 객체를 return하는 것이 일반적이나 복수 개의 JSON 객체로 구성된 배열을 return하는 경우는 배열에 포함된 객체들을 순차적으로 return한다.
    • Multiple output인 경우는 output 수에 대응하는 JSON 객체들로 구성된 배열을 return한다.
    • 조건에 따라 더이상 진행하지 않고 중단해야 하는 경우는 null을 return한다. 
    • 요약 정리하면 output은 최대 2차원 배열 형태로 구성할 수 있으며, multiple output port에 각 port는 순차적으로 복수 개의 메시지를 송출할 수 있다.
  • (Function Local) Context
    • context라는 이름을 가진 JSON 객체에 access 가능하며, 이는 JavaScript의 closure 방식으로 관리되는 객체로서 Node-RED가 실행되는 동안 유지된다. 
    • Flow 구조 상 동일 function 노드를 반복적으로 visit하는 상황에서 context를 이용하여 처음 visit할 때부터 마지막 visit할 때까지 계속 변화 추적하는 상태 변수들을 관리할 수 있다.
  • Global Context
    • 앞에서 설명한 context는 하나의 function 노드가 단일 Node-RED lifetime 동안 reference 가능한 것이지만, 여기서 설명하는 global context는 Node-RED의 canvas 내에 있는 모든 function 노드들이 공통으로 reference 가능한 context 객체이다.
    • 이러한 Global Context는 setting.js 파일의 functionGlobalContext라는 property에 정의함으로써 Node-RED가 시작할 때 바로 load되어 access 가능하게 된다. 
* Function 노드 관련 추가 상세 정보는 여기를 참조

Custom Nodes
Node-RED 노드는 Node-RED가 시작할 때 setting.js 파일의 nodesDir이라는 property에 정의된 directory 아래 혹은 디폴트로는 "nodes"라는 directory 아래에 위치한 노드 구성 파일들을 읽어서 palette에 등록되는 방식으로 관리된다.
따라서, Node-RED 노드 구성 파일 구조에 맞추어 개별적으로 작성하여 "nodes"라는 directory에 갖다 놓음으로써 손쉽게 Custom Node를 만들어 사용할 수 있다.

이제 Custom Node를 만들기 위해 구성 파일들을 만드는 방법에 대하여 알아 보자. Node-RED 노드는 런타임 상의 로직을 포함한 JavaScript 파일과 노드의 UI 구성 정보를 포함한 HTML 파일로 구성된다.

JavaScript 파일
JavaScript constructor pattern을 활용하여 new로 새로운 instance를 생성할 수 있게하는 구조로 설계되어 있다. "use strict"를 통해 내부에 구현된 코드에 대해 ECMAScript 5 기준을 엄격하게 적용하여 검사한다. (이는 권장사항이지만 필수는 아니다.)

module.exports = function(RED) {
    'use strict';
}

인자로 받는 RED는 Node-RED 인스턴스를 의미하는 객체이다. 여기에 각 개별 노드들을 관리하는 모듈을 reference하고 있는 nodes라는 property가 포함되어 있다. 본 Custom Node가 가질 기능은 특정 JavaScript constructor function 안에 구현해서 RED.nodes.registerType(typeName, constructorFunctionName)을 이용하여 등록한다.

module.exports = function (RED) {
    'use strict';
    
    function CustomNode(config) {
        
    }
    
    RED.nodes.registerType('custom', CustomNode);
};

CustomNode라는 이름을 갖는 constructor function 내부에 제일 먼저 추가해야 할 로직은 실제 인스턴스를 생성하는 것이다. this context에 config라는 이름으로 받은 JSON 객체에 정의된 설정 정보를 이용해서 인스턴스를 생성한다.

module.exports = function (RED) {
    'use strict';
    
    function CustomNode(config) {
        RED.nodes.createNode(this, config);
    }
    
    RED.nodes.registerType('custom', CustomNode);
}; 

Node-RED 노드에 발생하는 대표적인 두가지 이벤트는 노드로 메시지가 수신되는 경우(여기서는 'input'이라 이벤트 명을 설정)와 새로운 flow가 deploy되거나 Node-RED를 종료할 때 이를 알리는 'close' 이벤트가 발생하는 경우가 있다. 이를 위하여 이벤트 발생시 수행될 callback을 작성하여 등록하는 작업이 필요하다. 'input' 이벤트 처리하는 callback에서 기능 수행 코드를 작성하고 기능 수행이 완료된 시점에서 send()를 이용하여 flow 상 다음 노드로 메시지를 보내도록 한다. 앞에서 언급한 모든 것을 반영한 JavaScript 파일의 코드 템플릿은 다음과 같다.

module.exports = function (RED) {
    'use strict';
    
    function CustomNode(config) {
        RED.nodes.createNode(this, config);
        
        this.on('input', function (msg) {
            var newMsg;
            
            this.send(newMsg);
        });
        
        this.on('close', function () {
        
        });
    }
    
    RED.nodes.registerType('custom', CustomNode);
};

Logging을 위하여 this.log(logMsg), this.warn(warnMsg), this.error(errorMsg)를 사용할 수 있다. 이중 warn(), error()는 Node-RED가 running하고 있는 환경의 console, log 파일에 출력될 뿐만 아니라 editor의 debug 탭에도 출력된다.

HTML 파일
HTML 파일에는 노드가 editor 상에서 어떻게 보여져야 하는지를 정의한다. 이는 아래의 3개 파트로 구성되어 있다.
1) Edit Dialog 파트: 종방향으로 입력 필드 배열
  • 입력 필드 각각은 <div>로 wrapping하고 이것의 class는 "form-row"
  • 문자열 혹은 숫자값 입력: <input type = "text">
  • Boolean 선택: <input type="checkbox">
  • 다중 선택: <select>
  • Label과 같이 출력되는 아이콘은 <i>를 이용해서 출력하며 Font Awesome의 아이콘을 사용


<script type="text/x-red" data-template-name="inject">
    <div class="form-row">
        <label for="node-input-payloadType"><i class="icon-envelope"></i> Payload</label>
        <select id="node-input-payloadType" style="width:125px !important">
          <option value="date">timestamp</option>
          <option value="none">blank</option>
          <option value="string">string</option>
        </select>
    </div>
    <!-- partly omitted -->
    <div class="form-row">
        <label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
        <input type="text" id="node-input-topic" placeholder="topic">
    </div>
    <!-- partly omitted -->
    <div class="form-row" id="node-once">
        <label>&nbsp;</label>
        <input type="checkbox" id="node-input-once" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-once" style="width: 70%;">Fire once at start ?</label>
    </div>
    <!-- partly omitted -->
</script>

2) Help Text 파트: 아래 예시와 같이 노드를 선택하였을 때 도움말이 Info 탭에 출력되게 하는 기능을 구현하며, <p>를 이용하여 description 작성


<script type="text/x-red" data-help-name="inject">
    <p>Pressing the button on the left side of the node allows a message on a topic to be injected into the flow. This is mainly for test purposes.</p>
    <p>If no payload is specified the payload is set to the current time in millisecs since 1970. This allows subsequent functions to perform time based actions.</p>
    <p>The repeat function does what it says on the tin and continuously sends the payload every x seconds.</p>
    <p>The Fire once at start option actually waits 50mS before firing to give other nodes a chance to instantiate properly.</p>
    <p><b>Note: </b>"Interval between times" and "at a specific time" will use cron. This means that 20 mins will be at the next hour, 20 mins past and 40 mins past - not in 20 minutes time.
    If you want every 20 mins from now - use the basic "interval" option.</p>
</script>

3) 노드 정의 파트
JavaScript 파일에서와 동일한 RED.nodes.registerType()을 이용하여 등록을 진행한다.

<script type="text/javascript">
    RED.nodes.registerType('inject',{
        category: ,
        defaults: ,
        inputs: ,
        outputs: ,
        icon: ,
        color: ,
        label: ,
        labelStyle: ,
        align: ,
        oneditprepare: function () { },
        oneditsave: function () { }
    });
</script>

[IBM IoT Foundation Bootcamp @Korea] 4. IBM PaaS -- Bluemix

Cloud Service Models


  • IBM Infrastructure as a Service (IaaS) -- SoftLayer
    • Computing, Storage, Networking의 자원을 통합하여 가상화
    • OpenStack 기반
  • IBM Platform as a Service (PaaS) -- Bluemix
    • Cloud Operating Environment 상에서 세분화된 단위 서비스를 재조합하여 새로운 기능 및 서비스를 생성 (Composable Environment 개념)
    • CloudFoundry 기반

Bluemix Architecture
Bluemix는 IBM Softlayer를 기저의 IaaS로 가져가면서 Cloud Foundry의 application 개발 구조를 기반으로 설계되었다. 따라서, Bluemix 상에서 개발한 application을 deploy할 때 application을 SoftLayer의 virtual container에 넣어서 deploy한다는 것이다.

Buildpacks
  • 타겟하는 PaaS 상에서 개발자가 작성한 application code가 실행될 수 있게 설정정보 및 명령들을 포함한 스크립트 컬렉션
  • Application의 framework, runtime에 대한 dependency
  • Bluemix의 기본 built-in buildpack은 LibertyNode.js

Application Runtimes


Services


[Hands-on Lab]
IBM Bluemix 상에 IoT Application 개발 환경을 설정해 보자.

Step 1. IBM Bluemix 사이트에 계정등록하고 로그인한다.

Step 2. Bluemix는 개발 팀 구성의 Organization과 작업공간의 Space를 설정하고 application을 개발하도록 요구하고 있다. 디폴트로는 로그인 계정명으로 Organization이 설정되어 있고 "dev"라는 명칭의 Space가 설정되어 있다. 아래를 참조하여 본인이 원하는 구조로 Organization과 Space를 설정해 보자.
* IoT Cloud에도 Organization을 설정하고 device를 그에 바인드하게 했던 것을 기억할 것이다. Organization이라는 동일한 명칭과 개념을 사용하고 있지만 IoT Cloud와 Bluemix 각각에 설정하는 Organization은 상호 독립적인 것이라는 점에 유의하자.  IoT Cloud는 device로부터 수집한 데이터를 공유하는 사용자 그룹을 의미하는 반면에 Bluemix는 IoT application을 공동 개발한다고 할 때 개발자 그룹을 의미한다.
Organization 관리 메뉴
Space 관리 메뉴
Step 3. 주메뉴 중에서 "CATALOG"를 선택하면 다양한 Runtime, Service, Boilerplate들의 리스트를 볼 수 있다. 이중에서 "Internet of Things Starter"를 선택하자.


Step 4. 다음 화면에서 "Create an app:" 아래 내용을 입력하고 "CREATE" 실행한다.

  • Space: Step 2에서 정의한 Space로 선택
  • Name: Application name 지정
  • Host: Application이 Bluemix 상에서 Running할 때 액세스 가능한 URL의 host name 설정 (변경하지 않으면 application name과 동일하게 설정됨) 



Step 5. 아래 예시와 같이dashboard 상에서 IoT Starter 기능이 탑재된 Node.js runtime이 정상적으로 구동되는지 확인한다.
Overview
Runtime
Files and Logs
Step 6. Bluemix는 앞에서 확인한 것과 같은 web dashboard 방식뿐만 아니라 command line interface(CLI) 방식의 admin 기능을 제공하며, CLI의 설치는 여기를 참조하여 수행한다. CLI로 Bluemix에 로그인하여 IoT application이 Node.js 상에서 구동되면서 출력하는 로그를 확인할 수 있는 방법에 대하여 알아 보자. 주요 명령어는 다음과 같다.

  • cf login
  • cf logs <app-name>
  • cf logout

[IBM IoT Foundation Bootcamp @Korea] 3. MQTT Based Messaging

MQ Telemetry Transport (MQTT)
IoT Cloud가 제공하는 Device Connectivity는 MQTT 3.1.1을 표준 규격을 따르고 있다. MQTT는 기본적으로 아래 다이어그램에서 도식화한 Publish/Subscribe(PubSub) 방식의 메시징 규격이다.



Topic
  • Device로부터 data를 수신하기 위한 subscribe topic 형식은 다음과 같다.
    • iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>
  • IoT Cloud에 connect된 device로 command를 보내기 위한 publish topic 형식은 다음과 같다.
    • iot-2/type/<type-id>/id/<device-id>/cmd/<command-id>/fmt/<format-id>
  • Device가 IoT Cloud에 connect되었는지 disconnect되었는지 IoT Cloud의 system level에서 관리하고 이를 service application에서 알 수 있도록 publish하고 있다. 이에 subscribe하기 위한 topic 형식은 다음과 같다.
    • iot-2/type/<type-id>/id/<device-id>/mon
  • iot-2라는 topic의 root context 명 이후는 /key/value/ 형태의 key-value pair (KVP) 반복 구조로 정의한다.
  • KVP 구조에서 value에 해당하는 <type-id>, <device-id>, <event-id>, <command-id>, <format-id>는 최대 길이 제한 32의 문자열이어야 하며, 문자열 구성은 영문 대소문자, 숫자, '_', '-', '.'의 3개 기호 문자가 허용된다.
    • <type-id>: Device type을 정의하는 것으로 예를 들어 Galileo device는 'iotsample-galileo', Raspberry Pi는 'iotsample-raspberrypi'로 정의한다.
    • <device-id>: 각 device의 고유 MAC 주소값을 사용하며, ':'를 제외한 hex code값을 공백없이 붙이고 hex code값 중 영문 알파벳 해당값은 소문자로 맞추어 주어야 한다.
    • <event-id>: event code 명을 정의할 때 사용하며, 대표적인 것으로 'status'가 있다.
    • <command-id>: command code 명을 정의할 때 사용하며, 대표적인 것으로 'reboot', 'start', 'stop' 등이 있다.
    • <format-id>: IBM IoT Cloud는 송수신 데이터의 포맷으로 원칙적으로 다양한 형태를 지원하지만 JSON 사용을 권장하고 있다. 따라서, 대부분의 경우 'json'으로 정의하여 사용한다.
  • Value 문자열 대신 all을 의미하는 wildcard 문자로 대치할 수 있으며, '+'가 이를 위하여 reserve되어 있다.
  • /type/<type-id>/id/<device-id>를 생략한 축약형도 사용 가능하다. 예를 들어 모든 event를 subscribe하여 수신하고자 하는 경우에 'iot2/evt/+/fmt/json'로 topic을 설정할 수 있다.

Client ID
  • [Naming Convention] Broker에 연결하려는 client가 device인 경우는 'd:'를 Bluemix application인 경우는 'a:'를 사용한다.
  • Client ID는 MQTT connection 간에 중복 공유되지 않도록 신경써야 한다. 만일 두 MQTT connection이 동일한 Client ID를 사용한다면 시간 상으로 앞에 만들어진 connection이 그 뒤에 만들어지는 connection과 Client ID가 동일하다는 이유로 connection이 강제로 끊어지게 된다.

MQTT Transport Port Number
  • Internet Assigned Numbers Authority(IANA)에 의해 TCP 포트번호 1883이 MQTT 용도로 포트번호 8883이 MQTT over SSL/TLS 용도로 정의되어 있다. 

MQTT Client on the Galileo
  • Module dependency는 MQTT 프로토콜 처리를 위한 'mqtt', 로컬 파일 시스템 액세스를 위한 'fs'에 있다.
  • 설정 정보는 "device.cfg"의 디바이스 로컬 파일 형태로 관리한다.
  • Broker server의 URL은 디폴트 초기값으로 "quickstart.messaging.internetofthings.ibmcloud.com"를 사용하는데 이는 IoT Cloud에 등록하지 않은 디바이스에 대한 messaging test를 수행하는 Quickstart를 가정한 것이다.


  • Node.js의 'getmac' 모듈을 이용해서 디바이스의 MAC 주소를 읽은 후 ':'는 제거하고 hexa code 중 ABCDEF는 abcdef로 강제 변환한다.

  • Node.js의 'properties' 모듈을 이용해서 device.cfg에 정의되어 있는 "key:value" 형식의 설정값들을 읽어 들여 options 객체에 저장한다.
  • IoT Cloud에 디바이스 등록을 마치고 device.cfg에 "organization" property를 정의한 경우는 Broker server의 URL이 이에 맞게 변경된다.

  • Client ID는 device를 의미하는 'd'를 prefix로 사용하고 organization, device type, MAC address로 구성된 문자열을 사용함으로써 다른 ID와 겹치지 않게 유일성을 보장한다.
  • IoT Cloud로 publish하기 위한 topic은 "iot-2/evt/status/fmt/json"을 사용하고 1초 주기로 디바이스의 상태 정보를 수집하여 IoT Cloud로 송신한다.
  • 반대로 IOT Cloud에서 송신한 메시지를 수신하기 위하여 "iot-2/cmd/+/fmt/json"의 topic을 사용해서 subscribe한다.
  • IoT Cloud로부터 메시지를 수신할 때 디바이스의 MQTT Client Module에서는 "message" 이벤트가 발생한다. "message" 이벤트 처리 callback에서는 console에 log를 출력하고 수신한 메시지에 "send-status" property가 있는지 검사하여 그 값에 따라 주기적으로 상태 정보를 송신할 것인지 정보 송신을 중단할 것인지에 대한 action을 수행한다.


  • 앞에서 "iot-2/evt/status/fmt/json"을 이용해서 IoT Cloud로 주기적으로 메시지 송신하는 기능이 구현되어 있는데 메시지를 구성하는 것에 대한 것은 아래와 같이 "sys/class/thermal/thermal_zone0/temp" 파일을 읽어서 획득한 CPU 온도 값을 보내는 함수를 사용한다.


ibm-iot-quickstart.js를 실행하면 코드 내에 넣어 놓은 console.log()를 수행한 결과로 다음과 같은 정보를 확인할 수 있다.
  • protocolId: MQIsdp(MQ Integrator SCADA Device Protocol)
  • clean: true -- MQTT CleanSession flag


[IBM IoT Foundation Bootcamp @Korea] 2. Device Recipes (Intel Galileo)

Compatible Devices
현재 IBM IoT Cloud에 연결 가능하도록 지원하는 device는 다음과 같다.
* IBM에서 공식적으로 정리하여 공유하는 IoT Device Recipe는 여기를 참조
* 위에 리스트되어 있는 device 이외에 것도 여기에 정리되어 있는 가이드를 따라 IBM IoT Cloud에 연결 가능

[Hands-on Lab]
Intel Galileo를 IoT Cloud의 dashboard를 이용하여 등록하고 API key를 생성해 보자.


Step 1. 마이크로 SD 카드가 Galileo Customer Reference Board(CRB)에 탑재되어 있다면 분리하여 FAT 혹은 FAT32로 포맷한다.  Intel 공식지원 사이트로부터 SD Card Linux Image for Intel Galileo라고 명시된 압축파일을 다운로드받아 압축을 풀어서 마이크로 SD 카드로 복사한다.


Step 2. Galileo CRB를 아래 그림과 같이 마이크로 SD 카드 다시 탑재, 전원 연결, 유선 이더넷 케이블 연결, USB CLIENT라 명시되어 있는 마이크로 USB 포트에 USB 케이블을 연결하고 이를 개발 업무용 호스트 컴퓨터에 연결한다. 이때 마이크로 SD 슬롯 주변에 보면 CRB 상태 모니터링 가능한 LED가 있는데 초기화 단계에서 SD라 명시된 LED가 일정 시간 동안 깜박이는지 확인할 필요가 있다. SD 상태 LED가 깜박이지 않는다면 보드 초기화가 정상적으로 이루어지지 않았다는 것을 의미한다.


Step 3. Intel 공식지원 사이트로부터 Intel Galileo Arduino SW라 명시된 Galileo 전용 Arduino IDE를 다운로드받아 개발 업무용 호스트 컴퓨터에 설치하고 실행한다.

Step 4. IBM 사이트로부터 ibm-iot-quickstart.zip을 다운로드받아 압축을 푼 후 Arduino IDE 메뉴에서 File > Open을 실행하여 ibm-iot-quickstart/sketch/print_ipaddr/print_ipaddr.ino를 선택한다. 해당 파일이 정상적으로 import되면 아래 그림과 같이 되며, 여기서 File > Upload를 실행하여 바이너리를 Galileo에 올린다.
Tips:
- Upload 실행 전에 Tools > Board로 Intel Galileo가 선택되었는지, Tools > Serial Port로 USB 연결 포트가 정상적으로 선택되었는지 확인하는 것이 필요하다.
- Upload가 정상적으로 진행되지 않을 경우는 Firmware가 최신이 아님으로 인한 문제인지를 의심할 필요가 있다. 따라서, Galileo의 Firmware를 최신으로 맞추어 놓고 시작하는 것이 좋겠다. 이를 위해서는 먼저 전원 연결을 해제하고 마이크로 SD 카드도 슬롯에서 분리한다. 다시 전원을 연결한 후 Galileo 전용 Arduino IDE의 Help > Firmware Upgrade 메뉴를 수행하여 Firmware를 최신으로 업그레이드해 준다.

Step 5.  Tools > Serial Monitor를 실행하여 Galileo의 네트워크 연결 정보를 확인한다. 실행 결과 예시는 아래 그림과 같으며 'inet addr'에 표시되는 IP 주소를 읽어서 메모해 둔다. IP 주소 확인이 끝났으면 Arduino IDE를 종료한다.


Step 6. 개발용 호스트 컴퓨터에서 명령창 혹은 터미널을 열고 Step 4에서 다운로드받은 ibm-iot-quickstart.zip 파일을 아래 명령을 이용하여 Galileo CRB로 복사한다.
scp ./ibm-iot-quickstart.zip root@galileo_ip_addr:/tmp

Step 7. 개발용 호스트 컴퓨터에서 SSH를 이용하여 Galileo에 원격 접속을 수행한다.
ssh root@galileo_ip_addr

Step 8. Galileo 상에서 구동하는 application은 Node.js application 형태로 구현할 것이기 때문에 Node.js 설치가 필요하고, NTP를 이용하여 시간 설정을 할 것이기 때문에 해당 NTP관련 패키지를 설치해 보도록 하자. 설치 절차는 다음과 같다.

  • Galileo root directory로 이동: cd /
  • ibm-iot-quickstart.zip 압축해제: unzip /tmp/ibm-iot-quickstart.zip
  • cd ibm-iot-quickstart
  • 설치 명령을 배치 파일로 만든 setup.sh 실행: chmod +x setup.sh
  • ./setup.sh


Step 9. IBM IoT Cloud 사이트에 로그인한다. 로그인하면 DefaultOrg라는 organization이 선택된 상태로 dashboard 화면이 출력된다. 여기서 Devices 탭을 선택하면 "Add Device"라는 메뉴가 있다. 이를 선택하면 다음과 같은 device 등록 화면이 출력되는데 해당 device type을 선택하고 Device ID 필드에 MAC 주소를 입력한 후 Continue 버튼을 클릭한다.
다음 단계로 등록된 device의 등록정보를 확인할 수 있는데 이때 출력된 정보를 메모해 두어서 Step 10에서 활용할 수 있게 한다.

Step 10. 다시 Galileo에 SSH 접속한 터미널 화면으로 돌아와 ibm-iot-quickstart 디렉토리에 다음 예시와 같이 device.cfg 파일을 만들고 해당 device 정보를 입력한다.
vi device.cfg
Step 11. 아래 명령을 이용하여 Node.js 상에서 ibm-iot-quickstart application을 구동한다. (Application 종료시는 Control+C)
  • -v 옵션은 verbose 기능을 위한 것임
  • 위의 예시에서 확인할 수 있는 것처럼 MQTT 기반 메시징 기능을 제공하는 broker server의 URL은 <org-id>.messaging.internetofthings.ibmcloud.com
  • Auth Token 기반으로 인증정보(username, password)를 정확히 제시하여야 device가 publish하는 수집 정보에 대한 topic에 subscribe할 수 있음
Step 12. IBM IoT Cloud의 dashboard 화면으로 돌아오면 아래 예시처럼 device가 connected 상태임을 확인할 수 있다. (등록 해제를 하려면 "Remove Device" 메뉴를 이용)

 Step 13. API Keys 탭을 선택하면 API key 관리 화면으로 전환된다. 여기서 "Add API Key" 메뉴를 실행하면 다음과 같이 Key, Auth Token으로 구성된 API Key를 자동으로 생성하여 준다. 이 API Key는 IBM Bluemix에서 IoT Cloud의 API에 액세스할 때 필요한 것이므로 메모해 두어 필요할 때 참조할 수 있게 하자.
(생성된 API key를 삭제하고자 할 때는 Revoke 메뉴를 이용)

여기까지 성공적으로 모든 단계를 마쳤다면 IBM IoT Cloud에 등록되어 언제든지 연결가능한 Galileo 보드 하나를 갖게 된 것입니다.