みずかるちゃー

ガジェットやカメラ、ちょっとだけ技術の話題が中心のブログ

Raspberry Pi 4のBluetoothが不安定なので外付けアダプタ+USB延長ケーブルにしてみた

Raspberry Pi 4でHome Assistantを動かし、SwitchBot BotをBluetooth経由で操作しています。用途の一つが、CO2濃度に応じた換気扇の自動操作です。

ところが最近、Bluetoothまわりがかなり不安定になっていました。ソフトウェア側の問題を直したあともLE接続のタイムアウトや切断が続いていたため、今回は内蔵Bluetoothをやめて、外付けBluetoothアダプタ+USB延長ケーブルの構成に変更してみました。

外付けアダプタへの切り替え後、約5.4日間の記録ではLE接続タイムアウトが1日あたり約425回から約15回に減りました。10月6日に換気扇用Botの操作もBluetooth経由へ切り替え、10月11日までの241回はすべてHome Assistantからの操作が成功しています。

まずはソフトウェア側の問題が発生

2026年9月10日の深夜、Home Assistantで使っているSwitchBot系の29エンティティがすべてunavailableになりました。

調べてみると、このときはBluetoothの電波やハードウェアではなく、BlueZまわりの構成が原因でした。

  • Home Assistantのpassive scanningにはBlueZ 5.56以上が必要
  • Raspberry Pi OS bullseyeのBlueZは5.55
  • bluetoothd に --experimental が付いていなかった
  • D-Busポリシーで AdvertisementMonitor1 が許可されていなかった

スキャナの起動失敗とリトライが続き、最終的には LimitsExceeded のループに入っていました。2日間で16,074件です。

ここはBlueZ 5.87を自前でビルドして、/opt 配下に入れることで対処しました。

その後もBluetoothの接続失敗が続く

BlueZ側を直したあと、9月16日にはカーネルのBluetoothモジュールがOopsしました。

直前には Opcode 0x200d failed: -110 が多発していて、LE接続の作成がタイムアウトしていました。

厄介だったのは、hci0 が UP RUNNING と表示されたまま、実際にはスキャンが止まっていたことです。Home Assistant側では 1 scanner(s) registered, 0 scanning になっていました。

hciconfig down もD状態で固まり、Raspberry Piを再起動するまで復旧しませんでした。

再起動後はカーネルOopsこそ再発していませんが、9月19日から23日までの約4日間で以下のエラーが出ています。

内容 件数
LE接続タイムアウト(err -110) 1,701回
BleakNotFoundError 800回
device not found / poor RSSI 321回
Device unexpectedly disconnected 242回
BleakOutOfConnectionSlotsError 184回

ウォッチドッグによるBlueZやHome Assistantの再起動も1日5〜7回。さすがにこの状態では、換気扇の自動操作を安心して任せられません。

USB 3.0の外付けSSDによるノイズも疑ってみる

このRaspberry Pi 4にはUSB 3.0で外付けSSDを接続しています。

今回の不具合がUSB 3.0のノイズだけで起きているとは断定できません。ただ、2.4GHz帯への干渉も切り分けておきたかったので、Bluetoothアダプタを外付けにしてRaspberry Pi本体から離してみることにしました。

用意したのは「サンワサプライ MM-BTUD46」と「エレコム U2C-E10BK」です。

MM-BTUD46を選んだのは、Linux/Raspberry Piで使えそうだったためです。Bluetooth 4.0のClass 1対応で、今回は通信速度よりも接続の安定性を優先しています。

USB延長ケーブルは、参考にした記事を見て1mを選びました。BluetoothアダプタをPi本体やUSB 3.0接続のSSDから物理的に離すのが目的です。

機器の位置関係を示した模式図です。

内蔵Bluetoothを無効化して外付けアダプタへ

まずドングルを挿して認識を確認しました。

lsusb
hciconfig -a

挿した直後は、内蔵Bluetoothが hci0、USBドングルが hci1 になっています。

今回は比較を分かりやすくするため、内蔵Bluetoothを無効化しました。/boot/config.txt の [all] セクションに以下を追加します。

dtoverlay=disable-bt

あわせて内蔵Bluetooth用のサービスも無効化しました。

sudo systemctl disable hciuart

再起動すると、USBドングルが hci0 になります。

その後、Home Assistantの「設定 → デバイスとサービス → Bluetooth」で新しいアダプタを有効化し、内蔵Bluetoothのエントリを無効化しました。

ここで少しハマったのが、再起動してからHome Assistant側でドングルを追加するまでの間です。一時的にスキャナが0台になるため、No backend with an available connection slot が出ました。

自作のBluetoothウォッチドッグもHome Assistantを再起動しようとするので、切り替え時は再起動後すぐにアダプタを追加した方がよさそうです。

RSSIは導入直後から改善

