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

#はじめに
こんにちは、AITOYA株式会社の胡本（えべすもと）です！

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



#目次
- [これまでのダイジェスト](#これまでのダイジェスト)
- [バイナリパーサーとは](#バイナリパーサーとは)
- [バイナリパーサーのSORACOM側の設定方法](#バイナリパーサーのsoracom側の設定方法)
- [WioLTE側でのプログラムの構成](#wiolte側でのプログラムの構成)
- [実際の送信結果](#実際の送信結果)
- [バイナリパーサーを使用したデータ削減量](#バイナリパーサーを使用したデータ削減量)
- [終わりに](#終わりに)



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

[【第１回】【コロナ対策IoT】アルコール消毒状況がひと目で分かるデバイス作ってみた！](https://qiita.com/smile_besubesu/items/d32b35552096ae7125ba)
[【第２回】【SORACOM×コロナ対策】アルコール消毒状況から店の混雑度合いを可視化してみた](https://qiita.com/smile_besubesu/items/eb1344822f9b5c04d786)

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



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

……え？？？

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

一般的にデータを送る際は、主に ASCII コードと呼ばれる文字コード表に従ってテキスト形式で送信していたり、またそれを JSON というテキストベースのデータフォーマットに変換して送信しています。
[ASCIIコード表](http://www3.nit.ac.jp/~tamura/ex2/ascii.html)

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

また、さらに「 ” 」（0x22）や「 ; 」（0x59）が文字と文字の間につくことも多く、JSON のフォーマットを維持するバイト容量も必要なため、「20」という数値ひとつ送るにも多くのデータを使用してしまいます。

しかし、「バイナリー送信」という考え方では、最初に記述した通り、データ送信時には「0」と「1」のバイナリデータのままデータを送信し、そしてクラウド上で設定した独自の変換フォーマット（以下「バイナリパーサーフォーマット」と言います）を使用して JSON データやテキストデータに変換する機能です。

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

つまり、概要としては以下の図のようになります。
<img width="900" alt="binaryParser_detail" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/925b7185-9fae-b1d3-13c5-534baa9bf71a.png">
先程は「20」を例にしましたが、単純な bool 判定で「0をfalse」、「1をtrue」とバイナリパーサーフォーマットで決めておけば、データ送信上は「0」だけ（１ビット）を送るだけでデータの判別もできます。

**この方法によって、ASCII に変換する分や「 ” 」や「 ; 」といった表記を全て省くことができるので、データ量を８０～９０％！？とかなり圧縮することができます。 さらにデータ量を圧縮できるので通信料金をかなり下げることができます。**お得でしかないです……その他にも、**データを圧縮した分だけ通信時間も減るため、消費電力も削減されます。**お得尽くしです。

このようにデータ量の小さいバイナリデータを上手く変換してくれる便利な変換器が「バイナリパーサー」なのです。

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

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

#バイナリパーサーのSORACOM側の設定方法
さて、説明が長くなってしまいましたが、バイナリパーサーの設定をしていきましょう！
まずは SORACOM 側の設定です。ユーザーコンソール左上のメニューから「SIMグループ」をクリックし、
<img width="600" alt="SORACOM_group" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/ea640688-194c-b655-7618-d046c1ec041c.png">

自分が作成したSIMグループを選択します。
ここでは前回作成した「hand-wash」を選択しました。
（SIMグループを作成してない方は、下記リンクを参考にしてください）
[【SORACOM×コロナ対策】アルコール消毒状況から店の混雑度合いを可視化してみた「SORACOM 側の設定」 ](https://qiita.com/smile_besubesu/items/eb1344822f9b5c04d786#soracom%E5%81%B4%E3%81%AE%E8%A8%AD%E5%AE%9A)

その後、SIMグループ内の「SORACOM Air for Cellular設定」をクリックし、
<img="900" alt="SORACOM_Air-for-cellular" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/2352cf76-0c0e-1d58-0dc9-6febdfb59076.png">

バイナリパーサーフォーマットを「ON」に変更後、バイナリデータをどのように変換するかフォーマットを作成し記入します。
<img="900" alt="binary-parser-format" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/2bd1a77f-ac4e-3177-3a4b-1f546eb2c721.png">
今回フォーマットは

```
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](https://github.com/SeeedJP/WioLTEforArduino/blob/master/examples/soracom/soracom-harvest/soracom-harvest.ino)
この中のデータ送信のコードを変更していきます。

まず送信するデータを格納する変数を定義します。
今回はコード内45行目の **data** を書き換え、**byte data[13]** としました。この変数にビットのデータを格納していきます。
この時使われるのが「ビットシフト」という考え方です。これは文字通りビットを左右に移動させる方法です。
例えば、「00100110」というものを右に１だけシフトすると「00010011」となる。というものです。
詳しくはこちらをご覧ください。
[シフト演算子 - 演算子 - C言語 入門](https://www.javadrive.jp/cstart/ope/index7.html)

この方法を用いて、配列に順番にビットを詰めていきます。
８ビットごとに詰めていきたいので、右シフト演算子の >> を用いて詰めていきます。

今回のコードでは、１時間の総プッシュ回数を記録する変数を 
**int HourSprayCount = 0;** と定義し、data の各配列に

```
data[0] = (HourSprayCount >> 8) & 0xFF;
data[1] = HourSprayCount & 0xFF;
```
としていくことで数値を 16ビットに組み込んでいきます。
その後5分ごとの総プッシュ回数は **int MiniteSprayCount = 0;**
と定義し、data の各配列に

```
data[2] = MiniteSprayCount & 0xFF;
```
……と記述していくことでビットの配列で格納することができます。
最後に、１３バイト分送ることを設定するため、80行目の

```
Wio.SocketSend(connectId, data)
```
を変更し、

```
Wio.SocketSend(connectId, data, 13)
```
と記述して WioLTE 経由でデータ送信を行います。
これで WioLTE 側の設定が完了しました！


#実際の送信結果
さて、設定が終わったので、実際にデバイスを動かしてみましょう！
<img="500" alt="shiratoriMove" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/1b9262f7-055e-a712-927c-d237afed8d45.jpeg">
動かしたことで送信された WioLTE 側のデータはこちら！
<img="900" alt="result_WioLTE" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/6be72111-1923-7d75-2e3d-dea3a83d82cb.png">
今回はテストなので、総プッシュ回数は356回、５分ごとのプッシュ回数は22回に固定して送信しています。

シリアルモニター上では、１時間の総プッシュ回数は356回ですが、格納されたデータは、
**data[0]　(16進数表示) : 0x01**
**data[1]　(16進数表示) : 0x64**
と表示されています。

ただこれは間違いではありません。データは８ビットずつ送っています。

これは８バイト = 2の8乗 ＝ 256 なので、上位１バイトを格納している **data[0]** とは
**data[0] = 256 × 0x01 = 256 × 1 = 256**
となり、下位８バイトを格納している **data[1]** は
**data[1] = 0x64 = 100**
となります。なので、
**data[0] + data[1] = 256 + 100 = 356**
となり値としては合っています。

さて、これを SORACOM Harvest 上で確認した結果がこちら！
<img="1500" alt="result_SORACOM-Harvest" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/84ca6f1a-5836-4a65-ee39-42590e4419f0.png">
この結果から、バイナリパーサーを使用してデータ量を削減して送信できました！

また１時間の総プッシュ回数は送信時は
**data[0] = 0x01、data[1] = 0x64**
ですが、バイナリパーサーフォーマットでは先頭「１６ビット」を読み取るように設定してあるので、無事「356」と読み取ることができました。



#バイナリパーサーを使用したデータ削減量
さて、今回のバイナリパーサーを使用すると、どれくらいデータ量削減できるのでしょうか？
ここで作ったデバイスでは正確な削減量は計測していませんが、
[【新発表】SORACOM Air に省電力LPWAセルラー通信「LTE-M」が追加、合わせて２種のデバイスや新機能をリリース - SORACOM公式ブログ](https://blog.soracom.com/ja-jp/2018/09/27/lte-m-launch/) では、
「出力された JSON はスペースなどを削除して約 60 バイトになります。一方入力側のデータは 9 バイトです。この例では、おおよそ 85% のデータサイズ削減に成功しています。」と記載してあったり、

[SORACOM Beamによる通信量の削減効果を金額と電力量の数値で示す - Qiita](https://qiita.com/1stship/items/c8c6283940c1505ec918) では、「バイナリパーサーを使用することで98.1%のデータ量削減が行えた。」という記載があり、送信方法や送信データ内容にもよりますが、８０％以上のデータ量削減が行えているようです。
これはすごい 笑



#終わりに
ここまで読んでいただきありがとうございました！
バイナリパーサーの実装が完了したことで、高頻度で定期的に通信をしてもあまり通信量のかからない、より実用的なデバイスに仕上がった気がします 笑

元々情報系ではない（機械系出身の）自分が、２進数やメモリの概念をゴリゴリ使うバイナリパーサーを理解するのは苦戦しましたが、使えるようになると、メモリの概念も理解でき、知識を深めながら実装できるとても良い機会になりました！
難しいですが、皆さんも是非一度挑戦してみるのはいかがでしょうか？

当社は、cm級位置情報測位デバイスの「iChidori®（いちどり）」シリーズを始めとした、位置情報ソリューションをお客様に提供している企業です。 製品の説明は[こちら](https://www.aitoya.com/#products) をご覧ください！
<img="900" alt="よい、いちどりを。" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287136/f7892af8-541e-32f5-fbf3-8b95d6c9d027.jpeg">

本記事は、AITOYA株式会社HPに掲載している内容と同一のものです。→[AITOYA株式会社HP](https://www.aitoya.com/)