クリスマスにSORACOMからジェイソンを呼び出した話(メタデータサービスは使える)

#なんの話？
SORACOM Air メタデータサービスに感動して、やってみた話です。
SORACOMのTechnology Campのmaxさんのセッションで紹介されていました。

- SORACOM Technology Camp 2018 アドバンストラック2 | 売れば売るほど大変"を防ぐ！「IoT デバイス初期設定の工数削減」手法
https://www.slideshare.net/SORACOM/soracom-technology-camp-2018-2-iot-123686996/20

- 【SORACOM Technology Camp 2018 レポート】「売れば売るほど大変”を防ぐ！「IoT デバイス初期設定の工数削減」手法」#SORACOM ｜ DevelopersIO
https://dev.classmethod.jp/soracom/technology-camp-2018-fall-a2/

#何それ？
- SORACOMのユーザーコンソールを開いて
- SIMのチェックを入れて
- 「詳細」を押して
- 「タグ」のタブを開いて
- こんな風に設定したら
<img width="898" alt="meta.png" src="https://qiita-image-store.s3.amazonaws.com/0/307347/0c1ea765-ed47-d7b0-c9ca-b78e4d9800ca.png">

- Air SIMを挿した端末からこのURLでJSONが呼び出せる。
http://metadata.soracom.io/v1/subscriber.tags.conf

#何が便利なの？
端末に設定するコードを統一できる。

もう一回言います。

**端末に設定するコードを統一できる！！！！！**

いちいち端末側で定数をdefineしなくても、
SORACOMのコンソール側から自由に値を変更できる。
これがかなり使える。

#サンプルコード
WioLTEで定数として設定していた値を、メタデータサービスで取得した値に書き換えます。
超音波センサーの値をHarvestにアップロードする間隔を、20秒から5秒に変更します。
**SORACOMからジェイソンを呼び出します、クリスマスに。**

```c:usrtosoracom.ino
#include <WioLTEforArduino.h>
#include <ArduinoJson.h>
#include <Ultrasonic.h>
#include <stdio.h>

#define ULTRASONIC_PIN (WIOLTE_D38)

Ultrasonic UltrasonicRanger(ULTRASONIC_PIN);
WioLTE Wio;

int interval_sec=20000;
int receive_timeout_sec=10000;

void setup() {
  delay(200);

  SerialUSB.println("");
  SerialUSB.println("--- START ---------------------------------------------------");

  SerialUSB.println("### I/O Initialize.");
  Wio.Init();

  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyLTE(true);
  delay(500);

  SerialUSB.println("### Turn on or reset.");
  if (!Wio.TurnOnOrReset()) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Connecting to \"soracom.io\".");
  if (!Wio.Activate("soracom.io","sora","sora")) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Setup completed.");

  SerialUSB.println("### Get Interval...");
  char metadata[2048];
  
  if (Wio.HttpGet("http://metadata.soracom.io/v1/subscriber.tags.conf", metadata, sizeof(metadata))<0) {
    SerialUSB.println("### ERROR! ###");
    return;
  }
  
  SerialUSB.println("### Metadata:");
  SerialUSB.println(metadata);
  
  StaticJsonBuffer<2048> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(metadata);
  
  if (!root.success()) {
    SerialUSB.println("parseObject() failed");
    return;
  }else{
    SerialUSB.println("parseObject() success");

    interval_sec=atoi(root["interval_sec"]);
    receive_timeout_sec=atoi(root["receive_timeout_sec"]);

    SerialUSB.print("interval_sec:");
    SerialUSB.println(interval_sec);
    SerialUSB.print("receive_timeout_sec:");
    SerialUSB.println(receive_timeout_sec);
  }
}

void loop() {
  char data[100];
  long distance;

  distance = UltrasonicRanger.MeasureInCentimeters();

  SerialUSB.println("### Open.");
  int connectId;
  connectId = Wio.SocketOpen("harvest.soracom.io", 8514, WIOLTE_UDP);
  if (connectId < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err;
  }

  SerialUSB.println("### Send.");
  sprintf(data, "{\"distance\":%ld}", distance);
  SerialUSB.print("Send:");
  SerialUSB.print(data);
  SerialUSB.println("");
  
  if (!Wio.SocketSend(connectId, data)) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }

  SerialUSB.println("### Receive.");
  int length;
  length = Wio.SocketReceive(connectId, data, sizeof (data), receive_timeout_sec);
  if (length < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }
  if (length == 0) {
    SerialUSB.println("### RECEIVE TIMEOUT! ###");
    goto err_close;
  }
  SerialUSB.print("Receive:");
  SerialUSB.print(data);
  SerialUSB.println("");

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

err:
  SerialUSB.println("### Wait.");
  delay(interval_sec);
}
```
#ちなみに
##SIMグループ全体に設定することもできる
「ユーザーデータ」という仕組み：下記のURLで取得できる。
http://metadata.soracom.io/v1/userdata

→SIMグループ全体の接続先をメタデータに仕込んでおけば、端末で設定を変える必要がない。
例)
{"host":"funnel.soracom.io", "port":23080, "type":"WIOLTE_UDP"}

<img width="998" alt="group.png" src="https://qiita-image-store.s3.amazonaws.com/0/307347/c2837a8a-3964-8140-ee84-2604e78c1654.png">

#さいごに
**無事、アップロード間隔が自動的に変わり、**
**Harvestにアップロードできました。**
![log.png](https://qiita-image-store.s3.amazonaws.com/0/307347/0e77fd78-57e2-e0dc-0c18-6d24c5a7d7a4.png)
<img width="1089" alt="graph.png" src="https://qiita-image-store.s3.amazonaws.com/0/307347/4c64ab7c-10af-ba8e-a4b1-818e064251bc.png">

**メリークリスマス！**

#参考(にさせていただきました)
- IoTは小さく始めて素早く改善しよう！「Grove IoT スターターキット for SORACOM」とクラウドの本格連携 (6/6)：CodeZine（コードジン）
https://codezine.jp/article/detail/10675?p=6

- SORACOM Air メタデータサービスのご紹介 - SORACOM Blog
https://blog.soracom.jp/blog/2015/11/27/air-metadata/

- SORACOM Air メタデータサービス機能を使用する | Getting Started | SORACOM Developers
https://dev.soracom.io/jp/start/metadata/

- Wio LTEとAWSを連携させ、IoTサービスを開発する - IoT.kyoto
https://iot.kyoto/integration_case/2018/07/13/3739/