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


はじめに - SORACOM Lagoon とは

SORACOM Lagoon (以下 Lagoon) は Grafana をベースとした、可視化サービスです。何ぞやという方はまずこちらを読んでもらえればと思います。

Lagoon のデータソースは SORACOM Harvest Data (以下 Harvest) に格納されたデータです。簡単に図にすると以下のようなイメージです。温度湿度センサーで取った単純な情報も Lagoon を使うととてもおしゃれになります。

解決したい課題

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

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

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

SORACOM Inventory を使って解決するイメージ

Inventory は、デバイス管理のためのサービスです。デバイス登録の時だけ SORACOM SIM 経由で SORACOM プラットフォームから認証情報を受け取り、その後は Wi-fi 経由とかでも SORACOM の提供する LwM2M サーバとやり取りできます。サービスの説明はこちら

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

デバイスIDとデバイスシークレットを使用してHarvestにデータを送信する

こちらを読んでみると、なんと SORACOM SIM 経由でなくともデバイスを登録して認証情報を受け取れ、その認証情報を用いて Harvest に格納できるとのことです。
また、Harvest に格納されたデータは API でダウンロードできます。
つまり下記の図のようなことが可能なのでは...?と思いました。

というわけで、やってみようと思います。

注意点

  • 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 を使っています。あとは jq と curl でちょこちょこっとやっています。

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

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

#!/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

結果

こんな感じで不快指数も確認できるようになりました!

まとめ

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