外付けBluetoothに切り替えた直後のRSSIを確認すると、電波の弱かったBotで大きく改善しました。

デバイス 導入前 導入後
Bot1 -77 dBm -53 dBm
Bot2 -75 dBm -61 dBm
CO2センサー -66 dBm -47 dBm

ただし、導入前はエラー時のログから取った平均、導入後はアダプタ追加直後のログなので、条件は完全には揃っていません。ここはあくまで目安として見ています。

また、アダプタ追加直後は全デバイスへ一斉に接続したため、Device unexpectedly disconnected やLE接続タイムアウトが少し出ました。切り替え直後の一斉接続による切断警告は収まりましたが、その後もLE接続タイムアウトは記録されています。

導入後約5日間で接続失敗は大きく減った

9月24日16:26に外付けアダプタへ切り替えてから、9月30日2:58までの約5.4日間を集計しました。導入前は9月19〜23日の約4日間です。期間が異なるため、1日あたりの目安で比べています。

期間が異なるため、1日あたりに換算した接続エラーの比較です。
項目 導入前(1日あたり) 導入後(約5.4日合計/1日あたり)
LE接続タイムアウト 約425回 82回/約15回
ウォッチドッグのソフト復旧 5〜7回 0回/0回
接続スロット不足 約46回 0回

LE接続タイムアウトは1日あたり約96%減りました。カーネルOops、スキャン停止、接続スロット不足もこの期間には記録されていません。ただし、LE接続タイムアウトは82回あり、エラーが完全になくなったわけではありません。

導入後のRSSIは測るたびに揺れます。10月2日の単発測定では、換気扇用Botの「入」が-57 dBm、「切」が-68 dBmでした。導入前はエラー時ログの平均、導入後は bluetoothctl info の値なので、同条件で測った改善幅とは扱っていません。

9月25日には自作ウォッチドッグの誤検知でPiが一度再起動しました。プロセスの稼働時間をD状態の継続時間と取り違えていたスクリプトを修正し、上記の期間中にソフト復旧は発生していません。

換気扇用BotをBluetooth経由で操作した結果

10月6日からの操作経路と、10月11日までの集計です。

ここは途中で操作経路を変えています。10月6日19:27までは、換気扇BotをSwitchBotクラウドAPIからHub 2経由で押していました。9月24日から10月6日までの記録では「入」127回、「切」363回のAPI要求がすべて受け付けられています。ただし、これは外付けBluetoothの成果ではなく、Botのアームが実際に動いた証拠でもありません。

10月6日からは、まずHome AssistantのREST APIで操作し、Piの外付けアダプタからBotへBluetooth接続するようにしました。失敗した場合だけクラウド経由に切り替える構成です。10月11日までに「入」58回、「切」183回、合計241回をHA経由で操作し、すべて成功しました。クラウド経由への切り替えは0回です。

この成功はHA経由の操作が完了したという記録です。換気扇の実際の動作はBotから直接は返ってきません。CO2の変化から空振りが疑われたこともあり、アームの当たり方など物理的な問題は引き続き確認しています。導入前の換気扇操作はクラウド経由だったため、Botの実操作成功率をBluetoothの導入前後で同じ条件で比較することはできません。

9月30日にはPi全体が固まり、10月2日朝まで約53時間Home Assistantも停止しました。USB接続SSDのエラーが先に出ており、SSD側が原因の可能性がありますが確定していません。この停止時間はBluetoothの稼働期間の集計に含めていません。

10月2日8:39の再起動から10月4日8:00までの約47時間では、カーネルのLE接続タイムアウトは2回、Bluetoothウォッチドッグの検知は0回でした。ただし約5日間の比較と連続した期間ではないため、数値は分けて見ています。

約2週間使ってみた判断

9月24日に外付けBluetoothアダプタと1mの延長ケーブルへ変更してから、接続エラーは大幅に減りました。10月9〜11日のカーネルのLE接続タイムアウトは1日1〜3回で、ドングル導入後にカーネルOopsやスキャン停止は記録されていません。10月6日からBluetooth経由に切り替えた換気扇Botも、10月11日までの241回のHA操作では失敗せず、クラウドへの切り替えはありませんでした。私の環境では、この構成で実用できています。

ただし、最初にSwitchBot系が一斉にunavailableになった問題はBlueZのバージョンと設定が原因で、別途修正しています。9月30日のPi停止はSSD側のエラーが先に出ており、Bluetoothの不調として数えていません。Botの電池切れや自作ウォッチドッグの誤検知も別の問題でした。

内蔵BTの無効化、アダプタの変更、設置位置の変更を同時に行っているため、どれが効いたのかは分かりません。USB 3.0接続SSDのノイズが原因だったとも断定できません。換気扇が実際に動いたかについては、Botのアームの空振りが疑われる場面を含め、引き続き確認します。