obniz + Machinist でラクラク IoT センサーロガー：スマホでも開発可能！おうち IoT

# obniz でラクラク IoT センサーロガーを無料で維持したい！
[前回の記事](https://qiita.com/y-hira/items/bf2a161e90e3132b05a0)のように、Google Cloud Functions で [obniz](https://obniz.io/) を 1分おきに動かして、センサーの値を記録していました。しかし、Google スプレッドシートに記録していたため、データが溜まってくるとシート自体を開くにも重すぎて開けなくなってきてしまいました。

そこで、IoT 向けのデータ保存サービスを試してみたいと思っていたのですが、AWS IoT など少額かもしれませんが維持費がかかるため、とりあえずクレジットカード登録不要で無料プランのある、IIJ の [Machinist](https://machinist.iij.jp/) を使用してみました。

ハードウェアとインターネットが繋がる IoT 開発では、複数のプログラムが必要になることが多いですが、今回の方法では

- プログラムは**たった1枚**のHTML
- 環境構築不要・**スマホでも**開発可能
- 複雑な設定**なし**
- クラウドサービス月額費用**無料**

で IoT センサーロガーを開発することができます！！

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

# Machinist の料金プラン
執筆時点で Machinist の料金プランは以下の通りでした。
フリープランでは1ヶ月以上前のデータは消えてしまいますが、とりあえずラクに維持してみたいのでフリープランで試してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/e3a784da-aa6d-322f-85d7-af1d3a350b5a.png)

# Machinist は複雑な設定も不要で始められる
[Getting Started - Machinist](https://machinist.iij.jp/getting-started/getting_started/sign_up.html) の通り、必要な作業はたったこれだけでした。

- メールアドレスとパスワードを入力して新規登録
- 届いたメールから本登録用リンクをクリック
- ログインしてアカウント設定から**APIキー**をメモ


# obniz から Machinist に送信するプログラム

HTMLが開かれる、または[サーバーレスイベント](https://docs.obniz.io/ja/guides/cloud/serverless-event/)として実行されるたびに、obniz に繋いだ [BME280 （温湿度・気圧センサ）](https://obniz.io/ja/sdk/parts/BME280/README.md)の値を Machinist にアップロードするプログラムを作成しました。

[obniz 開発者コンソールのリポジトリ](https://obniz.io/ja/console/repository)にてHTMLを新規作成し、以下のコードをコピー&ペーストします。

以下のコードのうち、書き換える部分は以下のとおりです。

- obniz ID
- [Machinist](https://app.machinist.iij.jp/)のアカウント設定からコピーした**APIキー**
- BME280 の配線の定義：[BME280 - obniz パーツライブラリ](https://obniz.io/ja/sdk/parts/BME280/README.md)に従う
（他のセンサを使用する場合は、[obniz パーツライブラリ](https://obniz.io/ja/sdk/parts)に従い配線の定義とセンサ読み取り・送信部分を書き換える）

```html:sensor_logger.html
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@3.5.0/obniz.js" crossorigin="anonymous"></script>
</head>

<body>
    <div id="obniz-debug"></div>
    <h1>obniz Sensor Logger</h1>
    <button id="post">送信</button>

    <script>
        let obniz = new Obniz("XXXX-XXXX");//obnizのIDを指定してください
        const url = "https://gw.machinist.iij.jp/endpoint";
        const token = "YOUR_API_KEY";//MachinistのAPI KEYを指定してください

        let sensor;
        let param = {
            "agent": "Home",
            "metrics": []
        };

        function addMetrics(param, name, value) {
            param.metrics.push({
                "name": name,
                "namespace": "Environment Sensor",
                "data_point": {
                    "value": value,
                }
            });
        }

        function sendParams(url, param, token) {
            let xhr = new XMLHttpRequest();
            xhr.open('POST', url, true);
            xhr.setRequestHeader("Content-Type", "application/json");
            xhr.setRequestHeader('Authorization', 'Bearer ' + token);
            xhr.onreadystatechange = function () {
                if (this.readyState == 4) {
                    console.log(xhr.response);
                    if (typeof done === "function") {
                        obniz.close();
                        done();
                    }
                }
            }
            let p = JSON.stringify(param);
            xhr.send(p);
        }


        obniz.onconnect = async function () {
            obniz.io8.output(true);
            sensor = obniz.wired("BME280", {vio:0, gnd:1, sdi: 2, sck: 3 });
            await sensor.applyCalibration();

            const obj = await sensor.getAllWait();

            param.metrics = [];
            addMetrics(param, "temperature", obj.temperature);
            addMetrics(param, "humidity", obj.humidity);
            addMetrics(param, "pressure", obj.pressure);

            console.log(param);
            sendParams(url, param, token);
        }

        $("#post").click(async function (e) {
            const obj = await sensor.getAllWait();

            param.metrics = [];
            addMetrics(param, "temperature", obj.temperature);
            addMetrics(param, "humidity", obj.humidity);
            addMetrics(param, "pressure", obj.pressure);

            console.log(param);
            sendParams(url, param, token);
        });

    </script>
</body>

</html>
```

# obniz サーバーレスイベントに登録
[obniz 開発者コンソールのサーバーレスイベント](https://obniz.io/ja/console/events)にて、作成したプログラムが定期実行されるように登録します。

[obniz のサーバーレスイベント](https://docs.obniz.io/ja/guides/cloud/serverless-event/)では現在1日150回まで実行できるそうなので、10分おきに実行されるよう設定しました。

「テスト実行」を押せば、今すぐ実行もできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/e1241528-ce61-58df-6757-ecacf91a07c1.png)

実行履歴も見ることができます。プログラム中で `console.log` 等で出力したログも後から見返すことができるので、何かトラブルがあったときも安心ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/bcb923ba-d6f9-574f-5c43-4e6edf6d24d7.png)

# 記録されたデータ
Machinist に記録されたデータはこのようになりました！
スマホでもいつでもどこでも最新のデータが見られます。便利ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/4dadee41-4310-924e-f540-30f583f5e70e.png)

グラフもきれいで、拡大表示やCSVダウンロードなど機能が揃っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401669/669d4249-b6d9-3378-9626-24b7928ae978.png)

# 最後に
最初は jQuery の `$.ajax` で POST しようとしたのですが、 `Authorization Bearer` の部分がうまくいかなかったようで、 `XMLHttpRequest` を使って実装しました。

Machinist では複数の端末（agent）からのデータをまとめて閲覧することができるようですし、送信するデータにタグや、位置情報などのメタデータをつけることもできるようです。また、データを「監視」して「アクション」に繋げる設定も簡単にできるようになっているようです。

Machinist には、 JavaScript からでも簡単にデータを送信することができました。obniz との相性も良さそうです。

大量の obniz をばらまいてデータを収集したいですね！