公開日:2020年9月29日
コロナ対策 IoT 作ってみた ③

通信量80%削減! バイナリパーサー使ってデータ送ってみた!


はじめに

こんにちは、AITOYA株式会社の胡本(えべすもと)です!
弊社は、cm級位置情報測位デバイスの「iChidori®(いちどり)」シリーズを始めとした、位置情報ソリューションをお客様に提供している企業です。 製品の説明はこちらをご覧ください!

よい、いちどりを。2019年12月撮影

お待たせしました!「アルコール消毒状況がひと目で分かるIoTデバイス」シリーズ第3弾です!今回は「バイナリパーサー」を使用してデータ量を少なくして送信できるようにしてみようと思います。それでは始めていきましょう!

これまでのダイジェスト

これまでの記事では、「アルコール消毒状況がひと目で分かる」デバイスの作成手順や SORACOM Harvest を使ったクラウド管理の手順を記載してき ました。気になる方はこちらのリンクからご覧ください。

【第1回】【コロナ対策IoT】アルコール消毒状況がひと目で分かるデバイス作ってみた!
【第2回】【SORACOM×IoT】HarvestとLagoonを使ってアルコール消毒状況を可視化してみた!

今回はこの続きで、SORACOM 内にある「バイナリパーサー」というものを使用してデータ量を少なくしてみようと思います。

バイナリパーサーとは

そもそも「バイナリパーサー」はご存じでしょうか?バイナリパーサーとは、バイナリデータをテキストデータや JSON データなどに変換する変換器の役割を果たすものです。

……え???

だと思います(自分もはじめはそうでした)。なので、できるだけ簡単に説明していきます!

一般的にデータを送る際は、主に ASCII コードと呼ばれる文字コード表に従ってテキスト形式で送信していたり、またそれを JSON というテキストベースのデータフォーマットに変換して送信しています。ASCIIコード表

しかし、パソコンはバイナリデータという「0」と「1」の2進数の連続体(いわゆるバイト)でデータを記憶されています。そのため、例えば「20」という数字をテキスト形式で送信する際は、まずパソコン上で ASCII コードを通じて 2(0x32) と 0(0x30) に分けて変換され、0011001000110000 (0x32と0x30) の2バイトで送信されます。(ちなみに「0」と「1」ひとつずつがいわゆる「1ビット」と言い、8個で「1バイト」と言います。どちらもメモリー関連でよく聞く言葉です。)

また、さらに「 ” 」(0x22)や「 ; 」(0x59)が文字と文字の間につくことも多く、JSON のフォーマットを維持するバイト容量も必要なため、「20」という数値ひとつ送るにも多くのデータを使用してしまいます。しかし、「バイナリー送信」という考え方では、最初に記述した通り、データ送信時には「0」と「1」のバイナリデータのままデータを送信し、そしてクラウド上で設定した独自の変換フォーマット(以下「バイナリパーサーフォーマット」と言います)を使用して JSON データやテキストデータに変換する機能です。

例えば、バイナリパーサーフォーマットで「送信データの最初の1バイト(「0」と「1」の羅列8個分)を符号なしの数値(uint)として読み込む。」と決めておけば、先程の例の「20」は「00010100」(0x14)のたった1バイトのバイナリデータを送信するだけで良くなります。そのため送信時にかなりのデータ量を削減することができます。つまり、概要としては以下の図のようになります。

先程は「20」を例にしましたが、単純な bool 判定で「0をfalse」、「1をtrue」とバイナリパーサーフォーマットで決めておけば、データ送信上は「0」だけ(1ビット)を送るだけでデータの判別もできます。この方法によって、ASCII に変換する分や「 ” 」や「 ; 」といった表記を全て省くことができるので、データ量を80~90%!?とかなり圧縮することができます。さらにデータ量を圧縮できるので通信料金をかなり下げることができます。お得でしかないです……。

その他にも、データを圧縮した分だけ通信時間も減るため、消費電力も削減されます。お得尽くしです。このようにデータ量の小さいバイナリデータを上手く変換してくれる便利な変換器が「バイナリパーサー」なのです。

方法自体はビットを使ったデータの記憶であるため理解が難しいですが、理解できるとかなり便利な方法です。詳しいバイナリパーサーのフォーマット形式は SORACOM の公式ページをご覧ください。
バイナリパーサー詳細 | SORACOM Users

また、実際に実装する際はバイナリパーサーの挙動を気軽に試すサービスも出ているので、こちらも利用してみてください。自分はかなり利用させて頂きました 笑
Binary Parser Playground | SORACOM Developers

バイナリパーサーの SORACOM 側の設定方法

さて、説明が長くなってしまいましたが、バイナリパーサーの設定をしていきましょう!まずは SORACOM 側の設定です。ユーザーコンソール左上のメニューから「SIMグループ」をクリックし、

自分が作成したSIMグループを選択します。ここでは前回作成した「hand-wash」を選択しました。(SIMグループを作成してない方は、下記リンクを参考にしてください)
SORACOM HarvestとSORACOM Lagoonを使ってアルコール消毒状況を可視化してみた!「SORACOM 側の設定」

その後、SIMグループ内の「SORACOM Air for Cellular設定」をクリックし、

バイナリパーサーフォーマットを「ON」に変更後、バイナリデータをどのように変換するかフォーマットを作成し記入します。

今回フォーマットは

