안녕하세요,

"생각의 웹"입니다.


AllJoyn Framework (이하 올조인)은 퀄컴에서 개발한 P2P 기술을 오픈 소스로 공개 후 AllSeen Alliance (이하 올신) 주관으로 리눅스 재단의 프로젝트로 진행하는 만물 인터넷 (사물 인터넷보다 한단계 더 나아간 개념입니다만 저는 아직까지는 동의어 혹은 파생어로 봅니다.  ) 프레임 워크입니다.


이 기술을 공개된 지도 일 년이 지난 것으로 기억하는데 가장 최근인 올 해 7월 IFA 2014에서 공개한 데모에 대해 정리한 포스팅이 있어 올조인에 대해 아직 문외한인 분들은 읽어 보면 좋을 것 같아 링크 공유합니다.


퀄컴 올조인으로 물꼬튼 올신의 현재 (칫솔 - 초이의 IT 휴게실)  



올조인의 가장 긍정적인 면은 처음부터 누구나 소스 코드를 사용할 수 있도록 공개하고도 더불어 다양한 플랫폼 개발자들을 위해 여러 프로그래밍 언어의 API 문서와 프로그래밍 가이드를 잘 정리해 두었다는 점입니다.


튜토리얼: https://allseenalliance.org/alljoyn-framework-tutorial



오픈소스의 영향으로 인지는 모르겠지만 간단한 검색어를 통한 구글링으로도 꽤 많은 관련 포스팅이 눈에 띄는데 아래 '바쁜척쟁이 개발자의 블로그'에 기능 별로 잘 정리되어 있는 것 같아 살펴 보시길 추천합니다.


http://busydeveloper.tistory.com/category/Alljoyn



개인적으로 아쉬운 점이자 이 포스팅을 쓰게 된 동기는  official site의 가이드에는 JavaScript API가 준비되지 않았다는 점입니다.

개발 이력을 살펴 보니 NPAPI를 이용해 browser에서 사용 가능한 API를 만들려는 시도가 있었다가 실패한 듯 하고 (github에서 관련 프로젝트가 없어졌더군요.) 
대신 아래 경로처럼  node.js를 위한 npm 모듈이 존재하는 것을 확인했습니다.


https://github.com/octoblu/alljoyn


따라서, 현재 클라이언트의 주변에서는 올조인 기기들을 찾을 수 없겠지만 node.js를 탑재한 모바일 기기나 
클라이언트와 node.js 서버가 같은 네트워크 상에 있다는 가정 하에서는 Open API를 통해 기기 간 통신이 가능할 것으로 보입니다.


각론으로 들어가면 사실 올조인의 API는 P2P 개념이 부족한 분들에게는 조금 생소할 수도 있습니다.

하는 역할인 기기 간 통신에 비해 복잡해 보이기도 하고요. 

각 인터페이스들의 역할과 상호 작용의 개념을 명확히 이해하기 위해 먼저 위의 튜토리얼을 읽어 보실 것을 권합니다.

어느 정도 동작 방식에 대해 이해 하셨나요? 아래 코드는 위의 깃허브의 샘플 코드에서 유추해서 Web IDL 형태로 간단히 정리해 본 JavaScript API 입니다.

 


typedef DOMString AllJoynAppName; 

callback SignalMessageCallback = void (DOMString message, DOMString info);
[Constructor (DOMString appName)]
interface BusAttachment {

    void createInterface(AllJoynAppName name, InterfaceDescription description);

    void registerBusListener(BusListener listener);

    void start();

    void connect();

    void findAdvertisedName(AllJoynAppName name);

   void registerSignalHandler(BusObject bus, 
       SignalMessageCallback  smcb,
       InterfaceDescription description, 
       DOMString signalType);
};

[Constructor ()]
interface InterfaceDescription {

    void addSignal(DOMString target, 
        DOMString messageType,
        DOMString message);
};

callback FoundAdvertisedCallback = void (DOMString name);
callback LostAdvertisedCallback = void (DOMString name);
callback NameOwnerChangedCallback = void (DOMString name);

[Constructor (FoundAdvertisedCallback facb, 
    LostAdvertisedCallback lacb, 
    NameOwnerChangedCallback nocb)]
interface BusListener {
};

[Constructor (DOMString busName)]
interface BusObject {

