#はじめに
こんにちは、AITOYA株式会社の胡本(えべすもと)です!
お待たせしました!「アルコール消毒状況がひと目で分かるIoTデバイス」シリーズ第3弾です!
今回は「バイナリパーサー」を使用してデータ量を少なくして送信できるようにしてみようと思います。
それでは始めていきましょう!
#目次
#これまでのダイジェスト
これまでの記事では、「アルコール消毒状況がひと目で分かる」デバイスの作成手順や SORACOM Harvest を使ったクラウド管理の手順を記載してきました。気になる方はこちらのリンクからご覧ください。
【第1回】【コロナ対策IoT】アルコール消毒状況がひと目で分かるデバイス作ってみた!
【第2回】【SORACOM×コロナ対策】アルコール消毒状況から店の混雑度合いを可視化してみた
今回はこの続きで、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×コロナ対策】アルコール消毒状況から店の混雑度合いを可視化してみた「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
この中のデータ送信のコードを変更していきます。
まず送信するデータを格納する変数を定義します。
今回はコード内45行目の 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回ですが、格納されたデータは、
data[0] (16進数表示) : 0x01
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進数やメモリの概念をゴリゴリ使うバイナリパーサーを理解するのは苦戦しましたが、使えるようになると、メモリの概念も理解でき、知識を深めながら実装できるとても良い機会になりました!
難しいですが、皆さんも是非一度挑戦してみるのはいかがでしょうか?
当社は、cm級位置情報測位デバイスの「iChidori®(いちどり)」シリーズを始めとした、位置情報ソリューションをお客様に提供している企業です。 製品の説明はこちら をご覧ください!
本記事は、AITOYA株式会社HPに掲載している内容と同一のものです。→AITOYA株式会社HP