ここ数年、日本では「闇バイト」——SNS で実行役を使い捨てに募集する強盗・特殊詐欺の手口——による事件が相次いで、防犯意識は都市部だけの話ではなくなった。標的の下見リストが出回り、実行役が匿名アプリで指示を受けて他人の家に押し入る。そういうニュースが続けば当然で、うちは地方だが、近所を歩くと軒先に監視カメラを付けた家が目に見えて増えている。一軒家ほど「下見される側」なのだから自然な流れだと思う。
で、自分も付けることにした。買ったのは SwitchBot の屋外カメラで、月数百円を課金すればクラウド側の人物検知などの AI 機能が使える。普通はそれを契約して終わりだ。ただ、うちには既に Home Assistant が動いていて、カメラは RTSP を喋る。なら映像を宅内の GPU に食わせて通知まで自前で組めるはずで、要するに「俺でもできるやろ」と思ってしまった。どうせ付けるなら、24 時間の人物検知システムを自作してスキルの足しにする方を選んだ。
結果として今は、玄関に人が来ると家の Echo が「玄関に人です」と教えてくれて、スマホには人物に枠を描いたスナップショットが届く。クラウドにもサブスクにも依存せず、全部宅内で完結している。カメラは 9 千円弱、検知エンジンは押し入れで余っていたラップトップ。この構成に落ち着くまでに紆余曲折あったのだが(それは別記事にする)、まず現在形を説明する。
全体像
SwitchBot 屋外PTZカメラ ──RTSP──▶ Frigate (専用ラップトップ / YOLOv9 on GPU) │ 人物検知イベント ▼ MQTT (HA の Mosquitto) ▼ Home Assistant (binary_sensor) ├─▶ Echo 各部屋にアナウンス └─▶ スマホに枠付きスナップショット役割分担は「カメラは映すだけ、検知は宅内 GPU、鳴らし方は HA」。カメラのクラウド AI や通知機能は一切使わない。疎結合にしておくと、後でカメラを替えても通知側を触らずに済む。
カメラ: 検知用と鑑賞用でストリームを分ける
カメラは SwitchBot の屋外パンチルト機。RTSP と ONVIF を喋るので、メーカーアプリ無しで扱える。この価格帯の WiFi カメラで学んだ鉄則がひとつ:
カメラへの直接接続は 1 本に絞る。
安カメラの SoC は、高解像度 H265 のメインストリームを複数セッションで同時配信すると音を上げて、壊れたフレームを吐き始める。なので構成はこうしている。
- 検知は低解像度の H264 サブストリームで回す(検知に 4MP は要らない)
- カメラへの接続は go2rtc の restream に集約し、録画もライブ表示もそこから分岐
- 高画質が欲しいのは通知の一瞬だけなので、検知イベント時に単発で 1 枚だけメインストリームから grab し、Frigate が返す検知枠の座標を ffmpeg の drawbox で描いてスマホに送る
「常時 4MP を引く」のをやめて「必要な瞬間に数秒だけ接続して 1 枚もらう」に変えた、と言えばいいだろうか。
NVR: ラップトップは意外と NVR に向いている
検知エンジンは Dell Precision 5540。Xeon E-2276M / 16GB / Quadro T1000 4GB を積んだ 2019 年頃のモバイルワークステーションで、Windows 機として余っていたのを NixOS に載せ替えた。
ラップトップを 24/7 のサーバにするのは邪道に見えるが、NVR に限ってはかなり合理的だ。
- バッテリー = UPS 内蔵。瞬停でカメラの録画が飛ばない
- 静かで省電力。玄関検知のためにデスクトップを一台焚くほどではない
- 蓋を閉じて棚に置ける(lid スイッチと suspend 系は systemd で全部マスクした。これをやらないと蓋を閉じた瞬間に検知が止まる)
T1000 は 4GB の控えめな GPU だが、YOLOv9 の onnx 推論が 8ms、NVDEC でデコードも GPU に逃がせて、カメラ 1 台なら余裕。Frigate 公式が Coral USB を新規構成に非推奨としてから、こういう「余ってる dGPU/iGPU」が検知アクセラレータの本命になっている。
OS ごと宣言的に管理していて(NixOS + GitOps)、コンテナ定義からメモリ上限、sleep のマスクまで全部 git にある。box が死んだら同型機に config を当てれば復元できる。
なぜ専用機なのか
最初は自宅の GPU サーバ(RTX 5090 の LLM 実験機)に Frigate を間借りさせていた。VRAM は余っていたし、推論も数 ms で回った。そして 1 ヶ月で 4 回、検知がサイレントに死んだ。
実験機は実験するための箱で、モデルのロードで RAM を食い尽くすし、実験コードは GPU ごと巻き添えにする。「家族も使う本番機能」と「自分の遊び場」を同じ箱に住まわせたのが設計ミスだった。障害の顛末はそれだけで記事になる濃さなので別途書くが、結論だけ言うと、個々のバグを全部潰した上で、最終的に効いたのは「本番を実験機から降ろす」という引っ越しだった。
HA 連携: HACS は要らなかった
Frigate 統合というと HACS のカスタム統合が定番だが、使っていない。Frigate が MQTT に流すイベントを HA の MQTT binary_sensor で直接拾い、オートメーションで通知を組んだだけ。検知+通知しか要らないなら、この最小構成で足りる。
ハマった罠を 2 つだけ:
- Frigate は
FRIGATE_接頭辞の環境変数しか config に展開しない。{MQTT_PASSWORD}と書いて何度も起動クラッシュさせた - スマホ通知のタップで画像を開くのに絶対 URL を使うとヘアピン NAT で詰む。相対パス + キャッシュバスターに変えて解決
通知は 60 秒のクールダウンだけ入れて運用開始し、通行人で鳴りすぎたらゾーンを絞る方針にしていたが、玄関の画角ではクールダウンだけで十分だった。
監視: 検知システム自身を監視する
このシステムの一番嫌な故障モードは「黙って死ぬ」だ。カメラは映っている、コンテナも動いている、でも検知イベントだけが止まっている——という状態は外形上健全に見えるので、気づくのは「そういえば最近通知が来ないな」と思った時になる。
なので監視用の Raspberry Pi (Prometheus) から Frigate のメトリクスを scrape して、カメラ fps の停止・検知プロセスの再起動ループ・OOM をアラートにしている。このアラート設計自体が障害のたびに賢くなってきた歴史があるのだが、それも障害編で書く。
まとめ
- 防犯という実益と、スキルアップという口実が両立するのが自作監視カメラのいいところ
- カメラ 9 千円弱 + 余り物ラップトップで、月額課金無しの人物検知通知が動いている
- 安 WiFi カメラはカメラへの接続を 1 本に絞る。高画質は必要な瞬間だけ借りる
- ラップトップ NVR は UPS 内蔵・静音・省電力で理にかなっている。lid と suspend のマスクだけ忘れずに
- 本番と実験場は箱を分ける。これが一番高くついた教訓
次回、この構成に至るまでに検知が 4 回死んだ障害編を書く。