    void addInterface(InterfaceDescription description);
};

callback AcceptSessionJoinerCallback = void (unsigned short port, AllJoynAppName joiner);
callback SessionJoinedCallback = void (unsigned short port, DOMString sessionId, AllJoynAppName joiner);

[Constructor (AcceptSessionJoinerCallback asjcb, SessionJoinedCallback sjcb)]
interface SessionPortListener {
};

문서화 수준과 지원하는 OS (유닉스 계열 - OS X, linux 만 지원)이 부족한 것으로 보아 아직 신뢰할 만한 수준이 아닌 것으로 보입니다.
즉 이 모듈을 사용할 때 각자가 해야 할 삽질이 정해져 있다는 것을 의미합니다. -_-;; 


어쨌든 올신에는 꽤 많은 기기 제작업체가 가입해 있고 슬슬 호환 기기들도 출시를 앞두고 있은 것 같아 기존 레거시 시스템들과 혹은 올신에 가입하지 않는 업체들의 기기와의 대화를 위해 인터프리터 역할을 할 노드가 필요하리라고 예측합니다.

추후 좀 더 구체화된 내용이 있으면 포스팅하도록 하겠습니다.


감사합니다.


행복한 하루 되시길! 

안녕하세요, 생각의 웹입니다.


이번에는 이전에 소개드린 바 있는 Node.JS에서 Arduino를 제어하는 JavaScript API 모듈인 duino에 온습도 센서인 dht11 를 제어할 수 있도록 기능 추가한 사례를 소개하려 합니다.

이를 위해서 먼저 duino github 소스 코드를 다운로드 받습니다.

duino 프로젝트를 git clone 하거나 다운로드 받아 압축을 풀면 examples, lib, node_modules, src 폴더와 index.js 파일 등이 있습니다.


1. arduino에 DHT11 센서 코드 추가하기

src 폴더에는 du.ino 파일이 존재합니다. 이 파일은 Arduino IDE의 프로젝트 파일로써 Arduino 보드에서 동작할 firmware 코드를 담고 있습니다.

Arduino IDE를 이용해 du.ino 파일을 열면 다음과 같은 코드로 구성되어 있습니다.


#include <servo.h>
bool debug = false;
 // ... omitted ...
void setup() {
  Serial.begin(115200);
}
void loop() {
  while(Serial.available() > 0) {
    char x = Serial.read();
    if (x == '!') index = 0;      // start
    else if (x == '.') process(); // end
    else messageBuffer[index++] = x;
  }
}
/*
 * Deal with a full message and determine function to call
 */
void process() {
  // ... omitted ...
 switch(cmdid) {
    case 0:  sm(pin,val);              break;
    case 1:  dw(pin,val);              break;
    case 2:  dr(pin,val);              break;
    case 3:  aw(pin,val);              break;
    case 4:  ar(pin,val);              break;

    case 97: handlePing(pin,val,aux);  break;
    case 98: handleServo(pin,val,aux); break;
    case 99: toggleDebug(val);         break;
    default:                           break;
  }
}
 // ... omitted ...


코드를 간략히 설명하면, Arduino controller는 setup() 함수 호출하여 serial port의 전송 속도를 지정 후 loop() 함수로 진입하여 메세지를 패칭(fetching)하여 특정 동작을 수행하게 됩니다. 이때 process() 함수 내 switch() 문으로 명령 ID를 구분해 적절한 이벤트 핸들러 (event handler) 가 호출되는 방식입니다.

따라서, 여기에 DHT11 센서에서 정보를 가져오는 명령 ID를 추가하고 이에 걸맞는 이벤트 핸들러를 추가하도록 하겠습니다. 명령 ID는 96으로, 관련 이벤트 핸들러는 handleDHT11(pin, val); 로 정의하겠습니다.


#include <servo.h>
// webofthink:For supporting DHT11 sensor
#include 
dht11 rht01;
// webofthink:end

bool debug = false;
 // ... omitted ...
}
/*
 * Deal with a full message and determine function to call
 */
