Raspberry Pi/Raspberry Pi OS(Debian/Raspbian)とUSBカメラを使ってライブカメラ、見守りカメラ、防犯カメラなどのなんちゃらカメラを自作してみるページ。
使用するRaspberry Piのモデルは、3B+。
Raspberry Pi 2B x1、3B+ x2、400 x1とある内、順に1台ずつサーバ、自作スマートスピーカー、サブパソコンとした中、他の検証等々でいろいろ渡り歩いた後、のんびり佇んでいた3B+があったので。
現時点のRaspberry Pi OSのバージョンは11.3、開発コードはbullseye。
外出先からスマホなどモバイルデバイスなどで確認する手段としてはVPN。
用途は、防犯・監視・セキュリティ目的での不在時、また、在宅時含め、別室の幼児、要介護者やペットの見守りに、外出先からスマホなどモバイルデバイスなど、場所によってはPCで確認、在宅時は、LAN接続のそれらデバイスのブラウザで。
ライブ、動体検知録画・撮影のようなモードをブラウザ上で切り替えられるもの。
カメラは複数台に対応したく、クラウド含め、専用アプリを使うものは除外、コストは抑えたいので、少なくとも1台は手持ちのUSB/Webカメラや場合によってはESP32-CAMのチップを技適品に交換、または、技適済みM5Stack M5Camera(もうない?)などを使用、よって室内、外を撮るにしても室内からという室内用カメラ。
設置位置は、パン(横に首振り)すれば、任意のスペースの範囲を俯瞰で見渡せる場所を想定、パン機能は自作、もしかするとチルト(縦の首振り)も必要かも?
アクセス時、ブラウザ上には、映像と首振りボタンが表示され、映像がパンする様子を見て取れるようにする。
夜間の映像確認も想定し、暗視用IR投光機能を自作したい(今時点、USBカメラ等に紫外線カットフィルターがある場合、これを除去しない状態でカメラレンズ外側での赤外線透過フィルター+赤外線投光器の効果があるのかは不明、必要なら除去も検討)。
相互に会話もできるようにしたい...かな?
外出時、在宅者と会話する場合は、ビデオ通話含め、電話(スマホ)で良いですが、ペットが相手などの場合、専用アプリは避けつつ、自動応答させたい?いらないかな?
ハードウェアで想定しているものは、次の通りです。
ラズパイは、4Bの方がとは思いますが、コロナ・半導体不足による超品薄、品切れ状態でもありますし、ケース/ヒートシンク/ファン/5V 2.5A ACアダプタ/120GB SSDのある3B+が余ったので。
ラズパイ用電源は、安定している5V/2.5AのACアダプタを持っていますが、場合によっては、3A以上のものがよいかも。
もちろん電圧降下が著しくなく安定した良質なもの。
ストレージは、ラズパイサーバ側の、現状2TB HDDを使えばよいかなと。
カメラは、1台は中華で数百円の超チープなマイク内蔵Webカメラ、USBカメラは他に2台あるも使用中、他は手持ちで言うとESP32-CAM、というか、Webカメラを想定。
USBスピーカーは、通話機能を実装する場合のみ、その場合、マイクは、2つほど手持ちもありますが、負荷を増やさない意味でもWebカメラ内蔵のものを想定。
モーターは、DCモーターとステッピングモータ、サーボモータなどがあり、首振り機能には、サーボが向いている気もするも静音を考えると却下。
DCモータもギアボックスを考えると同様もカメラが超軽量だけにギア2つ3つ程度噛ませるだけでもいけそうなのが悩ましいところ。
が、転回に高速さは求めておらず、ゆっくりでよく静音となればステッピングモータ、なかでも既に持っていて実は、パワーもそこそこある28BYJ-48 5V、ステッピングモータードライバはA4988やDRV8825も手持ちはありますが、28BYJとセットになっていることが多いULN2003が有力候補。
って、そんなにパワーはいりませんけどね、USBカメラは軽量、赤外線投光器もそんなに重くなるはずもないので。
赤外線LED/MOSFET/抵抗/ユニバーサルボードは、暗視用IR投光器の自作を想定した材料。
赤外線LEDについては、30〜40個前後使用を想定。
というわけでハードウェアは、次の組み合わせで、自身は、全て手持ちあり。
もちろん、宅内Wi-Fiネットワークは必須なので環境に応じてインターネット回線及び無線ルーターも必要。
Wi-Fi(だけ)ではなく、有線で( || も)ということなら、これらに加え、LANケーブル。
ソフトウェアで想定しているものは、次の通りです。
VPNは、何でも良いですが、自身は、SoftEtherVPN。
ブラウザも実装機能を使えるものなら何でも良いですが、自身は、Firefox。
OSもなんでも良いですが、今回は、ラズパイ標準Raspberry Pi OS。
複数台対応のカメラ管理システムとして商用にも負けず劣らずな高機能防犯カメラ用管理プログラムとして作られていること、相応のスペックは必要も複数台のカメラに対応、動体検知や、その際の自動撮影なども標準装備で映像もスムース、既に動作確認できているZoneMinderにしようかと。
よってカメラの台数など状況によっては、4Bでないと4Bでも?厳しいこともあるかもしれませんが、とりあえず1台なので3B+で。
そもそもZoneMinderの代替となると本格的かつ相当高価な市販品しかなさげ、動体検知・自動撮影という意味では、若干映像遅延が気になるmotionに優り、OpenCVはGoogle発だし、おっと間違いインテルでした、それら機能は持たず、ライブのみのmjpg-streamerやustreamer、GStreamerやその他メディアプレイヤーなどは目的には合わないなと。
ブラウザを介したラズパイGPIO操作には、ラズパイ登場と同じ2012年が初版のWebサーバ+ラズパイGPIO操作機能を備えるWebIOPiか、別個にWebサーバアプリとGPIO操作アプリを組み合わせるか。
前者を選択すればラズパイGPIO操作も包含される一方、約7年前に開発は終わっている模様ながら、3B/3B+でも使えるっぽい2B用のパッチも出回っており、4Bでの利用方法を見出した人もいたり、利用者は多そう。
とは言え、開発が終わっているがゆえに今更、GPIOアクセスについてWebIOPi固有の文法を覚えることには抵抗がある。
そんな中、Raspberry PiフォーラムWebiopi with steppermotorのdanjperronさんのWebIOPi+RPi.GPIOのドンピシャなプログラム一式(pythonスクリプト+css/javascript込みのhtml)を見つけ、そのまま、あっさり、実行確認できました。
が、3B+のスペックゆえか、映像表示+パン機能を併用するとラズパイ自体が落ちることもある、数年前に既に開発が終わっている模様なのも、さることながら、それゆえにWebIOPiをインストールすると世の中が3系に完全移行済みのPython 2系が蘇るのは、どうにも微妙。
よって、このプログラムを流用させて頂く方向でWebIOPiは使わず、WebサーバとGPIO操作アプリを別個に検討することにしました。
Pythonを使うなら、WebサーバもPythonのフレームワークを使ってみようかなということでApacheのmod_wsgiを使うらしき、Bottle含め、Apache、nginxは除外。
ということでFlaskとtornadoで試してみることに。
続いてラズパイのGPIO操作アプリ。
Raspberry Piの初登場が2012年であることを考えるとRPi.GPIOもWiringPiも2013年頃初出と、この界隈では老舗にして有名らしい。
RPIOも2013年初出ながら同年リリース直後から開発が停止している模様。
2015年初版のgpiozeroは、RPi.GPIOをベースにわかりやすさを求めるアプリらしい。
pigpioの初出は不明も(初リリースは2020年?)DCモータやステッピングモータをというか、PWMを使うならpigpioが良さげな印象。
実は、Raspberry PiのGPIOをいじるのは、今回2度め、最初は、ラズパイ起動・再起動・シャットダウンボタンにgpiozeroを使ったものの、今回は、ステッピングモータを選択したのでpigpioにしてみようかと思っていました。
が、pigpioやWiringPiよりもモータ関連情報が多い気がしたRPi.GPIOでテストしてみたところ、まずまずだった、また、先のドンピシャなプログラムを見つけたのでRPi.GPIOにしてみようかと。
これでWebサーバは2つ、GPIO操作はRPi.GPIOに絞り込め、それぞれの使い方や実装方法がわかり、前述のWebIOPi+RPi.GPIO+28BYJ-48プログラムの移植にとりかかっていたわけですが、PythonとJavaScript間でマクロなるものを使って相互に通信している部分はどうやって...。
似たようなことができるものもあるのか?と検索してみるといわゆるデスクトップアプリを作ることができるというEelとpywebviewを発見...。
両方試してみた感じでは、後者が相性が良さそう。
そこでpywebviewへの先のプログラムの移植にも成功、完成させてみた...。
が、そこはデスクトップアプリ、途中で、もしやとは思ってはいたものの、インターネット接続はできるので任意のWebページを表示することは可能もリモートからブラウザ等での容易なアクセス・操作はできない...。
また、3B+だからか、デスクトップアプリの構造ゆえか、映像を表示させるとパン機能が効かない...。
ということで寄り道に終わり、ふりだし...。
ただ、元のプログラムにあったJavaScriptのコールバック関数がなくても実害がないことがわかったことなど収穫はありました。
もう1つの収穫は、Eelやpywebviewを使うまでもなく、自作スマート家電化で使った、一度のハンドシェイクで相互に何度も通信できて負荷の小さいWebSocketやMQTT使えばよいんじゃん...という、そもそも論に今更ながら気づいたこと...。
ただ、MQTTは、pub/subの他にブローカーもいるのでWebSocketに決定。
改めてFlask、tornadoでWebsocketを使ってみようと試すと後者には、素直にWebsocketがあるものの、前者では、サンプルの少ないFlask-WebSocketよりもAsync/awaitやSocket-IO、When to use Quart insteadにあるようにWSGIならぬASGIベースのFlask再実装Quart推しな印象。
pywebviewでは映像表示と併用するとモーターを動かすことができなかった一方、tornadoだとustreamerやmjpeg-streamerなどでの映像表示の併用はできるものの、なぜかラズパイが落ちることが頻発したのでFlask+WebSocketに傾きつつ、試行錯誤。
一方、Flaskで最初に見つけたWebsocketのプログラムは、メッセージ受信部分がクラスとして実装されており、先のプログラムの移植にあたり、クラス外の関数を呼びたいところも、そういうことはできそうもないという壁に。
Flaskで関数実装のサンプルないかなと思っていたところ、Flaskとwebsocketを使った簡易的なチャットを開発するを発見、これに先のプログラムを移植することに決定。
このステッピングモータのプログラム、わかってしまえば、なるほどながら、何をしているのかと眺めていたら、毎度眠くなってしまい、一向に先に進まない日々が過ぎつつ、pywebviewへの移植完了後、Flaskへの移植を再開したわけですが...。
そこでハマったのが、JavaScript側のjson。
JavaScript側でvar data = {x:"ABC", y:"123"}のようにしてws.send(data)してみてもWebsocketを介してPythonで受け取ると入力自体がstr型になっている為、dict型への変換すべく、json.loads()をしようとするとエラーになってしまう...。
そう、JavaScript側で明示的にJSON形式にすべく、JSON.stringify()する必要があることに気づくまでに数十分...。
これが解消したら、首尾よく、モータが動き出したという...。
そんなこんなでWebIOPi+RPi.GPIO+28BYJ-48同様の機能をFlask+WebSocket+RPi.GPIO+28BYJ-48に移植、USBカメラのパン部分が完成しました。
尤もコールバックしなかった分、簡素になり、まだスリム化できる部分もありますが。
というわけでソフトウェアはこんな感じ。
Raspberry Pi 3B+にZoneMinderは厳しいかもしれないぞと思えてきました。
そこで4B 4GBか8GBで代替する可能性もありつつ、3B+なら一定時間配信するESP32-WROVER/OV2640カメラからUDP通信で映像表示中だよメッセージを投げ、映像配信通知を受信・Python/OpenCVで動画/画像としてカメラサーバに保存のようにHTML/CSS/JavaScript、mjpeg-streamer/ustreamer含め、Python中心にやりくりする可能性も模索中。
4BだとRAMによってアップしますが、3B+や復活した4B RAM1GBだとすると電源、ケース、ヒートシンク、ファン込みラズパイ一式で国内相場は8000円〜くらいですかね。
容量にもよりますが、同じ容量ならUSBメモリもSSDもたいして変わらないとして安価なものなら、120GBで2000円〜、240GBで3000円〜、Webカメラが1000円〜、USBスピーカーはダイソーやキャンドゥなら300円や500円〜。
トータル1万2000円前後〜でしょうか。
ですが、ここのところ、コロナの影響もあっての半導体不足からラズパイも、どのタイプも超品薄というか品切れ。
そんな中、一時的措置との話もあるもラズパイも当初3B+と同価格だった4B RAM1GBモデルを廃止、3B+/4B RAM1GBレベルに下げた4B RAM2GB価格を戻すと共にRAM1GBモデルを復活させ、3B+と同価格に設定、以後、3B+を選ぶなら何かとスペックアップしている4B RAM1GBをと4Bを推奨しているようです。
そりゃ、そうでしょう。
CPUはクロックアップしてますし、USBポートとLANポートは独立、そのフルに使えるようになったLANポートはギガ対応、USB 2.0ポートx2の他にUSB 3.0ポートx2もあり、Wi-Fiも2.4GHzに加え、5GHzにも対応、micro HDMIポートながら2ポート(RAM1GBには荷が重い気もしますが)ありますし、電源入力のUSBポートも効率良さ気なType Cになりましたし。
これで本体の価格は同じなのですから、確かにこれから買うなら3B+を選ぶ理由は見当たらないですよね。
そうした影響なのか、3B+は、国内でも、それ以上にAliExpressでは驚くほど値がつり上がって国内以上に高い模様...。
ネットワークカメラについては、最近、中華製なら3000〜4000円くらいからあり、スマホとアプリがあれば、通話機能や動体検知含め、クラウドやmicroSDカードに映像や画像を保存できるものもありそうです。
ただ、専用アプリというのは微妙、用途からしてもそうですが、そもそもクラウドに抵抗があり、ローカルで完結したい、データ保存期間や容量制限など受けたくない、全く意味がないとは言わないまでもmicroSDカードに保存できても嬉しくない、仮に複数台のカメラを考えた場合、同一メーカーに縛られたくない等々の理由から自身にとっては、現状、USBカメラなどを流用した自作以外に選択肢はありませんでした。
チルトがつくと市販品も数千円アップしますが、今回はあえてつけなかったものの、自作ならそうでもないという点もあります。
カメラ1台で1万円は割高だとしても、カメラを複数台接続するとすれば、増えれば増えるほど、そうでもないかと。
ただ、4Bといえど、USBカメラを複数台使うのは、厳しそうなのでIPカメラ、先のデメリットを考えると自作が良いかなとは思いますが。
他方で映像にはRAM容量も重要、同じRaspberry Pi 4Bでも、できることなら1GBよりも2GB/4GB/8GBとメモリ容量はあるに越したことはないでしょう。
ESP32-CAM/deep sleep/PIR/タクトスイッチ/ext1復帰で映像表示のようにESP32-CAM、M5Camera、Raspberry Pi Zero等々+カメラなら、動体検知・撮影、パンチルト含め、格安市販品と同等以下で自作できそうですし、ブラウザを使うWebアプリを想定しているので専用アプリ不要、スマホ・タブレット、AndroidやiOSなどに限らず、Windows/macOS/*BSD/Linux等々からでも閲覧・操作可能ですし。
外出先からの接続にはVPNを想定しているので宅内にLAN環境があること、これが有線なら、スマホなどモバイルデバイスも使うので無線LAN環境もあること、常時もしくは外出時起動のVPNサーバは必須で稼働していること。
防犯カメラ用ラズパイもOSのインストール、Piユーザーは存在しない状態で他のユーザーで運用、ホスト名もデフォルトではないものに変更済み、SSH利用可(イメージを焼くところからならRaspberry Pi Imagerだと簡単にこれらを事前設定可)など初期設定は終わっていること。
VPNサーバを介して宅内LANに入った後の操作や、そうでなくともGPIO操作においてブラウザを介すなりラズパイへの接続にあたり、少なくともAndroidでは、BonjourやAvahiを使えないのでVPNサーバ機能のある機器(自身の場合は別途運用中のラズパイ)や防犯カメラ用コンピュータ(今回はラズパイ)のIPを固定しておくこと。
Raspberry Pi/スマホにSoftEther/OpenVPN互換でVPN参照。
Raspberry PiでZoneMinderインストールとカメラ映像表示やRaspberry Pi OS/Debian bullseyeにZoneMinderをインストール参照。
Flaskもpip install flaskでインストールできますが、Websocketを併用しようと思うと他にも必要になります。
RPi.GPIOは、Raspberry PiのGPIOを操作するためのPythonのフレームワークなのでpip/pip3でインストールできます。
例えば、Debianにpip3がない場合には、sudo apt install -y python3-pipをインストール。
その後、pip3 install RPi.GPIOとしてRPi.GPIOをインストールします。
基本的な使い方については、作者のWikiraspberry-gpio-pythonを参照。
カメラについては、技適のないESP32-CAMではなく、同額程度で技適対応カメラOV2640付きESP32-WROVER-DEVボードを発見、とりあえず4つ購入・動作確認済み。
というわけでUSBカメラ1台の他に電源・筐体・センサー等はともかく、Webカメラ/IPカメラ/ネットワークカメラ4台が仲間入り。
USBカメラだとラズパイなど接続デバイス性能により接続台数に制約がありますが、IPカメラ/ネットワークカメラなら、基本、無線ルーター(・アクセスポイント)の接続台数上限以外に、そうした制約がないのが嬉しいところ。
3台は外出時や在宅時には視界にない自作スマート家電の操作状況(期待通り動いたか)の確認用に、1台はドアカメラにでもしてみようかと。
ドアスコープ越しではなく、ドア外側に取り付けを想定している後者1台は、電源の取り方と風雨にも耐え得るよう、場合によっては暗視機能追加など工夫を要するでしょう。
が、前者3台は、単なるライブ映像で、なんなら動作確認用サンプルスケッチをちょっといじるだけで、電池+電池ケースにせよ、USBケーブル+USB充電器5V、ACアダプタ 12V+降圧モジュールにせよ、電源とちょっとしたケース程度のみで、何れも手持ちのものでよさそうなので、できているも同然かなと。
赤外線投光器については、ユニバーサルボードに30〜40個前後の赤外線LED、抵抗、MOSFETなど、はんだ付けして自作予定。
ただ、冒頭述べたようにUSBカメラにあるであろう赤外線カットフィルター除去をしなくてもいけるのかについて現時点では、未確認。
VoIP、ボイスチャット機能の自作情報は、限られ、Androidスマホも使いたいとなるとWebベース以外だと既存のAndroidアプリに縛られない前提だとAndroidアプリ自体を自作する必要があるが、そこまではしたくないなと。
であれば、これらの機能をもつマルチプラットフォームなソフトウェアを流用できないかといろいろ探してDiscord、TeamSpeakやMumble/Murmurだけではなく多々ありました。
が、まず、Raspberry Pi OS対応とは言わないまでもLinuxとAndroidは使いたいので、これらに対応していないものは除外。
また、ラズパイ+カメラ側は自動応答により、何もしなくても会話できる状態にしたりなどを考慮すると自作スマート家電でやったようにブラウザを介して自作Webサーバ側で自由に操作できるGUIパネルがなくても、デーモンでいけて、CLI、スクリプトからの操作ができるものが良さげ。
Discord/TeamSpeak/Mumbleは、これができないので除外。
TeamSpeakは、これができそうもないので除外。
Discordは、PCのみ機能制限はありつつも未登録で利用可能なWebインタフェースがあるも期待する使い方はできそうもないので除外。
MumbleにもWebインタフェースやCLIがあるものの、何れもサーバ構成用なので除外。
CLI、スクリプトで応答させることができるものは、あってTwinkleかLinPhone、Jitsiくらいしか見つけられませんでした。
スクリプトから操作できそうなTwinkleもLinPhoneもリポジトリにあり簡単も、前者は既に開発停止している模様、後者も邪魔な存在になったのか、Googleやベンダーの動きからしてSIP phoneの行く末が危ぶまれる雰囲気を感じたり、そもそも、なぜかSIPが無効になっているっぽい手持ちのAndroidスマホでSIPソフトフォンを使えるようにしてみても映像はいけても肝心の音声通話ができなさそうなので除外。
残るJitsiについては、クラウドやローカルで完結できないサービスを回避すべく、開発は終了ながらコミュニティにてメンテされ、ダウンロードできるJisti Desktopというデスクトップ版をRaspberry Pi OSにインストール・実行できたものの、Jitsi Meetのローカル(オンプレミス)版。
わけあって一度アンインストール後、pavucontrolをインストールしようとすると依存関係で失敗、Jitsiのリポジトリにあって必要となるバージョンと異なるパッケージが入っていたようで微妙、使うとしたらクラウド版か...。
また、ラズパイの場合、WebRTCなどブラウザベース、特に仕様上ブラウザを選ぶ場合、3B+では厳しいので4B 4GB/8GBあたりが前提となるが、品薄ゆえすぐには入手できそうもない、検証だけなら400で試す手はあるも、カメラ複数台運用時には、少なくとも4Bは必要になるとしても1台の今、通話機能のためだけに4Bを買う、結局3B+が余る...というのは憚られ、そもそも要らないという選択肢と迷い中...。
現在、事情があって映像は、apt install、LAN内で使えるように[ustreamer --host=0.0.0.0]しつつ、iframeのsrcにIPアドレス:8080/stream(mjpg-streamerでmjpg_streamer -i "./input_uvc.so -n -f 30 -r 640x480 -d /dev/video0"しつつ、imgのsrcにIPアドレス:8080/?action=stream)を指定したものとなっています。
が、通常は、Zoneminderのカメラ一覧やカメラ個別画面、パンするときは、ustreamerかmjpeg-streamerによる画面を両方採用する方が、むしろ、良いかなと思っています。
っていうか、先の事情でbullseyeでも一時はできたZoneMinderを常用させられず、謎現象に起因してVPNが使えないので、防犯・見守りカメラの運用は、これらの状況改善を待ってからということに。