家電の操作を、メーカー各社のクラウドに分散させず、単一の自己ホスト型基盤に集約する。中核はHome Assistantで、MQTTブローカー(Mosquitto)を介してセンサー類と、外部の音声アシスタントとも連携させている。

Home AssistantHome Assistant

画像: Home Assistantロゴ、Wikimedia Commons(CC BY-SA 4.0)

Home Assistant: 家電操作の集約点

Home Assistantは対応デバイス数が非常に多いオープンソースのホームオートメーション基盤である。エアコン・照明はNature Remo(赤外線家電コントローラー)経由で取り込んでいる。Nature RemoはHome Assistant本体から標準統合が削除されているため、HACS(コミュニティ製カスタム統合のパッケージマネージャー)経由で導入した。

取り込み直後、温度設定が華氏(°F)で送信されエアコンAPIがエラーを返す問題が発生した。原因はHome Assistant側のグローバル単位系が米国式になっていたことで、国・言語設定とは独立した設定項目だったため見落としやすかった。単位系をメートル法に変更して解決している。運用開始後は、Nature Remo連携でのDNS名前解決タイムアウトが短期間に複数回起きたこともあったが、いずれも自動的に復旧しており、現状は経過観察のみで実害は出ていない。

MQTT: Mosquitto

MosquittoはHome Assistant本体とは独立したMQTTブローカーで、将来のZigbeeセンサー統合(Zigbee2MQTT経由)を見据えて導入した。Home Assistant自体はMQTT統合を通じてMosquittoに接続し、MQTT経由で受信したセンサー値をエンティティとして扱える。

Zigbee統合の準備状況

Zigbeeデバイスを扱うZigbee2MQTTのサービス定義自体はすでに用意済みで、Mosquittoへの依存関係も設定してあるが、Zigbee USBドングルの到着待ちのため現時点では有効化していない。ドングル接続後にデバイスパス(/dev/ttyUSB*等)を確認し、コンテナへのデバイスパススルー設定とZigbee2MQTT側のシリアルポート設定を実機に合わせて修正してから起動する、という手順をあらかじめコメントとして残してある。ハードウェアが手元にない段階でソフトウェア側の配線だけ先に済ませておくことで、ドングル到着後は設定ファイルの数行修正だけで統合を開始できるようにしている。

統合方式は、Zigbee標準の別実装(ZHA)ではなく、Zigbee2MQTT+MQTTの組み合わせを選んだ。デバイス互換性の広さに加え、Home Assistant以外のツールからもMQTT経由でセンサー値を取得できる拡張性を重視した判断である。ソフトウェア側の準備を進める過程で、USBデバイスを仮想化環境(WSL2)へパススルーする仕組み自体にも1つ抜け漏れが見つかった。Windows側のUSB/IPクライアントは導入済みだったが、WSL2側にはこれに対応するクライアントコマンドが標準では入っておらず、標準リポジトリにも該当パッケージが存在しないため、別パッケージ経由での導入が必要だと判明した。導入してコマンドの動作自体は確認済みだが、これに気づかないままドングル到着後に作業を進めていたら、Windows側のアタッチ処理自体は成功して見えるのに、WSL2側にはデバイスが一向に現れないという、原因の切り分けが難しい詰まり方をしていた可能性が高い。ハードウェア到着前にソフトウェア側の配線を先に済ませておく効能は、こうした「実際に繋いでみて初めて分かる」種類の欠落を前倒しで潰せることにもある。

Alexaとの音声連携: OAuthとAWS Lambda

音声アシスタントとの連携は、メーカー純正のクラウド連携を使わず、AWS Lambda上に自作したスキルを経由してHome Assistantに接続する構成にした。これにより、音声コマンドの処理ロジックを自分の管理下に置ける。AWSアカウントは通常のクラシック個人アカウントで新規作成している。リージョン制限が強い簡易サンドボックス型アカウントでの構築も検討したが、Lambdaのリージョン選択に制約が強すぎるため断念した経緯がある。Lambda関数はPython 3.14ランタイムで作成し、実行ロールには基本的な実行権限のみを付与するAWS管理ポリシーを割り当てている。

連携の要はOAuthによるアカウント連携(Account Linking)である。この認可フローには3つの異なる通信経路があり、それぞれ制約が異なる。

  1. ログイン画面(ブラウザ経由): 任意のポートで動作する
  2. 認可コード発行: ブラウザのリダイレクトで行われる
  3. トークン交換(サーバー間通信): 音声アシスタント側のバックエンドから直接呼ばれる

3番目のトークンエンドポイントは、標準のHTTPSポート(443番)以外への通信を許可しないという制約があった。ログイン画面自体は非標準ポートでも正常に通過するため、原因の切り分けが難しい。ブラウザ経由の手動アクセスでは再現せず、自動化されたサーバー間通信でのみ失敗するのが特徴である。当初は非標準ポートで構成しており、ログイン自体は成功するのにトークン交換エンドポイントが一度も呼ばれず「アカウントをリンクできません」を繰り返す状態が続いた。標準ポートに変更した途端に即座に解決しており、自己ホスト型の基盤で外部の音声アシスタントとOAuth連携する場合は、この制約を前提に設計する必要がある。