void process() {
  // ... omitted ...
 switch(cmdid) {
    case 0:  sm(pin,val);              break;
    case 1:  dw(pin,val);              break;
    case 2:  dr(pin,val);              break;
    case 3:  aw(pin,val);              break;
    case 4:  ar(pin,val);              break;
    case 96: handleDHT11(pin, val);    break; /* webofthink:add DHT11 support */
    case 97: handlePing(pin,val,aux);  break;
    case 98: handleServo(pin,val,aux); break;
    case 99: toggleDebug(val);         break;
    default:                           break;
  }
}
 // ... omitted ...

/* Handle DHT11 Humidity & Temperature
 * @author webofthink
*/
void handleDHT11(char *pin, char *val) {
  int p = getPin(pin);
  int chk = rht01.read(p - A0); 
  char m[12];
  sprintf(m, "%s::%03d,%03d", pin, rht01.temperature, rht01.humidity);
  Serial.println(m);
}


DHT11 센서에서 값을 가져오는 로직은 DHT11이라는 라이브러리로 제공되기 때문에 다운로드 받으신 후 헤더 파일을 추가(include)해서 사용하시면 쉽게 코딩할 수 있습니다.

여기에 주의 깊게 봐둘 사항은 Node.JS 측으로 전송할 메세지 형태입니다. handleDHT11() 함수의 sprintf() 문의 두 번째 인자를 참고하기 바랍니다.


2. duino library 추가하기


이번에는 lib 폴더로 이동합니다. 여기에 보면 duino 프로젝트가 기 지원하는 센서 및 엑추에이터들의 API 모듈이 존재합니다.

여기에 DHT11 센서를 지원하기 위한 API 모듈인 dht11.js을 추가합니다.


    var events = require('events'),
    util = require('util');
/*
 * The main DHT11 constructor
 * Connect to the serial port and bind
 */
var DHT11 = function (options) {
    if (!options || !options.board || !options.pin) throw new Error('Must supply required options to DHT11 Sensor');
    this.board = options.board;
    this.pin = options.pin;
    // Loop and trigger fire-read sequences
    setInterval(function () {
        var msg = '96' + this.pin;
        this.board.write(msg);
    }.bind(this), options.throttle ||  500);
    // When data is received, parse inbound message
    // match pin to instance pin value
    this.board.on('data', function (message) {
        
        var m = message.slice(0, -1).split('::'),
            err = null,
            pin, data;
        if (!m.length) {
            return;
        }
        pin = m[0]
        data = m.length === 2 ? m[1] : null;
        if (pin == this.pin) {
            // console.log("emitting data to read event: " + data);
            var values = data.slice(0).split(',');
            this.temperature = parseInt(values[0]);
            this.humidity = parseInt(values[1]);
            this.emit('read', err, this.temperature, this.humidity);
        }
    }.bind(this));
 };
/*
 * EventEmitter, I choose you!
 */
util.inherits(DHT11, events.EventEmitter);
module.exports = DHT11;


이 API 모듈 소스의 구성은 다음과 같습니다. 먼저 DHT11 클래스와 생성자를 선언합니다. 생성자에서는 options 라는 객체를 인수로 받아 필요한 초기 환경을 설정합니다. 아두이노 보드와 센서가 연결된 핀 정보가 설정되었다면, Arduino 측에 DHT11 정보를 요청하는 메세지를 setInterval() 함수를 통해 정기적으로 전달합니다.

이 명령이 Arduino 보드에 전송되면 첫번째 항목에서 구현한 이벤트 핸들러 handleDHT11()가 호출되어 요청받은 온습도 정보를 Node.JS에 회신합니다.

그러면 Node.JS에서는 this.board.on()의 'data' 이벤트가 발생(trigger)하게 되면서 해당 정보를 가져올 수 있게 됩니다.

마지막으로 이 온습도 정보를 EventEmitter의 'read' 이벤트로 재 전송하도록 구현합니다.


3. duino API에 DHT11 추가하기


다시 root 폴더로 돌아가서 index.js를 열어 DHT11를 다음과 같이 추가합니다.


    
module.exports = {
  Board:  require('./lib/board'),
  Led:    require('./lib/led'),
  Piezo:  require('./lib/piezo'),
  Button: require('./lib/button'),
  Servo:  require('./lib/servo'),
  Sensor: require('./lib/sensor'),
  Ping:   require('./lib/ping'),
  PIR:    require('./lib/pir'),
  LCD: require('./lib/lcd'),
    DHT11: require('./lib/dht11') /* add to support DHT11 sensor */
};


