Wio LTEでGPSモジュールからデータを拾ってSORACOM Harvestへ届ける

# Wio LTEでGPSモジュールからデータを拾ってSORACOM Harvestへ届ける

[Wio LTEの開発環境セットアップとLチカまで](https://qiita.com/cactanaka/items/6ca0bcf3964c8146ed52)に従ってWIo LTEの開発環境のセットアップが終わっている状態から始めます。

## 必要なもの

- Wio LTE本体
- 開発用のPC
  - テスト環境はWindows10 64bitです
- PCとWioLTEをつなぐUSBケーブル

## SORACOM側の準備

[詳細な部分については公式サイトの解説を読んでください。](https://dev.soracom.io/jp/start/harvest/)

### SORACOMのユーザーコンソールにログインする

[SORACOM ユーザーコンソール](https://console.soracom.io/#/?coverage_type=jp)にログインします。

### Harvest用のグループを作成してSIMをグループに所属させる

WioLTEに挿入したSIMのチェックボックスにチェックをつけて、操作▼ボタンから所属グループの変更を選択します。
ウィンドウが開くので、新しい所属グループから適当な名前でグループを作成し、所属させます。

### Harvest用のグループでHarvestを利用できるようにする

リストの中でWio LTEのSIMに新しいグループが割り当てられると、グループ名がリンクになります。
グループ名のリンクをクリックしてグループの設定画面を開きます。
グループの設定画面から、> SORACOM Harvest 設定 を選択し、スライドスイッチをクリックしてharvestをONにして保存ボタンを押します。
確認ダイアログが表示されるので、内容を確認してOKボタンを押します。

## Wio LTEからHarvestへデータを送る

### Wio LTEにGPSモジュールを接続する

Wio LTE本体のD38ポートに[Grove - ボタン](https://www.seeedstudio.com/Grove-Button-p-766.html)を接続します。
Wio LTEのUARTポートに[Grove - GPS](https://www.seeedstudio.com/Grove-GPS-p-959.html)を接続します。
そしてアンテナ2本を接続します。

### サンプルコードを切ったり貼ったりして動きそうなスケッチを作る

スケッチ例のWio LTE for Arduinoを参考に、関連しそうな機能を切ったり貼ったりして動きそうなスケッチを作成して書き込みます。

```C:WIOLTEGPS.ino

#include <WioLTEforArduino.h>

#define BUTTON_PIN      (WIOLTE_D38)
#define GPS_OVERFLOW_STRING "OVERFLOW"
#define INTERVAL        (1000)
#define RECEIVE_TIMEOUT (10000)

// for Wio LTE
WioLTE Wio;

// for pushbutton
int buttonState;

// for GPS module
HardwareSerial* GpsSerial;
char GpsData[200];
char GpsDataLength;

// for SORACOM connect
int connectId;

void setup() {
    delay(200);
    SerialUSB.println("Start Initialize.");

    // for push button
    buttonState = 0;
    pinMode(BUTTON_PIN, INPUT);

    // for GPS module
    GpsBegin(&Serial);

    // Wio LTE Init
    Wio.Init();

    // Power to Grove connecter
    Wio.PowerSupplyGrove(true);

    // Power to LTE module, LTE module need 500ms delay after module power on
    Wio.PowerSupplyLTE(true);
    delay(500);

    SerialUSB.println("Turn on or reset.");
    if (!Wio.TurnOnOrReset())
    {
      SerialUSB.println("### ERROR : TURN ON OR RESET ###");
      return;
    } else {
      SerialUSB.println("### POWER : LTE ON ###");
      delay(500);
    }

    SerialUSB.println("### Connecting to \"soracom.io\".");
    if (!Wio.Activate("soracom.io", "sora", "sora")) 
    {
      SerialUSB.println("### ERROR : CONNECT FAILED ###");
      return;
    } else {
      SerialUSB.println("### LTE : CONNECT TO SORACOM ###");
    }

    SerialUSB.println("### Initialized");
}

void loop() {
    // read GPS data from UART line :
    const char* data = GpsRead();

    // read the state of the pushbutton value :
    buttonState = digitalRead(BUTTON_PIN);

    // Write GPS data when button pushed
    if (buttonState != 0)
    { 
        Wio.LedSetRGB(30, 30, 30);
        if (data != NULL && strncmp(data, "$GPGGA,", 7) == 0) 
        {
            // Display data for debug
            SerialUSB.println(data);
            // LED blink to Blue for guide
            Wio.LedSetRGB(0, 0, 100);
            SendDataToSoracom(data);
        } else{
            // LED blink to Green for guide
            Wio.LedSetRGB(0, 100, 0);
        }
    } else {
        // Reset LED blink 
        Wio.LedSetRGB(0, 0, 0);
    }
    
    delay(100);
}

void GpsBegin(HardwareSerial* serial)
{
    GpsSerial = serial;
    GpsSerial->begin(9600);
    GpsDataLength = 0;
}

const char* GpsRead()
{
    while (GpsSerial->available()) {
      char data = GpsSerial->read();
      if (data == '\r') continue;
      if (data == '\n') {
        GpsData[GpsDataLength] = '\0';
        GpsDataLength = 0;
        return GpsData;
      }
    
    if (GpsDataLength > sizeof (GpsData) - 1) { // Overflow
        GpsDataLength = 0;
        return GPS_OVERFLOW_STRING;
    }
    GpsData[GpsDataLength++] = data;
  }

  return NULL;
}

bool SendDataToSoracom(const char* dataToSend)
{
    connectId = Wio.SocketOpen("harvest.soracom.io", 8514, WIOLTE_UDP);
    if (connectId < 0)
    {
        SerialUSB.println("### ERROR : Fail socket open ###");
        goto err;
    }

    if (!Wio.SocketSend(connectId, dataToSend))
    {
        SerialUSB.println("### ERROR : Fail data send ###");
        goto err_close;
    }

    int length;
    char receiveData[100];
    length = Wio.SocketReceive(connectId, receiveData, sizeof (receiveData), RECEIVE_TIMEOUT);


    if (length < 0) 
    {
        SerialUSB.println("### ERROR! ###");
        goto err_close;
    }

    if (length == 0)
    {
        SerialUSB.println("### RECEIVE TIMEOUT! ###");
        goto err_close;
    }

err_close:
    SerialUSB.println("### Close.");
    if (!Wio.SocketClose(connectId))
    {
        SerialUSB.println("### ERROR! ###");
        goto err;
    }

err:
    delay(INTERVAL);
}

```

### SORACOM Harvestへデータを送る

Wio LTEにスケッチを書き込み終えたら、RSTボタンを押して通常モードに切り替えます。
しばらくするとRSTボタンの近くの赤いLEDが点滅し始めますので、適当なタイミングでD38に接続したプッシュボタンを押します。
ボタンを押すとLEDがグリーンかブルーに光ります。ブルーに光るまでプッシュボタンを押し続けてください。
(実測値では5～6回転に1回はデータ転送のタイミングが回ってきますので、1秒以内で1回は転送されると思われます。)

## SORACOM Harvestでデータを見る

まず[SORACOM ユーザーコンソール](https://console.soracom.io/#/?coverage_type=jp)にログインします。
リストからWio LTE用のSIMの左チェックボックスにチェックを入れ、操作▼からデータを確認を開きます。

画面中央に No Data Available と出ますが、落ち着いて画面をスクロールします。
下の方に 一次処理済みデータ という項目があり、ここに送信したデータが蓄積されているのが確認できると思います。
{"value":"$GPGGA, ..."} という形になっていれば、正常に送信されています。
これはGPSで取得した情報が、未加工のままの形式(NMEA Format)で送信されているためです。このままではHarvestのマップ機能とは連携できませんが、lat/lon形式に変換するライブラリを噛ませればHarvestの画面上でそのまま扱えるようになるはずです。

## 参考資料

[Wio LTE Reference](https://github.com/SeeedJP/WioLTEforArduino/wiki/Home-ja)
[Wio LTE API Reference](https://github.com/SeeedJP/WioLTEforArduino/wiki/Reference-ja#turnonorreset)
[SORACOM Blog - SORACOM Harvest で位置情報データをサポートしました](https://blog.soracom.jp/blog/2018/04/26/harvest-map-support/)