Wio LTEでGPS情報を取得した情報をSORACOM Harvestの地図プレビューで見る

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

[前回作成した切り貼りスケッチ](https://qiita.com/cactanaka/items/96521b9139793f24c465)に[TinyGPS++](http://arduiniana.org/libraries/tinygpsplus/)というNMEAフォーマットを扱いやすくしてくれるライブラリを噛ませて、Harvestの地図プレビューで直接扱えるように書き換えます。

## 必要なもの

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

## ソースコード改修

### TinyGPS++のダウンロード

[GitHubのTinyGPS++のページ](https://github.com/mikalhart/TinyGPSPlus/releases)から Source code (zip) をダウンロードします。
ダウンロードしたファイルは分かりやすい場所に保存してください。

### Arduino IDEにライブラリを登録する

Arduino IDEを起動し、「スケッチ」から「ライブラリをインクルード」へ進み、「.ZIP形式のライブラリをインストール」を選択します。
ファイル選択ウィンドウが開くので、先ほどダウンロードしてきたTinyGPSPlus-n.n.n.zip(執筆時点ではTinyGPSPlus-1.0.2.zip)を選択して「開く」ボタンを押します。

### コードを更新する

前回のコードを以下のように改修します。
(かなり変わってしまったので、上書きしてください。)

```C:WIOLTEGPS.ino

#include <WioLTEforArduino.h>
#include <TinyGPS++.h>
#include <stdio.h>
#include <string.h>

#define BUTTON_PIN      (WIOLTE_D38)
#define INTERVAL        (1000)
#define RECEIVE_TIMEOUT (10000)

// for Wio LTE
WioLTE Wio;

// for pushbutton
int buttonState;

// for GPS module
HardwareSerial* GpsSerial;
char GpsDataLength;

// for SORACOM connect
int connectId;

// for TinyGPS++
TinyGPSPlus gps;

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 :
    GpsReadWithTinyGPS();

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

    // mode select GPS or LTE-Base :
    if(gps.location.isValid())
    {
        // Bring for GPS mode
        Wio.LedSetRGB(0, 0, 100);
        if(buttonState != 0)
        {
            const char* dataByGPS = SendDataCreatorViaGPS();
            SerialUSB.print("INFO : Send SORACOM to : "); SerialUSB.println(dataByGPS);
            Wio.LedSetRGB(0, 100, 0);
            SendDataToSoracom(dataByGPS);
        }
    } else {
        // Bring for LTE-base mode
        Wio.LedSetRGB(100, 0, 0);
        if(buttonState != 0)
        {
            const char* dataByLTEbase = SendDataCreatorViaLTE();
            SerialUSB.print("INFO : Send SORACOM to : "); SerialUSB.println(dataByLTEbase);
            Wio.LedSetRGB(0, 100, 0);
            SendDataToSoracom(dataByLTEbase);
        }
    }
}

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

void GpsReadWithTinyGPS()
{
    while (GpsSerial->available()) {
        if(gps.encode(GpsSerial->read())){
            displayGPSInfo();
        }
    }
}

void displayGPSInfo(){
    SerialUSB.println("");
    SerialUSB.print("LAT= "); SerialUSB.println(gps.location.lat(), 6);
    SerialUSB.print("LON= "); SerialUSB.println(gps.location.lng(), 6);
}

const char* SendDataCreatorViaGPS()
{
    return SendDataCreator(gps.location.lat(), gps.location.lng());
}

const char* SendDataCreatorViaLTE()
{
    double baseLatitude;
    double baseLongitude;
    if(!Wio.GetLocation(&baseLongitude, &baseLatitude))
    {
        baseLatitude = 00.0000;
        baseLongitude = 000.000;
    }
    SerialUSB.print("LTE-Base_LAT= "); SerialUSB.println(baseLatitude);
    SerialUSB.print("LTE-Base_LON= "); SerialUSB.println(baseLongitude);

    return SendDataCreator(baseLatitude, baseLongitude);
}

const char* SendDataCreator(double argLatitude, double argLongtitude)
{
    // Return values format is follows as JSON
    // {\"lat\":*,\"lng\:*"}

    char* returnPointer;
    char workBuffer[200] = "{\"lat\":\0";

    char latitude[32];
    snprintf(latitude, 16, "%f", argLatitude);

    returnPointer = strcat(workBuffer, latitude);
    returnPointer = strcat(workBuffer, ",\"lng\":");

    char longitude[32];
    snprintf(longitude, 16, "%f", argLongtitude);

    returnPointer = strcat(workBuffer, longitude);
    returnPointer = strcat(workBuffer, "}");

    return returnPointer;
}

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);
}


```

## 実際に動作させてデータを取得する

1. LEDが青く光るまで待ちます
2. LEDが青く光ったらプッシュボタンを押します
3. SORACOM Harvestの画面でデータが来ていることを確認します

### LEDの光り方

- 青 : GPS測位のデータが利用できる状態
- 緑 : SORACOMへデータを送信している状態
- 赤 : GPSが利用できないため、LTEで接続している基地の基地局情報を送信する状態

### SORACOM Harvestでの位置情報の確認

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

まず画面右側の方にある入力エリアから日付を設定して検索ボタンを押します。

次に画面左側にある選択ボタン群のうち、一番右にある、下向きに尖った丸のようなアイコンをクリックします。

そうすると画面中央の地図上に、位置情報を取得した場所がプロットされます。

### 注意事項

- GPSは測位のために4つ以上のGPSからデータを受信する必要がありますので、起動後しばらく待つ必要があります
  - オフィス街でも10分ほど歩いていればGPSが利用可能になるはずです
- USBから給電する場合はUSB 3.0以上のポートを利用する
  - USB 2.1以下のポートでは給電できていない場合があります