Nature株式会社ファームウェアエンジニアの中林 (id:tomo-wait-for-it-yuki) です。スマートリモコンNature Remoシリーズを手がけるNatureでは、スマートホーム新標準のMatter1に注目しています。
GitHubでMatterのプロトコルスタックやいくつかのサンプルが公開されて2います。今回は比較的簡単に動かせるM5Stack3のBLE/無線LANを使ったサンプルを試しながらMatterについて学んでみたいと思います。
Matter
MatterはCSA (Connectivity Standards Alliance) が策定している新しいスマートホームの標準規格です。これまでのスマートホームデバイスは各デバイスメーカーがそれぞれの規格に沿って開発していましたが、各社のデバイスが共通して使う規格を決めることで、デバイス間の相互接続性を高めよう、という狙いです。Google, Apple, Amazonなどが参画しており、今後スマートホームデバイスの標準になっていくことが期待できます。
無線LAN, BLE, Threadといった通信規格の上位にIPv6をベースとする共通プロトコルを定義しています。このことにより、下位の通信規格に依存せず、相互接続を可能とします。元々CHIP (Connected Home over IP) という名称で、まだところどころにその名残が残っています。技術者視点だとConnected Home over IP
はずばり何したいのかそのまんまの名称だったわけですね。
サンプル動かしてみる
注意!
- 2021/09/29時点の手順です
- 著者の環境はUbuntu20.04です
用意するものはこれだけです。
- ホストPC
- M5Stack BASICを1つ
M5Stack Core2はディスプレイ非対応とのことなので、動かせるものを全て動かしたい場合、M5Stack BASICが安定択です。
M5Stackでall-clusters-appサンプルを動かし、ホストPCのデバイス制御用CLIツールからコミッショニングおよび制御を行います。
all-clusters-app
これまでいくつかサンプル動かしてみましたが、お手軽に雰囲気掴みたい場合、examples/all-clusters-app/esp32
4を使うのがおすすめです。all-clusters-app
ではデバイスのコミッショニング (機器の初期設定) とデバイスの制御を試すことが可能です。
今回はM5Stackを使用しますが、DevKitCなどもっと安価なデバイスでも動きます。RISC-Vコアが搭載されたESP32C3-DevKitMで動かすこともできます。デバイスを用意したら、all-clusters-appのREADME.md5に記載の手順通り進めていきます。
all-clusters-appでは、次のようなデバイスがあるかのようにM5Stackが振る舞います。
時計のバッテリ残量やドアロックの状態などは、M5Stackの画面とボタンから変更することができます。ライトのようなコントローラから制御するデバイスは制御に合わせて画面の表示内容が変わります。
サンプルのビルド
次の手順でサンプルをビルドします。
- ESP-IDF v4.3のセットアップ
- Matter開発環境のセットアップ
- サンプルアプリケーションのビルド
ESP-IDF v4.3のセットアップ
ESP-IDF (Espressif ESP32 IoT Development Framework) とxtensa用のビルドツールチェインをセットアップします。セットアップ手順は下記を参照ください。
https://docs.espressif.com/projects/esp-idf/en/v4.3/esp32/get-started/index.html
環境変数IDF_PATH
が設定されていることを確認した上で、ESP-IDFの環境をセットアップし、Matter開発環境をセットアップします。
source $IDF_PATH/export.sh # このコンソールで次の手順へ
Matter開発環境のセットアップ
submoduleのcloneなどあるので、サンプルをビルドする前に実行します。
git clone https://github.com/project-chip/connectedhomeip.git cd connectedhomeip source ./scripts/bootstrap.sh source ./scripts/activate.sh
2回目以降はsource ./scripts/activate.sh
だけでOKです。
サンプルアプリケーションのビルド
# connectedhomeipのルートディレクトリから cd examples/all-clusters-app/esp32
デフォルトではESP32-DevKitCがターゲットになっているので、M5Stackに切り替えます。
idf.py menuconfig
Demo
-> Device Type
からM5Stack
を選択して、保存します。
サンブルアプリケーションをビルドします。
idf.py build
サンプルの実行
M5StackをホストPCにUSBケーブルで接続して、ファームウェアを書き込みます。
idf.py flash monitor
次のような画面が表示されればOKです。CHIPと表示されているのはご愛嬌ですね。
コミッショニングと制御
ホストPCからM5Stackのコミッショニング (初期設定) を実施して、Matterデバイスとして制御します。具体的にはBLE経由でコミッショニングして、M5StackをホストPCと同じ無線LANアクセスポイントに接続し、無線LAN経由で制御します。
CLIツールのセットアップ
ホストPCからM5Stackのコミッショニングと制御を行うためのCLIツールをセットアップします。
# connecteddhomeipのルートディレクトリ ./scripts/build_python.sh -m platform source ./out/python_env/bin/activate
python contollerを起動します。
$ chip-device-ctrl [1632729563.198847][112356:112356] CHIP:DL: Avahi client registered [1632729563.199274][112356:112356] CHIP:ZCL: Using ZAP configuration... # ... [1632729563.200628][112356:112356] CHIP:CTL: Loaded credentials successfully [1632729563.203879][112356:112364] CHIP:DL: Platform main loop started. Chip Device Controller Shell chip-device-ctrl >
BLE経由のコミッショニング
まずBLEをスキャンします。無事見つかりました。
chip-device-ctrl > ble-scan 2021-09-29 09:52:43,642 ChipBLEMgr INFO scanning started 2021-09-29 09:52:45,344 ChipBLEMgr INFO Name = None 2021-09-29 09:52:45,344 ChipBLEMgr INFO ID = 5f294ca3-b123-465a-aa2f-e48633e07dbe 2021-09-29 09:52:45,345 ChipBLEMgr INFO RSSI = -56 2021-09-29 09:52:45,345 ChipBLEMgr INFO Address = 08:3A:F2:68:37:1E 2021-09-29 09:52:45,347 ChipBLEMgr INFO Pairing State = 0 2021-09-29 09:52:45,347 ChipBLEMgr INFO Discriminator = 3840 2021-09-29 09:52:45,347 ChipBLEMgr INFO Vendor Id = 9050 2021-09-29 09:52:45,347 ChipBLEMgr INFO Product Id = 17729 2021-09-29 09:52:45,348 ChipBLEMgr INFO Adv UUID = 0000fff6-0000-1000-8000-00805f9b34fb 2021-09-29 09:52:45,348 ChipBLEMgr INFO Adv Data = 00000f5a234145 2021-09-29 09:52:45,348 ChipBLEMgr INFO
M5StackにBLEで接続します。
chip-device-ctrl > connect -ble 3840 20202021 135246 Device is assigned with nodeid = 135246 [1632877083.478955][19975:19979] CHIP:BLE: BLE removing known devices. [1632877083.487762][19975:19979] CHIP:BLE: BLE initiating scan. [1632877084.025243][19975:19979] CHIP:BLE: New device scanned: 08:3A:F2:68:37:1E [1632877084.025283][19975:19979] CHIP:BLE: Device discriminator match. Attempting to connect. # たくさんログが出る [1632877096.354977][19975:19983] CHIP:ZCL: NOCResponse: [1632877096.354993][19975:19983] CHIP:ZCL: StatusCode: 0 [1632877096.355000][19975:19983] CHIP:ZCL: FabricIndex: 0 [1632877096.355007][19975:19983] CHIP:ZCL: DebugText: 0 [1632877096.355018][19975:19983] CHIP:CTL: Device returned status 0 on receiving the NOC [1632877096.355028][19975:19983] CHIP:CTL: Operational credentials provisioned on device 0x23baba8 Secure Session to Device Established Device temporary node id (**this does not match spec**): 135246
これでデバイスとのセキュアセッションが確立できたようです。おおよそ10秒くらいでしょうか?ちょっとわかりにくいですが、BLE接続ができるとM5Stack画面の左側にある青色の四角が明るくなります。
少しコマンド connect -ble 3840 20202021 135246
のパラメータを説明しておきます。3840
と20202021
は、それぞれ識別用のIDとPINコードで、ビルド時のパラメータとして設定可能です。135246
はノードIDでこの後のコマンドでは一貫してこのIDを使用しなければなりません。接続時の最後のログにDevice temporary node id (**this does not match spec**): 135246
と出ていて、一時的なデバイスノードIDであろうことがわかります。ちなみにconnect-ble
実行時にこのパラメータを指定しなければ、chip-device-ctrl
がIDを生成して表示してくれます。
無線LANアクセスポイントに接続するために、SSID/passwordを設定し、無線LANネットワークを有効化します。
chip-device-ctrl > zcl NetworkCommissioning AddWiFiNetwork 135246 0 0 ssid=str:TESTSSID credentials=str:TESTPASSWD breadcrumb=0 timeoutMs=1000 chip-device-ctrl > zcl NetworkCommissioning EnableNetwork 135246 0 0 networkID=str:TESTSSID breadcrumb=0 timeoutMs=1000
1つ目のコマンドでSSID/passwordをM5Stackに送信します。TESTSSID
とTESTPASSWD
の部分は使用するアクセスポイントのものに置き換えて実行します。2つ目のコマンドでnetworkID
で指定したアクセスポイントに接続します。
M5Stack側のログでもアクセスポイントに接続したことがわかります。
I (390625) wifi:new:<3,1>, old:<1,1>, ap:<255,255>, sta:<3,1>, prof:1 I (391125) wifi:state: init -> auth (b0) I (391135) wifi:state: auth -> assoc (0) I (391155) wifi:state: assoc -> run (10) I (391165) wifi:connected with TESTSSID, aid = 3, channel 3, 40U, bssid = xx:xx:xx:xx:xx:xx I (391175) wifi:security: WPA2-PSK, phy: bgn, rssi: -50 I (391185) wifi:pm start, type: 1 I (391185) wifi:AP's beacon interval = 102400 us, DTIM period = 3
アクセスポイントに接続すると黄色い四角が明るくなります。
もうBLEは使わないのでBLEを切断します。これ以降はBLEのadvertiseをしなくなるようで、scanに引っかからなくなります。BLE切断しても青色の四角は明るいままのようです。
chip-device-ctrl > close-ble
M5StackのIPアドレスを取得します。M5Stack上でmDNSが動いており、これで通信するIPアドレスが取得できます。
chip-device-ctrl > resolve 0 135246 [1632878616.341733][38115:38123] CHIP:DL: Avahi resolve found [1632878616.341806][38115:38123] CHIP:DIS: Node ID resolved for 0x000000000002104E to [192.168.1.16]:5540 Node address has been updated [1632878616.342207][38115:38123] CHIP:CTL: OperationalDiscoveryComplete for device ID 135246 [1632878618.350885][38115:38123] CHIP:EM: Received message of type 0x31 with vendorId 0x0000 and protocolId 0x0000 on exchange 39023 Commissioning complete Current address: 192.168.1.16:5540
ログを見ると0x000000000002104E (135246)
が[192.168.1.16]:5540
に解決された、とあります。これでコミッショニングは完了です。次はデバイスの制御を試します。
デバイスの制御
まずはライトのOn/Offを制御してみます。上から1番目の緑の四角が明るくなります。
chip-device-ctrl > zcl OnOff On 135246 1 1
ライトは2つあるので、もう1つの方を制御してみます。上から3番目の水色の四角が明るくなります。
chip-device-ctrl > zcl OnOff On 135246 2 1
コマンドのフォーマットはこのような感じです。先程はendpoint
を変えることで、異なるライトを制御しました。
zcl <cluster> <command> <nodeid> <endpoint> <groupid> [key=value]
次は温度計から温度を読み取ってみます。
chip-device-ctrl > zclread TemperatureMeasurement MeasuredValue 135246 1 0 #... [1632883644.088914][38115:38123] CHIP:ZCL: ReadAttributesResponse: [1632883644.088919][38115:38123] CHIP:ZCL: ClusterId: 0x0000_0402 [1632883644.088922][38115:38123] CHIP:ZCL: attributeId: 0x0000_0000 [1632883644.088924][38115:38123] CHIP:ZCL: status: Success (0x0000) [1632883644.088925][38115:38123] CHIP:ZCL: attribute TLV Type: 0x00 [1632883644.088930][38115:38123] CHIP:ZCL: attributeValue: 2100 #...
2100
が返ってきています。これはZigBee Cluster Library Specificationによると21.0℃を表しています。
MeasuredValue = 100 x temperature in degrees Celsius.
値はプログラムの初期化時に設定されたものがそのまま返ってきています。M5Stackの画面とボタンから温度の値を変更すると、取得できる値も変わります。
大体雰囲気はつかめてきましたね。
サンプルを動かしてわかったこと
けっこうZigBee
Matterを策定しているCSA (Connectivity Standard Alliance)6は元々ZigBee Allianceだったこともあり、随所にZigBeeの資産を活用している様子が伺えます。プロトコルスタックの少し下の方をみると、ZigBee Cluster Library (zcl) を利用しているのも見て取れます。clusterの仕様などはZigBee Cluster Library Specification7を見ると読み解くことができます。
デバイス初期設定も標準化
デバイスの初期設定 (コミッショニング) が標準の中に含まれていて、その実装も与えられているのは嬉しいですね。今は各デバイスで独自の初期設定を持っていると思いますが (Nature Remoも)、これも統一化されることでユーザーが戸惑うことも少なくなるのではないか、と期待できます。BLE/IP/QRコードあたりが初期設定で使えるようになりそうです。
C++実装
ぱっと見、スタックもAPIもC++です。スマートホーム用の標準でその実装なので当然マイコンをターゲットとしていますし、サンプルも複数のマイコン上で動くものが提供されています。こういうところもCではなくC++で作っていく感じなのでしょうね。Matterに関しては少なくとも暗号化処理やIPスタックが必要になってくるため、それなりの性能があるマイコン使うのが前提というのも言語選定の根底にありそうです。
今後C言語のbinding作られるのかどうかは少し注目です。
他のサンプル
今回はall-clusters-appサンプルをM5Stackで動かしましたが、複数のサンプルがいくつかのターゲットデバイスに対して提供されています。
nRF52840を使ったサンプルでは、モバイルアプリも含めてサンプルが提供されているので、けっこうそれっぽい雰囲気を味わうことができます。が、nRF52840を2台用意して、1台をThread Border Routerにして…、みたいな感じで動かすのが大変です。興味がある場合は、lock-app8を見てください。
Matterでこまったーこと
CLIツールを起動するとBluetoothペアリングが解除される
ホストPCからBLE接続するときにCLIツールを起動するとBluetoothのペアリングが解除されてしまいます。初回Bluetoothイヤホンで音楽聞きながら作業していたわけですが、急に音が止まりました。BLE使うししゃーないか、と思って改めてMatterのサンプル動かし終わった後にWeb会議のためBluetoothイヤホン接続しようとしたら、接続できなくて焦りました。
あとからペアリング自体が解除されていることに気づいてことなきを得ました。
2回目以降のコミッショニング方法が謎
M5Stackにファームウェアを書き込んで、CLIツールでBLE接続するところからコミッショニングすれば制御できるのですが、M5Stackを再起動したあとにコミッショニングする方法がわからず、事故ったら最初からやり直していて不便です!助けてください!
ツールをしらばく起動しているとCPU使用率が100%になる
Matterのサンプルで遊んでいると、特にPCに負荷かけていないはずなのに急にファンが唸りだしました。なんだろう?と思ってシステム負荷確認してみると…
うーん、なんかイベントループの実装ミスってたりするのでしょうか…。
最後に
簡単にではありますが、Matterのサンプルを動かしてみました。ホストPCとM5Stack間のやり取りしかしていないのであまりスマートホーム感は出ませんでしたが。…スマートホームのデモとしてはやはりスマートスピーカーから制御できるようなものがあると見栄えが良いですね。
ソースコードもそれなりに読んでいるので、別の機会で紹介していければ良いな、と考えています。今後、Matterがもっと盛り上がるとおもしろいな、と思っているのでぜひ皆様もお試しください。
エンジニア積極採用中です
We are hiringです。ファームウェアのポジションもオープンしていますので、一緒にMatterでこまったー、となってくれる方からのご応募をお待ちしております。カジュアル面談等も歓迎なので、その場合はTwitterなどでお声がけくださると嬉しいです。
-
https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/esp32↩
-
https://github.com/project-chip/connectedhomeip/blob/master/examples/all-clusters-app/esp32/README.md↩
-
https://zigbeealliance.org/news_and_articles/chip-is-now-matter/↩
-
https://zigbeealliance.org/wp-content/uploads/2019/12/07-5123-06-zigbee-cluster-library-specification.pdf↩
-
https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/nrfconnect↩