Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
102
Help us understand the problem. What is going on with this article?
@joeartsea

Node-REDでハマりがちな罠

More than 1 year has passed since last update.

Node-REDでハマりがちな罠をまとめます。

1. Debugの内容が途切れる

人にNode-REDを薦めると最初に言われるのがコレ。

ほとんどの場合、プロパティを絞り込んでデバッグするのでデフォルトの文字数で問題ないのですが、用途によってはどうしてもメッセージ全体を確認しないといけないような場合もあります。

その場合はDebugに表示できる文字数を増やしましょう。Debugに表示できる文字数はsettings.jsdebugMaxLengthの値を増やすだけです。

2. データ型

Debugで処理対象のデータがJSONに見えたとしても、それはObjectでなくString(文字列)かもしれません。

以下は、あるMQTTブローカをSubscribeしているflowですがDebugをよく見るとStringと表示されてます。
mqtt_node.png

これをこのままswitch nodeで条件分岐しようとすると、以下のような「プロパティがない」というエラーが表示されます。
switch_node.png

ここでは条件の対象としてpayload.d.idというプロパティを指定していますが、対象データがStringのままなので何を指定してもダメです。まずは対象のデータ型をObjectへ変換します。

JSON StringをObjectに変換するにはfunction nodeでJSON.parse()しても良いのですが同様のことはJSON nodeで可能です。

以下のようにするとMQTTブローカから取得したJSON Stringを一旦JSON Obejctへ変換してから条件分岐へ流すようにできます。
json_node.png

3. HTTPレスポンス

http in nodeでNode-REDにEndpointを作成してWebサーバとして処理を待ち受けるというようなユースケースはよくあります。

たとえば以下のように[get]/red/testというEndpointを作成してアクセスが来たらtemplate nodeに指定したWebページを表示します(Webページは「テスト」という文字だけ表示されるようになっています)
http_in_node.png

しかし実際に/red/testにアクセスしてみるとタイムアウトします(Node-REDが動作している環境によって挙動は変わります)
template_node.png

これは、先ほどのflowのhttp in nodeでHTTPリクエストを受け付けたのにHTTPレスポンスを返す処理を設定していないため、クライアント(ブラウザ)が延々とHTTPレスポンスを待ち続けている状態になっているからです。

以下のようにhttp out nodeを設定して正しくHTTP通信を実装してください。
http_out_node.png
htt_out_node.png

ちなみにhttp out nodeの位置にも気をつけましょう。flowのどこかに配置すれば一応HTTP通信が成立して動いているようには見えますが、flowで一連の処理をした後の値をクライアントへ返したいような場合は、その処理の後続としてhttp out nodeを配置するようにしましょう。

4. flowの冗長化

同じような動作をするflowを幾つも並べていませんか?以下は先ほどのWebページへアクセスするflowをNode-REDサイトだけでなくGoogleとYahooに対しても行うようにコピーしただけです。
redundancy.png

もちろんコレでも良いのですが、アクセス先が増えたりflowが複雑になってくると破綻してきます。flowの共通部分が何かを意識して差異を動的な値として1本のflowに与えていくような設計にしてみましょう。

たとえば上記flowの場合はアクセス先以外はすべて共通なので、Node-RED, Google, YahooのURLを動的なパラメータとして渡せるようにしてみます。

http request nodeのinfoを見るとアクセスするURLはmsg.urlとして動的に値を渡すことができます(他にもmethodやheaderも渡すことができると書いてます)
http_in_node_info.png

ということでアクセス先のURLを配列として保持して以下のようにloopさせることで1本の処理に動的なパラメータを渡して処理するflowになります。
loop.png

以下をインポートするとサンプルフローを再現できます。

