##概要
SORACOM Air for セルラー のLTE-M回線を使って、センサから吸い上げたデータを、SORACOM Unified Endpointに送信します。
通信量を削減すると、通信料金を安くできるだけでなく、消費電力の節約にもつながります。
そこで、バイナリパーサーを使って、通信量の削減に挑戦してみます。
##開発環境
Arduino IDE: 1.8.9
Wio_cell_lib_for_Arduino
こちらのライブラリをフォークして、開発しております。
##SORACOMコンソールでバイナリパーサーを設定
コンソールにログイン後、左上の MENU を開き、 SORACOM Air for Cellular を選択します。
基本設定 内の SORACOM Air for Cellular 設定 を開きます。
すると、最下部に
バイナリパーサー設定 が出てきますので、ONにして保存します。
画像の右側の フォーマット 部分に、設定を記述していきます。
##バイナリパーサーのフォーマットを作成
SORACOMさんの解説記事を参考にしながら、フォーマットを作成していきます。
バイナリパーサーに送るデータは、「経度:139752101」、「緯度:35682501」です。
バイナリパーサーは floatにも対応していますが、使用しているライブラリの UDP通信のメソッドが charのみに対応しているので、 10^6をかけています。
フォーマットは、lat:offset:length:operations lng:offset:length:operationsという形になります。
###16進数への変換
経度: (139752101)10 = (85472A5)16
緯度: (35682501)10 = (22078C5)16
変換した16進数をくっつけます。
バイナリパーサーで変換するバイナリは、0x85472A522078C5となります。
このバイナリの1文字は、16進数ですので4bitsです。
そのため、 length = 4 * 8です。
###offsetの指定
経度・緯度を16進数で表したものはそれぞれ7桁ですが、送信されるデータは先頭に0が付与されて8桁です(1Byteごとに送信されるため)。
そのため、offsetは
lat: 0
lng: 4
となります。
###operationsの設定
こちらは、10^6で割れば良いので、/1000000です。
###作成されたフォーマット
以上より、作成されたフォーマットは、lat:0:uint:32:/1000000 lng:4:uint:32:/1000000です。
##バイナリへの変換
ここで私は、つまづいてしまいました。
心優しい方が、実装してくださっていたので、それを活用しております。
SORACOM バイナリパーサーで、位置情報送ってみよう!
私の失敗に関しては後ほど触れます。
バイナリパーサーでの変換に成功したソースコードはこちらです。
float lat = 139.752101;
float lng = 35.682501;
unsigned long int const lat_decimal = (unsigned long int)(lat * 1000000);
unsigned long int const lng_decimal = (unsigned long int)(lng * 1000000);
// Calculating the digits of lat, lng in hexadecimal.
unsigned long int lat_to_calc_digit = lat_decimal;
unsigned long int lng_to_calc_digit = lng_decimal;
unsigned int lat_digit_hex = 0;
unsigned int lng_digit_hex = 0;
while (lat_to_calc_digit!=0) {
lat_to_calc_digit /= 16;
lat_digit_hex++;
}
while (lng_to_calc_digit!=0) {
lng_to_calc_digit /= 16;
lng_digit_hex++;
}
int size_of_post_data_lat = (int)(ceil((double)lat_digit_hex/2));
int size_of_post_data_lng = (int)(ceil((double)lng_digit_hex/2));
// Convert into binary data to post to SORACOM binary parser.
// Binary parser configuration on SORACOM console: "lat:0:uint:32:/1000000 lng:4:uint:32:/1000000"
char *post_data_lat[size_of_post_data_lat];
char *post_data_lng[size_of_post_data_lng];
memcpy(&post_data_lat[0], Nectis.ConvertDecimalToHex(lat_decimal, size_of_post_data_lat), size_of_post_data_lat);
memcpy(&post_data_lng[0], Nectis.ConvertDecimalToHex(lng_decimal, size_of_post_data_lng), size_of_post_data_lng);
char post_data[] = {0x00};
memcpy(&post_data[0], post_data_lat, size_of_post_data_lat);
memcpy(&post_data[0]+size_of_post_data_lat, post_data_lng, size_of_post_data_lng);
char *NectisCellular::ConvertDecimalToHex(unsigned long int const decimal, int byte_size) {
// The last index of post_data is filled with 0x00 for print function.
memset(&HexConvertedFromDecimal[0], 0X00, sizeof(HexConvertedFromDecimal));
for (int i = 0; i < (int) byte_size; i++) {
// 16進数に変換し、4ビットずつ post_data を埋めていく
HexConvertedFromDecimal[i] = (decimal >> (8 * ((byte_size - 1) - i))) & 0xff;
}
return HexConvertedFromDecimal;
}
ポイントは、 memcpy() を用いて、取得した緯度経度のデータをくっつけているところです。
実際に送信したデータをArduinoIDEのシリアルモニタで確認すると、
Send:Tr⸮ x⸮
と文字化けしており、変換に成功したことが確認できます。
##送信データをSORACOMコンソールで確認
{"lat":139.752101,"lng":35.682501,"binaryParserEnabled":true}
となっており、バイナリパーサーで正確に変換できていることを確認できました。
##失敗したバイナリへの変換
こちらの記事にまとめております。
SORACOM Air のバイナリパーサーでうまくデータを変換できない。
##参考文献
https://blog.soracom.jp/blog/2018/09/27/lte-m-launch/