もう一点、音声アシスタントアプリの公式サーバーサイド機能(WebSocket)には、Home Assistant運用時に別の技術的な罠がある。TailscaleのFunnel(一般公開)はデフォルトでHTTP/2をALPN経由で提示するが、HTTP/2上でのWebSocketアップグレード(RFC 8441)にHome AssistantのaiohttpサーバーやImmichのSocket.IOが対応していないため、リアルタイム接続が確立できない。通常のページ閲覧はHTTP/2でも問題なく動くため見過ごされやすい。対処は、HTTPSプロキシモードではなく「TLS終端のみの生TCP転送モード」でFunnel/Serveを構成し、ALPNでHTTP/2が提示されないようにすることである。実際にHTTPリクエストへの応答コードでWebSocketへの切り替えが成立していることを確認済みだが、この修正だけではスマートフォン公式アプリ単体の接続不良が完全には解消しなかった。ブラウザ経由でのアクセスは問題なく安定しているため純粋なネットワーク到達性の問題ではなく、アプリ内のサーバー登録情報自体に起因する可能性が高いとみて、現状はブラウザ経由での利用に切り替えて運用している。

さらに、この作業中にもう一つ想定外のことが起きている。ポート設定を修正する過程で、元々別の設定で正常に公開されていたメディアサーバー(Jellyfin)側のトンネル設定を誤って上書きし、一時的に外部からアクセスできなくしてしまった。原因は、トンネルの外部公開用リスナーとメディアサーバー自身の待受ポートが衝突し、TLSハンドシェイクレベルのエラーになっていたことによる。外部公開用のポート番号と内部の待受ポート番号を意図的に分離する構成に直し、他の自己ホスト型サービス群と同じ「外部/内部ポート分離」のパターンを踏襲することで復旧した。この経験から、1つのサービスの設定変更が別サービスの公開設定に波及していないか、変更後は影響範囲を横断的に確認する習慣がついた。

Home Assistantの設定移行という別の罠

Home Assistantのhttpコンポーネント設定には、YAML経由での変更が効かなくなるという既知の罠がある。バージョンによっては、httpコンポーネントの設定が初回起動時に内部の永続化ストレージへ一度だけ移行され、以降はconfiguration.yaml側のhttp:ブロックをいくら変更しても無視される仕様になっている。リバースプロキシ越しのアクセスで「reverse proxyの設定が正しくない」という趣旨のエラーが出た場合、原因はYAML側の記述ミスではなく、この移行済みフラグによって変更が反映されていないことにある。復旧には、内部の永続化ストレージファイルを直接編集する必要がある(変更前に日付入りのバックアップを取得してから作業している)。ドキュメント通りの設定変更が効かない場合、まず「その設定は本当にYAMLから読まれているか」を疑う必要があるという教訓である。

デバッグの過程では、一時的にHome Assistant本体の認証まわりのコアファイルにログ出力を仕込んで通信の流れを追跡する手法も使った。原因判明後は元のファイルに復元している。

音声アシスタント側のコード実装

音声アシスタント開発者コンソールに標準搭載されたブラウザ内コードエディタは、直接コードを貼り付けると一部の文字が非決定的に欠落し構文エラーになる事象が複数回発生した。原因の特定は断念し、ローカルでファイルを作成してZIP化し、一括アップロードする方式に切り替えて解決している。

未解決事項: 一部デバイスの統合失敗

ロボット掃除機(Ecovacs製)の標準統合は、アカウント追加時にDevice verification required(エラーコード1013)で認証が継続的に失敗する。調査の初期段階ではローカル設定の問題を疑ったが、コンテナのログを直近24時間分確認したところ、同一のエラーが12回発生していることを確認した。この情報を元にGitHub上で同様の事象を検索すると、統合ライブラリ側・Home Assistant本体側の両方のリポジトリで同一事象の報告が複数見つかり、いずれも未解決(Open)のままだった。

原因の切り分け: デバイス側メーカーがクラウドAPIにメール認証によるデバイス検証を新たに要求するよう変更し、統合ライブラリ側もこれに追従する形で検証フロー自体は実装済みだった。しかし、検証自体は成功してもその直後に内部的な再ログイン処理が走り、そこで再び同じ検証要求が発生してセットアップ全体が失敗するという、ライブラリ側に残る上流のバグが根本原因と判明した。ローカルの設定やアカウント情報そのものの問題ではないため、再設定・再ログインを試みても解消しない。

対応方針: 実用上はメーカー純正の音声アシスタントスキル連携で操作できているため、優先度を上げず静観している。上流のIssueの解決状況を定期的に確認し、ライブラリがアップデートされたタイミングで再度統合を試す方針にしている。ローカル側でできることが尽きた場合、上流の対応を待つという判断を明確にしておくこと自体に一定の価値がある。

参考リンク

#Home Assistant #Alexa #AWS Lambda #MQTT