이로써, duino에서 DHT11 API를 사용할 수 있게 되었습니다.


4. DHT11 API 예제


examples 폴더로 이동하면 제공하는 API 모듈 별 예제 코드가 있습니다. 여기에 이번에 추가한 DHT11 API의 예제도 추가해 봅시다.


    
/* following is a test code for DHT11 sensor. */
var arduino = require('duino');
          
console.log("Initializing arduino board...");
var board = new arduino.Board({
    device: 'COM6',
    debug: false
});
var dht11 = new arduino.DHT11({
    board: board,
    pin : 'A2'
});
board.on('ready', function () {
    console.log("arduino board is ready to serve.");
});
dht11.on('read', function (err, temp, humidity) {
    console.log("temperature: " + temp + " degree of Celcius, " + "humidity: " + humidity + "%");
});


예제를 보면 알 수 있듯이 Arduino 보드 객체와 알맞은 핀 정보를 options 객체의 속성으로 전달 후 on 함수의 'read' 이벤트 핸들러로 온습도 정보를 가져올 수 있습니다.


5. DHT11 API


지금까지 추가했던 DHT11 API의 Web IDL은 다음과 같습니다.


    enum DHT11EmitterType { "read"};

    dictionary DHT11Option {
        Board board;
        DOMString pin;
        unsigned short throttle; // time interval per each measurements
    };
     
    callback DHT11OnCallback = void (Error err, short temperature, unsigned short humidity);
    
    [Constructor, Constructor (DHT11Option option)]
    interface DHT11 {
        void on(DHT11EmitterType type, DHT11OnCallback cb); 
    };


지금까지 Node.JS를 통해 arduino의 센서를 제어하기 위해 필요한 단계를 정리해 보았습니다. duino에는 상당한 센서와 엑추에이터를 지원하는 API가 존재하나 이처럼 지원하지 않는 센서가 있을 경우에도 추가 구현이 용이하도록 구조화 되어 있습니다.

서두에 링크한 문서를 살펴보면 arduino board 에 ethernet이나 wi-fi 모듈을 추가하여 이런 센서 정보를 곧바로 웹으로 노출시키는 방법도 있습니다만 이렇게 Node.JS를 gateway로 두고 서비스를 확장하는 것이 context data를 지식화 하는데 유용한 구현 방법이라고 생각합니다.

긴 글 읽어 주셔서 감사합니다. 늘 행복하시길!

"생각의 웹"입니다.


Server side JavaScript platform인 Node.JS에서 사용할 유닛 테스트 프레임워크를 찾던 중 xUnit 계열인  nodeunit이 있어 이렇게 소개드리려고 합니다.

1. 설치

nodeunit은 https://github.com/caolan/nodeunit 에서 다운로드 받아 컴파일하거나 NPM을 통해 다운로드 받을 수 있습니다. 이때 node와 별개의 프로세스로 동작하기 때문에 -g 옵션을 주고 설치해야 합니다.

npm install nodeunit -g

설치가 완료되면 console 상에서 nodeunit 명령을 실행할 수 있습니다. 다음과 같이 수행하면 nodeunit의 사용법을 출력합니다.

nodeunit --help

2. 테스트 케이스란?


유닛 테스트 케이스(unit test case)는 테스트 대상 API (API under test), 테스트 조건(pre-condition and post-condition), 테스트 입력 값 (test input) 그리고 예상 출력 값 (expected output)으로 구성됩니다. 테스트 결과 판별 (assertion)은 보통 입력 값과 예상 출력 값이 같은 지를 비교하여 이뤄지며 그 결과를 취합하여 출력하게 됩니다.

3. 테스트 케이스 작성


다음은 가장 간단한 형태의 테스트 케이스 작성법입니다.


exports.testSomething = function(test){
    test.expect(1);
    test.ok(true, "this assertion should pass");
    test.done();
};

exports.testSomethingElse = function(test){
    test.ok(false, "this assertion should fail");
    test.done();
};


상기 예제를 보면 두 개의 테스트 케이스 (testSomething, testSomethingElse)가 존재하며, 결과 판별을 위해 test.ok()라는 API를 제공하고 있습니다.

이 API의 상세는 다음과 같습니다. 

interface Test {
   /**
    * Test if is a true value
    *
    */
    void ok(boolean value, optional DOMString message);
};


