🐈

ThingsBoard / Rule ChainのDebug

2025/02/10に公開

Overview

Rule Chainは、装置から送信されたデータをThingsBoard内でどう処理するかを定義する機能です。最もシンプルなRule Chainはこんな感じです。

  • input: データフローの始点
  • message type filter: Post Telemetry(Telemetryの送信)のみに絞る
  • save timeseries: TelemetryとしてThingsBoardのDeviceに登録する

最低限このようなRule ChainがあってはじめてDeviceのLatest telemetryにデータが表示されます。save timeseriesがなければ、いくらデータを送信してもDeviceにその値は表示されません。

Rule Chainの構成を工夫すればいろんなことができます。

  • Telemetryの値を変換する
  • 現在のTelemetryと一つ前のTelemetryとの差分から新たな値を算出する
  • AWS/GCPなどのPaaSにデータを転送する
  • 異常値を検出した場合に、Slackやメール送信を行う
    などなどです。「これできるかな」と思ったことは大体できます。(結構すごいと思ってます)

上の図のようにNode(処理の定義)とEdge(処理の流れ)で構成しますが、どんなNodeがあるかは公式ドキュメントに任せるとして、この記事ではデバッグ方法について記載します。

Rule Chainが複雑になると処理の途中経過を把握したくなります。そのための機能もあるのですが、私が見る限りこれに言及した公式ドキュメントはありません。Rule Chainの開発を効率よく進めるためには知っておくべき機能かと思います。

準備

まずはDebug機能を触るための準備です。sandboxのためのRule ChainとDeviceを作成して、実際にデータをPOSTしてみてDebug機能にPOSTしたデータがどのように反映されるか確認できるようにします。Rule ChainをDeviceに紐づけるには、それぞれ同じDevice Profileに紐づける必要があるため、おさらいがてらこれもワンステップずつ示します。

Rule Chainを作る

sandbox用に簡単なRule Chainを用意します。本稿では以下のようなRule Chainを作って「script」ノードでDebug機能を触ってみます。

message type filter nodeで Post telemetry を選択(Telemetryのみを通す)以外の設定は特に何も行っていない状態です。

JSONをimportしてRule Chainを作成することもできますのでご入用の方はお使いください。

Rule Chain JSON

{
"ruleChain": {
"name": "Test",
"type": "CORE",
"firstRuleNodeId": null,
"root": false,
"debugMode": false,
"configuration": null,
"additionalInfo": {
"description": ""
}
},
"metadata": {
"version": 6,
"firstNodeIndex": 1,
"nodes": [
{
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
"name": "Save Timeseries",
"debugSettings": {
"failuresEnabled": false,
"allEnabled": false,
"allEnabledUntil": 1738831289626
},
"singletonMode": false,
"queueName": null,
"configurationVersion": 0,
"configuration": {
"defaultTTL": 0,
"skipLatestPersistence": false,
"useServerTs": false
},
"additionalInfo": {
"description": "",
"layoutX": 864,
"layoutY": 151
}
},
{
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode",
"name": "Filter Post Telemetry",
"debugSettings": null,
"singletonMode": false,
"queueName": null,
"configurationVersion": 0,
"configuration": {
"messageTypes": [
"POST_TELEMETRY_REQUEST"
]
},
"additionalInfo": {
"description": "",
"layoutX": 300,
"layoutY": 151
}
},
{
"type": "org.thingsboard.rule.engine.transform.TbTransformMsgNode",
"name": "Replace Temperature Value",
"debugSettings": {
"failuresEnabled": false,
"allEnabled": false,
"allEnabledUntil": 1739188202106
},
"singletonMode": false,
"queueName": null,
"configurationVersion": 0,
"configuration": {
"scriptLang": "TBEL",
"jsScript": "return {msg: msg, metadata: metadata, msgType: msgType};",
"tbelScript": "return {msg: msg, metadata: metadata, msgType: msgType};"
},
"additionalInfo": {
"description": "",
"layoutX": 584,
"layoutY": 149
}
}
],
"connections": [
{
"fromIndex": 1,
"toIndex": 2,
"type": "True"
},
{
"fromIndex": 2,
"toIndex": 0,
"type": "Success"
}
],
"ruleChainConnections": null
}
}

Device Profileを作る

メニューからDevice profilesを選択し、Device Profileを新規作成します。名称は適当な値で、Default rule chainにさきほど作成したRule Chainを選択します(ここでは Test という名前で作ったのでそれを選択しています)。

Deviceを作る

Deviceを作ります。メニューからDevicesを選択し、Deviceを新規作成します。Device Profileにはさきほど作成したDevice Profileを選択します(ここも同じくさきほど作ったDevice Profileに test という名前をつけたのでそれを選択しています)。

これで準備は整いました。適当なTelemetryをPostして、DeviceのLatest telemetryに値が反映されれば問題なしです。

Debug機能

機能の有効化

