ハードなしでMatterゲートウェイを動かす:PCとスマホだけでApple Home連携
開発ボードが届く前に、Windows PCをゲートウェイ、nRF Connectを入れたスマホをBluetooth機器にして、Apple Homeでのペアリング、操作、状態同期を確認しました。
前回の記事では全体の構成を紹介しました。Bluetooth デバイスと Apple Home のあいだに Matter ゲートウェイを置き、ゲートウェイに双方のメッセージを翻訳してもらう、という形です。
構成は紙の上ならいくらでもきれいに描けます。実際に手を動かす前に、まず確かめておきたいことがありました。自作したゲートウェイを Apple Home はちゃんと認識してくれるのか、そしてその配下の Bluetooth デバイスを操作できるのか?
これはハードウェアがなくても確認できます。開発ボードはまだ配送中だったので、手元にあった Windows パソコンとスマホだけで、経路全体を通しで動かしてみました。
まずはソフトウェアで、ハードウェアはそのあと
ハードウェアのプロジェクトだと、つい最初にボードを買って、モジュールをはんだ付けして、ファームウェアを焼きたくなります。ただ、経路が長くなると、問題が起きたときにどの層が悪いのか切り分けにくいんですよね。Matter のペアリングが失敗したのか、ゲートウェイにバグがあるのか、シリアル通信でバイトが落ちたのか、それとも Bluetooth の電波が弱いだけなのか。
先にソフトウェアで上の2層を通しておけば、実機に切り替えたときに疑うべき範囲がぐっと狭まります。しかもコストはほぼゼロ。パソコンとスマホがあればできます。
誰が何の役を演じるか
| 役割 | 実際の製品では | 今回のデモでは |
|---|---|---|
| コントローラー | Apple Home | Apple Home(本物) |
| ゲートウェイ | Linux ゲートウェイボード + Bluetooth モジュール | Windows パソコン(内蔵の Bluetooth を使用) |
| Bluetooth デバイス | スイッチ、照明 | スマホ(nRF Connect を使用) |
Apple Home は本物で、ゲートウェイのプログラムも後で製品に載せるものと同じです。一番下の「Bluetooth デバイス」だけをスマホが演じています。
nRF Connect は Nordic が出している無料の Bluetooth デバッグツールで、Android にも iPhone にもあります。周囲の Bluetooth アドバタイズをスキャンできるだけでなく、自分でアドバタイズを出すこともできるので、デバイス役にちょうどいいんです。
なぜ Bluetooth Mesh デバイスを直接シミュレートしないのか
実際の製品では、デバイスとゲートウェイのあいだは SIG Mesh で通信します。ただ、スマホは Mesh デバイスを演じられません。Android も iOS も「Mesh ノードになる」機能を公開していないからです。nRF Mesh のようなアプリは、プロビジョニング用のツールやリモコンとしてしか使えません。
そこでデモでは、もっと単純な方法に切り替えました。デバイスとゲートウェイのあいだは、平文の Bluetooth アドバタイズで直接やりとりするという方法です。ゲートウェイが照明をつけたいときは「オン」をアドバタイズし、デバイスの状態が変わったら、その内容をゲートウェイに向けてアドバタイズします。
この形式は暗号化もリプレイ対策もしていないので、経路の検証専用で、製品には使いません。それでも価値があるのは、一番下の通信方式を除けば、ゲートウェイの中身がすべて本物だからです。Matter のペアリング、デバイステーブル、コマンドの変換、状態の同期、どれも本物のまま検証できます。
デモ用のアドバタイズ形式
形式はシンプルなほどよく、スマホアプリで手打ちして組み立てられるくらいがちょうどいいです。
ゲートウェイ → デバイス(ダウンリンク):製造者固有データ(Manufacturer Data)を1つ使い、Company ID は 0xFFFF にします。これは Bluetooth SIG がテスト用に確保している番号で、正式な製品には使えません。
| バイト | 内容 | 例 |
|---|---|---|
| 1~2 | 固定の GW |
47 57 |
| 3~4 | デバイスアドレス(リトルエンディアン) | 02 00 は 0002 |
| 5 | オン/オフの状態 | 01 がオン、00 がオフ |
| 6 | シーケンス番号(毎回 +1) | 05 |
デバイス → ゲートウェイ(アップリンク):Android と iPhone でそれぞれ書き方が違います。
- Android:同じく製造者固有データで、Company ID は
0xFFFF、データは4456020001にします。4456がDV、0200がアドレス 0002、最後の01がオンを表します。 - iPhone:iOS ではアプリがアドバタイズに独自の製造者固有データを載せられず、できるのはデバイス名の変更だけです。そこでデバイス名を
DV0002:1にします。意味はアドレス 0002、オンです。
ゲートウェイ側のパースは数行で済み、どちらの書き方にも対応しています。
pub fn uplink(sections: &[(u8, Vec<u8>)]) -> Option<(u16, bool)> {
sections.iter().find_map(|(t, d)| match (*t, d.as_slice()) {
// Android:製造者固有データ FF FF 'D' 'V' アドレス 状態
(0xFF, [0xFF, 0xFF, b'D', b'V', a0, a1, on, ..]) => {
Some((u16::from_le_bytes([*a0, *a1]), *on != 0))
}
// iPhone:デバイス名 DV0002:1
(0x08 | 0x09, name) => {
let s = std::str::from_utf8(name).ok()?.strip_prefix("DV")?;
let (addr, on) = s.split_once(':')?;
Some((u16::from_str_radix(addr, 16).ok()?, match on {
"1" => true,
"0" => false,
_ => return None,
}))
}
_ => None,
})
}
ゲートウェイのプログラム
ゲートウェイは Rust で書いていて、Matter まわりにはオープンソースの rs-matter を使っています。パソコン側の Bluetooth 送受信は Windows 標準の Bluetooth API を呼んでいるので、追加のドライバーは要りません。
起動すると、プログラムは次の3つのことをします。
- Matter ゲートウェイとして振る舞う:ローカルネットワーク上に自分の存在を知らせ、Apple Home からのペアリングを待ちます。まだペアリングしていなければ、ペアリング用の QR コードがターミナルにそのまま表示されます。
- デバイステーブルを管理する:ターミナルで
add 0002 リビングの照明と入力すると、照明が1つ追加されます。各デバイスは Matter 上では独立した「ブリッジデバイス」になります。 - Bluetooth アドバタイズを送受信する:Apple Home から来たコマンドはダウンリンクのアドバタイズに変換して送り出し、スマホからのアップリンクのアドバタイズをスキャンしたら、状態を更新して Apple Home に同期します。
デバイステーブルとペアリング情報はローカルのファイルに保存されるので、プログラムを再起動してもペアリングし直す必要はありません。
Apple Home に追加する
iPhone の「ホーム」アプリでターミナルの QR コードを読み取れば追加できます。注意点がいくつかあります。
- 「認証されていないアクセサリ」という警告が出ます。開発中は Matter 公式のテスト用証明書を使っていて、認証を受けていないため、iOS が警告を出すんです。「このまま追加」を選べば大丈夫です。量産時には、認証を取った正式な証明書に差し替える必要があります。
- パソコンと iPhone は同じローカルネットワークに接続しておく必要があります。また、Windows ファイアウォールでこのプログラムの通信を許可しておいてください。ペアリングがタイムアウトするときは、まずここを確認しましょう。
- ホームハブが必要です。Apple Home で Matter デバイスを操作するには、HomePod か Apple TV をハブとして用意しておく必要があります。
追加に成功すると、Apple Home にゲートウェイが1つ現れ、その配下に「リビングの照明」と「書斎の照明」がぶら下がります。普通の照明と同じように、それぞれ別の部屋に振り分けることもできます。
ダウンリンク:Apple Home から照明をつける
- スマホで nRF Connect を開き、スキャン(Scanner)画面に入ります。
- Apple Home で「リビングの照明」をタップします。
- パソコンのターミナルに
BLE TX -> 0002と1行表示され、ゲートウェイがそのコマンドを1秒間アドバタイズします。 - nRF Connect のスキャン一覧にデバイスが1つ増え、製造者固有データは
0xFFFFに4757 0200 01 xxが続く形になります。つまり「ゲートウェイから、0002 番のデバイスをオンに」という意味です。
パソコンはアドバタイズのたびに別の Bluetooth アドレスを使うことがあります。一覧から探しにくいときは、製造者固有データか電波強度で絞り込んでみてください。
アップリンク:デバイスから Apple Home に伝える
- nRF Connect で新しいアドバタイズ(Advertiser)を作ります。Android なら製造者固有データに
0xFFFF/4456020001を入力し、iPhone ならデバイス名をDV0002:1にします。 - アドバタイズを開始します。
- パソコンのターミナルに
BLE RX <- 0002 (リビングの照明): ONと表示されます。 - Apple Home のリビングの照明がオンの状態に変わります。
これは、ユーザーが壁のスイッチを押した状況を再現したものです。ダウンリンクよりもこちらのほうが大事かもしれません。デバイスの状態が戻ってこないと、Apple Home の表示が実際の状態とずれてしまうからです。
ハマったところ
全体としては難しい作業ではありませんが、初めてだと詰まりやすいところがいくつかありました。
1. スマホのアドバタイズした状態が、消したばかりの照明をまたつけてしまう。 スマホは同じパケットを延々と繰り返し送り続けます。最初はゲートウェイが受信のたびに状態を更新していたので、Apple Home で照明を消しても、1秒後にスマホの「オン」のパケットで元に戻されてしまいました。内容が変わったときだけ1回の報告として扱うように直したところ、解決しました。実機でも同じで、重複したメッセージは必ず除去する必要があります。
2. iPhone のデバイス名はスキャンレスポンスに入っている。 iPhone がアドバタイズするとき、デバイス名は最初のアドバタイズパケットではなく「スキャンレスポンス」に入っています。パソコンのデフォルトであるパッシブスキャンでは受け取れないので、アクティブスキャンに切り替える必要があります。
3. Bluetooth アドレスではデバイスを識別できない。 スマホもパソコンも、アドバタイズにはランダムアドレスを使っていて、しばらくすると変わってしまいます。そのため、デバイスの身元はアドバタイズの内容、つまりあの2バイトのアドレスに持たせました。これは Mesh の考え方とも一致しています。Mesh のデバイスも MAC ではなく、割り当てられたユニキャストアドレスで識別されます。
4. Windows では複数のアドバタイズを同時に出すと干渉する。 照明を続けて何回かタップすると、複数のアドバタイズが同時に出て、お互いに上書きし合ってしまいました。キューに入れて、1件送り終えてから次を送る方式に変えています。
5. アドバタイズの送信で Matter が止まる。 Windows ではアドバタイズを1回出すのにしばらく時間がかかります。Matter の処理の流れの中で直接呼ぶと、その間は Apple Home から来る他のコマンドがすべて待たされてしまいます。そこで、アドバタイズの送信は別のスレッドに切り出しました。
6. ゲートウェイの製造元や型番を変えても、ペアリングし直す必要はない。 これらの情報は Apple Home がゲートウェイから読み取っているので、ゲートウェイを再起動すれば新しい値が反映されます。ただ、Apple Home にはキャッシュがあり、いつ更新されるかはよく分かりません。すぐに確認したいなら、削除して追加し直すしかありません。ただし、ゲートウェイを削除すると、配下のデバイスもすべて一緒に消えるので注意してください。
ちなみに、ビルドしたてのプログラムは最初かなり大きかったのですが、サイズ優先の最適化にしてデバッグ情報を削ったところ、リリースビルドは 2.3 MB ほどになりました。ゲートウェイボードのストレージには余裕で収まります。
このデモで分かったこと
確認できたこと:
- 自作したゲートウェイを Apple Home が認識し、ペアリングできる
- ブリッジしたデバイスを Apple Home で個別に操作できる
- ダウンリンクのコマンドも、アップリンクの状態も、どちらも通る
- デバイスの追加や削除、接続が切れたあとの再起動でも、Apple Home の状態が追従する
まだ確認できていないこと:
- 実際の Bluetooth Mesh でのプロビジョニング、暗号化、ネットワーク構築
- Silicon Labs のモジュールと Telink のデバイスが相互に接続できるか
- Linux のゲートウェイボード上での動作
- 数十から数百台のデバイスが同時にオンラインのときの挙動
言い換えると、Matter 側の半分は検証が済み、Bluetooth Mesh 側の半分は実機を待つ段階です。次のステップは、パソコンの平文アドバタイズを、シリアルポートでつないだ Bluetooth モジュールに置き換えること。ゲートウェイのプログラムから見れば、アダプター層を1つ差し替えるだけです。
おわりに
このステップで一番の収穫は、ハードウェアにお金をかける前に、いちばん肝心なことを確認できたことです。Apple Home はこのゲートウェイを受け入れてくれました。この先何か問題が起きても、少なくとも Matter の層はもう疑わなくて済みます。
同じようなゲートウェイを作っている方や、ハードウェアがない状態で先に Matter を動かしてみたい方は、ぜひ気軽に声をかけてください。コードの細かい部分やハマったポイントなど、何でも情報交換しましょう:linktr.ee/weiyii
デモのコードは、小さくまとめたバージョンに整理してオープンソースにする予定です。公開したら、この記事にリンクを追記します。