見出し画像

ストリーミングでハムスターの監視ができるシステムを RaspberryPi と PHP でつくったので仕組みとかを公開してみます

はじめに

こんにちは、めもりー (@m3m0r7) です!
ハムスター監視システムを自作したということで、この内容でプロポーザルを出していたりするのですが、この内容と同時に出しているプロポーザルが採用されてしまうことが多々あり、アウトプットできないなと思い note に開発のモチベーションや過程などをまとめることにしました。 

ハムスター監視システムとは?

ハムスター監視システムとは、私が飼っているペットのハムスターを 24 時間 365 日リアルタイムに監視するためのプライベートなウェブサービスのことです。

開発のきっかけとプロダクト

3 年前くらいに RaspberryPi でなにかしようかなって考えて買ってみたけど、特に何も思い浮かばず家の物入れにしまってありました。

そして、去年の 12 月くらいからペットであるハムスターの「Lily」ちゃんをお迎えしました。ちなみに種類はキンクマです。

どうみても頬袋がエリマキトカゲなので、前世はハムスターではなくきっとエリマキトカゲなのかもしれません。

そして、ふと「そういえば、RaspberryPi あったよね」と RaspberryPi の存在を思い出し「そうだ、これでハムスターを外部からでも監視できるリアルタイムにストリーミングができるプライベートなサービスを作ろう」となったのが開発のきっかけです。
思い立った当日に秋葉原にあるヨドバシカメラに RaspberryPi 用のカメラをワクワクしながら買いに行ったのを今も覚えています。
事前にある程度調べるとカメラモジュールは Python で API 触れるらしいのですが、私は Python は numpy くらいしか使ったことがなく、初心者の中の初心者だったんですが、それでもそれほど難しくはなかったかなと思います。

また、今年の 4 月にジャンガリアンの「Iris」ちゃんをお迎えしました。
彼女らの名前はすべて花言葉と花の名前から名前付けをしました。

「Lily」ちゃんをお迎えしてから、最初の月で大体 3 日から 5 日ほどで最初の監視システムをデプロイしました。

最初はストリーミングの実装をせずに RaspberryPi から 60 秒おきに画像データを中継サーバーのプライベート API を叩いて、画像をアップロードする仕組みのみでした。そして、ある程度時間ができたタイミングでストリーミングの実装をはじめました。

ただ、プライベートということもあり、だいぶ雑に作っていて、2 日に 1 回謎に落ちるという不具合が発生していても、ログを取るのが難しいような仕組みだったため、スクラッチから作り直そうということで、作り直して最近ようやく入れ替えが完了しました。

前までは、上でも書いているように60秒おきの更新だったり、ストリーミングはベータテストみたいな位置づけでしたが、スクラッチで作り直した今現在は、ストリーミングが常時再生されるようになっており、モバイル回線など回線速度が遅い場合は、30秒おきにストリーミングから取得した画像を配信するような仕組みになっています。

このストリーミングサーバーのシステムにおけるスクラッチの開発自体は、オープンソース化をしているということもあり、 3 ヶ月ほどの開発期間を要しました。転職する直前とした直後だったり、家庭の事情で取れる時間が 1 日 1 時間ほどだったりしたのもあって、割と長い戦いになってしまっていました。

また、新しくスクラッチで開発したものは、今年の 5 月 26 日の私の誕生日に Sensor Hat を友人から頂いて、それを今現在稼働している RaspberryPi に装着して Sensor Hat から取得できるデータ (室温, 湿度, 気圧) も配信できるようになりました。
なお、室温はある程度補正を入れているんですが、どうしても近い値にならないという問題が… 装置が CPU に近いので CPU の熱に影響してしまうようです。補正を入れないと 40℃ くらいになります。

ソースは下記なので、興味がある方はぜひ!

どういう仕組み?

使用している技術スタック

使用している技術スタックは下記のとおりです。

- 中継サーバー ... PHP, Swoole, Nginx, Docker

- ユーザーフロント ... TypeScript, React, Redux, Material UI, Node

- カメラサーバー ... Python3, picamera module

技術選定について

