SORACOM Harvest DataのデータをCSV形式で自動取得する（中編）


# 概要
SORACOM Harvest Dataのデータをダウンロードし、CSVで取得する中編です。
[前編](https://qiita.com/ozk009/items/c880d234a4b91f4882d0)を読んでない方は[前編](https://qiita.com/ozk009/items/c880d234a4b91f4882d0)からお読みください。

# 取得するデータ
取得するデータは以下のレシピで取得できるGPSマルチユニットの温湿度データとします。

https://soracom.jp/recipes_index/2962/

今回の手法でやる場合は[バイナリパーサー設定](https://users.soracom.io/ja-jp/docs/binary-parser/predefined-format/#gpsmultiunit)が必要となります。
SIMグループ設定画面で「SORACOM Air for セルラー設定」の「バイナリパーサー」をONにして、フォーマットを「`@gpsmultiunit`」として保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/13713616-437e-117b-ddcf-48af1d9d3d05.png)


またAPIで[SIM ID](https://users.soracom.io/ja-jp/resources/glossary/#sim-id)が必要となります。
SIM管理画面から対象のSIMのIDをメモしておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/8ce3c816-0ed1-400d-cc3c-e18e0e00990d.png)
SIM IDの列が表示されない場合、以下手順で表示できます。
1. SIM管理画面右上部の歯車アイコンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/b0c54f6c-ea8f-0786-1adf-1486d3ae68aa.png)
1. SIM IDをONにして、「閉じる」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/29507589-6dfe-4078-3147-59f58a8c5a7e.png)


# JSONデータダウンロード
ここからTalend Open Studio（以降TOSとします）でSORACOM Harvest DataをJSONでダウンロードします。

## ジョブ作成
1. TOSを起動、プロジェクトを選択して、画面が表示されたら「Job Design」を右クリックし、「Create job」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/46a05ed9-2ce6-5c95-cdad-465c328af5b9.png)

1. Nameを「HarvestData」として「Finish」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/0f87d998-0f53-f4c9-fbca-86462892d5fa.png)

## APIキーとトークンの取得（認証）
SORACOM APIを使うにはまず、認証を行い、実行に必要なAPIキーとトークンを取得してからデータダウンロードを実施します。

1. 作成したジョブをダブルクリックして開いたら、右のパレット検索で「tREST」を出して、デザインワークスペースに置きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/c99a1ba9-cc7d-3c3c-f302-b643b568ee4a.png)

1. tRESTをダブルクリックすると、初回のみ警告が表示されるので、「Install...」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/033d0d9f-b555-8c50-e96f-86fae5594897.png)

1. 表示された画面で「Download and install all modules available」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/3b261587-66a9-c2c5-2143-9a83ef378b2f.png)

1. tRESTの各属性を設定し、tLogRowとつなぐ
    - URL：`"https://api.soracom.io/v1/auth"`
    - HTTP Method：`POST`
    - HTTP Header（name）：`"Content-Type"`
    - HTTP Header（value）：`"application/json"`
    - HTTP Body：`"{\"authKeyId\": \"keyId-で始まるSAMユーザーの認証キーID\", \"authKey\": \"secret-で始まるSAMユーザーの認証シークレット\"}"`[^1]
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/4d614a2a-fe11-5eef-313d-f6f97b3d05b6.png)

1. この状態で実行すると、apiKeyとoperatorId、tokenのJSONっぽい文字列が取得できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/3692753b-8417-e032-f72c-4f3e2678888d.png)

1. 取得したJSON文字列をJSONデータに変換するため、tLogRowを削除し、tExtractJSONFieldsを置いて、「Edit Schema」の隣の「...」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/a28629ed-3eb7-2a20-f5ac-3aaeb7cef904.png)

1. 設定画面が表示されるので、カラムを3つ追加し、「apiKey」「operatorId」「token」とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/4664fda4-3b96-01ed-b192-c77b1d671bba.png)

1. 追加した列の値をそれぞれ「"apiKey"」「"operatorId"」「"token"」とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/332d69a1-4010-7bf3-1f40-2832a76a9c49.png)

1. tLogRowを追加して実行すると、JSONに変換されたことが確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/7d8c93da-7a77-52c6-189c-44215ac0e25e.png)

1. tJavaRowで認証情報（APIキーとトークン）をグローバル変数にセットする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/22d94d3b-07d7-8c10-dae0-34d50352e7b4.png)
```java
globalMap.put("apiKey", row3.apiKey);
globalMap.put("token", row3.token);
```

以上で認証情報の取得が完了です。

## データの取得
ここから少し難易度が上がります。
先ほど取得した認証情報（APIキーとトークン）を使って、Harvest Dataからデータを取得します。

