うっかりエンジニアのメモ

未来の自分に宛てたメモ

Google SpreadsheetからGASでSwitchBot API v1.1にアクセスして消費電力を可視化する

古来より、自作erはマシンを組み上げるとベンチマークと消費電力を計測するものという言い伝えがある(要出典)

私の家にも「ワットチェッカー」がある。自作er御用達の消費電力測定ツールだ。ただ、ワットチェッカースタンドアロン。つまり、測定データをCSVで出力したり、リアルタイムに他システムに送信したりといったことは当然できない。

ちょっと探してみるとIoT隆盛の今をときめくスマート家電の中に、あるじゃないですか、消費電力を計測できるスマートプラグが。しかも測定データはREST APIで取得可能? …便利な世の中になったものよ。

SwitchBotプラグミニ、これは面白そう。

この記事の対象読者

  • SwitchBotのAPIから取得したデータをGoogle Spreadsheetで触りたい人
  • かつ、SwitchBot API v1.1を使いたい人

記事を書いている2022/09/24時点ではv1.0も生きているのでそちらを使うこともできたのだけど、基本この手の仕組みは一度作ったらほったらかし運用をしたいので、よりdeprecatedになるのが遅いであろうv1.1を使うことにした。

必要な機材

Google Spreadsheetの準備

Switchbot API アクセストークン/シークレットの取得

こちらの記事で手順をまとめてくださっている。10回タップというのがスーファミの裏技っぽくて良かった。 qiita.com

v1.1からAPI呼び出し時のお作法が変更

従来は単にtokenをAuthorizationヘッダーに付与すればよかったが、v1.1からsecretを用いたリクエストへの署名(signature)が必須になった。

How to Sign?

We have attached a python script for you to quickly generate a sign. If you prefer to write your own script or routine, here is the procedure.

  1. Print the 13 digit timestamp and concatenate it with your token
  2. Create a signature using your secret and the string produced in the previous step
  3. Convert the signature to upper case

引用: GitHub - OpenWonderLabs/SwitchBotAPI: SwitchBot Open API Documents

v1.1では下記のように処理が増える。

  1. 13桁のタイムスタンプとnonceを連結した文字列を、シークレットによりHMAC-SHA256で署名する
  2. 署名をbase64エンコードし、大文字にする
  3. リクエストヘッダのAuthorizationtokenを、signに署名を、t13桁のタイムスタンプ を、nonceにnonceの文字列を格納してAPIを呼び出す

Google Apps Scriptの作成

スクリプトプロパティにトークン/シークレットを格納

トークン/シークレットのスクリプトへのベタ書きは避ける。具体的にはあらかじめGASのIDE
プロジェクトの設定 > スクリプトプロパティトークン/シークレットを登録する。ここではそれぞれ SWITCHBOT_API_TOKEN SWITCHBOT_API_SECRET とした。 スクリプトで利用する際は PropertiesService.getScriptProperties().getProperty() で取得する。

実装

流れは以下。最終的な実装はgistに載せた。

  • GET /v1.1/devices を呼び出し、ミニプラグのdeviceIdを取得する(最初に1回だけ)
  • GET /v1.1/devices/{deviceId}/status を呼び出し、ミニプラグの現在の測定値を取得する
  • 測定値を整形してspreadsheetの末尾行に書き込む

考慮点1: GASにおける署名生成のやり方

前述の通り、SwitchBotのAPIではv1.1からHMAC-SHA256による署名が必要だ。公式ドキュメントにはpythonJavaScriptのサンプルコードはあるが、Google Apps Script用のサンプルコードはない。JavaScriptのサンプルは部分的に参考になるものの、GASで使える関数は限られるのでその制約のもと、実装する必要がある。(たとえばcryptoはGASでは使えない)
GASにおけるHMAC-SHA256署名処理の実装をググると、様々な記事で「Utilities.computeHmacSha256Signature()の戻り値はByte[]でありそのまま署名文字列として使えないので、下記のコードでbase64に変換する」と書かれている。おそらく2017年のこのStackoverflowの回答を参考にしているっぽい。

var byteSignature = Utilities.computeHmacSha256Signature(message, secret);
// convert byte array to hex string
var signature = byteSignature.reduce(function(str,chr){
  chr = (chr < 0 ? chr + 256 : chr).toString(16);
  return str + (chr.length==1?'0':'') + chr;
},'');

ところが上記gistの通り、2022年9月時点ではこのような回りくどい実装は不要で、Utilities.base64Encode() でシンプルにbase64エンコードできた。昔はByte[]を引数に取るbase64Encode()は実装されてなかったのかもしれない。

考慮点2: データの書き込み先シートを月ごとに分ける

シートに毎分1行データを追加するということは、1日あたり1440行、1ヶ月あたり44640行増えていくので、Spreadsheetの制約が気になった。 探し方が下手くそなのか、唯一公式ドキュメントで見つけられた制約は「1スプレッドシートは1000万セルまで、または18278列まで」というもの。それ以外は野良サイトが「1シートに18278行まで」「1シートに65536行まで」「 行数の上限はない」などと書いていて、よくわからなくなってきたので、とりあえず1ヶ月毎に書き込み先シートを分けることにした。これなら4.5年くらいは持つ。

トリガーを設定

スクリプトのトリガーはタイマー(定期実行)とする。GASの仕様では最短の実行周期は1分ごと。SwitchBotプラグミニではおそらく数秒単位でデータ測定がされているが、毎分でも実用上問題ないので、毎分のトリガーを設定する。

出力の様子

消費電力だけでなく電圧変動もわかる

単に可視化するだけでなく、様々な分析ができて楽しい。
たとえば、私の環境ではプラグミニをPCに接続しているので、PCだけで毎月1000円くらい電気代がかかるだろうということが分かる。

まとめ

  • SwitchBotプラグミニとGoogle Spreadsheetを組み合わせて消費電力を可視化する仕組みを作れる
  • SwitchBot API v1.1はAPI呼び出し時のお作法含め、Google Apps Scriptの実装例を紹介した

参考