屋内外の温度と湿度を計測してダッシュボードで表示する

いつの間にか公式APIが公開されていたようで、ハブを使うことでWeb上で完結するようになっています。別途記事を投稿しました。（2021年8月15日）
https://qiita.com/kunikada/items/28981ecdeee6e47a229f

## 目的

温湿度計を使って屋内外の様子をダッシュボードで確認したい。

SwitchBotの温湿度計を購入してみても、いまいち使い切れていない感がありましたが、こちらの記事から気付きを得て制作に至りました。感謝:bow:
[家の中のセンサデータをRaspberryPiで取得しまくり、スーパーIoTハウスを実現](https://qiita.com/c60evaporator/items/283d0569eba58830f86e)

## 概要

ラズパイを使って処理する記事が多いのですが、今回はすでに稼働している自宅のx86_64サーバを使います。
センサーからの値の取得は、WonderLabs社が公開しているPythonプログラムを使用します。
https://github.com/OpenWonderLabs/python-host
取得値は、Google Apps Scriptを経由して、Googleスプレッドシートに記録します。これをデータソースにしてGoogleデータポータルで視覚化します。

以上の流れです。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131050/01943686-5742-ebd8-53ea-e1a48836d403.png)


## 準備

* [SwitchBot温湿度計](https://www.switchbot.jp/products/switchbot-meter)
* x86_64サーバ（普通のパソコンでも可、ラズパイは未検証）  
* Bluetooth LE（マシンが対応していない場合はドングル等の用意が必要）

## 手順

### SwitchBot温湿度計の設置

購入したら電池を入れて計測する場に設置します。屋外に設置する場合は防水対策をしてください。何かで囲えばいいのですが、金属だと通信に支障が出ます。
次の手順で必要となるBLEのMACアドレスを調べるために、SwitchBotのアプリをインストールします。

### Googleスプレッドシートの作成

任意の場所、名前でスプレッドシートを作成します。
このとき1行目を下の画像のように入力してください。（_tと_hの前をBLEのMACアドレスに）
次の手順でURLが必要です。
![logs-Google-スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131050/820d68a3-497d-4882-b44d-a41cc3cd5106.png)

### Google Apps Scriptの作成

任意の場所、名前でGoogle Apps Scriptを作成します。
作成する方法、準備については他の記事を参照してください。
https://qiita.com/tags/googleappsscript
スクリプトを下の内容に書き換えます。

```javascript
var SPREADSHEET_ID = "********"; // ここにSpreadsheetのURLを

// Compiled using ts2gas 3.6.3 (TypeScript 3.9.7)
var MySpreadsheet = /** @class */ (function () {
    function MySpreadsheet(id, sheetId) {
        if (sheetId === void 0) { sheetId = 0; }
        if (id.match(/^https:\/\//)) {
            this.ss = SpreadsheetApp.openByUrl(id);
        }
        else {
            this.ss = SpreadsheetApp.openById(id);
        }
        this.sheet = this.ss.getSheets()[sheetId];
    }
    MySpreadsheet.prototype.headers = function () {
        var range = this.sheet.getRange(1, 1, 1, this.sheet.getMaxColumns());
        return range.getValues()[0];
    };
    MySpreadsheet.prototype.appendRow = function (row) {
        var insertRow = [];
        this.headers().forEach(function (name, index) {
            insertRow.push((name && name in row) ? row[name] : "");
        });
        this.ss.appendRow(insertRow);
    };
    MySpreadsheet.prototype.unshiftRow = function (row) {
        this.sheet.insertRowAfter(1);
        var range = this.sheet.getRange(2, 1, 1, this.sheet.getMaxColumns());
        this.headers().forEach(function (name, index) {
            if (name) {
                range.getCell(1, index + 1).setValue(row[name]);
            }
        });
    };
    return MySpreadsheet;
}());
var MyResponse = /** @class */ (function () {
    function MyResponse(status, message) {
        this.status = status;
        this.message = message;
    }
    MyResponse.prototype.toJSON = function () {
        return {
            status: this.status,
            message: this.message
        };
    };
    MyResponse.prototype.create = function () {
        var output = ContentService.createTextOutput();
        output.setMimeType(ContentService.MimeType.JSON);
        output.setContent(JSON.stringify(this));
        return output;
    };
    return MyResponse;
}());
function doPost(e) {
    var data = JSON.parse(e.postData.contents);
    var response = new MyResponse("success", "ok");
    try {
        var ss = new MySpreadsheet(SPREADSHEET_ID);
        ss.unshiftRow(data);
    }
    catch (err) {
        console.error(err);
        console.log(data);
        response.status = "error";
        response.message = err.message;
    }
    return response.create();
}
```

### Google Apps Scriptの公開

スクリプトを保存したら、公開します。
メニュー > 公開 > ウェブアプリケーションとして導入...
次の手順でURLが必要です。

### サーバプログラムの設置

Pythonプログラムで取得したセンサーの値を特定のURLにPOSTするところまでを、Dockerコンテナにまとめて公開しています。こちらを動かしてください。
https://hub.docker.com/r/kunikada/switchbot-meter-relay
POST_URLにさきほど公開したURLを指定してください。

そもそものDockerコンテナを動かすまでの過程は他の記事を参照してください。
https://qiita.com/tags/docker

ここまで行えばGoogleスプレッドシートにデータが蓄積されているはずです。

### Googleデータポータルの設定

![SwitchBot温湿度計-›-PC用レイアウト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131050/c483f139-de12-d777-fcea-6f96a08d8ae3.png)
具体的な手順は省きますが、試行錯誤した結果、画像のようなものができました。
上に温度、下に湿度、屋内外のデータと差異を一つに表示します。左側が履歴で右側に現在値を表示しています。
履歴については、色々とパラメータはありますが時系列グラフ1つで設定できます。
現在値の表示は、ドーナツグラフ2つとスコアカード2つを重ねて表示しています。データソースもスプレッドシートの別シートで専用のデータを作成しています。

もし質問があればコメントからどうぞ。

## 備考

* 複数個の温湿度計を同じ場所に設置しても値にズレがあり個体差があることがわかります。~~SwitchBotアプリに校正機能があるのですが個別に修正することができないため、スクリプトかスプレッドシートかデータポータルかで修正を入れる細工が必要になります。スクリプト内で数値を増減するのが手っ取り早いです。~~アプリから個別の校正ができるようになっているのは確認しましたが、出力値に反映されるのかは未検証です。反映されないようであればスクリプト側での対応が必要です。
* 計測回数を増やすと、データの件数が増えるのと、温湿度計のバッテリー低下を早めるかもしれません。考慮した上で計測間隔を調整してください。
* サーバと温湿度計の位置関係やその他条件により、計測できずにスプレッドシート上の数値が欠損することがあります。設置状態を見直したり、計測回数を増やすことで補完してください。どうしても値を取得できない場合は、Class1のBluetoothアダプタを使用することで改善するかもしれません。

## 参考

温湿度計API仕様
https://github.com/OpenWonderLabs/python-host/wiki/Meter-BLE-open-API

Google Apps Script リファレンス
https://developers.google.com/apps-script/reference

Docker日本語リファレンス
https://docs.docker.jp/index.html

Googleデータポータル ヘルプ
https://support.google.com/datastudio/?hl=ja