← ThreadMapper

Raspberry PiでThreadMapperプローブを組み立てる

何もない机から、アプリにThreadの実測データが出るまでを順を追って。

一晩を見ておいてください。その大半はダウンロード待ちと、20分ほどのビルド1回です。


買う前に読んでください

この作業が割に合うかどうかは、2つの点で決まります。判断の基準になるのは、ご自身の環境です。どちらも、部品が届くまでは見落としがちです。

1. Raspberry Pi単体ではThreadを扱えません

Raspberry Piには802.15.4の無線が載っていません。Wi-FiとBluetoothは別の無線であり、Threadを話せません。USBドングルが必要で、しかもそこにはRCPファームウェアが要ります——市販のドングルが最初から積んでいるものではありません。

2. 本当に難しいのは、ご自身のThreadネットワークへの参加です

自分で新しいネットワークを作ったボーダールーターは、自分自身しか見えないまま置かれているだけになります。実際のデバイスは、HomePodやApple TV、Nestハブが作ったネットワークの側にいます。それを観測するには、プローブがそのネットワークに参加しなければなりません——つまり、その認証情報(Active Operational Dataset)を手に入れる必要があります。

ご自身の環境プローブは実際のネットワークに参加できるか
Home Assistantを使っているはい。HAのiOSコンパニオンアプリがAppleのThread認証情報を取り出せます——設定 → デバイスとサービス → Thread → 設定 → Home Assistantに認証情報を送信——そこからデータセットをプローブに渡せます。
すでにOTBRを運用している(HAのアドオンなど)はい。そこからデータセットを直接読み出してください。
AppleまたはGoogleのボーダールーターだけで、Home Assistantなし今のところ無理です。AppleのThread認証情報を書き出す、ユーザー向けの手段がありません。プローブ側で、新しいネットワークを作り、アクセサリをいくつかコミッショニングしてアプリが一通り動くところまでは確かめられますが、既存のメッシュは見えません。

3行目は本物の壁で、このプロジェクトが外側から壊せるものではありません。公式な道はAppleのcom.apple.developer.thread-network-credentialsエンタイトルメントで、ThreadMapperは申請済みですが、まだ持っていません。これが通れば、アプリが認証情報を直接プローブに渡せるようになり、この節はまるごと不要になります。

3行目に当てはまり、既存のAppleメッシュを監視したいだけなら、そのエンタイトルメントが下りるまでここで止めておくことを検討してください。


買い物リスト

品目備考
Raspberry Pi 4または5RAMは2 GBで十分です。Pi Zero 2 Wでも動きますが、手順4のビルドがはるかに長くかかります。
microSDカード、16 GB以上素性の確かなものなら何でも。
USB-C電源アダプタ純正品を。Threadドングルは電圧の落ち込みに敏感です。
802.15.4ドングル1本どれか1つを選んでください——下記参照。

ドングルの選択肢、どちらでも構いません。


手順1 — ドングルにRCPファームウェアを書き込む

これはPiに触れる前に、お手元のMacまたはPCで行ってください。インストーラーがあえて自動化していない唯一の手順です。間違ったイメージを書き込むとドングルは文鎮になりますし、ベンダー純正のツールなら確実にやってくれるからです。

RCP(「Radio Co-Processor」)ファームウェアは、ドングルをotbr-agentが制御する単純な無線機に変えます。Zigbee用として出荷されたドングルは別のファームウェアを積んでおり、書き換えるまでは動きません。

Silicon Labs(SkyConnect、Sonoff ZBDongle-E)

pipx install universal-silabs-flasher     # or: pip install universal-silabs-flasher
universal-silabs-flasher --device /dev/tty.usbserial-XXXX probe
universal-silabs-flasher --device /dev/tty.usbserial-XXXX flash --firmware <ot-rcp-firmware.gbl>

ot-rcp.gblは、Home Assistantのsilabsファームウェアのリリースから入手してください——OTBRアドオンが使っているのと同じイメージです。ファイルはお使いのドングルの型番に正確に合わせてください。SkyConnectとZBDongle-Eは互換ではありません

