Google Cloud Functions で obniz を 1分おきに動かしてみた

この記事は [obniz Advent Calendar 2019](https://qiita.com/advent-calendar/2019/obniz) の11日目の記事です。

# obniz で高頻度なセンシングをラクに実現してみたい！
今年の首都圏を襲った台風をきっかけに、 obniz で自宅の気温や気圧などのログを取って可視化してみたいと考え、~~obniz Cloud の12分おきのセンシングではもの足りず、~~ Google Cloud Functions で obniz を 1分おきに動かしてみました。

# obniz とは
[obniz（オブナイズ）](https://obniz.io/)は日本の CambrianRobotics 社が開発したマイコンボードで、Wi-Fi に接続してインターネット経由で操作します。簡単に Wi-Fi に繋がり、ファームウェアの書き込み不要で API 経由で操作するので、インターネットと連携したハードウェアをサクッと作れるのが特徴です。

# obniz の動かし方
## obniz の動かし方の種類
obniz の動かし方は以下のように分類することができます。

- [obniz 開発者コンソール](https://obniz.io/ja/console)から JavaScript やブロックプログラムで記述
    - ブラウザ上で実行
    - [サーバーレスイベントで実行](https://obniz.io/ja/doc/obniz_cloud/about_event)
        - Webhook
        - 決められたある時間(11:11など)
        - 決められた時間の間隔(1時間毎など)
        - obnizがオンラインになったら
        - obnizのボタンが押されたら
- [Python で動かす](https://obniz.io/ja/lessons/python/quickstart)
- [Node.js で動かす](https://obniz.io/ja/lessons/server_side/lessons_nodejs)
    - 手元のPCで Node.js を走らせておく
    - サーバーを用意する
    - サーバーレスアーキテクチャを使用する

## obniz を1分おきに動かしてセンサの値を記録したい
### obniz サーバーレスイベントは？
[obniz サーバーレスイベント](https://obniz.io/ja/doc/obniz_cloud/about_event)を使えば、定期的にセンサの値を記録するようなアプリケーションを作成することができます。ただ、 `各イベントの実行は1日に120回まで` という制限があります。一定間隔で実行しても12分に1回実行できるわけで、IoTセンシング用途としては十分だと思いますが、 **もっと高頻度なセンシングをラクに実現してみたい！** ということで、別の方法を調べてみました。

### 専用のPCやサーバーを用意する？
Raspberry Piなど常時起動できるPCを1台用意して、定期的に走るように設定する方法もありますが、常に起動しておく必要があり、万が一エラーが起きてシャットダウンされた場合、復旧するのが面倒そうです。

### FaaS
そこでクラウドサービスを利用することを検討しました。Node.js で数十秒間の関数を定期的に実行したいとなると、FaaSと呼ばれる、イベント駆動型コード実行サービスを使用するのが、容易で適していそうでした。
例えば [Google Cloud Functions](https://cloud.google.com/functions/) では、既にNode.js を動かせる環境が入っているため、環境設定が記載されたファイルや、実行する関数が記載されたファイルをアップロードするだけで、クラウド上で実行できるのです。

obniz 公式サイトにも、[AWS Lambda で obniz を動かすレッスン](https://obniz.io/ja/lessons/server_side/lessons_lambda)がありますが、今回は無料制限回数が多かった（上無料体験期間が残っていた） Google Cloud Functions を使用してみました。
[料金 - Google Cloud Functions](https://cloud.google.com/functions/pricing-summary/) によると月200万回、100万秒、5GBまで無料で実行できる？ようです。
毎分実行しても1ヶ月に5万回未満なので、無料の範囲に収まりそう…？
（その他の部分で料金がかかるかもしれません。この記事を参考にして生じた損失に関して一切の責任を負いません。）

# 作るもの

Google Cloud Functions を使用し、 obniz を1分おきに動かしてセンサの値を読み取り、Google Spreadsheet に記録します。測定する量は、温度、湿度、気圧、照度とします。
https://qiita.com/y-hira/items/b8fe1268a12492bd865c
の記事のように、obniz のセンサの値を Google Spreadsheet に記録することができます。

# 手順
手元のPCで Node.js で obniz を動かすプロジェクトを作成し、 ZIP ファイルに固めて Google Cloud Functions にアップロードする流れになります。macOS 10.13 にて行いました。

## obniz に配線
今回は BME280 とアナログ照度センサを配線しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/d89c3466-ac18-471d-a4ab-9bbdce6b940c.png)

ついでにテレビやエアコンの操作用に赤外線LEDも配線してありますが（笑）

## データ記録用のスプレッドシートを作成
https://qiita.com/y-hira/items/b8fe1268a12492bd865c
の手順に従って、スプレッドシートと、GAS のプロジェクトを作成しました。GAS のプロジェクトの「現在のウェブアプリケーションのURL」をメモしておきます。

## Node.js と npm をインストール
まず、手元の PC で Node.js と npm を使えるようにしておきます。

## Node ファイルの作成
適当なフォルダ（ここでは `obniz_gcf`） を作成し、 obniz のライブラリをインストールします。

```
mkdir obniz_gcf
cd obniz_gcf
npm init
```

`npm init` では簡単な質問に答えていくと `package.json` が生成されます。デフォルトのままで良ければ `Enter` を押していくことで進めます。

```
npm install obniz
```

obniz のコードを書くファイル `index.js` を作成します。

```
touch index.js
```

## コードを作成
POST するために、慣れているjQuery を使いたかったので、[NodeJSでjQueryを使う](https://qiita.com/gitcho/items/251c66947c0b1d5b5523) を参考にコードを作成しました。

```javascript:index.js
var Obniz = require("obniz");
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const dom = new JSDOM(`<html><body><div id="aaa">AAA<div></body></html>`);
const { document } = dom.window;
const jquery = require('jquery');
const $ = jquery(dom.window);

exports.handler = function (event, context, callback) {
    var obniz = new Obniz(process.env.OBNIZ_ID);
    const url = process.env.POST_URL;
    var sensor;

    obniz.onconnect = async function () {
        obniz.io8.output(true);
        sensor = obniz.wired("BME280", { gnd: 9, sck: 10, sdi: 11, address: 0x77 });
        await sensor.applyCalibration();
        const illum = await obniz.ad7.getWait();

        const obj = await sensor.getAllWait();
        var param = { sheet: "log", obniz_id: obniz.id, temperature: obj.temperature, humidity: obj.humidity, pressure: obj.pressure, illuminance: illum };
        console.log(param);
        $.post(url, param)
            .done(function (data) {
                console.dir(data);
                obniz.close();
                callback(null, "success");
            });
    }
};
```

追加で使用するライブラリもインストールします。

```
npm install jquery
npm install jsdom
```

## Google Cloud Functions にアップロード
### ZIP に圧縮
解凍したときに `index.js` がトップの階層に来るように ZIP に圧縮します。

```
zip -r obniz_gcf_codes.zip index.js node_modules/ package-lock.json package.json
```

[Google Cloud Platform のコンソール](https://console.cloud.google.com/) で新たにプロジェクトを作成し、 `Cloud Functions` のメニューから新たに関数を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/f210e696-9f87-951b-94c4-f553f76a72c5.png)

### 定期実行の設定
1分ごとに実行するため、トリガーには `Cloud Pub/Sub` を選択します。
「新しいトピックを作成」し、適当な名前を付けます。
Cloud Scheduler を開き、「ジョブを作成」します。トピックには先程作成したトピック名を指定してください。毎分実行したい場合は、頻度として `* * * * *` を指定します。その他の時間間隔もこの文字列次第で設定することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/3f18c8ad-6405-a19b-6714-feec189cd688.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/f7c4b915-7752-a8f7-3095-fd78d84a7cae.png)

### Google Cloud Functions の設定
ソースコードは `ZIPアップロード` とし、さきほど圧縮してできた ZIP ファイルを選択します。
実行する関数は `handler` です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/f856503f-4b3b-4fa9-d0de-c6b4f444e036.png)

また追加の設定項目を開き、環境変数として、 `OBNIZ_ID` に obniz の ID, `POST_URL` には GAS アプリケーションのURLを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/c4289c07-9d5a-75c6-5478-1fc91c878695.png)

最後に **デプロイ** !
アップロードに少々時間がかかるかもしれません。
うまくいけば、1分おきに、関数の実行が開始されます！
スプレッドシートを確認して、センサの値が正しく記録されているか確認してみましょう！

# 約2ヶ月間動かしてみた結果
既に2ヶ月近く動かしているのですが、安定して実行できています。 obniz はコンセントに挿した USB - AC アダプタに挿しっぱなしです。万が一停電が起きても、復旧時にも特に何もする必要がないのが楽でいいですね。

## Google Cloud Functions の記録
obniz を接続している Wi-Fi ルーターがもともと不安定でときどき再起動してしまうこともあり、ときどきタイムアウトしていますが、おおむね安定して実行できているようです。Google Cloud Functions の設定では、50秒でタイムアウトとなっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/36751287-d19b-b5ed-3ee8-68db2fb4907b.png)

どうやらタイムアウト時間の50秒近くかかっている場合もあるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/e8a63bac-3826-a243-af2b-0725e6b91813.png)

## GAS の記録
GAS の方では1回あたり大体10秒ちょっとかかっているようですね。エラーもほぼないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/6b8b0775-b03c-4262-91b2-eef740b35e1c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/368e800b-d680-19bc-0e0e-bf85e90558a0.png)

## スプレッドシートの記録
2ヶ月もデータを溜めると、スプレッドシートを開くのにも時間がかかるようになってしまいました（笑）
GAS で毎日 Google スプレッドシート上のグラフを画像にして Google ドライブに保存するようにもしており、またデータにアクセスしたい場合は Google Colab を使って Python で処理すれば、 Google スプレッドシートを直接開く必要がないので、端末のスペックに依存しなくて済むかと思いますが、これ以上データを蓄積したい場合は、 IoT 向けのストレージを使うべきでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/67d087fb-e9c5-25f8-5da8-2d59b1335df0.png)

試しに11月1日0時0分〜11月30日23時59分59秒までにスプレッドシートに記録された行数を数えてみると、42951行ありました。
60*24*30=43200 なので、249回だけ記録できなかったことがあるようですね。でも、 **99.4% 以上の割合で記録できています！**

また台風通過時の気圧のグラフです。肝心の台風の目通過時は、 obniz Cloud で12分おきに取得していたのですが、それでも台風通過の様子がよく分かりますね。
たまに値が飛んでいますが、自宅の環境センシングとしては十分です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/f47f25c5-3048-e984-5124-b58263b75aca.png)

## 気になる請求金額は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/abf85e98-7db7-101c-835e-d44be961f53d.png)

ちゃんと無料枠に収まっていました！
ただし他にもプロジェクトがある場合や設定次第で課金される可能性も十分あるので、無料枠で使いたい方は十分お気をつけください！

# 最後に
Google Cloud Functions で obniz を1分おきに動かすことができました！
台風通過時の気圧の変化、季節や時間による温度や湿度の変化を可視化できて満足です。
エアコンをつけたときの温度と湿度の変化など、グラフを見て気付かされることもありますね。逆にグラフを見ればエアコンをいつつけたかも分かります。もっとセンサの種類を増やしたくなりました。
ただ、蓄積したデータへのアクセスが問題なので、より良いデータの蓄積方法も考えてみたいと思います。

Let's IoT!
Let's obniz!