[{"id":"1d42eedf.e2bd11","type":"http request","name":"","method":"GET","ret":"txt","url":"","x":157,"y":150,"z":"96d4a95.f692b58","wires":[["e8e419f0.171be8"]]},{"id":"a0f49389.5f0b7","type":"inject","name":"","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":false,"x":145,"y":88,"z":"96d4a95.f692b58","wires":[["eb81bea6.147e4"]]},{"id":"e8e419f0.171be8","type":"html","tag":"title","ret":"html","as":"single","name":"","x":318,"y":150,"z":"96d4a95.f692b58","wires":[["963ff6aa.69c008"]]},{"id":"963ff6aa.69c008","type":"debug","name":"","active":true,"console":"false","complete":"payload","x":477,"y":150,"z":"96d4a95.f692b58","wires":[]},{"id":"6c9c4de.f9363b4","type":"function","name":"","func":"msg.url = msg.payload;\nreturn msg;","outputs":1,"x":498,"y":97,"z":"96d4a95.f692b58","wires":[["1d42eedf.e2bd11"]]},{"id":"eb81bea6.147e4","type":"function","name":"for each item","func":"if( msg.i     == undefined ) msg.i = 0;\nif( msg.items == undefined ) {\n\tmsg.items = [\n\t\t\"http://nodered.org/\",\n\t\t\"http://google.com/\",\n\t\t\"http://yahoo.com/\"\n\t];\n}\n\nmsg.payload = msg.items[ msg.i ];\n\nreturn msg;","outputs":1,"x":322,"y":92,"z":"96d4a95.f692b58","wires":[["794b0123.86b5","6c9c4de.f9363b4"]]},{"id":"794b0123.86b5","type":"function","name":"++","func":"if ( (msg.i += 1) < msg.items.length ) {\n\treturn msg;\n}","outputs":1,"x":323,"y":44,"z":"96d4a95.f692b58","wires":[["eb81bea6.147e4"]]}]

もちろんアクセス先が数千とか数万箇所になってくれば、配列ではなくDBやファイルに永続化してflowからアクセス先情報を完全に分離しましょう。

また、このように後続のnodeに動的な値を渡すことがNode-RED活用のコツの一つだと思います。データベース系のnodeはSQLなどデータベース操作をするスクリプトを前段のnodeから渡すようにinfoに書かれていることがほとんどです。

5. プロパティ値の上書き

先ほどのWebアクセスのflowでhttp request nodeのURLを指定したまま外部から動的に値を渡すと以下のようなエラーが表示されます。
override.png

これはメッセージ内に表記されているリンク先( http://bit.ly/nr-override-msg-props )の通り、nodeに設定した固定の値を上書きすることで予期しない結果になる事象があるため、file系nodeやhttp系nodeでプロパティの上書きを推奨しないというものです。

特にfunction nodeで以下のように msg を返すような書き方が散見されますが、これは msg オブジェクトの他のプロパティを無意識に消滅させてしまいます。Node-REDのnodeは msg オブジェクトの受け渡しを前提に動作している場合が多いので以下の書き方をしてしまうと思わぬハマりに遭遇してしまいます。

retuen msg = {
  payload: "hoge"
};

6. template nodeでのプロパティアクセス

template nodeでデータをバインドしてWebページとして返したり、メールの本文として整形したりといったユースケースはよくあります。

この時のプロパティアクセスは必ず.(ドット)で辿ります。['title']などブラケットでは辿れません。

template_node.png

上記のようなObjectを流した場合はハマらないのですが、配列を流した時に慣習的に[0]と書いてしまいがちです。

7. あるnodeの状態によって後続のflowを実行したい

例えば、以下のようにメール送信するflowがあったとします。ただ、email nodeの後続に端子がないので後続のflowを作りたくても作れません。

スクリーンショット 2018-08-03 11.58.12.png

こういう場合は、以下のようにstatus nodeを置いてemail nodeの状態を監視します。

スクリーンショット 2018-08-03 11.59.17.png

こうすることでメール送信してみると、以下のようにメール送信時とメール送信完了時の2回、email nodeの状態がdebug nodeに通知されますので、あとはswitch nodeなどで status.text の内容で後続の処理を分岐するような流れになります(ステータスメッセージはnodeの作り次第になりますのでemail nodeの送信完了時のように何もメッセージがないというような場合も往々にしてあります...)

スクリーンショット 2018-08-03 12.01.09.png

以上、今後もハマり次第こちらに追加していきたいと思います。

最後に: Node-REDについてさらに知りたい

Node-RED User Group Japan へどうぞ!

102
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
joeartsea
Chief Technical Officer at Uhuru Corporation. enebular, Milkcocoa, Node-RED
uhuru
株式会社ウフルはインターネットによる革新的なサービスがお客様企業の価値向上につながる事を目指し「テクノロジーと自由な発想で未来を創る」を企業理念に掲げています。エッジとクラウドを “つなぐ” IoTオーケストレーションサービス「enebular®」をベースにIoTやデジタルマーケティングの領域で顧客のビジネスに変革をもたらし続けております。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
102
Help us understand the problem. What is going on with this article?