SORACOM Air のバイナリパーサーを使ってみた


概要

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 バイナリパーサーで、位置情報送ってみよう!

私の失敗に関しては後ほど触れます。

バイナリパーサーでの変換に成功したソースコードはこちらです。

grove-gps.ino
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);
NectisCellular.cpp
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 のバイナリパーサーでうまくデータを変換できない。

参考文献