はじめに
node-redのカスタムノード、node-red-contrib-linking-device の開発時に気づいたことや調べたことを書きます。
なお、公式サイトにある 独自のNodeを作成するガイドの内容に目を通していることを前提とした内容となります。
また、こちらの記事もおすすめです:Node-REDのノードをつくる手順
node.js側 のTips
nodeのcloseイベントへの非同期応答
再デプロイするときなどに、ノードを閉じるための'close'イベントが来ますが、ここで時間のかかる終了処理が必要になる場合、以下のように終了時にdone()コールバックを呼ぶ形での実装になります。
this.on('close', function(done) {
doSomethingWithACallback(function() {
done();
});
});
15秒以内に処理が終了しないと 18-08-20 14:28:35 [error] Error stopping node: TimeoutError: timed out after 15000ms
というエラーをnode-redが出します。これのデバッグをする際は、他のノードが存在しない状態で行って原因が本当に自分のカスタムノードにあるのかどうか、まず切り分けをすることをお勧めします。
自分の場合、このエラーに悩まされてなんどもプログラムをいじってたのですが、実はmqtt out
ノードがタイムアウトの原因で、無駄な時間を使ってしまいました。
ステータス表示を充実させる
正常動作しているかエラーかなどを、色と文言で表示すると、ユーザーは使いやすいし、自分もデバッグもしやすいです。
node.state({fill:'red', shape:'dot', text:'error'})
なお灰色を指定する際、gray
ではなくgrey
なので注意。
MQTT (Beebotte) フレンドリーなメッセージフォーマット
データ出力系ノードを作成する場合は、メッセージフォーマットを以下のようにしておくと、メッセージを MQTT out ノードにほぼそのまま渡して、BeebotteなどのMQTTブローカーにデータを送信できるので使いやすくなります。
- msg.payload.data : データを格納
例: 温度センサーのLinkingデバイスの場合、msg.payload.data = 27.5 (温度)
- msg.topic : MQTTのchannel, resource情報を含んだ"
channel
_resource
" の文字列フォーマットとする
Linkingデバイスの場合、"linking/デバイス名
_センサー種別
" としています。
例: msg.topic = "linking/Tukeru_th012345_temperature"
こうしておいて、Beebotte側でChannel: linking
, Resource: Tukeru\_th012345\_temperature
を作成すればデータのPublishが出来るようになります。
htmlで記述するUI側(編集ダイアログ)のTips
ドキュメントにない標準アイコン
ノードに表示するアイコンですが、node-redのドキュメントに記入されているもの以外にも、いくつか標準アイコンが存在します。
ソースコードのiconフォルダ参照:
https://github.com/node-red/node-red/tree/master/editor/icons
html側のスクリプトではjQueryが標準
自分でjQueryを読み込まなくても最初から$が使えるようになってます。
編集ダイアログでインタラクティブな処理を実現する
ドキュメントに書いてある例では、編集ダイアログで設定した内容をnodejs側に一方通行で通知するだけですが、自分が作ったノードの場合はスキャンしたデバイス一覧をリスト表示するなど、html側とnodejs側で相互に情報をやり取りする必要がありました。
既存のカスタムノードを参考にしたところ、以下のような仕組みになってました:
- html側はjQueryのgetJSONなどのAPIでnodejs側に非同期リクエストを行う
- nodejs側はhtml側からのリクエストを、ExpressベースのWebアプリケーションとして処理
アイコンにFontAwesomeが使える
サンプルのhtmlを見ると、fa-xxx と見慣れないクラスがありますが、Font Awesomeを使ってます。
Spinner icon は回るアニメーションをCSSでサポートしているので、リクエスト中の表示に便利です。
ノードにport labelをつける
出力ポートが複数ある場合、ポートラベルをぜひつけるべきです。html側で記述します。
編集ダイアログの UI Widgets
Editor UI Widgets で、TypedInput, EditableListというウィジェットが紹介されています。selectノードなどで使われている複雑な設定を可能にしています。
EditableListはnode-red-contrib-linking-deviceでも、デバイスのリスト表示に使わせてもらいました。その際、node-red-contrib-generic-ble を参考にしています。
デバッグのために
エディタのノード定義のhtmlファイルは、開発時とは別のVM184800'などのランダムな名前でブラウザには読み込まれているため、デバッグ時にソースコードが探しにくくなります。ノード定義のoneditprepare()に、console.log('mynode: editprepare')とかのログを入れておけば、Consoleから当該ファイルにすぐにジャンプするので便利です。
ローカライゼーション
最初からやっておくことをおすすめします。なんとなく面倒に思って後回しにしてましたが、ドキュメントを読んだらそんなに複雑ではありませんでした。
なお、ドキュメントに
コアのnode-redカタログには、よく使用されるいくつかのステータスメッセージがあります。
とありますが、よく使いそうなッセージの定義場所は、ソースのここです
"common": {
"label": {
"name": "名前",
"ok": "OK",
"done": "完了",
"cancel": "中止",
"delete": "削除",
"close": "閉じる",
"load": "読み込み",
"save": "保存",
"import": "読み込み",
"export": "書き出し",
"back": "戻る",
"next": "進む",
"clone": "プロジェクトをクローン",
"cont": "続ける"
}
}
"common": {
"label": {
"payload": "ペイロード",
"topic": "トピック",
"name": "名前",
"username": "ユーザ名",
"password": "パスワード",
"property": "プロパティ"
},
"status": {
"connected": "接続済",
"not-connected": "未接続",
"disconnected": "切断",
"connecting": "接続中",
"error": "エラー",
"ok": "OK"
}
}