MotionBoardはリアルタイムデータを直接受信、蓄積し可視化するまでの一連の機能を含んだリアルタイム連携機能を持っています。MotionBoardへ1件ずつリアルタイムにデータを送る方法は下記記事にて紹介しています。
一方で、JSONファイルに書き出された複数件のデータを一括でMotionBoardへ送信する方法も用意されています。本記事ではこちらの方法を紹介します。ゲートウェイ機器側で複数のセンサーデータをまとめ、加工したのちに送信するといった運用を想定している場合に便利な機能です。
※ 本記事で紹介するリアルタイム連携機能には専用のライセンスが必要です。ご利用の環境を確認ください。
事前準備
今回は下記の記事で作成したテンプレートをもとに、データを送るプログラムを紹介しているので「設定方法」章-「テンプレートの作成」節まで実施してください。
JSONファイルの作成
フォーマット
MotionBoardへ送信できるJSONのフォーマットは決まっており、1つのJSONファイルに複数のデータを含めることが可能です。JSONのフォーマットについては下記のマニュアルをご一読ください。
では下記のJSONファイルを例にフォーマットについて解説していきます。こちらは合計2件のデータを送る場合のJSONファイルとなっています。
{
"template": "WebAPI_POST",
"locations": [
{
"time": 1706425758957,
"uptime": 1706425758957,
"lat": 0,
"lon": 0,
"accuracy": ""
},
{
"time": 1706425758958,
"uptime": 1706425758958,
"lat": 0,
"lon": 0,
"accuracy": ""
}
],
"status": [
{
"time": 1706425758957,
"enabled": "true",
"values": [
{
"name": "sample_string",
"type": "2",
"value": "Vv0SL3Agxu"
},
{
"name": "sample_num",
"type": "3",
"value": 834136
},
{
"name": "sample_bool",
"type": "1",
"value": "False"
}
]
},
{
"time": 1706425758958,
"enabled": "true",
"values": [
{
"name": "sample_string",
"type": "2",
"value": "RqSXNE2VHE"
},
{
"name": "sample_num",
"type": "3",
"value": 33994
},
{
"name": "sample_bool",
"type": "1",
"value": "true"
}
]
}
],
"msg": {
"send": "send msg",
"next": "next",
"read": "read"
}
}
上記のJSONは大きく4ブロックに分けられます。
- 基本情報
「Template」や「loginId」などを記載します。「loginId」は必須ですが、Web API共通のパラメータにある「id」を指定することで、JSONファイル内に含めずに送信することも可能です。
"template": "WebAPI_POST",
"name": "name",
"loginId": "login id",
"retry": "true"
- Locationsブロック
データ作成時刻やセンサの位置情報を記載します。必須項目として「time」があります。「time」には、データが発生した日時をミリ秒(いわゆるUNIX time)で表現した値を指定します。
その他、「lat」や「lon」などのパラメータがあり、センサーの位置情報などがあればこちらに指定しましょう。そもそも位置情報がなかったり、送る必要がない場合は省略もしくは適当な値を指定すればOKです。
"locations": [
{
"time": 1706425758957,
"uptime": 1706425758957,
"lat": 0,
"lon": 0,
"accuracy": ""
},
{
"time": 1706425758958,
"uptime": 1706425758958,
"lat": 0,
"lon": 0,
"accuracy": ""
}
],
日付をUNIX timeに変換するサイトは、検索すると出てきます。テストとしてJSONを手作りする場合は使ってみてください。
- Statusブロック
データ作成時刻と位置情報以外のデータを記載します。Locationブロックの「time」と同じく、必須項目として「time」があります。ミリ秒で指定する点も同様です。
位置情報以外のデータは「values」項目に記載します。「name」/「type」/「value」の3項目はそれぞれテンプレートに指定したステータス名/データ型/値に対応します。データ型は下記のように数値で指定するのでご注意ください。
"status": [
{
"time": 1706425758957,
"enabled": "true",
"values": [
{
"name": "sample_string",
"type": "2",
"value": "Vv0SL3Agxu"
},
{
"name": "sample_num",
"type": "3",
"value": 834136
},
{
"name": "sample_bool",
"type": "1",
"value": "False"
}
]
},
{
"time": 1706425758958,
"enabled": "true",
"values": [
{
"name": "sample_string",
"type": "2",
"value": "RqSXNE2VHE"
},
{
"name": "sample_num",
"type": "3",
"value": 33994
},
{
"name": "sample_bool",
"type": "1",
"value": "true"
}
]
}
],
- Messageブロック
メッセージテキストを記載します。必須項目はないためMessageブロック自体省略してもOKです。またMotionBoardのsystem datasourcesにも格納されません。
"msg": {
"send": "send msg",
"next": "next",
"read": "read"
}
注意点
データを2件以上送る場合は、LocationsブロックとStatusブロックの各データの「time」値は一致させる必要があります。
cURLで送信
手動で実行
前章のJSONファイルを使って実際にデータを送ってみましょう!今回は簡単にWeb APIを実行できるcURLというコマンドを使ってみます。
今回はJSONファイルを「C:/API_Test/MB/json/data.json」に配置した前提で、cURLコマンドを実行してみます。コマンドプロンプトやPower Shellで下記コマンドを実行してください。
curl -X POST -F "id=1" -F "uploadFile=@C:/API_Test/MB/json/data.json" "http://localhost:8787/motionboard/rest/tracking/data/upload/public"
コマンド末尾のURLは環境に合わせて変更ください。URLの詳細については下記をご覧ください。
では、実際にMotionBoardへデータが送られたか確認しましょう。「事前準備」章で紹介した記事の「設定方法」章-「データの確認」節と同様に、[system Datasources]-[Realtime]-[LocationAndStatus]-[WebAPI_POST]のデータを明細表アイテムで描画してみましょう。JSONファイルに登録した2件分のデータが送信されていることが確認できますね!
JSONファイルを変更せずに再度送信すると同じデータが追加されてしまう?
もう一度上記のコマンドを実行するとどうなるでしょうか。結果としては件数・内容ともに変化しません。Statusブロックの「values」の中身を変えて再度実行しても同様に変化しません。
一方で、LocationsブロックおよびStatusブロックの「times」を変更したり、共通パラメータである「id」を変更した場合はデータが追加されます。「LocationAndStatus」のテーブルではどのセンサー(=「id」)からいつ(=「time」)データが送られたかという情報でユニークとなるようにデータが保持されています。したがって、仮に同じJSONファイルがMotionBoardへ2度送信されたとしても、同じデータが重複して格納される心配はありません。
実際のケースでは、ゲートウェイ機器などのデバイス側(データ生成側)がJSONファイルを作成するタイミングと、データを送信するマシン側(データ送信側)のタイミングが交互になる保証が無い(非同期である)可能性もあります。こういった場合でも、データを生成するデバイス側はJSONファイルを常に上書きする形で格納していけばOKということですね!
PythonでJSONファイル生成&送信
実際に、データ生成側とデータ送信側の処理をそれぞれPythonで動かし、MotionBoardでリアルタイムにデータが追加されていく様子を見ていきましょう!
データ送信側
まずはデータ生成側がJSONファイルをリアルタイムに上書きしている前提で、一定間隔でMotionBoardへデータを送信するPythonスクリプトを紹介します。
import requests
import time
###### user settings ######
URL = "http://localhost:8787/motionboard/rest/tracking/data/upload/public"
INTERVAL = 1 # データを送る間隔(秒)
JSON_FILE_NAME = "C:/API_Test/MB/json/data.json" # JSONファイルの場所
###########################
headers = {
"Content-Type": "multipart/form-data",
}
params = {
"id" : 1
}
def main():
while(True):
file = {'uploadFile': open(JSON_FILE_NAME, 'rb')}
res = requests.post(url = URL, params=params, files=file)
if(res.status_code == 200):
print(f"{res.status_code}: Seccessfully posted. ")
else:
print(f"{res.status_code}: {res.text}")
time.sleep(INTERVAL)
if "__main__" == __name__:
main()
スクリプトの上部にある「user setting」は、環境に合わせて変更ください。
データ生成側
続いて、JSONファイルを一定間隔で出力するデータ生成側のPythonスクリプトを紹介します。
import time, string, random, json
###### user settings ######
SAVE_PATH = "C:/API_Test/MB/json/data.json"
INTERVAL = 5 # JSONファイルを生成する間隔
RECORDS_PAR_CALL = 5 # 一度に生成するデータ件数
STRING_LENGTH = 10 # ランダム生成する文字列の長さ
NUM_MIN = 0 # ランダム生成する整数値の最小値
NUM_MAX = 1000000 # ランダム生成する整数値の最大値
TEMPLATE = "WebAPI_POST"
###########################
def gen_random_string(length: int) -> str:
randlst = [random.choice(string.ascii_letters + string.digits) for i in range(length)]
return ''.join(randlst)
def gen_locations(unixtime: int) -> list:
location_list = []
for i in range(RECORDS_PAR_CALL):
tmp = {
"time": unixtime + i,
"uptime": unixtime + i,
"lat": 0,
"lon": 0,
"accuracy":""
}
location_list.append(tmp)
return location_list
def gen_status_records(unixtime: int) -> list:
status_list = []
for i in range(RECORDS_PAR_CALL):
tmp = {
"time": unixtime + i,
"enabled":"true",
"values":
[
{"name":"sample_string","type":"2", "value":gen_random_string(STRING_LENGTH)},
{"name":"sample_num","type":"3", "value" : random.randint(NUM_MIN, NUM_MAX)},
{"name":"sample_bool","type":"1", "value": random.choice(["true", "False"])}
]
}
status_list.append(tmp)
return status_list
def gen_msg():
return {
"send":"send msg",
"next": "next",
"read":"read"
}
def main():
while(True):
now_unixtime = int(time.time() * 1000)
data = {
"template": TEMPLATE,
"locations": gen_locations(now_unixtime),
"status": gen_status_records(now_unixtime),
"msg": gen_msg()
}
with open(SAVE_PATH, 'w') as f:
json.dump(data, f, indent=4)
print("Data generated. ")
time.sleep(INTERVAL)
if "__main__" == __name__:
main()
スクリプトの上部にある「user setting」は、環境に合わせて変更ください。
デモンストレーション
ではそれぞれのスクリプトを実行して、MotionBoardでどのように見えるのか確認してみましょう。実行時の様子は下記のGIFアニメーションのとおりです。
データ生成側(GIFアニメーションの左下にて実行)では5件のデータを含んだJSONファイルを5秒間隔で出力しています。データ送信側(GIFアニメーションの右下にて実行)は1秒間隔でMotionBoardへデータを送信していきます。5件ずつデータが追加されていることが確認できますね!
さいごに
本記事ではJSON形式のデータをリアルタイムにMotionBoardへ送信する方法について紹介しました。複数のデータを一括で送ることができるため、複数のセンサーから送られるデータをゲートウェイ機器でまとめて加工したのち、送信するといった運用を想定している場合に便利な機能です。
また、実際の運用シーンを模してリアルタイムにJSONデータを生成するPythonスクリプト及び、非同期で送信するPythonスクリプトについて紹介しました。本記事で紹介したようにJSONデータとして纏めて送る方法と、一つずつ直接送る方法、それぞれシーンに合わせて使い分けてくださいね!