SORACOMバイナリーパーサーのCBOR向けフォーマットを試してみた
これは
SORACOM Advent Calendar2023の5日目の記事です。
バイナリーパーサーがCBORに対応
SORACOMのサービス更新情報をつらつらと眺めていて、2023/5/12のアップデートで「バイナリパーサーが Concise Binary Object Representation (CBOR) に対応しました」というものがありました。
私は普段バイナリーパーサーといえばボタン用の@button
やGPSマルチユニット用の@gpsmultiunit
くらいしか使ったことがなかったのですが、公式ドキュメントを見てみるとそれ以外にも定義済みのフォーマットが結構沢山あることに今更ながら気がついたので、この機会に試してみました。
バイナリーパーサーとは
バイナリパーサーは、デバイスが送信したデータを変換し、JSON形式のデータとしてBeam/Funnel/Funk/Harvest Dataに出力する機能です。
Unified Endpointとソラコムの各サービスとの間に挟まり、デバイスから送信されたバイナリデータを、設定されたフォーマットに従ってJSON形式に変換してくれるサービスです。
これを使うと、デバイスから送るときにはできるだけ小さなデータになるようにバイナリにパックして送り、クラウドに送るときにはクラウド側で扱いやすいようにJSONにするということができます。これによってデバイスからの通信量が削減でき、ひいては通信料や消費電力量を削減することが可能になります。
詳しくは公式ドキュメントを参照ください。
Concise Binary Object Representation(CBOR)とは
Concise Binary Object Representation(CBOR)とは、RFC8949で定義されたバイナリーデータのフォーマットです。JSONデータモデルに基づいており、手軽かつデータを節約しつつ、JSONのように柔軟な形式のデータをバイナリの列で表現できます。
詳しくは公式ページをご確認ください。
データ形式やデータ長が固定の物であれば単純なバイナリパックにする方がデータ量は小さくなりますが、JSON由来の柔軟さも備えているところが特徴だと思います。
CBORで送る準備
では、早速CBORでデータを送ってみましょう。バイナリーパーサの定義済みフォーマットの説明にある例も参考にしつつ、適当なJSONをudpで送るプログラムを作成します。
今回はSORACOM ArcでPCをSORACOMプラットフォームに繋ぎ、プログラムはpythonで記載しました。pythonでcborを取り扱うには、cbor2というライブラリを利用します。
from cbor2 import dumps, loads, load
import json
import socket
serv_address = ("uni.soracom.io",23080)
json_text = '{"integer":1,"string":"str","array":["array1","array2"]}'
json = json.loads(json_text)
data = dumps(json)
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
send_len = sock.sendto(data,serv_address)
print(send_len)
SORACOM BeamのUDPToHTTP機能を使い、AWS Lambdaにデータを送信します。Lambdaは単純に受け取ったデータをそのままログにダンプするだけの以下のようなpythonプログラムとしました。
import json
def lambda_handler(event, context):
body = {
"event": event
}
print(json.dumps(body))
return {
'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
},
'body': json.dumps('Hello from Lambda!')
}
SORACOM側の準備は以下の通りです。
- 新しいSIMグループの作成
- 作成したSIMグループに、ArcのvSIMを所属させる
- 作成したSIMグループの設定で、BeamのUDPToHTTPを設定する
そのまま送ってみる
では、まずはバイナリーパーサを設定せずに送ってみます。Lambda側のログを見ると、以下のようになっています(ヘッダ情報等は省略しています)。
"body": "{\"payload\":\"o2dpbnRlZ2VyAWZzdHJpbmdjc3RyZWFycmF5gmZhcnJheTFmYXJyYXky\"}"
バイナリーデータはそのままでは送れないので、Base64で送られています。Base64デコードツールでこの文字列を復元してみましょう。
要素の前にデータタイプを表す文字が入っていて、CBORのバイナリっぽいですね。
@cbor
を設定
バイナリーパーサーにでは、次にバイナリーパーサーに@cbor
を設定して送ってみます。Lambdaのログは以下の通りです。
"body": "{\"integer\":1,\"string\":\"str\",\"array\":[\"array1\",\"array2\"],\"binaryParserEnabled\":true}"
ちゃんと元のJSONになっていることが分かります。
JSONで送ってみる
定義済みデータを見ると、@json
があることに気がつきました。せっかくですのでちょっとこれも試してみましょう。
まずはプログラムを以下のように修正します。
import json
import socket
serv_address = ("uni.soracom.io",23080)
json_text = '{"integer":1,"string":"str","array":["array1","array2"]}'
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
send_len = sock.sendto(json_text.encode('utf-8'),serv_address)
print(send_len)
そしてバイナリーパーサーを一旦無効にしてからデータを送ってみます。Lambdaのログは以下の通りです。
"body": "{\"payload\":\"eyJpbnRlZ2VyIjoxLCJzdHJpbmciOiJzdHIiLCJhcnJheSI6WyJhcnJheTEiLCJhcnJheTIiXX0=\"}"
バイナリーで送られているので、Base64で送られています。デコードしてみましょう。
元のJSONになりました。
では、バイナリーパーサーに@json
を設定して送ってみます。Lambdaのログは以下の通りです。
"body": "{\"integer\":1,\"string\":\"str\",\"array\":[\"array1\",\"array2\"],\"binaryParserEnabled\":true}"
バッチリですね!
まとめ
SORACOMバイナリーパーサーを使うと、デバイスから送信するデータ量を削減することができます。CBOR形式はそれほどデータ量自体は減らないものの、単純なバイナリパックに比べると柔軟性があるのでなかなか使いやすそうです。
また、JSONを送る際にもHTTPで送らずにUDPで送ってバイナリーパーサーを使うことでデバイス側の処理量や通信量を削減できます。
独自にバイナリーパックして送信するとデータ量は小さくできますが、それに対応するバイナリーパーサーを書くのはそこそこ面倒です。定義済みフォーマットとCBOR等を使うことでその辺りの苦労を軽減できそうです。
Discussion