또한, 유심히 볼 필요가 있는 부분은 test.expect(1); 와 test.done(); 인데 이 API들은 JavaScript 특유의 비동기 동작(asynchronous operation)으로 인해 의도치 않은 결과가 나오는 것을 막기 위해 추가되었습니다.

좀 더 상세히 설명드리면, JavaScript는 콜백 함수(callback function)라는 형태로 요청한 동작의 결과를 되돌려 받는 경우가 많은데 이때 이 콜백 함수는 비동기적으로 호출되기 때문에 테스트 케이스를 잘못 작성하는 경우에는 호출되기 전에 테스트가 종료되는 경우가 종종 발생합니다.

이런 실수를 방지하기 위해서 nodeunit에서는 테스트가 끝나는 시점을 알려주는 test.done() API를 명시적으로 호출하도록 설계되었습니다.

또한, 테스트 케이스가 종료되기 전에 수행되어야 할 판별 (assertion)의 수를 test.expect(number) API로 호출하도록 해서 의도치 않는 결과 (false-positive)가 나오지 않도록 했습니다.

4. 보다 복잡한 테스트 케이스 작성


DB API와 같이 시간이 오래 걸리고 테스트 조건을 설정하는 데 많은 비용이 걸리는 경우를 위해 테스트 스윗(test suite)이라는 테스트 묶음을 위한 구조가 존재합니다.

테스트 스윗의 경우, 각 테스트 마다 선행 조건과 후행 조건이 실행될 수 있도록 setUp, tearDown 이라는 API를 제공합니다.

module.exports = {
    setUp: function (callback) {
        this.mysql = require('mysql');
        this.connection = this.mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: 'password',
            database: 'db'
        });
        this.connection.connect();
        callback();
    },
    tearDown: function (callback) {
        // clean up code here
        this.connection.end();
        callback();
    },

    testSqlWrite : function (test) {

        test.expect(1);
        this.connection.query('insert into tempData(tempDate, tempCelsius) values(?, ?)', [new Date(), 10],
            function (err, rows, cols) {
                if (err) {
                    test.ok(false, err);
                } else {
                    test.ok(true, rows);
                }
                test.done();
            });
    },

    testMysqlRead : function (test) {   
        test.expect(1);
        this.connection.query('select * from tempData',
            function (err, rows, cols) {
                if (err) {
                    test.ok(false, err);
                } else {
                    test.ok(true, rows);
                }            
                test.done();
            });
    }
};


상기 예제 코드는 Node.JS에서 MySQL를 사용할 수 있도록 mysql 모듈을 이용해 테스트 케이스를 작성한 것입니다.

이 코드를 수행하면, 1) setUp -> testMysqlWrite -> tearDown 2) setUp -> testMysqlRead 순으로 호출되게 됩니다. 코드 중 비 동기로 결과를 반환하는 API가 많음을 유념하시기 바랍니다.


이상으로 Node.JS 상에서 유닛 테스트 케이스를 작성하는 간단한 사용법을 소개드렸습니다. 코드를 작성하면서 테스트를 위해 작성했던 코드 뭉치 (code snippet)를 이와 같이 테스트 케이스로 작성하면 이후 변경 시 품질 관리 등에 유용하게 활용할 수 있습니다.


이상입니다. 감사합니다.  

안녕하세요. '생각의 웹'입니다.


한국의 테크 샵인 대디스랩 지원에 힘입어 빠르게 프로토타이핑한 '홈 센서 프레임워크'을 소개합니다.

'홈 센서 프로임워크'는 스마트 홈 환경에서 사용자에게 필요한 서비스를 발굴하기 위해 데이터를 모으고 데이터를 분석해 컨텍스트를 발굴하기 위한 JavaScript 개발 환경입니다. 


 상세한 내용은 아래 슬라이드를 참고하시기 바랍니다.



덧붙여 제가 생각하는 이 프레임워크가 가지는 장점은 다음과 같습니다.

    • 오픈 소스 하드웨어를 이용해 스마트 홈 관련 아이디어를 손쉽게 DIY 
    • 웹 월드의 일등 시민인 JavaScript 만으로 서비스 개발 가능
    • Open API (RESTful Web API)와 연동한 서비스 개발 가능
    • 사생활 침해의 우려가 있는 민감한 컨텍스트 정보를 클라우드가 아닌 댁 내에 저장
    • HTML5 기반 멀티 스크린 (N-Screen) 서비스 ready   