プライベートなので特にあんまり考えておらず、私自身が脳死してても書けそうな技術を選びました。
ただ、 Swoole に関しては開発中かつドキュメントが少ないということもあり、本家の swoole-src を見ながら開発をしていて色々とつまづきポイントがあったなと思っています。

例えば

- Swoole で SSL を設定するのに PHP の stream_context_set_option を使用しないといけないんですが、これのオプションが Swoole 上で未実装だった
- SSL 設定したのはいいものの、ハンドシェイクに極稀に失敗する
- coroutine 内の Fatal エラーが  try-catch できず PHP が終了してしまうためデバッグがしづらい
- timeout 類がマイクロ秒に対応していない
- 稀にバッファが詰まる
- lock が deprecated になっているので、ソケットを Lock できず同ソケットに同時書き込みをしようとして、エラーがでて死ぬ

などなど。ストリーミングの性質上 1 秒あたりどうしても多くのデータを送る必要があり、衝突してしまうといった問題がありました。
ちなみに、このハムスター監視システムは 1 秒あたり 24 枚の画像データを中継サーバーで受け取っています。

違う書き方にしてみるとか、設計そのものを見直すとかで、工夫したりした結果が上のレポジトリになります。
SSL の問題は未だ解決できず、 HTTP だと問題ないので Nginx のリバースプロキシを使って解決しました。

データの流れ

データの流れは下記のとおりで、そこまで難しい仕組みではないことがわかります。

WebSocket で Nginx と通信し、 Nginx は Swoole の coroutine で作られた HTTP サーバー につないでいます。
一方で、 Raspberry Pi からの独自プロトコルからも常にカメラのデータを送信しており、それも Swoole の coroutine で作られたオリジナルのサーバーでデータを受け取っています。
また、一定時間ごとに Sensor Hat から室温, 湿度, 気圧などのデータが送られてくるのでそれを Redis に TTL をつけて保存したりしています。

全体的には、それらのデータを API サーバーとして Swoole の coroutine でレスポンスを返せるような仕組みになっています。

ユーザーフロント側はその API を fetch で取得しているだけです。
カメラのデータを受信する WebSocket については wss:// で繋ぐようになっています。

開発費用

気になるお値段を公開します。

イニシャルコスト

- Raspberry Pi Model 3 ... 約 ¥6,000
- カメラモジュール ... 約 ¥4,000
- ルーター ... 約 ¥10,000

初期投資で大体 ¥20,000 ほど。
ちなみに監視カメラを普通に買うと ¥5,000 くらいです。つまり、¥15,000 は(いい意味での)勉強代です。

ランニングコスト

ランニングコストはストリーミングで配信されているデータを自宅 LAN ではなく、別サーバーにおくことで自宅 LAN が外部に公開される危険性や、そもそも固定 IP アドレスではないので通信事業者の都合で変わってしまう問題を防ぐという意味でも使用しています。

- ConoHa ... 月約 ¥2,300
- ロリポップマネージドクラウド ... 月約 ¥2,500

だいたいストリーミングの中継サーバーで月約 ¥5,000 かかっているようです。
ロリポップマネージドクラウドはコンテンツキャッシュを有効にしているので、基本利用料にプラス月 ¥1,500 かかっているようです。
ただ、ロリポップマネージドクラウドに関しては、10 万円分のクーポンを所持しているので実質 0 円です。
理由は下記から。

まったく、関係ないんですが AWS もなぜか月 ¥500 くらい請求されているんですよね。使ってるものすべて削除した気がするんですけど…

課題

現状の課題は、たまにストリーミングサーバーに繋がらなくなるくらいですかね。それでもストリーミングサーバーだけ reboot すればまたつながるので、特に問題は感じてないかなと思ってます。
強いて言うなら supervisor を設定なり定期的な再起動なりをしたいかなというくらいかなと。

あとは、録画もできるようにしたいなと思っているんですが、データが大きすぎるのでどうしようかなと考えています。

まとめ

ということで、ハムスター監視システムの開発のきっかけから仕組みまで書いてみました。

この記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。

7
ねこになりたい
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。