SwitchBot スマートロック を BLE APIで開閉 ネットがなくても制御できる(noble/NodeJS編)
以前の記事で、Web APIを使ってSwitchBotスマートロックを開閉しました。
Web APIはインターネット接続が必要になります。 一方、 近距離無線のBluetooth BLE を使えば、近くにあるスマートロックは、インターネット接続がなくとも開閉でるきるはず。
幸いなことに筆者の推しであるSwitchBotは Web AP 仕様に加え、Bluetooth API仕様も公開されています。
この点が筆者がSwitchBot 推しである最大の理由でもあるのですが、問題はSwitchBotのBluetooth APIは文書化されていないプロトコルが存在することです。 特に、スマートロックの BLEプロトコルに関しては、 以下の仕様書を読んでも、ロック開閉のためのプロトコルが書かれていません。
この記事で述べたように、文書化されていないプロトコルに関してもgithubでソースコードが公開されているようなのです。
そこで今回の記事では、 文書化されてないソースコードをもとに、SwitchBotスマートロックをWeb APIを使わずにBluetoothだけで開閉してみます。
SwitchBotスマートロック製品は 指紋認証 ができるタッチキーと言う製品もあり、これを使うとネットを使わずにスマートロックを操作できます。これと同様のことを自作のプログラムから行うイメージです。
SwitchBotスマートロックのBLEプロトコルは暗号化されている
当初、筆者はSwitchBotが公式に公開しているBLE APIのプロトコル仕様の中に、スマートロックのプロトコルがないので、仕様は非公開なのだと考えました。
しかし、ネット上をいろいろ調べてみると、node-switchbotと言う Javascriptを使ったライブラリがBLEを使ったスマートロックの制御を実装していることを見つけたのです。
このソースコードを読むと、公開されているBLE APIの仕様書の中には存在しない方法により、暗号通信していることがわかります。
その情報ソースに関しては、前回の記事でまとめておりますので、そちらも併せてご覧ください。
ここで実装されているプロトコルを利用すれば、自前でBluetoothの通信によりスマートロックを開閉するプログラムができるはずです。
暗号化の仕組みについて
ここでは、 筆者がソースコードを解析して理解した、スマートロックの BLEプロトコルにおける暗号の仕組みを説明します。
暗号化は2段階の作業が必要になります。
- SwitchBotのアカウントからキーIDを取得する
- キーIDを使ってBLEコマンドを暗号化する
それぞれ説明します。
SwitchBotのアカウントからキーIDを取得する
最初の作業工程は、クラウドサービスを利用して、SwitchBotのアカウントからキーIDを取得することです。
pySwitchBotと言うオープンソースのPythonのプログラムの中にAPIを呼び出すコードがありました。
ここで使われるクラウドのWeb APIも筆者が探した限り、どこにも文書化された仕様書はありませんでした。しかし、pySwitchBotのスクリプトを使うと、キーIDとエンクリプションキーと呼ばれる2つの情報を入手することができるのです。実行時は、ユーザIDとパスワード、及び制御したいスマートロックのMACアドレスが必要になります。つまり、これは、ユーザ情報を元に、そのユーザが登録している(使用している)スマートロックの認証情報が取得できるスクリプト、というわけです。
筆者はpySwitchBotを解析し、キーIDとエンクリプションキーを取得する部分だけ、試しにJavaScriptのプログラムにしてみました。スマートロックを解除するためのIDを取得するプログラムをnpmのパッケージとして公開しました。以下のリンクから利用することができます。npmの使い方に慣れている方にはこちらの方が便利でしょう。
2024年10月28日追記:
上記のスクリプトは、node-switchbotの本家のGithubからもリンクを張ってもらうようにドキュメントを修正しPull Reuqestして取り込んでもらいました。
キーIDを使ってBLEコマンドを暗号化する
スマートロックと通信するためには、上で得られたキーIDとエンクリプションキーが必要になります。
SwitchBot スマートロックと自前で実装するBLE セントラルの間のシーケンスは、以下の図のようになります。
上の図はシーケンスの全体像ですが、特に赤枠の中を見てください。
赤枠の中の最初の呼び出しは、キーIDを暗号化せずにスマートロックに送り、IVと言う値を得るものです。 IVはイニシャルベクトルと呼ばれ、 暗号をより強固にする仕組みの1つです。
次に、このイニシャルベクトルを使って、 解錠または施錠を行うBLEコマンドを暗号化します。
暗号アルゴリズムは、AES 128ビットCTR モードと言うものを使っているようです。
このフローは後ほど説明するnode-switchbot のライブラリの中で実装されているものです。筆者はこのBLEプロトコルをEPS 32プラットフォームの上で使うことを考えており、ライブラリのソースコードを解析しています。
解析結果として得られるプロトコルの詳細については別の記事でお届けする予定です。お楽しみに!
スマートロックを BLE 制御する ソースコード
今回は、上述のJavaScriptライブラリーであるnode-switchbot を使い、クラウドから得られたキーIDとエンクリプションキーが正しく使えるものなのか、検証してみることにしました。
確認したのはMacOSです。node-switchbot はnobleというBLE 通信のためのパッケージに依存していますので、適切にインストールしておく必要があります。
node-switchbot を使ったコードは以下のようなものです。
このプログラムでは、最初にSwitchBotオブジェクトを作成し、そのインスタンスのdiscover()と言う関数を実行します(22行目)。 discovery()の引数には操作したいスマートロックのMACアドレスを指定します。MACアドレスは上でキーIDとエンクリプションキーを取得したときに使ったものと同様です。期待するデバイスが見つかると、それを示すオブジェクトが返ってきます。
オブジェクトには setKey()と言う関数があるので、 解錠・施錠のための関数を呼び出す前に、上で得られたキーIDとエンクリプションキーをセットします(29行目)。
後はlock()かunlock()か、好きなほうの操作を行えば良いわけです(30行目)。
筆者の手元では、MacOS上でこのプログラムは動作しました。つまり、インターネット経由ではなく、Bluetoothを使ってMacのコマンドLINEからスマートロックの施錠解除ができました。
次のステップはESP32-Arduinoへの組み込みだ!
この記事では、SwitchボットスマートロックをDLのBluetooth energyのプロトコルを使って自前のプログラムから解錠、または施錠ができるかどうか確認しました。
非公開のWeb APIを使って、暗号化のためのキーIDとエンクリプションツーを入手すれば、 自前のプログラムからスマートロックを制御することができました。 使用したのはnode-switchbot と言う JavaScript のライブラリです。
オープンソースのJavaScriptの実装が動作することがわかったので、今後はこのプログラムをで使われているBLEコマンドを解析しESP32の実装に移植して行きます。 以下の記事では、ESP32を搭載したM5 ATOM S3 Liteという小型のボードを使って、node-swtichbotと同等の動作をArduino-ESP32で実現しています。併せてご覧ください。
ディスカッション
コメント一覧
まだ、コメントがありません