Nordic nRF52840

OpenThreadのNordic向け移植版からファームウェアをビルドし、USB DFUで書き込みます。

git clone --recurse-submodules https://github.com/openthread/ot-nrf528xx.git
cd ot-nrf528xx && ./script/bootstrap && ./script/build nrf52840 USB_trans
# → build/bin/ot-rcp  (convert to .hex/.zip per the repo's README, then:)
nrfutil dfu usb-serial -pkg ot-rcp.zip -p /dev/tty.usbmodemXXXX

パッケージング手順の現行版は、そのリポジトリのREADMEに従ってください——ときどき変わるので、ここに写したものより、そちらを読んだほうが確実です。

うまくいったかの確認:あとでドングルをPiに挿すと、install.shFound <family> radio at /dev/serial/by-id/...と表示します。何も見つからなければ、ファームウェアが入っていません。


手順2 — Raspberry Pi OSを書き込む

  1. Raspberry Pi Imagerをインストールします。
  2. Raspberry Pi OS Lite(64-bit)を選びます。Liteです——デスクトップは要りません。
  3. 書き込む前に歯車 / Edit Settingsボタンを押して、次を設定します: - ホスト名:threadmapper-probe - SSHを有効化。パスワードまたは鍵で。 - ユーザー名とパスワード - Ethernetを使わないなら、Wi-Fiの認証情報
  4. カードに書き込み、Piに挿し、ドングルを取り付けて電源を入れます。

ここではEthernetのほうがWi-Fiより信頼できますし、ボーダールーターは安定した上流回線の恩恵を受けます。使えるなら使ってください。


手順3 — ログインする

ssh <your-username>@threadmapper-probe.local

ホスト名が解決できないときは、ルーターのクライアント一覧でPiのIPアドレスを調べ、代わりにssh <user>@<ip>としてください。

先へ進む前に、ドングルが見えていることを確認します。

ls -l /dev/serial/by-id/

お使いのドングル名を含むエントリが1つ見えるはずです。ここが空なら、そこで止めてください——この先は動きません。挿し直し、別のUSBポートを試し、手順1を見直してください。


手順4 — プローブをインストールする

sudo apt-get update && sudo apt-get install -y git
git clone https://github.com/tintronix-lab/ThreadMapper.git
sudo ./ThreadMapper/tools/pi-image/install.sh

ドングルを検出し、otbr-agentとプローブエージェントをインストールして、どちらもsystemdサービスとして有効化します。

Pi 4では20分ほどかかりますが、その大半はotbr-agentのコンパイルです。固まっているわけではありません。終わるとプローブのアドレスを表示します。

検出に失敗しても、デバイスのパスが分かっているなら、次のようにします。

sudo ./ThreadMapper/tools/pi-image/install.sh --radio-url spinel+hdlc+uart:///dev/ttyACM0

再実行しても安全です——冪等ですし、あとでエージェントを更新するときもこの方法を使います。


手順5 — Threadネットワークに参加する

「買う前に読んでください」で自分に当てはまった行を選んでください。

経路A — 既存のネットワークに参加する(本当にやりたいのはこちら)

すでに認証情報を持っているものから、Active Operational Datasetを16進文字列として取得します。

既存のOTBR(Home Assistantのアドオンを含む)から取る場合は、次のようにします。

curl -s http://<existing-otbr>:8081/node/dataset/active \
     -H 'Accept: text/plain'

長い16進文字列が1つ返ってきます。Pi側では、次のようにします。

sudo ot-ctl dataset set active <that-long-hex-string>
sudo ot-ctl ifconfig up
sudo ot-ctl thread start

30秒ほど待ってから、次を実行します。

sudo ot-ctl state

childまたはrouterと出れば、参加できています。ここでleaderと出たら、自分で別のネットワークを作ってしまったということで、この経路で望む結果ではありません。

経路B — 新しいネットワークを作る(テスト用、または認証情報が手に入らない場合)

sudo ot-ctl dataset init new
sudo ot-ctl dataset commit active
sudo ot-ctl ifconfig up
sudo ot-ctl thread start
sudo ot-ctl state          # expect: leader

