Mackerel に部屋の温湿度を記録する
Amazon プライムデーだぜ!ということで SwitchBot の温湿度計を買いました。
https://www.amazon.co.jp/gp/product/B07L4QNZVF
とりあえず仕事部屋に置いているのですが、いい感じです。寝室用にも欲しい。買い足そうかな…。
ただ置くだけでも温湿度が見れて便利なのですが、スマートホーム的な観点でメトリクスをとっていきたい。一年を通した記録を見ることで除湿・加湿器を買う際のスペックの参考にもなりそうですし、体調との関連性とかも見れたら面白そう。特に妻は頭痛持ちなので何か法則とか見出せたら役立ちそう (おそらく気圧が主な影響ぽいですが)。
構成
主な構成は以下です。
図だと以下。
EventBridge Scheduler で定期的に Lambda 関数を実行し、Lambda 関数で SwitchBot の API を呼び出し、取得した結果を Mackerel に送信する流れです。
今回、言語は JavaScript を使用しています。
デプロイは AWS SAM で行っています。
SwitchBot API について
去年 v1.1 が公開されていました。
大きな変更として、今までは Authorization ヘッダーにトークンを指定するだけで API の認証を行っていましたが、v1.1 からはトークンとシークレット、タイムスタンプとナンス (使い捨ての値) を使用して一意の署名を作成する方法になりました。
署名の作成方法はいくつかの言語毎にサンプルコードが公開されておりほぼそのまま使えます。
まず curl コマンドで検証してみます。Python のサンプルコードを使用して署名を作成します。リクエストに必要な各情報が出力されます。
$ python3 sigh.py
Authorization: xxxx
t: 1111111111111
sign: yyyy
nonce: zzzz
これを使って curl コマンドでリクエストを送信します。デバイスの一覧を取得してみます。
$ curl \
-H "Authorization: xxxx" \
-H "sign: yyyy" \
-H "t: 1111111111111" \
-H "nonce: zzzz" \
https://api.switch-bot.com/v1.1/devices
上のコマンドでデバイスの一覧が取得でき、各デバイスのデバイス ID が取得できます。デバイス個別の情報はこのデバイス ID を使用して取得できます。
$ curl \
-H "Authorization: xxxx" \
-H "sign: yyyy" \
-H "t: 1111111111111" \
-H "nonce: zzzz" \
https://api.switch-bot.com/v1.1/devices/<デバイス ID>/status
今回の場合、温湿度計から情報を取得したいです。各デバイスの持つ情報は以下にまとめられています。
温湿度計の場合、以下ですね
temperature が温度、humidity が湿度です。
署名の取得はこんな感じで書いてます。ほぼサンプルの通りです。ナンスに UUID を使用してます。
const signToSwichbot = async (token, secret) => {
const t = Date.now();
const nonce = crypto.randomUUID();
const data = token + t + nonce;
const signTerm = crypto
.createHmac("sha256", secret)
.update(Buffer.from(data, "utf-8"))
.digest();
const sign = signTerm.toString("base64");
return { sign: sign, t: t, nonce: nonce };
};
温湿度情報の取得はこんな感じ。
const getTempHum = async (switchbot_endpoint, switch_bot_token, sign) => {
const res = await axios.get(switchbot_endpoint, {
headers: {
Authorization: switch_bot_token,
sign: sign.sign,
t: sign.t,
nonce: sign.nonce,
},
});
return res.data.body;
};
実装の雑な部分は許して…。
Mackerel サービスメトリックについて
自分の場合、こんな感じでサービスメトリックを使用してスマートホームのメトリクスを集約しています。SmartHome というサービスの配下に、スマートホーム関連の各メトリックを集約しています。
今回、メトリック名の設計は以下のようにしてみます。
homeoffice.temphum.temperature
: 仕事部屋の温度homeoffice.temphum.humidity
: 仕事部屋の湿度homeoffice.temphum.battery
: 仕事部屋の温湿度計のバッテリー残量
Mackerel へ送信するコードはこんな感じ。
const sendTempHumToMackerel = async (
temp_hum,
mackerel_endpoint,
mackerel_api_key
) => {
const date = new Date();
const sec = Math.floor(date.getTime() / 1000);
const res = await axios.post(
mackerel_endpoint,
[
{
name: "homeoffice.temphum.temperature",
time: sec,
value: Number(temp_hum.temperature),
},
{
name: "homeoffice.temphum.humidity",
time: sec,
value: Number(temp_hum.humidity),
},
{
name: "homeoffice.temphum.battery",
time: sec,
value: Number(temp_hum.battery),
},
],
{
headers: { "X-Api-Key": mackerel_api_key },
}
);
console.log(res);
};
作成されたグラフ
順調に記録されていっていますね。🎉
バッテリーと湿度についてはパーセント表記にしたいですが、メトリックの単位はサービスメトリック単位で設定可能で、メトリック名個別の単位では設定できないので、とりあえず整数として設定してます。まあわかるとは思いますが、メモの部分に単位の説明書いておこうかな。
感想
全体を通して特に特別なことはしておらず、公式のサンプル等ほぼそのままで出来ました。今後は寝室等にも設置して、bedroom.temphum.* といった形で記録していければと思います。その際は今回作成した関数を使用し、コードもちょっと整理していい感じに使いまわせるようにしていければ!
しかしスマートデバイス、めっちゃ手軽になりましたね。Raspberry Pi で何かする気分にならないくらい… (良い感じの使い道考えないと…)。