SwitchBot BLE API で機器にBluetoothで直接コマンドを送る ESP32でスマートホームをもっと便利に
以前、このブログ「テック大家さん」にて、公開されているBLE (Bluetooth Low Energy)のプロトコルでSwitchBot機器から直接データを取得する方法について解説しました。
以下の記事に詳しく書かれています。
本日の記事はその続編です。
以前書いた記事では、BLEのアドバタイズパケットに載っているSwtichBot製品のセンサーの値を読み取る方法について書いていました。続編としては、BLEのGATT通信についてより詳細に解説していきます。
SwitchBot製品群と公開APIについて「おさらい」
SwitchBotは、スマートホームを手軽に実現するためのIoT (Internet of Things)製品群のブランド名です。電球やスイッチ、温度計や人感センサーなどの製品があり、全てスマホで操作できる製品です。
こういったスマート家電商品はいくつものメーカーから販売されていますが、SwitchBotの良いところはプログラマーが独自の機能を実現できるよう、API(Application Programming Interface)が公開されている点です。
ソフト開発大好きな、テック大家さんとしてはSwitchBotのこの点が気に入っています。推しの理由に関しては以下の記事に詳しく書いておりますので、合わせてご覧いただけると幸いです。
公開されているAPI情報は2つ。Web APIと今回説明するBLE APIです。以前の記事でも説明しているのですが、この2つのAPIの関係は下図のようになっています。
つまり、SwitchBotクラウド経由で操作する、例えば、家の外からでも操作が必要な場合はWeb APIを使い、室内でレスポンスよく操作する場合はBLEを使う、というイメージです。
BLE GATT通信の仕組み
SwtichBotのおさらいができたところで、BLEに話を戻します。
SwitchBotのBLE APIを使うには、Bluetooth Low Energyの規格の一部である。GATT通信について基本的な理解が必要になります。
BLEで通信する場合、規格上は機器のどちらかがセントラル(クライアント)になり、どちらかがペリフェラル(サーバー)になる必要があります。
SwitchBot BLE API の前提としては、SwtichBot機器はペリフェラルになります。したがって、筆者が作るプログラムはセントラルの機器、ということになるわけです。言い方を変えると、SwitchBot が公開しているBLE APIはペリフェラル、つまりサーバー側のAPI仕様ということになります。
公開されている仕様はGithubにありまして、全て英語なのではありますが、以下のリンクから参照することが出来ます。
ただし、率直に言って、この資料はとにかくわかりにくいです。APIというよりはプロトコル仕様なのですが、被筆者は当初、この資料のByte 0 がどこのパケットの先頭の話をしているのか理解できませんでした。英語だからということではないと思います。筆者自身がBLEにそれほど精通していないせいもあるかも知れません。が、正直、不親切な説明に感じました。
ちなみに、上記の仕様では、ペリフェラルを「Device」、セントラルを「Terminal」と呼んでいます。資料(英語)を読むときは本記事の説明を読み替えて下さい。
さて、SwtichBot機器と通信をするには、BLEのGATT通信という仕組みを理解している必要があります。
BLEの規格では、GATTのサーバーは以下のような構造でコマンドを体系化することになっています。
つまり、ペリフェラルは「サービス」(Service)という概念で括られる機能を有しており、「サービス」というグループの中に個々の機能「キャラクタリスティック」(Characteristic)を搭載している、というモデルです。
実際にコマンドを送ったり、値を取得する際にはペリフェラルの「キャラクタリスティック」を指定してやり取りすることになります。
したがって実際の通信は、
- 機器を見つける
- 機器に「コネクト」(接続)する
- 機器の「サービス」を見つける
- 機器の「キャラクタリスティック」を見つける
という一連の操作を行った上で、キャラクタリスティックに対してコマンドのWrite(書き込み)を行うことで通信が成立します。以下で説明する、実際のプログラミングでもこのような手続きを踏むことになります。
サービスとキャラクタリスティックには、それぞれ固有のUUIDが付けるのがBLE GATTの規定です。これに従い、SwitchBotの API仕様書にはそれぞれの機器に応じてUUIDが書かれています。実際にSwitchBotの機器を呼び出す際は、これ使ってアクセスするというわけです。
ESP32 の Arduino BLEライブラリ
実際にBLEを通信を使ってSwtichBot製品を制御するセントラル(クライアント)を作ってみましょう。
使用するのはESP32系のチップが搭載されているM5 Atom S3U という機器です。
写真では大きく見えますが、親指ほどの小さな機器です。小さくてもESP32が搭載されており、これによりBLE通信が可能です。
小さな筐体にボタンもついているし、フルカラーのLEDもついているので、ユーザーインターフェースもバッチリです。Amazonには売っていないようですが、ディスプレイが付いた類似品などM5の機器で動作するはずです。
この機器にArduinoの BLEライブラリ (C++)を使ってコードを書くことにします。
BLEライブラリは、Platform IOでespressif32のプラットフォームをインストールするとBLEというライブラリが入るのですが、筆者が使った時点ではどうもうまく動作しませんでした。
そこで、nkolbanという方が作っているバージョンを試しました。以下に置き換えの方法が書かれています。
若干手間はかかります。
手順としては、https://github.com/nkolban/esp32-snippets.gitをcloneしてきて、ビルドしてできるESP32_BLE.zipというライブラリを使います。Platform IOがインストールするBLEライブラリをまるっと入れ替えるという作業です。
このライブラリは、上述のBLE GATT通信の論理的な構造をうまく抽象化したクラス構成になっています。以下にライブラリの構造の一部をクラス図にしてみました。かなり端折って単純化しています。
クラス名は、プレフィックスの"BLE"を除いた名前を書いているので本物とちょっと異なりますのでご注意を。
これを見てわかるように、BLEDeviceクラスからcreateClient()によりクライアント(つまり、セントラル)用のBLEClientクラスのインスタンスを生成します。ここで、BLEClientに対してconnect()を呼ぶと相手のデバイス(=SwitchBot機器)と通信を開始します。
BLEClientには、getService()という関数があり、サービスのUUIDを指定して呼び出すことによりBLEServiceインスタンスを取得。BLEServiceにはgetCharacteristic()という関数があるので、これも同様にキャラクタリスティックのUUID指定で、BLECharacteristicのインスタンスを取り出します。
BLECharacteristicクラスにはメンバーとしてwirte()、read()の関数があります。このwrite()関数を使うと該当キャラクタリスティックを持つSwitchBot機器の操作ができるというわけです。
SwitchBot機器へBLEコマンドを送る(例: スマート電球)
では具体的に、BLECharacteristic::write()に送るコマンド(データ)はどのような形式になるのでしょうか。
それが、SwitchBot BLE APIとして公開されているサイトに書かれている仕様を参考にする部分です。
ここでは実例として、スマート電球のオフ・オンをするケースを考えます。スマート電球は、仕様書では”ColorBubble”と呼んでいます。
この仕様には、以下のようにあります。
BLECharacteristicクラスのwrite関数の形式は具体的には以下のようになっています。
bool writeValue(uint8_t* data, size_t length, bool response = false);
引数にはデータの配列の先頭アドレス(data)と長さ(length)を指定します。
この関数に送るべきデータは、SwitchBotの仕様の上の表にあるREQ Packet NO encriptionのByte 0からのデータです。(この表の読み方も結構ややこしい…)
以下は電源オンとオフを行うコード(抜粋)です。(最終行にあるsendValue()関数に渡しているパラメータがBLECharacteristic::writeValue()に渡る値です)
オンするときは、writeValueに書き込むデータは、0x57を先頭に、上記表の"Turn On Bulb"の列に書かれたコードを書きます(Byte:2まで)。
同様に、オフにするときは、0x57を先頭に、上記表の"Turn Off Bulb"の列に書かれたコードを書きます(Byte:2まで)。
(上の表とコードをジッと見比べてみると意味がわかるのではないでしょうか)
bool setEnabled(boolean onOrOff)
{
uint8_t writeDataOn[] = {0x57, 0x0f, 0x47, 0x01, 0x01};
uint8_t writeDataOff[] = {0x57, 0x0f, 0x47, 0x01, 0x02};
uint8_t *pWriteData = onOrOff ? writeDataOn : writeDataOff;
size_t writeLen = onOrOff ? (sizeof(writeDataOn) / sizeof(writeDataOn[0])) : (sizeof(writeDataOff) / sizeof(writeDataOff[0]));
return sendValue(pWriteData, writeLen);
}
SwitchBot BLEを呼び出すサンプルコード
執筆時点では、全体のコードはちょっとまだ完全に整理できておらず、残念ながらそのまま公開状態ではありません。別途公開したい考えていますので、お楽しみに!
ですが、それだとちょっと物足りないので、BLEライブラリでSwitchBotを操作する部分のコード(クラス)のみを公開します。ご興味があれば参考にしてみて下さい。
どのSwitchBot機器にも共通に使える基底クラスを作りました。
ヘッダ(SwitchBotBaseDevice.h)です(ファイル全体を表示するには、ファイル名のリンクをクリックして下さい)
その実装(SwitchBotBaseDevice.cpp)です。(ファイル全体を表示するには、ファイル名のリンクをクリックして下さい)
個々のSwitchBot機器に対する実装は来てクラスから派生して実装します。例えば、ColorBubble用のクラスなら以下のようなコードです。(ファイル全体を表示するには、ファイル名のリンクをクリックして下さい)
というわけで、最後は少し駆け足になりましたが、ESP32でSwitchBotをBLEで制御する方法論について解説しました。今日はここまで〜。
ディスカッション
コメント一覧
まだ、コメントがありません