この記事は
Treasure Data Advent Calendar 2015 の 15日目です。
前々日の記事:
Jupyter から見た Treasure Data の使い方
前日の記事:
翌日の記事:
6月に開催された LinuxCon 2015 Tokyo で Treasure Data のエンジニアが
Fluent-bit を紹介していました。 Fluent-bit とは、 Fluentd のデザインを継承した、組み込み用途向けの情報収集ツールだそうです。
ただ、その時点では利用できる Input プラグインが限られており、そのノードのシステム情報などの取得が中心でした。 XBee 対応もモック状態でしたので、適当にいじって動くようにしてみました。今回は in_xbee がどんな感じに動くかを紹介します。いま Fluent-bit で実現できるすべての入力を紹介します。
1. Fluent-bit + XBee でできること
Fluent-bit は、 Treasure Data 社が作っている、組み込み Linux 向けの IOT データコレクタで、各種センサからの値を取り込むためのツールです。取り込んだデータは、 Fluentd へ送信したり、もしくは Treasure Data 社のサービスへ送り蓄積できます。インプット/アウトプットのモジュールはプラグイン型となっているため、新たなインプットやアウトプットに対応することも可能です。以下は
Fluent-bit プレゼンテーション で示されている概要です。
XBee は Digi International 社による無線モジュールで、 ZigBee (802.15.3) や WiFi(802.11) など様々なタイプのものがあります。特に、 ZigBee 規格はセンサネットワークを構築する用途に向いています。Fluent-bit から XBee を実際に扱えるような
Pull Request をマージしてもらいました ので、いまだと XBee をデータソースとして使えます。
XBee にはいくつかの種類がありますが、どのモデルでも下記の入力が扱えます。
デジタル/アナログ信号を一定間隔、もしくは変化があったときに送信
接続されたコンピュータ(マイコンやPC)からのシリアル通信内容により送信
今回は、 Fluent-bit と XBee を使ってデータを収集するしくみを作る例、マイコン(Arduino)からFluent-bitにデータを送信する方法を紹介したいと考えています。
2. Raspberry Pi 2 で Fluent-bit を動かす
XBee との連携について説明する前に、 Raspberry Pi 2 上の Raspbian で Fluent-bit を動かすための最低限の方法について説明したいと思います。
Fluent-bit を GitHub からクローンしてきます。本記事の公開時点では最もあたらしいリリースである v0.5.1 がよいでしょう(私は maser を使いました)。 Fluent-bit をコンパイルするには下記の要領で作業します。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ git clone git@github.com:fluent/fluent-bit.git
$ cd fluent-bit/build/
$ cmake -DWITH_IN_XBEE=1 ..
$ make -j8
コンパイルが成功したら下記の要領で動作確認が可能です。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hasegaw@raspberrypi2:~/advent/fluent-bit/build$ bin/fluent-bit -i mem -o stdout
Fluent-Bit v0.5.1
Copyright (C) Treasure Data
[2015/12/15 16:24:30] [ info] starting engine
[0] [1450164271, {"total"=>949408, "free"=>803420}]
[1] [1450164272, {"total"=>949408, "free"=>803428}]
[2] [1450164273, {"total"=>949408, "free"=>803428}]
[3] [1450164274, {"total"=>949408, "free"=>803428}]
^Chasegaw@raspberrypi2:~/advent/fluent-bit/build$
または、下記要領で Fluentd へのログ送信も確認できます。 Fluentd へは "fluent_bit" タグで送信されますので、 Fluentd の設定を済ませておいてください。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ bin/fluent-bit -i mem -o fluentd://127.0.0.1:24224/
3. はじめての XBee
では、 Fluent-bit で XBee を使って情報を集約するために必要なモジュール、部品を揃えていきたいと思います。今回は秋月電子で揃えられる部品で実装しますが、同等品などでも構いません。
今回はXBee Series 2 モデルを 2 台準備しました。
備考:
XBee用シリアルインターフェイスは利用前にハンダ付け作業が必要です。
XBee用シリアルインターフェイスは最低1個あれば本記事の作業を行えますが、初めてXBeeを扱う場合など、疎通を確認する段階で2個あると便利です。
本稿執筆時に使用したXBeeモジュールはSeries 2、もしくはXBeeZBと呼ばれるモデルですが、XBee Series 1, XBee WiFiなども(たいして変更なく)利用可能と思われます。
相互通信のためには同じシリーズを利用する必要があります。たとえばXBee S1とXBee WiFi, またXBee S2の間は相互通信できません。
XBeeのアンテナタイプには外付け、アンテナ付きタイプ、PCBアンテナ(基板に内蔵)タイプがあります。アンテナ付き、もしくはPCB対応がよいでしょう。
エンドポイント側 XBee の設定
エンドポイント(センサデバイス)側として使用する XBee モジュールを USB インターフェイスボードに装着し、 USB ケーブルで作業用 PC に接続します。設定は XCTU と呼ばれるツールを使用します。 XCTU は Digi International 社のサイトから入手してください。紹介するスクリーンショットは OS X 版のものです。
XCTU Software - Product Detail - Digi International
http://www.digi.com/support/productdetail?pid=3352
XCTU で XBee モジュールに End Device API のファームウェアをロードし、下記設定値をプログラムします。
コーディネータ側 XBee の設定
同様に、コーディネータ(Raspberry Pi 2)側として使用する XBee モジュールも、先と同じ要領で設定を行います。こちらのファームウェアは Choordinator API のファームウェアをロードし、下記の設定値をプログラムします。
この時点でエンドポイント用 XBee の電源がオンであれば、5秒毎にデータが送られてきているはずです。ターミナルのアイコンでコーディネータ側 XBee のシリアルポートに接続すると、エンドポイント側から送られてきた IO Data Sample RX Indicator というパケットが見えるはずです。
エンドポイント側からのパケットが届いていることが確認できたら、XCTUを終了し、 USB ケーブルを抜きます。
4. Fluent-bit とコーディネータ側 XBee の接続
コーディネータ用XBeeをRaspberry Pi 2に接続します。 USB ケーブルで Raspberry Pi 2 に接続すると、 /dev/ttyUSB0 もしくは相当のデバイス名で認識されるはずです。 FTDI の USB Serial ドライバがないとダメですのでカーネルモジュールを削ってしまっている場合はビルドしてロードしてください。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hasegaw@raspberrypi2:~/advent/fluent-bit/build$ ls -l /dev/ttyUSB*
crw-rw---T 1 root dialout 188, 0 Dec 15 17:34 /dev/ttyUSB0
Fluent-bit 設定ファイルの作成
設定ファイル xbee.conf を作成します。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[xbee]
File /dev/ttyUSB0
Baudrate 9600
XBeeMode XBeeZB
# XBeeLogLevel 100
※ XBeeLogLevel を設定した場合は、 XBee の通信に関する細かなログが表示されるようになりますので、うまく動作しない場合にはコメントアウトを解除して試してみてください。
Fluent-bit の起動と XBee パケット 受信確認
Fluent-bit を起動し、実際に XBee のパケットが拾えるか確認してみます。特に設定をしない限り、/dev/ttyUSB0 は root:dialout の権限になっていますので、 sudo を使って root 権限で動作させます(お使いのユーザを dialout グループに所属させてもよいでしょう)。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ sudo bin/fluent-bit -c ~/xbee.conf -i xbee -o stdout
起動後、XBee エンドポイント側からの定期送信パケットが表示されれば、ここまでは OK です。もしうまく表示されない場合は、 XBeeLogLevel のコメントアウトを解除して、 XBee の受信処理などのメッセージが出力されるか等から、表示がされない原因を切り分けます。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hasegaw@raspberrypi2:~/advent/fluent-bit/build$ sudo bin/fluent-bit -c xbee.conf -i xbee -o stdout
Fluent-Bit v0.5.1
Copyright (C) Treasure Data
[2015/12/15 17:37:12] [ info] starting engine
[2015/12/15 17:37:12] [ info] XBee device=/dev/ttyUSB0, baudrate=9600
[0] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>0, "DIO10"=>0}]
[1] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>1, "DIO10"=>0}]
[2] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>1, "DIO10"=>1}]
[3] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>1, "DIO10"=>0}]
[4] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>1, "DIO10"=>1}]
[5] [1450168640, {"src_addr"=>"0013a200406256dc", "DIO5"=>1, "DIO10"=>0}]
^Chasegaw@raspberrypi2:~/advent/fluent-bit/build$
エンドポイント側 XBee からデジタル信号を入力する
GND ピンと DIO1 ピンをショートさせる "DIO1" として 0 が送られてきます。 DIO1 ピンに 3.3V かけると 1 が送られてきます。たとえば、以下のようなデータが Fluent-bit に出力されます。5秒おきのポーリング結果に加えて、ピン状態が変化したタイミングに特定ピンへのデータが届いているためこのような表示になります。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[2015/12/15 18:24:55] [ info] starting engine
[2015/12/15 18:24:55] [ info] XBee device=/dev/ttyUSB0, baudrate=9600
[0] [1450171498, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171503, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171508, {"src_addr"=>"0013a200406256dc", "DIO1"=>0}] ※DIO1が0に変化
[1] [1450171508, {"src_addr"=>"0013a200406256dc", "DIO1"=>0, "AD0"=>1023}]
[2] [1450171509, {"src_addr"=>"0013a200406256dc", "DIO1"=>0, "AD0"=>1023}]
[0] [1450171514, {"src_addr"=>"0013a200406256dc", "DIO1"=>0, "AD0"=>1023}]
[0] [1450171519, {"src_addr"=>"0013a200406256dc", "DIO1"=>0, "AD0"=>1023}]
[0] [1450171523, {"src_addr"=>"0013a200406256dc", "DIO1"=>1}] ※DIO1が1に変化
[0] [1450171529, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171535, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171540, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171546, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
実際にはドアのスイッチを接続したりすることになるでしょう。たとえばトイレ個室のドア開閉状況を Fluentd で収集し Kibana などに投げてやればトイレのビジー率などをグラフ化できるでしょう。
エンドポイント側 XBee からアナログ信号を入力する
次にアナログピンの実験をしてみましょう。 XBee には、 0V 〜 3.3V の範囲で、どれぐらいの電圧がアナログピンにかかっているかを検出する ADC 機能があります。アナログタイプの照度センサなどのデバイスを使えば、状態を電圧として XBee のアナログピンに入力することができます。
3.3V 端子と AD0 端子を繋ぎ、 Fluent-bit の出力をみると AD0 が 1023 になっています。逆に、 GND 端子を AD0 端子に繋いでみます。すると、今度は AD0 が 0 に近い値になります。 AD0 に 3.3V をあらためてかけると、また AD0 の値が 1023 に戻ります。 実際には日照センサなどを接続することになるでしょう。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[0] [1450171834, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171840, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171845, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171851, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171856, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171861, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171867, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>0}]
[1] [1450171867, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>0}]
[0] [1450171872, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>0}]
[0] [1450171877, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>0}]
[0] [1450171883, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>0}]
[0] [1450171893, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171898, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171904, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171909, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171915, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
[0] [1450171920, {"src_addr"=>"0013a200406256dc", "DIO1"=>1, "AD0"=>1023}]
入力したデータの取り扱い
Fluent-bitでデータが入力できたら、 Fluentd によって Treasure Data Serivce 、もしくは Fluentd を介してお好きなミドルウェアに集約することができます。
5. XBee meets MCU
ここまでは、 XBee 自体の機能だけを使い、デジタル/アナログピンの状態をを収集しました。しかし、実際には、センサを動かすためにマイコンが必要であったり、またはセンサからの入力値を送信する過程でマイコンで処理をしなければならない場合も多いでしょう。今回は、そのような状況を想定し、 Arduino を使って情報を収集し、 XBee モジュールを介して Fluent-bit に送信するセンサノードを試作してみます。
今回使用する Arduino Duemilanove は 2010 年頃に流通していたモデルで現在は見かけませんが、現在の Arduino UNO R3 相当品だとお考えください。
in_xbee プラグインが受け取れる MessagePack フォーマット
in_xbee プラグインは、以下の形式で MessagePack でシリアライズされたペイロードを受け取れます。
[ time, { key => val, ... } ]
{ key => val, ... }
タイムスタンプがついていない MessagePack ペイロードの場合 Fluent-bit が受信した時刻がそのペイロードの時刻となります。センサノードやマイコンには、現在の時間を扱うリアルタイムクロック(RTC)が搭載されていないこともしばしばです。時刻が分からないノードの場合は Fluent-bit 側でタイムスタンプを付加させることができます。
サンプルの概要
Arduino と XBee 、そして温湿度センサを使って、 MessagePack でシリアライズしたデータを送信し、 Fluent-bit で受け取るサンプルを作ってみます。
Arduino は I2C バスを介して温度センサ AM2320 から温度、湿度情報を読み取ります。
Arudino は 温度、湿度情報を MessagePack でシリアライズします。
Arudino はシリアライズしたデータを XBee でブロードキャストします。
Fluent-bit で先の MessagePack を受信します。
Arduino から I2C デバイスを制御するには wire という標準ライブラリがありますが、 AM2320 をコントロールするには不十分だったため
SoftI2CMaster と呼ばれる別のライブラリを利用しています。取り込んだ値は下記構造で MessagePack でシリアライズします。
{ "degC" => 23.0f, "humidity" => 40.0f }
ワンチップマイコンでは 16bit どころか 8bit アーキテクチャのものも多数あり、またモノによっては POSIX どころか malloc() すら標準提供されていないものも多くあります。また、マイコンによっては浮動小数点フォーマットが IEEE754 ではないとかの機種依存事項もあります。このため msgpack-c のようなライブラリを MCU で使うには、いくらかハードルがあります。
このような環境を想定した MessagePack 実装として、ワンチップマイコン向けの
msgpack-mcu を試作しました。 msgpack-mcu は GNU C コンパイラやマイコン向けのベンダ製コンパイラでなんとなくコンパイルでき、各種マイコンで利用できることを想定しており、別に性能もコードもすごくありませんのであしからず。
MessagePack でシリアライズされたデータは XBee を介してコーディネータに送信します。今回は Aruduino スケッチは XBee の API モードでデータをブロードキャストする最低限の実装となっています。
Arduino への XBee, 温度センサの取り付け
Arduino と温湿度センサ、XBeeをArduinoに接続していきましょう。ブレットボードを使えば、半田付け作業なしで回路の試作が可能です。今回はブレットボード上に温湿度センサとXBeeを載せます。下記の要領で SDA/SCL を AM2320 へ、 Arduino の TX を XBee の TX に接続します。
Arduino は 5V でデジタル信号を扱いますが、 XBee は 3.3V のデジタル信号を扱います。 XBee に Arduino の信号をそのまま入力すると死んでしまいますので、5V ←→ 3.3V のレベル変換が必要です。今回は Arduino (5V) → XBee (3.3V) ですのでレベル変換 IC などは使わずに抵抗を利用した分圧で済ませます。 5V を 3V に落とすため、抵抗の比率を1:2にします。
スケッチをArduinoへアップロード
以下に AM2320 から I2C で値を読み出して MessagePack でシリアライズし、 XBee API を使ってブロードキャストするサンプルを示します(SoftI2CMasterおよびmsgpack-mcuが必要です)。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* in_xbee plugin for fluent-bit
* End-point device implementation example
* =======================================
* Copyright (C) 2015 Takeshi HASEGAWA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* You need to copy both of umsgpack.[ch] into this directory before
* open and run this sketch. umsgpack.[ch] files are in MessagePack for MCU
* (msgpack-mcu) distribution.
* https://github.com/hasegaw/msgpack-mcu
*
* XBee2 module should be properly configured with API mode. This sketch
* assumes serial tx pin is connected to XBee2 module. You may need to
* convert voltage level between Arduino (5V) and XBee (3.3V).
*/
#define XBEE_SERIAL_SPEED 9600
extern "C" {
#include "umsgpack.h"
}
#define SDA_PORT PORTC // SDA (I2C Data)に使用するI/Oポート
#define SDA_PIN 4 //
#define SCL_PORT PORTC // SCL (I2C Clock)に使用するI/Oポート
#define SCL_PIN 5 //
#define I2C_TIMEOUT 10 // I2Cのスレーブの応答タイムアウト時間(ms)
#include "SoftI2CMaster.h"
#define AM2320_ADDRESS 0xb8 // AM2320のI2Cアドレス
float temp;
float humidity;
char buf[100]; // sprintf用バッファ。 出力文字数に注意
void Serial_write(unsigned char i) {
#if 1
Serial.write(i);
#else
// Send in human-readable ascii code
char hex_buf[10];
snprintf(hex_buf, sizeof(hex_buf), "0x%2.2x, ", i & 0xFF);
Serial.print(hex_buf);
#endif
}
void xbee2_tx_broadcast(struct umsgpack_packer_buf *buf) {
unsigned char checksum = 0xFF;
unsigned char write_cmd[14] = { 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00 };
int i;
int xbee_payload_len = sizeof(write_cmd) + umsgpack_get_length(buf);
Serial_write((unsigned char) 0x7E);
Serial_write((unsigned char) xbee_payload_len >> 8);
Serial_write((unsigned char) xbee_payload_len & 0xFF);
for (i = 0; i < sizeof(write_cmd); i++) {
Serial_write(write_cmd[i] & 0xFF);
checksum -= write_cmd[i] & 0xFF;
}
for (i = 0; i < (buf->pos); i++) {
Serial_write(buf->data[i] & 0xFF);
checksum -= buf->data[i] & 0xFF;
}
Serial_write(checksum & 0xFF);
}
int am2320_start() {
char cmd[3] = { 0x03, 0x00, 0x04 }; // I2Cで送信すべきコマンド
if (! i2c_start(AM2320_ADDRESS | I2C_WRITE)) {
/* スレーブアドレスを送信してもセンサが応答しなかった */
delay(1);
goto error;
}
/* コマンドを送信する。センサがACKを返さなかったらエラー処理 */
for (int i = 0; i < sizeof(cmd); i++)
if (! i2c_write(cmd[i]))
goto error;
i2c_stop();
return 1; /* 成功 */
error:
i2c_stop();
return 0; /* 失敗 */
}
int am2320_read() {
char data[8];
/* 読み出し開始 */
if (! i2c_start(AM2320_ADDRESS | I2C_READ)) {
i2c_stop();
return 0; /* 失敗 */
}
/* 8バイトのデータを受け取る。最後のバイトの場合は True、
それ以外のバイトの場合は False を i2c_read() に渡す */
for (int i = 0; i < sizeof(data); i++)
data[i] = i2c_read(i == (sizeof(data) - 1));
i2c_stop();
/* ToDo: 本来なら受信したバイト列が正しいか CRC の確認をするべき */
/* 受信したデータを元に気温、湿度情報を求める */
temp = ((data[4] << 8) + data[5]) / 10;
humidity = ((data[2] << 8) + data[3]) / 10;
return 1; /* 成功 */
}
int am2320() {
/* AM2320 にコマンドを送信する。1度目がエラーになった場合は
センサのウォームアップ時間が必要なため、1ms おいてから再実行 */
int r = am2320_start();
if (! r) {
delay(1);
r = am2320_start();
}
if (! r)
return 0; /* コマンドが受け付けられなかったため断念 */
delay(16); /* センサの処理待ちのため 16 ミリ秒停止 */
/* 値の読み取りとデコード */
if (! am2320_read())
/* センサの値が読めなかった */
return 0;
return 1;
}
void setup() { /* 起動直後の設定(シリアルポート、I2C) */
delay(2000);
Serial.begin(XBEE_SERIAL_SPEED);
/* I2C通信に必要な配線がされていれば 1, そうでなければ 0 が出力される */
int r = i2c_init();
snprintf(buf, sizeof(buf), "{ \"i2c_init\", %d }", r);
Serial.println(buf);
}
void am2320_msgpack(struct umsgpack_packer_buf *buf) {
umsgpack_pack_map(buf, 2);
umsgpack_pack_str(buf, (char *) "degC", 4);
umsgpack_pack_float(buf, temp);
umsgpack_pack_str(buf, (char *) "humidity", 8);
umsgpack_pack_float(buf, humidity);
}
void loop() {
char mp_buf[100];
struct umsgpack_packer_buf *buf = (struct umsgpack_packer_buf*)&mp_buf;
if (am2320()) {
umsgpack_packer_init(buf, sizeof(mp_buf));
am2320_msgpack(buf);
xbee2_tx_broadcast(buf);
}
delay(2000);
}
このスケッチを Arduino にプログラムしてシリアルポートを見ていると、この配線をした状態であれば Arduino の起動から2秒後に { "i2c_init": 1 } という出力が見えるはずです。すべてがうまく行っていれば温度情報が数秒ごとに MessagePack over XBee API でブロードキャストされます。
Fluent-bitでの受け取り確認
先の Arduino から送られてきた MessagePack ペイロードが Fluent-bit の in_xbee に入力されると、次のようになります。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hasegaw@raspberrypi2:~/advent/fluent-bit/build$ sudo bin/fluent-bit -c xbee.conf -i xbee -o stdout
Fluent-Bit v0.5.1
Copyright (C) Treasure Data
[2015/12/15 18:49:42] [ info] starting engine
[2015/12/15 18:49:42] [ info] XBee device=/dev/ttyUSB0, baudrate=9600
[0] [1450172996, {"degC"=>31.000000, "humidity"=>18.000000}]
[0] [1450172998, {"degC"=>31.000000, "humidity"=>18.000000}]
[1] [1450173000, {"degC"=>31.000000, "humidity"=>18.000000}]
[0] [1450173002, {"degC"=>31.000000, "humidity"=>18.000000}]
[1] [1450173004, {"degC"=>31.000000, "humidity"=>18.000000}]
[2] [1450173006, {"degC"=>31.000000, "humidity"=>18.000000}]
[0] [1450173008, {"degC"=>31.000000, "humidity"=>18.000000}]
[1] [1450173010, {"degC"=>31.000000, "humidity"=>18.000000}]
[0] [1450173012, {"degC"=>31.000000, "humidity"=>17.000000}]
[1] [1450173014, {"degC"=>31.000000, "humidity"=>17.000000}]
[2] [1450173016, {"degC"=>31.000000, "humidity"=>17.000000}]
この表示が得られれば、 XBee を介して Fluent-bit が MessagePack のデータを受信できているはずです。あとは、お手元の Fluentd の Forward ポートへ転送してあげるだけです(もちろん Treasure Data Service に送るのもよいでしょう!)。
セキュリティ上の注意
今回の記事では、データの暗号化を行っていません。実際の利用にあたってはデータの暗号化、また XBee モジュールの無線出力の調整などが必要になるかと思われます。 XBee モジュールは AES による暗号化機能を搭載していますので活用してください。
(おまけ) TWE-Lite
参考までに、 XBee は無線モジュールであり、全モデルに共通して”しっかりしたマイコン”は付いていません。このため何かしようとするとすぐにマイコンを併用することになります。そうなると部品点数が増えますし配線も面倒です。
ここで TWE-Lite がちょっと便利です。モノワイヤレス(株)が販売する TWE-Lite は XBee の別メーカー版のようなかんじで、 ZigBee ベースでメッシュネットワーク ToCoNet が構成できる上に 32 ビットのマイコンも搭載されており、エンドポイントでちょっとしたプログラムを走らせるのに向きます。ZigBee と 32bit マイコンがワンパッケージに収まっていて 2000 円以下で入手できますので、安くセンサネットワークを作るにはアリだと思います。ちょっとした試作であれば
TWE-Lite DIP を使うとブレットボード上で作業できます。
当然 TWE-Lite は XBee の API をしゃべるわけではありません。そこで、わたしは個人的に、”ホストからみると TWE-Lite が XBee API を話すような”プログラムをコーディネータ相当の TWE-Lite に書き込んでいます。これを使うと Fluent-bit + in_xbee で ToCoStick (TWE-Lite + USB インターフェイス)が受信した ToCoNet のペイロードをあたかも XBee のネットワークで送られてきたかのように振る舞います。
一方、センサノード側の TWE-Lite DIP には先の msgpack-mcu などを組み合わせて温度センサなどから集めた情報を MessagePack にシリアライズし、 ToCoNet を介してコーディネータに送りつけるようプログラムしてあります。
上記2点のプログラムを組み合わせることで、少ない部品代と部品点数で XBee もどきノードを作り、データを収集して Fluentd + Kibana を動かしてみたのが下のスクリーンショットです。
6. まとめ
今回は Fluent-bit と XBee ネットワークを通じて情報を収集する方法を紹介しました。本記事を通じて、 Fluent-bit どのような事ができるのか、また Treasure Data Service もしくは Fluentd を使ったデータ集約にあたって、Fluent-bit をどのように活用できるのか、イメージを掴んでいただけたのではないかと思います。
Fluent-bitの登場により、Linuxが動作するコンピュータと、数千円で用意できるセンサノードを組み合わせて、(ほとんど)ソフトウェアを書かずにセンサーデータが集約できるようになりました。空間の環境情報、ドアの動きのモニタリングなど、皆さんのまわりで物理的な情報を集約する必要が出てきた場合には、 Fluent-bit の利用を検討してみてはいかがでしょうか。
この記事は
Treasure Data Advent Calendar 2015 の 15日目です。
前々日の記事:
Jupyter から見た Treasure Data の使い方
前日の記事:
翌日の記事: