0%

Arduinoから大気圧センサーモジュールBMP180のデータをMeshbluにPOSTする

Docker上に構築したMeshbluへArduinoからセンシングデータを送信してみます。前回起動したコンテナではMongoDBを使わない設定なので、POSTしたデータはNeDBにJSONファイルとして保存されます。大気圧センサーモジュールはBMP180を使います。前回Intel Edisonでこのモジュールを使ったときはcylon-i2cmraaが使えず、bmp085パッケージを使いました。Arduinoの場合cylon-firmataが動作するようです。Cylon.jsを使ってセンシングデータを取得してMeshbluにデータをPOSTしてみます。

cylon-skynetが古い

Cylon.jsからMeshbluのAPIを使う場合、Skynetモジュールを使います。名前が古いようにdependenciesのパッケージも古くなっています。

clone

とりあえずリポジトリをcloneしてmasato/cylon-skynetしました。lib/adaptor.jspackage.jsonを修正します。

$ git diff HEAD^^
diff --git a/lib/adaptor.js b/lib/adaptor.js
index 4f8a361..18aecb9 100644
--- a/lib/adaptor.js
+++ b/lib/adaptor.js
@@ -8,7 +8,8 @@

"use strict";

-var Skynet = require("skynet"),
+//var Skynet = require("skynet"),
+var Skynet = require("meshblu"),
Cylon = require("cylon");