1. 初期処理を行うため、tJavaを上に追加し、コードを記入して、先ほど作成した認証サブジョブに「OnSubjobOk」でつなぎます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/279aea76-ed47-1268-552f-73f459c1d3bc.png)
    ```java
    // 開始時刻と終了時刻をセット
    String from_str = "2023/07/23 0:00:00";
    String to_str = "2023/07/23 23:59:59";
    
    // 開始時刻と終了時刻を日付に変換
    Date from_dt = TalendDate.parseDate("yyyy/MM/dd hh:mm:ss", from_str);
    Date to_dt = TalendDate.parseDate("yyyy/MM/dd hh:mm:ss", to_str);
    
    // 開始時刻と終了時刻をUNIX時間に変換
    long from_lng = (long)from_dt.getTime();
    long to_lng = (long)to_dt.getTime();
    
    // グローバルにセット
    globalMap.put("from", from_lng);
    globalMap.put("to", to_lng);
    ```

1. 続いて認証サブジョブの下にtRESTを置いてOnSubjobOkで繋ぎ、設定値を設定する。
    - URL：`"https://api.soracom.io/v1/sims/（SIM ID）/data?from=" + globalMap.get("from").toString() + "&to=" + globalMap.get("to").toString() + "&sort=asc&limit=5000"`
    - HTTP Headers：
        |name|value|
        |:-:|:-:|
        |"X-Soracom-API-Key"|(String)globalMap.get("apiKey")|
        |"X-Soracom-Token"|(String)globalMap.get("token")|

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/3a230daa-f8f6-7e6b-9427-bef4bb80b65d.png)

1. tLogRowをつないで実行すると、それっぽい値が取得できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/37e5c84f-cba9-ab44-56c7-79082b9f35e6.png)

1. tLogRowを削除し、tExtractJSONFieldsを置いて取得したデータを時刻とcontentに分離する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/d5ec3816-2410-9ca8-a0c8-29a3aa20e2b3.png)

1. 取得したデータはUnixTimeになっているので、tMapで変換する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/56de4abd-fcf8-ed63-6ae7-7242b8b4b371.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/8bdd60f0-b1b0-8f48-13d3-d081496bccf5.png)
time列（Long）をdatetime列（Date）に変換する。
    ```java
    new java.util.Date((long)(row5.time))
    ```
    Date-Patternは`"yyyy-MM-dd HH:mm:ss"`にする。

1. tLogRowをつなげて動かすと、datetimeとcontentに分かれて出力されていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/92c802a9-d6db-8ac4-cfd9-1e1e0b58329f.png)

1. 最後にtFileOutputJSONでファイルに書き出す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/cf73ab7d-06e2-8ccc-e025-4d6c659fdb96.png)
**※ TOSのフォルダは\（円マークやバックスラッシュ）ではなく、/（スラッシュ）で表記する必要があります。**

以上でHarvest DataからJSONが以下のような形でダウンロードできます。
```json
{
  "data": [
    {
      "datetime": "2023-07-23 20:30:00",
      "content": "{\"lat\":null,\"lon\":null,\"bat\":3,\"rs\":4,\"temp\":27.3,\"humi\":57.1,\"x\":null,\"y\":null,\"z\":null,\"type\":0,\"binaryParserEnabled\":true}"
    },
    {
      "datetime": "2023-07-23 20:30:55",
      "content": "{\"lat\":null,\"lon\":null,\"bat\":3,\"rs\":4,\"temp\":27.1,\"humi\":57.5,\"x\":null,\"y\":null,\"z\":null,\"type\":0,\"binaryParserEnabled\":true}"
    },
…
  ]
}
```
**※ 実際には1行です。**


## JSONデータのCSV変換
PythonでJSONデータをCSVに変換します。
Pythonおよびpandasライブラリをインストールしたパソコンに以下のコードのファイルを「soracom_json_csv.py」という名前で保存します。
```python
import os
import sys
import json
from pandas import json_normalize

def json_to_csv(json_file, csv_file):
	json_open = open(json_file, 'r', encoding='UTF-8')
	json_data = json.load(json_open)['data']
	
	# contentの文字列を変換
	for i in range(len(json_data)):
		json_data[i]["content"] = json.loads(json_data[i]["content"])
	
	# CSV変換と保存
	norm = json_normalize(json_data)
	norm.to_csv(csv_file)

if __name__ == "__main__":
	args = sys.argv
	if len(args) < 2:
		print(f"エラー: ファイルが指定されていません。 （引数：{len(args) - 1}）")
		sys.exit(1)
	
	file_name = args[1]
	if not os.path.exists(file_name):
		print(f"エラー: 指定されたファイルが存在しません。 ({file_name})")
		sys.exit(1)
	
	json_file = file_name
	csv_file = json_file.replace(".json", ".csv")
	json_to_csv(json_file, csv_file)
```
コマンドプロンプトで引数にJSONファイルのパスを与えて実行すると、拡張子がCSVのファイルが作成されます。
```
> python soracom_json_csv.py （ダウンロードしたJSONファイルのパス）
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/db1d747d-abf2-7942-e53c-3cbd1f274469.png)

以上でCSVファイルの変換ができるようになりました。

[次回](https://qiita.com/ozk009/items/c32c1fd4aff371f76428)は最終回で、JSONダウンロードとCSV変換を自動実行できるようにします。

[^1]: SAMユーザーの認証キーIDと認証シークレットは[前編](https://qiita.com/ozk009/items/c880d234a4b91f4882d0#soracom%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89)で取得したもの