개발 관련해서 궁금한 점이나 아이디어 있으시면 댓글로 남겨주세요.


감사합니다.


덧글1. 

라즈베리 파이에서 MySQL 설치가 제대로 되지 않을 경우, 아래 링크를 참고하시기 바랍니다.

http://likeplex.com/Blog/Archives/92


덧글2. 

'밸브의 신' 덕분에 의도치 않게 이 슬라이드가 관심을 많이 받게 되었네요.

슬라이드를 보고 진행하시다가 막히는 부분을 댓글로 연락처와 함께 남겨주시면 A/S 해드리도록 하겠습니다. 







안녕하세요.


웹 API과 IoT의 만남을 주제로 블로깅을 시작한지도 꽤나 시간이 흐른것 같네요.

사실 의도하지는 않았지만 연구를 진행해가면 갈수록 더욱 재밌는 것들을 발견하게 되어 너무나 기쁩니다. 

이번 포스팅에서 소개하고자 하는 내용은 node.js에서 Arduino를 제어하는 API를 제공하는 duino입니다.  (여담입니다만 이 글을 Internet of Things 목록에 넣어야 할지 아니면 JavaScript API 목록에 넣어야 할지 한참 고민했네요. ;-) )


https://github.com/ecto/duino


자세한 소개가 링크에 나와 있기는 하지만 아래와 같이 한글로 번역해서 정리하니 참고하시기 바랍니다.

  1. 설치



  2. npm install duino
    

      상기 git hub의 ./src/du.ino 코드를 scatch 도구를 이용해 arduino에 flash

  3. LED 점멸 코드 예제

  4. var arduino = require('duino'),
        board = new arduino.Board({
         device: 'USB0'
    });
    
    var led = new arduino.Led({
      board: board,
      pin: 13
    });
    
    led.blink();
    
      라즈베리파이와 아두이노 연결 시 /dev/ttyUSB0를 통해 serial 통신하게 되어 device attribute에 USB0라고 입력
      MS Windows / MAC 계열에서는 아래 파일로 node_modules/duino/lib/board.js를 대체한 뒤 device 명으로 시리얼 포트가 연결된 COM포트 명 입력 ex) COM4

    board.js




  5. API Signatures (using Web IDL)

  6. // duino uses arduino namespace by default.
    
    enum EmitterType { "data", "connected", "ready" };
    enum Mode {"in", "out"};
    
    dictionary BoardOption {
        DOMString device;
        boolean debug;
    };
    
    dictionary LEDOption {
        Board board;
        DOMString pin = '13';
    };
    
    callback BoardOnCallback = void (optional DOMString msg);
    callback BoardSerialCallback = void (DOMString msg);
    
    [Constructor, Constructor (BoardOption option)]
    interface Board {
    
        const DOMString LOW = '000';
        const DOMString HIGH = '255';  
        void on(EmitterType type, BoardOnCallback cb); 
        void serial(BoardSerialCallback cb);
        void write(DOMString msg);
        void pinMode(DOMString  pin, Mode mode);
        void digitalRead(DOMString pin);
        void digitalWrite(DOMString pin, DOMString val);
        void analogRead(DOMString pin);
        void analogWrite(DOMString pin,DOMString val);
        void delay(unsigned short ms);    
    };
    
    [Constructor, Constructor (LEDOption option)]
    interface LED {
    
        void on();
        void off();
        void blink(unsigned short interval = 1000);
        void fade(unsigned short interval = 2000);
        unsigned short bright();
    };
    
    interface LCD {
      // TODO: See the details at the original link
    };
    
    interface Piezo {
      // TODO: See the details at the original link
    };
    
    interface Button {
      // TODO: See the details at the original link
    };
    
    interface Ping {
      // TODO: See the details at the original link
    };
    
    interface Servo {
      // TODO: See the details at the original link
    };
    
    

    Web IDL에 관한 문법은 http://www.w3.org/TR/WebIDL/ 를 참고하시기 바랍니다.


    API를 사용하는데 도움이 되시기 바랍니다.

    감사합니다. ;-)


+ Recent posts