温度センサーシミュレータのデータをIoT Platform経由でCloudantのsensorというDBに保管し、温度の値が40度を超えていた時にはalertというDBにも保管するという処理を、BluemixのサーバーレスであるCloud Functions(OpenWhisk)を使って構成します(以下、OpenWhiskと呼びます)。
構成概略はこんな感じです。sensor DBの更新処理はNode-REDで実装し、温度に応じてalertにも保管する処理をOpenWhiskのトリガーとアクションで実装します。
手順は次のとおりです。
- Cloudantを更新するNode-REDフローを作成する
- CloudantにFilterを作成する
- Cloud FunctionsのためのCLI環境を準備する
- Cloud Functionsのアクション、バインディング、トリガー、ルールを作成する
- センサーの温度を上昇させてalert DBのデータが増加することを確認する
1. Cloudantを更新するNode-REDフローを作成する
フローの完成形を以下に示します。フローデータも添付しておきます。
[{"id":"4c042e90.7d6608","type":"ibmiot in","z":"f5969270.b73f","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"b5f57846c141","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IBM IoT","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","qos":0,"x":90,"y":40,"wires":[["1e65aa7e.46adbe"]]},{"id":"5c421e96.e77248","type":"cloudant out","z":"f5969270.b73f","name":"","cloudant":"","database":"sensor","service":"nr-bmx01-cloudantNoSQLDB","payonly":true,"operation":"insert","x":450,"y":120,"wires":[]},{"id":"1e65aa7e.46adbe","type":"delay","z":"f5969270.b73f","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":260,"y":80,"wires":[["5c421e96.e77248"]]}]
各ノードの設定方法を説明しておきます。
1-1. IBM IoT入力ノード
温度センサーシミュレータ(https://quickstart.internetofthings.ibmcloud.com/iotsensor/) の右上のセンサーIDの値(ここではac4b21be7d61)を、IBM IoT入力ノードの「Device id」にコピペします。AuthenticationはQuickstart(デフォルト)です。他もデフォルトのままでOKです。設定したら右上の完了をクリックします。
1-2. Delayノード
中央のノードはdelayノードです。料金プランがLite(無料)のCloudantはスループットが1件/秒以下に制限されています。温度センサーシミュレータのデータ発生頻度が1秒なので、これにCloud Functionsの動作が加わると1件/秒を超えるため、温度センサーのデータをdelayノードで間引きます。上図の設定ではスループットを5秒に1件とし、間で発生したデータは削除することにしています。
1-3. Cloudantノード
Service名はデフォルトでOKです。Node-REDインスタンス作成時に一緒に作成されていたCloudantを使用します。Database名はsensorとしておきます。Only store msg.payload object? のチェックボックスにはチェックを入れておきます。
各ノードの設定が終了したら右上のデプロイをクリックして、フローの完成です。
Cloudantのダッシュボードを見ると、sensorというDBができて、文書件数が増加していることが確認できます。
動作が確認できたら、一旦はCloudantをフローから外しておいて下さい(無駄なデータ蓄積を防ぐため)。
2. CloudantにFilterを作成する
「温度が40度を超えたら」という判断は、CloudantのFilterを使って実装します。OpenWhiskのトリガーはCloudantの更新をきっかけにして呼ばれ、トリガーはFilterを利用してアクションを呼び出すかどうかを判断する、という仕組みです。
Filterの実体は以下のJSON文書です。よく見ると「40以下ならfalse,そうでなければtrue」という分岐ロジックが入っているのがわかります。
{
"_id": "_design/hightemp",
"filters": {
"over40": "function(doc, req){if (parseInt(doc.d.temp) <= 40){return false;} return true;}"
}
}
これをCloudantのsensor DBのDesign Documentsに登録します。CloudantダッシュボードのDB一覧から、「sensor」をクリックしてsendor DB内の文書一覧画面に入ります。
Design Documents横の「+」をクリックし、プルダウンメニューから「New Doc」を選択します。
ここにフィルターを記述します。初期値として{ "_id":"xxxxx..."}という値が入っていますが必要ありません。上記のフィルターのJSON文書をそのままコピペして上書きして下さい。
コピペしたらCreate Documentをクリックして保管します。
Design Documentsの下に「hightemp」という項目が現れるはずです。これでフィルターは完成です。
Cloudantのポータルを開いたついでに、温度が40度超の時の保管先DBのalertも作成しておきます。
Databasesの画面で「Create Database」をクリックします。
データベース名としてalertと入力し、Createをクリックします。
3. Cloud Functions(OpenWhisk)のためのCLI環境を準備する
OpenWhiskのトリガーやアクションの作成の操作は、CLI(コマンドライン・インターフェース)で実行することにします。BluemixにはOpenWhisk管理用のGUIも用意されているのですが、今回は触れません。
CLIインストール、セットアップの手順はBluemixのオンライン・マニュアルの記述に従います。
BluemixのCLIのプラグインとしてOpenWhiskのCLIが提供されているので、BluemixのCLIをインストールしていない場合は、まずそちらからインストールする手順から始めて下さい。
https://console.bluemix.net/docs/cli/reference/bluemix_cli/index.html#getting-started
続いてOpenWhiskのCLIをインストールします。手順は以下のリンク先を参考にして下さい。
https://console.bluemix.net/docs/openwhisk/bluemix_cli.html
OpenWhisk用プラグインをインストールするコマンドをいかに転記しておきます。
bx plugin install cloud-functions -r Bluemix
続いてBluemixにログインし、環境をセットアップします。
まずはログインします。以下の実行例を参考にして下さい。Email>には各自のBluemixアカウント登録したメールアドレス(=BluemixのユーザーID)を入力して下さい。
ログインしたら、次に「組織名」「スペース名」を登録します。これらはBluemixポータルから最初にログインした際に設定した値です。まだBluemixポータルにログインしたことがない場合は、先にポータルにログインして自分の「組織名」「スペース名」を設定してからこの手順を実行して下さい。以下に例を示します。引数「-o」の後ろが組織名、「-s」の後ろがスペース名です。
環境設定の最後に、OpenWhiskの動作確認をしておきます。動作確認用のアクションがありますので、CLIでそのアクションを呼び出します。{"message":"hello"}が返ってきたらOKです。
4. Cloud Functionsのアクション、バインディング、トリガー、ルールを作成する
4-1. アクションの作成
OpenWhiskで実行するプログラムはアクションとして実装します。今回は以下のJavaScriptコードをアクションとして使用します。
// Cloudant更新のトリガーを受けて、更新データを取得する
var Cloudant = require('cloudant');
var user="4217f8ad-efc9-4545-9442-8096cad73a00-bluemix";
var pass="2d388131558dfeebe0ef6eee82c80f6de9196c78cfe97858a084a987e9da81b7";
var host="4217f8ad-efc9-4545-9442-8096cad73a00-bluemix.cloudant.com";
var indb="sensor";
var outdb="alert";
function main(params) {
var cloudantUrl = "https://" + user + ":" + pass + "@" + host;
var cloudant = Cloudant({url:cloudantUrl});
var idb = cloudant.db.use(indb);
var odb = cloudant.db.use(outdb);
return new Promise(function(resolve, reject) {
idb.get(params.id, {revs_info:true}, function(err, ibody, header) {
if (err) {
reject("### Error:" + err);
}
else {
odb.insert({"d":ibody.d,"original_id":ibody._id}, function(err, obody, header) {
if (err) {
reject('??? Error = ' + err.message);
}
else {
resolve( obody );
}
});
}
});
});
}
コードはPC上にalert01.jsという名前で保管して下さい。名前は任意ですが、アクションを登録するコマンドでファイル名を指定する際に間違えないようにして下さい。
このコードの最初の方にあるuser,pass,hostの値はユーザー毎に異なるので、自分の値で修正して下さい。これらの値はBluemixのダッシュボードから確認できます。
まずhttps://bluemix.net でBluemixのダッシュボードを開き、サービスの一覧からCloudantのサービスインスタンスを選択(クリック)します。
Cloudantの管理画面が開いたら、左列タブを「サービス資格情報」に切り替え、「資格情報の表示」をクリックして展開します。表示されたJSON文書の中に"username","password","host"の値が含まれています。これらの値を使用します。
コードの準備ができたらアクションを登録します。以下のコマンドを実行します。
コマンドの引数のうち、alert01がアクション名、alert01.jsがアクションのコードのファイル名(先程PCに保管したもの)です。
bx wsk action create alert01 alert01.js
4-2. アクションの動作確認
トリガーからアクションを呼び出す際に、JSON文書形式のイベントがトリガーからアクションに渡されます。Cloudantの更新のトリガーの場合は次のような書式になっています。
{
"id": "6ca436c44074c4c2aa6a40c9a188b348",
"seq": "2-g1AAAAL9aJyV-GJCaEuqx4-BktQkYp_dmIfC",
"changes": [
{
"rev": "2-da3f80848a480379486fb4a2ad98fa16"
}
]
}
ここでidはCloudantの文書IDで、実際の文書内では"_id"という名前で存在しています。以下にsensor DBの文書の例を示します。
上記のイベントのidを実在の文書のIDで置き換えてアクションに渡してやることで、アクションの動作確認ができます。
アクションは、受け取ったIDでsensor DBを検索してヒットした文書を取得し、その文書をalert DBに保管するという仕組みになっています。テストがうまく行けば、先程作成した空のalert DBに文書がひとつ追加されるはずです。
まずは上記のイベントのJSON文書を、idの値を実在のIDで置き換えてPCに保管します。ファイル名はevent01.jsonと命名しておきます。
ファイルが準備できたら、次のコマンドでアクションを呼び出します。成功したら"ok":true を含むJSON文書がターミナルに返ってきます。
bx wsk action invoke --result alert01 --param-file event01.json
Cloudantも見てみましょう。空だったalert DBに文書がひとつできているはずです。以下は文書を開いた画面です。"original_id"のところに、event01.json内で指定したIDが入っています。
4-3. バインディングの作成
OpenWhiskのトリガーがCloudantにアクセスするために、まずCloudantのバインディングを作成します。コマンドは次のとおりです。
bx wsk package bind /whisk.system/cloudant Cloudant -p username 4217f8ad-efc9-4545-9442-8096cad73a00-bluemix -p password 2d388131558dfeebe0ef6eee82c80f6de9196c78cfe97858a084a987e9da81b7 -p host 4217f8ad-efc9-4545-9442-8096cad73a00-bluemix.cloudant.com
ここで-p username, -p password, -p hostの各引数の値は、アクションのコードの中で指定したuser,pass,hostの値と同じものを指定します。ユーザーによって異なりますので、コマンドの値を自分の環境の値に置き換えて実行して下さい。
上記コマンドの実行後、packageの一覧を取得するコマンドを実行してCloudantが表示されたらバインディングは成功です。以下に一覧取得コマンドと実行例を示します。
bx wsk package list
4-4. トリガーの作成
OpenWhiskで実行するプログラム(すなわちマイクロサービス)はアクションとして実装します。このアクション呼び出すきっかけとなる事象はトリガーとして登録します。
以下にトリガー登録コマンドのサンプルを示します。
bx wsk trigger create myCloudantTriggerOver40 --feed /bmx01_Dallas/Cloudant/changes --param dbname sensor --param filter "hightemp/over40"
各自で実行する際には以下の箇所を修正して下さい。
- myCloudantTriggerOver40 --- トリガー名です。任意の名前を指定して下さい。
- bmx01_Dallas --- 「組織名_スペース名」です。環境設定時にbx targetコマンドの引数で指定した値を指定して下さい。
- sensor --- 監視対象のCloudant DB名です。ここではこのままでOKです。
- hightemp/over40 --- フィルター名です。hightempというDesign Documentの中のover40というフィルターを使用するという定義です。ここではこのままでOKです。
4-5. ルールの作成
トリガーとアクションを結びつける定義として、ルールを作成します。以下のコマンドを実行します。
ここでmyRule01はルール名です。任意の名前を指定して下さい。
myCloudantTriggerOver40とalert01は、このルールで関連づけるトリガー名とアクション名です。トリガーおよびアクション作成時に命名した名前を指定して下さい。
bx wsk rule create myRule01 myCloudantTriggerOver40 alert01
以上でアクション、トリガー、ルールの作成は完了です。
作成したアクション、トリガー、ルールは、以下のコマンドで照会できます。
bx wsk list
5. センサーの温度を上昇させてalert DBのデータが増加することを確認する
以上でOpenWhiskの準備は整いましたので、Node-REDのフローに戻ってフローをもう一度つないでデプロイして下さい。デプロイが成功したらsensor DBへのデータ追加が再開します。
データ追加が再開したら、センサーの温度を40度よりも高くしてみて下さい。CloudantのDatabasesの画面をリフレシュして、alertの# of Docsのカウントが上昇すれば成功です。
動作を確認したら、またNode-REDのフローを切って更新を止めておいて下さい。
以上です。
参照:
Bluemix CLI 入門
Cloud Functions CLI
Cloudant パッケージの使用
温度センサーシミュレータ