SORACOM Inventory を使って SORACOM Harvest => SORACOM Lagoon に格納するデータを加工する

# はじめに - SORACOM Lagoon とは
SORACOM Lagoon (以下 Lagoon) は Grafana をベースとした、可視化サービスです。何ぞやという方はまず[こちら](https://dev.soracom.io/jp/start/lagoon-dashboards/)を読んでもらえればと思います。

Lagoon のデータソースは SORACOM Harvest Data (以下 Harvest) に格納されたデータです。簡単に図にすると以下のようなイメージです。温度湿度センサーで取った単純な情報も Lagoon を使うととてもおしゃれになります。
![whatIsHarvest+Lagoon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/3395d74d-01c2-53be-7f1f-feebced32d83.png)

# 解決したい課題
Lagoon を使いこなしてくると次に浮かぶ欲望は、「℃ (摂氏) 表示を F (華氏) に変換できないかな...」とか「温度・湿度を組み合わせて不快指数とか表示できないかな...」というカスタマイズになるかと思います。私はそういう欲望がわきました。

残念ながら、2019 年 10 月時点においては、Harvest のデータを加工する機能は Lagoon にはありません。またデータソースは Harvest 以外を選べないため、たとえば計算結果を外部のデータベースサービスに置いてそれを Lagoon に取り込んで...とかもできません。(この辺りは今後に期待！！) とはいえ、簡単に可視化できる Lagoon は捨てがたい。

そこで回避策の一案として考えたのが SORACOM Inventory (以下 Inventory) を利用する方法です。

# SORACOM Inventory を使って解決するイメージ
Inventory は、デバイス管理のためのサービスです。デバイス登録の時だけ SORACOM SIM 経由で SORACOM プラットフォームから認証情報を受け取り、その後は Wi-fi 経由とかでも SORACOM の提供する LwM2M サーバとやり取りできます。サービスの説明は[こちら](https://soracom.jp/services/inventory/)

しかし、上記 URL の中にこんなリンクがありました。

[デバイスIDとデバイスシークレットを使用してHarvestにデータを送信する](https://dev.soracom.io/jp/start/inventory_harvest_with_keys/)

こちらを読んでみると、なんと SORACOM SIM 経由でなくともデバイスを登録して認証情報を受け取れ、その認証情報を用いて Harvest に格納できるとのことです。
また、Harvest に格納されたデータは API でダウンロードできます。
つまり下記の図のようなことが可能なのでは...？と思いました。
![useInventry+Harvest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/ef622c7c-a3e6-9517-ac9d-a207aa78eb25.png)
というわけで、やってみようと思います。

# 注意点
- Harvest, Lagoon の費用に加えて Inventory の費用も掛かります。無料枠もありますので、ご利用は計画的に！
https://soracom.jp/services/inventory/price/

- SORACOM の SIM <=> Harvest 間の通信は閉域網ですが外部サーバにダウンロードする際や外部サーバから Harvest へアップロードする際はインターネット経由となります。特に外部サーバのセキュリティ担保にはご注意ください。

# 実装

今回は外部サーバにて「直近 5 分平均の温度・気温・不快指数」を計算して Inventory 経由で Harvest に格納することにしました。不快指数 THI (temperature-humidity index) は以下の計算式で求められるようです（Tは乾球気温℃、Hは湿度％）
 
`THI = 0.81T + 0.01H × (0.99T − 14.3) + 46.3`


外部サーバは Lambda とかでもいいと思うのですが、とりあえず Linux VM + シェルスクリプト + cron でやってみました。Harvest から API でデータをダウンロードするには SORACOM の認証情報が必要なので、そこもサクッとできる [soracom cli](https://github.com/soracom/soracom-cli/blob/master/README_ja.md) を使っています。あとは jq と curl でちょこちょこっとやっています。

1. SORACOM Inventory のデバイスを作成し、認証情報を発行する (方法は[この URL](https://dev.soracom.io/jp/start/inventory_harvest_with_keys/#device-registration) を参照)
2. 外部サーバに soracom cli をダウンロードする
3. 外部サーバで soracom cli を用いて SORACOM アカウントにログインする
4. 後述するシェルスクリプトを実行する or cron に仕込む

シェルスクリプトはこちらになります。deviceId や secretKey の取り扱いには注意して、実際に活用する場合はセキュリティ対策を講じましょう。

```bash
#!/bin/bash
imsi="[元データのIMSI]"
fromts=`date -d '5 minute ago' +%s%3N` # 過去 5 分を取得していますがここはお好みで
deviceId="[Inventory で発行した deviceId]"
secretKey="[Inventory で発行した secret]"
postUrl="https://api.soracom.io/v1/devices/${deviceId}/publish"

/usr/local/bin/soracom data get --imsi ${imsi} --from ${fromts} --sort desc > ~/tmp.json
json_file=`cat ~/tmp.json`
json_length=`echo ${json_file} | jq length`

if [ ${json_length} = 0 ]; then
    echo "no data"
    exit

else

tempsum=0
humisum=0
thisum=0

for i in `seq 0 $(expr ${json_length} - 1)`
do
    temp=`echo ${json_file} | jq .[${i}].content | sed -e 's/\\\\//g' | cut -f 5 -d '"' | base64 -d | jq .temp`
    humi=`echo ${json_file} | jq .[${i}].content | sed -e 's/\\\\//g' | cut -f 5 -d '"' | base64 -d | jq .humi`
    thi=`echo "scale=1; (0.81 * ${temp}) + (0.01 * ${humi}) * ((0.99 * ${temp}) - 14.3 )  + 46.3" |bc`
    tempsum=`echo "scale=1; ${tempsum} + ${temp}" | bc`
    humisum=`echo "scale=1; ${humisum} + ${humi}" | bc`
    thisum=`echo "scale=1; ${thisum} + ${thi}" | bc`
done

avetemp=`echo "scale=1; ${tempsum} / (${json_length})" | bc`
avehumi=`echo "scale=1; ${humisum} / (${json_length})" | bc`
avethi=`echo "scale=1; ${thisum} / (${json_length})" | bc`

echo 'average temperature is' ${avetemp}
echo 'average humidity is' ${avehumi}

postJson=$(cat << EOS
{
  "avetemp": ${avetemp},
  "avehumi": ${avehumi},
  "avethi": ${avethi}
}
EOS
)

echo "${postJson}"

curl -X POST --header "x-device-secret: ${secretKey}" -d "${postJson}" ${postUrl}

fi
```

# 結果
こんな感じで不快指数も確認できるようになりました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/41357768-f580-26e7-38d1-fb791f84e459.png)

# まとめ

- SORACOM Lagoon はおしゃれ
- SORACOM Havrvest のデータを加工して Lagoon に入れることはできない (2019/10 現在。今後に期待！)
- SORACOM API で Harvest のデータをダウンロードして、Inventory 経由で格納するという回避策がある
- SORACOM Lagoon はおしゃれ