안녕하세요, 생각의 웹입니다.
이번에는 이전에 소개드린 바 있는 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 #includedht11 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를 지식화 하는데 유용한 구현 방법이라고 생각합니다.
긴 글 읽어 주셔서 감사합니다. 늘 행복하시길!
'Web of Humans > JavaScript_API' 카테고리의 다른 글
duino module로 RedBoard 온도센서 구현하기 (0) | 2014.11.04 |
---|---|
AllJoyn JavaScript API for node.js (0) | 2014.11.04 |
Node.JS Unit Test Framework - nodeunit (0) | 2014.09.05 |
Web IDL로 JavaScript API 설계하기 - 속성과 메소드 정의 (0) | 2014.08.20 |
Web IDL로 JavaScript API 설계하기 - 객체 정의와 생성 (0) | 2014.08.14 |