var Adaptor = module.exports = function Adaptor(opts) {
@@ -48,7 +49,8 @@ Adaptor.prototype.connect = function(callback) {
this.connector = Skynet.createConnection({
uuid: this.uuid,
token: this.token,
- host: this.host,
+ //host: this.host,
+ server: this.host,
port: this.portNumber,
forceNew: this.forceNew
});
@@ -102,3 +104,7 @@ Adaptor.prototype.message = function(data) {
Adaptor.prototype.subscribe = function(data) {
return this.connector.subscribe(data);
};
+
+Adaptor.prototype.data = function(data,fn) {
+ return this.connector.data(data,fn);
+};
diff --git a/package.json b/package.json
index d076c05..6c0a386 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,6 @@

"dependencies": {
"cylon": "~0.22.0",
- "skynet": "latest"
+ "meshblu": "latest"
}
}

Node.jsプログラムのデバイス/サービス登録

MeshbluではIoTプラットフォームにつながる、人、モノ、サービスをすべてUUIDとTOKENで管理します。そのため操作する人も、コネクテッドデバイスも、連携するWebサービスも対等にUUIDとTOKENを発行する必要があります。今回はOSXのNode.jsプログラムをサービスとして登録します。MESHBLU_URLはTLS/SSL通信するMeshbluサーバーです。オレオレ証明書を使っているので--insecureフラグが必要です。

$ export MESHBLU_URL=https://{Meshbluのドメイン名}:4443
$ curl -X POST \
-d "name=iot-http" \
--insecure \
"$MESHBLU_URL/devices"
{"uuid":"xxx","online":false,"timestamp":"2015-03-23T03:46:19.254Z","name":"mqtt-osx","type":"host","ipAddress":"172.17.42.1","token":"xxx"}

BMP180のサンプル

プロジェクトを作成します。

$ mkdir -p ~/node_apps/firmata-bmp180-meshblu/
$ cd !$

package.jsonのcylon-skynetはcloneして修正したリポジトリを指定します。

~/node_apps/firmata-bmp180-meshblu/package.json
{
"name": "firmata-bmp180-meshblu",
"version": "0.0.1",
"private": true,
"dependencies": {
"cylon-firmata": "0.19.0",
"cylon-skynet": "masato/cylon-skynet"
},
"scripts": {"start": "node app.js"}
}

app.js

Arduinoのデバイスファイルは、MacBook Proの右側のUSBポートにを挿したので/dev/tty.usbmodem1421になりました。hostuuidtokenはそれぞれ上記のデバイス登録で取得した値を使います。

~/node_apps/firmata-bmp180-meshblu/app.js
"use strict";
var Cylon = require("cylon");
var host = "wss://{Meshbluのドメイン名}";
var portNumber = 4443;
var uuid = "{Node.jsプログラムのUUID}}";
var token = "{Node.jsプログラムのTOKEN}}";
Cylon.robot({
connections: {
arduino: { adaptor: "firmata", port: "/dev/tty.usbmodem1421" },
skynet: { adaptor: 'skynet',
host: host,
portNumber: portNumber,
uuid: uuid,
token: token}
},
devices: {
yellow: { driver: 'led', pin: 13, connection: 'arduino' },
bmp180: { driver: "bmp180" }
},
work: function(my) {
my.skynet.on("message", function(data) {
console.log('data: ' + JSON.stringify(data));
if(data.payload.yellow === "on") {
my.yellow.turnOn();
} else if(data.payload.yellow === "off") {
my.yellow.turnOff();
}
});

every((5).seconds(), function() {
my.bmp180.getAltitude(1, null, function(err, val) {
if (err) {
console.log(err);
return;
}
my.skynet.data({
"temperature": val.temp,
"pressure": val.press,
"altitude": val.alt
},function(data){
console.log(data);
});
});
});
}
}).start();

connectionsディレクティブにはArduinoとMeshblu(Skynet)の2つを定義します。devicesにはMeshbluからメッセージをsubscribeしてLチカするLEDと、大気圧センサーモジュールのBMP180を定義します。Arduinoがonのメッセージを受信するとLEDが点灯し、offで消灯します。BMP180からは5秒間隔でセンシングします。温度(temperature)、大気圧(pressure)、標高(altitude)のデータをJSON形式にフォーマットして、Meshbluに送ります。

サンプルの起動

Node.jsのサンプルプログラムを起動します。my.skynet.data()のコールバックで実装している標準出力が表示されます。

$ nvm use 0.10
Now using node v0.10.37
$ npm start
...
{ timestamp: '2015-03-23T06:33:15.610Z',
temperature: '28.6',
pressure: '100153',
altitude: '98.03716036353367' }
{ timestamp: '2015-03-23T06:33:20.615Z',
temperature: '28.6',
pressure: '100146',
altitude: '98.62549086806833' }
{ timestamp: '2015-03-23T06:33:25.619Z',
temperature: '28.6',
pressure: '100150',
altitude: '98.2892979312604' }

Meshblu側のデータベース

今回のMeshbluの構成ではMongoDBの利用をコメントアウトしているので、センシングデータはNode.jsの組み込みデータベースのNeDBにJSONファイルとして保存されました。

Meshbluコンテナを動かしているDockerホストにログインして、ボリュームにアタッチしている作業ディレクトリに移動します。

$ cd ~docker_apps/meshblu-dev

センシングデータはdata.dbファイルに生のJSONとして保存されています。

$ tail data.db
{"timestamp":"2015-03-23T06:33:15.610Z","temperature":"28.6","pressure":"100153","altitude":"98.03716036353367","_id":"krDon5OH6Frs17ic"}
{"timestamp":"2015-03-23T06:33:20.615Z","temperature":"28.6","pressure":"100146","altitude":"98.62549086806833","_id":"JGdcd8c4ycXXlKEk"}
{"timestamp":"2015-03-23T06:33:25.619Z","temperature":"28.6","pressure":"100150","altitude":"98.2892979312604","_id":"lMj4o7MaYB3RmLrW"}

Pub/Subのテスト

次はメッセージのPub/Subのテストをします。テストに使う環境変数を作成します。

$ export MESHBLU_URL=https://{Meshbluのドメイン名}:4443
$ export PUB_DEV_UUID={Node.jsプログラムのUUID}
$ export PUB_DEV_TOKEN={Node.jsプログラムのTOKEN}

--headerには認証情報としてNode.jsプログラムのUUID/TOKENを指定します。送信データのdevicesキーに、メッセージ送信先デバイスのUUIDを指定します。今回は認証UUIDと送信先UUIDが同じなので自分自身にメッセージを送るサンプルになります。payloadキーにはデバイスに送信するメッセージの本文をJSON形式で指定します。onをデバイスが受信するとLEDを点灯(my.yellow.turnOn();)します。

$ curl --insecure -X POST  \
"$MESHBLU_URL/messages" \
-d '{"devices": ["'"$PUB_DEV_UUID"'"], "payload": {"yellow":"on"}}' \
--header "meshblu_auth_uuid: $PUB_DEV_UUID" \
--header "meshblu_auth_token: $PUB_DEV_TOKEN"
{"devices":["xxx"],"payload":{"yellow":"on"}}

offのメッセージを受信するとLEDを消灯(my.yellow.turnOff();)します。

$ curl --insecure -X POST  \
"$MESHBLU_URL/messages" \
-d '{"devices": ["'"$PUB_DEV_UUID"'"], "payload": {"yellow":"off"}}' \
--header "meshblu_auth_uuid: $PUB_DEV_UUID" \
--header "meshblu_auth_token: $PUB_DEV_TOKEN"
{"devices":["xxx"],"payload":{"yellow":"off"}}