それではRule ChainのDebug機能を触ります。まずはさきほど作ったRule Chainを開き、scriptノードを開きます。以下画像の虫アイコンがDebug機能の有効化ボタンです。 Failures onlyAll messages の2つのオプションがありますが、 All messages にチェックを入れて Apply をクリックします。これでDebug機能が有効化されます。

2025年2月現在、Failures only( = エラーメッセージのみ)には 24/7All messages (全メッセージ)には 15min と括弧で書かれていますが、このあと見るログの保持期間を表しています。全メッセージ全期間ログを保存するのはThingsBoard側のコストが大変なことになるから勘弁してね、ということですね。

scriptノードの設定が完了したら、Rule Chain自体も保存する必要があります。 ノードの設定完了したらできた気になってしまって、いくらPost telemetryしてもDebug機能に値が反映されないミスをやらかしがちですのでご注意ください。

ログの確認

Debug機能を有効化できたら、さきほど作成したDeviceに適当なTelemetryをPostしてみます。再度Rule Chainのscriptノードを開き、Eventsタブをクリックすると、このような画面になってログらしきものが表示されるはずです。

ノードに入ってきたときのログ(Type=IN)と出ていった時のログ(Type=OUT)の2行がペアで表示されています。各フィールドの値は書いてある通りなので説明は割愛しますが、どのEntity(Deviceなど)から来たどのタイプのメッセージ(POST_TELEMETRY_REQUESTなど)でIN/OUTはどのRelation Type(直前/直後のノードをどの経路を辿るのか)などのメタ情報が示されています。

ここでは以下のようなTelemetryをPostしました。

curl -v -X POST http://thingsboard.cloud/api/v1/${access_token}/telemetry --header Content-Type:application/json --data "{temperature:25}"

DataとMetadataの3点リーダーをクリックするとそれぞれ以下のような表示になります。DataはTelemetryを、MetadataはPost元のDeviceの情報が入っています。

送るデータとメッセージタイプによって中身は変わりますが、ここでどのようなデータが入ってきて出ていったのかが把握できるようになっています。

ログのFilter機能もあって、運用中のRule Chainで大量のDeviceからデータが来ていたとしてもここでログを絞って確認することもできます。

Scriptのデバッグ

では、scriptノードでtemperature = 25で送られてくるTelemetryを 30 に書き換えるようにscriptを変更してみます。

msg.temperature = 30;
return {msg: msg, metadata: metadata, msgType: msgType};

これは非常に簡単な(そして非現実的な)例なので多分問題なく動作するだろうとは思いますが、通常のソフトウェア開発と同じでテストしないと何とも言えません。Rule Chain自体を更新する前に、本当に期待通り動作するか確認してみます。下図の「Test transformer function」をクリックします。

するとこのような画面になります。

左上の"Message"の枠に {"temperature: 25} が入力されていることを確認し(入力されていなかったら入力する)、左下の「Test」ボタンをクリックします。すると、右下の"Output"枠に、"Message"の内容を左下枠の"function"で処理した結果が出力されます。期待を設定して出力結果と比較する、いわゆるユニットテストの自動化のようなことはできませんが、scriptがある程度妥当かどうかを判断するには十分でしょう。

異常系のログ

scriptノードで、強制的にエラーが発生するようにscriptを変更してみます。以下のscriptを書き、Debug機能が有効になっていることを確認した上で、ノードの設定の保存とRule Chainの更新を行います。

msg.temperature = 30;

var array = new int[1]; // 1つの要素のみからなる配列を用意。
array[1] = 2; // Error! 要素は1つなのに、2番目の位置に値を代入しようとしている。

return {msg: msg, metadata: metadata, msgType: msgType};

この状態でさきほどのTelemetryを再度Postしてみます。scriptノードの"Events"タブを見ると以下のような表示になっています。

Type=OUTの方のログの Relation TypeFailureになり、Errorの列に3点リーダーが表示されています。この3点リーダーをクリックすると以下のようなエラーメッセージが表示されます。

具体的に何が原因なのかわかりにくくはあるのですが、どこでエラーが出ているのかあたりをつけることはできるかと思います。

ここで示した例があまりよろしくないのですが、実際にはInputのデータが想定外のフォーマットや外れ値になっていて、これを十分に考慮できておらずエラーが発生するケースが多いはずです。ですので、"Data"の値をコピーしてscriptのDebug機能のInputとして設定し、テストすることでエラーが出ないようにscriptを更新する、というサイクルを回しつつRule Chainを更新することになります。

実は「"Data"の値をコピーしてscriptのDebug機能のInputとして設定」の部分は簡単にできるように機能が実装されています。下図の矢印で示している虫アイコンです。これを押せばそのログのInputとなるデータが、scriptのDebug機能がそのInput枠に入力された状態で開きます。

まとめ

Rule Chainのデバッグ方法について記載しました。先述のとおり、このDebug機能に関して公式ドキュメントに記載がないように思いますが、あればご教示ください。「見ればわかるよね」っていうことなのかもしれません。。

Discussion