これで、ノードが1つだけの空のネットワークができました。何か意味のあるものを見るには、アクセサリをこちらにコミッショニングする必要があります——つまり、先にAppleのネットワークから外すということです。普段頼りにしているデバイスでこれをやってはいけません。

あとで他のものをこのネットワークに参加させたいなら、データセットを表示しておきます。

sudo ot-ctl dataset active -x

手順6 — アプリから参照させる

curl http://localhost:8099/health

"otCtlReachable": trueroleが返るはずです。そのうえで、同じネットワークにつないだiPhoneから、ThreadMapper → 設定 → ThreadMapperプローブで次を指定します。

http://threadmapper-probe.local:8099

iOSで.localが解決できない場合は、代わりにPiのIPアドレスを使ってください。「接続をテスト」をタップします——問題があるときは、赤い×を出すだけでなく、何が失敗したのかを名指しします。


手順7 — 何が見えるようになったか

まず見るべきはチャンネルスキャナです。これまでアプリが見せられたものと、いま見せられるものとの違いが、いちばんはっきり出ます。


トラブルシューティング

症状原因と対処
install.shが「No 802.15.4 dongle detected」と表示するドングルが挿さっていないか、手順1が効いていません。ls /dev/serial/by-id/を確認してください。
接続をテスト:「隣のボーダールーターに到達できません」エージェントは動いていますが、otbr-agentが動いていません。sudo systemctl status otbr-agent、続いてjournalctl -u otbr-agent -n 50。たいていは無線URLの誤りか、ドングルの電源が落ちたかです。
接続をテスト:「ThreadMapperのプローブエージェントではありません」そのポートで別の何かが応答しています。エージェントは8099で、8081はボーダールーター自身のREST APIです。
接続をテスト:「そのアドレスに到達できませんでした」IPが違うか、iPhoneが別のサブネットかゲストVLANにいます。
ot-ctl statedetachedと表示する認証情報はありますが、ネットワークを見つけられません。データセットが違うか、他のどのノードの電波も届かない場所にあります。
ot-ctl statedisabledと表示するifconfig up / thread startが実行されていないか、無線が起動しませんでした。
Threadネットワーク画面にピアが1つも出ないプローブが自分だけのネットワークにいます。参加させるつもりだったのにleaderになっていないか確認してください。
すべて動いていたのに、再起動後に動かなくなるsystemctl is-enabled otbr-agent threadmapper-probe——どちらもenabledと出るはずです。

両方のサービスのログをまとめて見るには、次を実行します。

journalctl -u threadmapper-probe -u otbr-agent -f

まだ動かないこと

ノードには名前が付きません。Threadはノードを拡張アドレスで識別し、HomeKitはアクセサリを不透明な識別子で識別します。その2つを結び付けるものがありません。そのため見えるのは、「キッチンのランプ」ではなく、名前のないノードからなる本物の、正しいトポロジーです。

解決策は作ってあるものの、仕上がっていません。エージェントの/trafficエンドポイントはノードごとの通信状況を返すので、HomeKit経由でデバイスを操作し、どのノードが反応するかを見れば、両者を結び付けられます。その作り込みには、本物のメッシュ上に本物のアクセサリが必要です——まさに、これが動きだせば手に入るものです。WORKPLAN.mdではH1として管理しています。

メッシュタブは今も推論のままです。そのグラフはHomeKitのアクセサリから組み立てているため、上記が解決するまではプローブのデータを使えません。実測を見せているのは、Threadネットワーク画面とチャンネルスキャナです。


ここに間違いがあったら

このガイドは、実機で最初から最後まで通して試したものではありません——プロジェクトの誰も、まだPiもドングルも持っていないのです。プロビジョニングスクリプトはDebian Bookworm arm64に対してテストしてあり、エージェントの各エンドポイントもシミュレートした無線上で動く本物のotbr-agentに対してテストしてありますが、上記の物理的な手順は、実際にやってみた結果ではなくベンダーのドキュメントをもとに書いています。

手順に誤りがあれば、それはこのファイルで直す価値のあるものです。