messyなkitchenなブログ

ただひたすらに散らかった台所や人生やその他を晒す。

MENU

ラズパイで見守りカメラ #2

前回の続き。タイトル変わったけど。期間がだいぶ空いたけど。

振り返り

前回の記事はこれです。
ラズパイ Zero W に motion 入れて、動画ファイルをクラウドへ保存してみた件。

messykitchen.hateblo.jp

しかし課題がいろいろ。

  • 画像サイズを大きくすると、動画ファイルがクラウドへ保存されない
  • 保存されていても、ファイルが壊れていることが多い
  • そもそもクラウドディレクトリがマウントされないことがある
  • motion の起動が手動

マウントをどうにかする

fstab で InfiniCloud をマウントする設定にしたんだけど、どうにも安定しないです。
そこで、スクリプトを組んでみました。
マウントできていなければ指定回数(ここでは 3回)だけマウントを繰り返す感じです。

▶ mount_retry.sh(クリックすると展開されます)

#!/bin/bash

mount_point="/mnt/infinicloud"
max_retries=3
retries=0

until [ $retries -ge $max_retries ]
do
    mount -a -t davfs
    if mountpoint -q "$mount_point"; then
        echo "Mount successful!"
        break
    else
        echo "Mount failed. Retrying..."
        retries=$((retries+1))
        sleep 5
    fi
done

if [ $retries -eq $max_retries ]; then
    echo "Mount failed after $max_retries retries. Exiting."
fi

動画ファイルを一時置きする

motion.conf の設定で /mnt/infinicloud を動画ファイルの出力先にしていたのを /tmp に変更しました。

そして、/tmp へ保存されるファイルがクローズされるのを待ち、 クローズされていればそのファイルを /mnt/infinicloud へコピー、 つまりクラウドへアップロードする処理をスクリプトで書いてみました。
これでアップロードした動画ファイルが壊れなくなることを期待。

▶ upload_mp4.sh(クリックすると展開されます)

#!/bin/bash

while true; do
  # /tmp/motionディレクトリ内のmp4ファイルの中で、最も古いファイルを選択する
  selected_file=$(ls -t /tmp/motion/*.mp4 | tail -1)

  if [[ -f "$selected_file" ]]; then
    echo "選択したファイル: $selected_file"

    # 選択したmp4ファイルがクローズされているか確認する
    if lsof "$selected_file" >/dev/null; then
      echo "ファイルはまだ開かれています"
    else
      echo "ファイルはクローズされています"

      # 別のディレクトリにmp4ファイルをコピーする
      cp "$selected_file" /mnt/infinicloud/motion/

      # コピー後、mp4ファイルを削除する
      rm "$selected_file"

      echo "ファイルをコピーして削除しました"
    fi
  fi

  # 10秒間処理を停止する
  sleep 10
done

追記

アップロードしたら LINE Notify に通知を飛ばすようにしてみました。

       echo "ファイルをコピーして削除しました"
+      filename=$(basename "$selected_file")  # ファイル名のみを抽出
+      curl -X POST -H "Authorization: Bearer {アクセストークン}" -F "message=$filename" https://notify-api.line.me/api/notify
      fi

motion を起動させる

スクリプト 3つ目。
motion を設定ファイル指定で起動するスクリプト
念のため起動前 10秒待ち。いらないかもしれないけど。

▶ motion_startup.sh(クリックすると展開されます)

#!/bin/bash
sleep 10
motion -c /root/motion/motion.conf

仕上げ。自動起動

systemd で起動させるため、service ファイルを記述しました。
有効化します。

systemctl enable motion.service 

▶ /etc/systemd/system/motion.service(クリックすると展開されます)

[Unit]
Description=Motion Service
After=network.target
RequiresMountsFor=/mnt/infinicloud

[Service]
ExecStartPre=/bin/sleep 10
ExecStart=/bin/bash -c '/root/mount_retry.sh && /root/motion_startup.sh && /root/upload_mp4.sh'
Restart=always
User=root

[Install]
WantedBy=multi-user.target

動作確認

ラズパイの電源を入れ直し、しばらく待ちました。

カメラ前で手を振ってみて、しばらく待ちました。

しばらく待って、InfiniCloud のディレクトリを見てみました。

ちゃんとファイルが上がっている!

うまくいきました。
起動時間、画質、動体検知設定 などいろいろ調整することはありそうですが、これで当初の目的は達成できました。

おまけ

InfiniCLOUD の 紹介コード: 8E2Q5