t_0:0:uint:16 t_1:2:uint:8 t_2:3:uint:8 t_3:4:uint:8 t_4:5:uint:8 t_5:6:uint:8 t_6:7:uint:8 t_7:8:uint:8 t_8:9:uint:8 t_9:10:uint:8 t_10:11:uint:8 t_11:12:uint:8 t_12:13:uint:8

と設定しました。最初の16ビット(2バイト)を「1時間の総プッシュ回数」、その後の8ビット(1バイト)をそれぞれ「5分間のプッシュ回数」を記録するように設定しています。

これにより送信データ数はたった13バイトなのですが、最初の2バイトで最大65536までの数値を、その後の1バイトで最大256までの数値をそれぞれ読み込むことが出来ます。
最後に「保存」を押せば、SORACOM 側の設定は完了です!

WioLTE 側でのプログラムの構成

WioLTE 側で書くソースコードは、SeeedJP の公式ライブラリに SORACOM Harvest と通信を行うソースコードが記載してあります。今回もこちらのソースコードを使用させて頂きました。
WioLTEforArduino/soracom-harvest.ino at master · SeeedJP/WioLTEforArduino · GitHub

この中のデータ送信のコードを変更していきます。まず送信するデータを格納する変数を定義します。今回はコード内の、dataを書き換え、

byte data[13]

としました。この変数にビットのデータを格納していきます。
この時使われるのが「ビットシフト」という考え方です。これは文字通りビットを左右に移動させる方法です。
例えば、「00100110」というものを右に1だけシフトすると「00010011」となる。というものです。
詳しくはこちらをご覧ください。
シフト演算子 - 演算子 - C言語 入門

この方法を用いて、配列に順番にビットを詰めていきます。8ビットごとに詰めていきたいので、右シフト演算子の>>を用いて詰めていきます。今回のコードでは、1時間の総プッシュ回数を記録する変数を

int HourSprayCount = 0;

と定義し、dataの各配列に

data[0] = (HourSprayCount >> 8) & 0xFF;
data[1] = HourSprayCount & 0xFF;

としていくことで数値を 16ビットに組み込んでいきます。その後5分ごとの総プッシュ回数は

int MiniteSprayCount = 0;

と定義し、dataの各配列に

data[2] = MiniteSprayCount & 0xFF;

……と記述していくことでビットの配列で格納することができます。
最後に、13バイト分送ることを設定するため、80行目の

Wio.SocketSend(connectId, data)

を変更し、

Wio.SocketSend(connectId, data, 13)

と記述して WioLTE 経由でデータ送信を行います。
これで WioLTE 側の設定が完了しました!

実際の送信結果

さて、設定が終わったので、実際にデバイスを動かしてみましょう!

動かしたことで送信した WioLTE 側のデータはこちら

今回はテストなので、総プッシュ回数は356回、5分ごとのプッシュ回数は22回に固定して送信しています。シリアルモニター上では、1時間の総プッシュ回数は356回ですが、格納されたデータは、

Wio.SocketSend(connectId, data, 13)
data[1](16進数表示) : 0x64

と表示されています。
ただこれは間違いではありません。データは8ビットずつ送っています。
これは8バイト = 2の8乗 = 256 なので、上位1バイトを格納しているdata[0]とは

data[0] = 256 × 0x01 = 256 × 1 = 256

となり、下位8バイトを格納している data[1] は

data[1] = 0x64 = 100

となります。なので、

data[0] + data[1] = 256 + 100 = 356

となり値としては合っています。

さて、これを SORACOM Harvest 上で確認した結果がこちら!

この結果から、バイナリパーサーを使用してデータ量を削減して送信できました!また1時間の総プッシュ回数は送信時は

data[0] = 0x01、data[1] = 0x64

ですが、バイナリパーサーフォーマットでは先頭「16ビット」を読み取るように設定してあるので、無事「356」と読み取ることができました。

バイナリパーサーを使用したデータ削減量

さて、今回のバイナリパーサーを使用すると、どれくらいデータ量削減できるのでしょうか?

ここで作ったデバイスでは正確な削減量は計測していませんが、【新発表】SORACOM Air に省電力LPWAセルラー通信 「LTE-M」が追加、合わせて2種のデバイスや新機能をリリース - SORACOM公式ブログでは、

出力された JSON はスペースなどを削除して約 60 バイトになります。一方入力側のデータは 9 バイトです。この例では、おおよそ 85% のデータサイズ削減に成功しています。

と記載してあったり、SORACOM Beamによる通信量の削減効果を金額と電力量の数値で示す - Qiitaでは、

バイナリパーサーを使用することで98.1%のデータ量削減

という計測結果がありました。送信方法や送信データ内容にもよりますが、80%以上のデータ量削減が行えているようです。これはすごい 笑

終わりに

ここまでお読み頂きありがとうございました!

バイナリパーサーの実装が完了したことで、高頻度で定期的に通信をしてもあまり通信量のかからない、より実用的なデバイスに仕上がった気がします 笑
元々情報系ではない(機械系出身の)自分が、2進数やメモリの概念をゴリゴリ使うバイナリパーサーを理解するのは苦戦しましたが、使えるようになると、メモリの概念も理解でき、知識を深めながら実装できるとても良い機会になりました! 難しいですが、皆さんも是非一度挑戦してみるのはいかがでしょうか?

次回もお楽しみに!

製品紹介

当社が開発した、GNSS(全球測位衛星システム)を利用したIoT対応センチメートル級位置情報サービス「iChidori®」です。デバイス等の詳しい紹介はこちらよりご覧ください。

iChidoriバナー