防犯カメラシステムの自作⑤~クラウドストレージへの動画ファイルの自動アップロード+α~

 本投稿は,「防犯カメラシステム with Raspberry Pi」(←開発がすべて完了したら「開発物」にページを作成する予定)に関する投稿です.Tipsでの投稿は,内容ごとに分け,下記の通り分割して投稿してゆきます.

Reolink社製カメラ「RLC-1212A」の挙動確認
Raspberry PiへのPoE HATのセットアップ
VPNを用いたリアルタイム映像視聴の環境構築
クラウドストレージへの動画ファイルの自動アップロード
⑤クラウドストレージへの動画ファイルの自動アップロード+α(本投稿)
ウォルボックス内環境に対する温湿度センサとファン制御の実装
⑦人物など動体検知時におけるスマホへのプッシュ通知機能の実装(予定)

 前回のTip④[1]では,「防犯カメラシステム with Raspberry Pi」に向けて,防犯カメラが録画した映像を,クラウドストレージへ自動保存する方法を説明しました.
 これに対し本投稿では, 動画ファイルのアップロード中におけるRaspberry Piの再起動や通信障害によって,動画ファイルのアップロードが中断された場合にも,再度アップロード処理を実行し漏れなくクラウドストレージに動画ファイルを避難させる処理の追加を行います.また,各ストレージの管理として,一定期間経ったファイルや,ストレージの空き容量が一定よりも少なくなった場合に,動画ファイルを削除する処理の追加を行います.
 使用したRaspberry Piは,Pi 4 Model B 8GBです.OSは,rasRaspberry Pi OS(64bit)において執筆時点で最新バージョン(Debian 13 Trixieがベース.Release Date: 18 Jun 2026)を用いています.

目次

  1. 本投稿で使用するもの
  2. 各種ファイルおよび作成ファイルの役割
  3. 未アップロードファイルの漏れ対策~Raspberry Pi再起動時~
    • .shファイルの加筆修正
    • 実行・動作確認
  4. 未アップロードファイルの漏れ対策~定期確認~
    • .shファイルの作成
    • .serviceファイルの作成
    • .timerファイルの作成
    • 実行・動作確認
  5. ストレージ管理~Raspberry Pi上の動画ファイル削除~
    • .shファイルの作成
    • .serviceファイルの作成
    • .timerファイルの作成
    • 実行・動作確認
  6. ストレージ管理~GoogleDrive上の動画ファイル削除~
    • .shファイルの作成
    • .serviceファイルの作成
    • .timerファイルの作成
    • 実行・動作確認

1. 本投稿で使用するもの

 筆者が自作しようとしている防犯カメラシステム全体ではなく,本投稿で扱った機材のみを,以下にあげる.

  • 防犯カメラ:Reolink社製 RLC-1212A
  • Raspberry Pi 4 Model B 8GB(Tips②[2]より,下記がセットアップ済み)
    • Waveshare社製 PoE HAT(B)
    • Raspberry Pi 4 Model B用のヒートシンク
  • micro SDカード×2枚
    • 防犯カメラに使用 (256GB,class10,UHS-1/U3,最大読込100MB/s)
    • Raspberry Piに使用(64GB,class10,UHS-1/U3,最大読込100MB/s)
  • PoEスイッチングハブ:TPLINK社製 TL-SG1005
  • LANケーブル×2本
    • ハブ―Raspberry Pi間の接続
    • ハブ―防犯カメラ間の接続
  • Googleアカウント
    • クラウドストレージとして,Google Driveを使用するために作成が必要
  • Rclone(v1.60.1)
  • inotifywait(v4.23.9.0)

2. 各種ファイルおよび作成ファイルの役割

 本投稿では,これまでのTipsで扱った.shファイルや.serviceファイルの他に,新たに.timerファイルを扱う.そこでまずこの第1章では,.shファイル/.serviceファイル/.timerファイルの役割を表1に示す.
 Tips④[1]で説明した,動画ファイルが書き込み中でないか常時監視するsecurity-camera-monitorでは,.shファイルと.serviceファイルしか作成しなかった.これは,1度サービスを起動したら動作し続け常時監視を行うものであり,起動そのものは1回しかしていない.そのため,.timerファイルによる定義が不要であった.

表1 各種類のファイルの役割
ファイルの種類役割
.sh実際の処理=What(何をする)
.serviceその処理のサービスを定義=How(どのように)
.timerそのサービスを定期的に起動するための定義=When(いつ)

 本投稿で,目的ごとに作成する各.sh/.service/.timerファイルの役割と違いを,表2に示す.

表2 各種類のファイルの役割
security-camera-monitor(第3章)
.sh動画ファイルのアップロード状況の監視とアップロード処理
.service1度サービス起動したら,稼働し続ける
security-camera-retry.service(第4章)
.sh未アップロードの動画ファイルがないか定期的確認とアップロード処理
.service1度サービスを起動し.shが処理を終えたら,サービスを終了する
.timer5分ごとにサービスを起動する
security-camera-cleanup-pi(第5章)
.sh7日の保存期間を超過した動画ファイルを削除する
.service1度サービスを起動し.shが処理を終えたら,サービスを終了する
.timer1時間ごとにサービスを起動する
security-camera-cleanup-cloud(第6章)
.shストレージ使用量が14GiBを超過している場合,最も古い動画ファイルを削除する
.service1度サービスを起動し.shが処理を終えたら,サービスを終了する
.timer1時間ごとにサービスを起動する

3. 未アップロードファイルの漏れ対策~Raspberry Pi再起動時~

 何らかのシステムトラブルでRaspberyy Piが落ちるなどし,動画のアップロードが未完了となってしまった場合を想定する.これに対する対策として,Raspberry Pの再i起動時に,防犯カメラからFTPで転送された記録映像を格納しているディレクトリ内を検索し,マーカである.uploadedファイルが存在しない動画ファイルを,Google Driveへアップロードする.

 「マーカである.uploadedファイルが存在しない動画をアップロードする」機能の本質は,Tips④[1]で作成したsecurity-camera-monitor.shと重複するため,これに加筆修正する形で実装する.
 まずは,下記コマンドで,security-camera-monitor.shをnanoエディタで開く.

sudo nano /usr/local/bin/security-camera-monitor.sh

 そして,以下のように加筆修正を行う.

#!/bin/bash

MOVIE_DIR="/home/<user_name>/SecurityCamera/logMovie" # 録画した動画ファイルがあるディレクトリ
MARKER_DIR="/home/<user_name>/SecurityCamera/logMovie/uploaded" # アップロードが完了した動画ファイルのマーカを格納するディレクトリ
CLOUD_STORAGE="MyGoogleDrive:SecurityCamera" # 動画ファイルをアップロードするクラウドストレージのサービスとプロジェクト名

mkdir -p "$MARKER_DIR" # マーカを格納するディレクトリが存在していない場合は作成する

# 動画をアップロードする関数
upload_file()
{
    FILE="$1" # 引数として渡された動画ファイルの絶対パスを格納する
    FILENAME="$(basename "$FILE")" # 絶対パスからファイル名だけを抽出する
    MARKER="$MARKER_DIR/$FILENAME.uploaded"
	
	# 対象動画ファイルに既にマーカが存在していたら,その旨を表示し,関数の処理を終了する
    if [ -f "$MARKER" ]; then
        echo "Already uploaded: $FILE"
        return 0
  else
         echo "Uploading: $FILE"
    fi

	# 動画ファイルのアップロード処理
    if /usr/bin/rclone copy "$FILE" "$CLOUD_STORAGE"; then
         # アップロード(クラウドストレージへのコピー)が成功したら,マーカを作成
        touch "$MARKER"
        echo "Upload completed: $FILE"
        echo "Upload marker created: $MARKER"
    else
        echo "Upload failed: $FILE"
        return 1
    fi
}

# アップロード漏れ対策(Raspberry Pi 起動時)
echo "Checking existing files..."
for FILE in "$MOVIE_DIR"/*.mp4
do
    if [ -f "$FILE" ]; then
        upload_file "$FILE"
    fi
done
echo "Existing file check completed."

# リアルタイムのファイル監視
# -m:監視を1回だけでなく継続実行
# -e close_write:「ファイル書込が行われその書き込みが終了した」というイベントを監視する
# --format '%w%f':検出時にディレクトリとファイル名の出力
# 検出したファイル名(絶対パス)をパイプでWhile文に渡し、.mp4ファイルならアップロードする関数を実行する
/usr/bin/inotifywait \
    -m \
    -e close_write \
    --format '%w%f' \
    "$MOVIE_DIR" |
while IFS= read -r FILE
do
    if [[ "$FILE" == *.mp4 ]]; then
        echo "Detected: $FILE"
        upload_file "$FILE"
    fi
done

 スクリプトの加筆修正が完了したら,意図した通りの挙動をするか確認を行う.
 挙動確認をするために,アップロードが未完了な動画ファイルがある状況を,意図的に作る.任意の動画ファイルに対し,それと対応する.uploadedファイルを削除する.
 加筆修正前のスクリプトにおいては,動画ファイルそのものが新規作成(ファイル書き込み)された場合にしか,クラウドストレージへのアップロードは行われなかった.これに対し,動画ファイル自体は元々存在し,しかし.uploadedファイルは無い動画ファイルに対し,Google Driveへアップロードが成されたら,加筆修正後の挙動として成功である.
 下記コマンドを実行し,サービスを再起動し,スクリプトの変更内容を反映させる.

 sudo systemctl restart security-camera-monitor.service

 成功した場合,ターミナルには下記のように表示される.

# 実行結果
Checking existing files...
Already uploaded: /home/<user_name>/SecurityCamera/logMovie/...
Uploading: /home/<user_name>/SecurityCamera/logMovie/...
Upload completed: /home/<user_name>/SecurityCamera/logMovie/...
Upload marker created: ...
Existing file check completed.
Setting up watches.
Watches established.

4. 未アップロードファイルの漏れ対策~定期確認~

 この第4章では,なんらかのトラブルによりクラウドストレージへのアップロードが完了しなかった動画ファイルを漏らさぬよう,アップロード漏れの有無を定期的に確認する機能を実装する.この第4章からは,.shファイルや.serviceファイルに加え,新たに.timerファイルを扱う.

 はじめに,下記コマンドで.shファイルを作成すると共に,nanoエディタで開く.

sudo nano /usr/local/bin/security-camera-retry.sh

 作成した.shファイルに対し,以下のコードを記述する.

#!/bin/bash

MOVIE_DIR="/home/<user_name>/SecurityCamera/logMovie" # 録画した動画ファイルがあるディレクトリ
MARKER_DIR="/home/<user_name>/SecurityCamera/logMovie/uploaded" # アップロードが完了した動画ファイルのマーカを格納するディレクトリ
CLOUD_STORAGE="MyGoogleDrive:SecurityCamera" # 動画ファイルをアップロードするクラウドストレージのサービスとプロジェクト名

mkdir -p "$MARKER_DIR" # マーカを格納するディレクトリが存在していない場合は作成する 

# アップロード漏れ対策(定期確認)
for FILE in "$MOVIE_DIR"/*.mp4
do
    # 通常のファイルとして存在していなければ,この回のループを終了し,次のファイルの処理に移行する
    if [ ! -f "$FILE" ]; then
        continue
    fi

    FILENAME="$(basename "$FILE")" # 絶対パスからファイル名だけを抽出する
    MARKER="$MARKER_DIR/$FILENAME.uploaded"

    # 対象動画ファイルに既にマーカが存在していたら,この回のループを終了し,次のファイルの処理に移行する 
    if [ -f "$MARKER" ]; then
        continue
    fi

    echo "Retry uploading: $FILE"

    # 動画ファイルのアップロード処理
    if /usr/bin/rclone copy "$FILE" "$CLOUD_STORAGE"; then
        touch "$MARKER" # アップロード(クラウドストレージへのコピー)が成功したら,マーカを作成
        echo "Retry upload completed: $FILE"
        echo "Upload marker created: $MARKER"
    else
        echo "Retry upload failed: $FILE"
    fi
done

 スクリプトの作成が終わったら,下記コマンドで実行権限の付与と付与状況の確認を行う.実行結果が図1のようであれば,成功である.

sudo chmod +x /usr/local/bin/security-camera-retry.sh
ls -l /usr/local/bin/security-camera-retry.sh
図1 security-camera-retry.shに対する実行権限の確認結果

 次に,スクリプトをサービスに登録し自動化するための.serviceファイルを作成する.下記コマンドで,.serviceファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-retry.service

 作成した.serviceファイルに対し,以下のコードを記述する.

[Unit]
Description=Security Camera Failed Upload Retry
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=<user_name>
ExecStart=/usr/local/bin/security-camera-retry.sh

 .serviceファイル単体での実行確認はせず,後述の第4.3節で作成する.timerファイルが完成した後,第4.4節で実行・動作確認を行う.

 最後に,サービスを定期起動するための.timerファイルを作成する.下記コマンドで,.timerファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-retry.timer

 作成した.timerファイルに対し,以下のコードを記述する.以下のコードにおいては,クラウドストレージへのアップロード漏れファイルの確認と実行を,5分ごとに行う.

[Unit]
Description=Retry Security Camera Uploads Every 5 Minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=security-camera-retry.service

[Install]
WantedBy=timers.target

 この第4.4章では,1度サービスを起動し終了したサービスが,次の5分後の起動に向けて待機状態になっているかを確認する.確認は下記コマンドで行う.
 まずは,作成した.serviceファイルや.timerファイルに対し,下記コマンドでsystemdにその新たな設定を認識させる.

sudo systemctl daemon-reload

 設定を認識させたら,下記コマンドにて.timerファイルを有効化し,その起動と確認を行う.

sudo systemctl enable --now security-camera-retry.timer
systemctl status security-camera-retry.timer

# 実行結果が,Active: active (waiting) なら成功

 実行確認そのものは,上記で完了である.
 今後の運用/保守の観点で補足する.下記コマンドを用いることで,この.timerファイルが次回実行される時刻を確認することが可能である.

systemctl list-timers security-camera-retry.timer

5. ストレージ管理~Raspberry Pi上の動画ファイル削除~

 この第5章および後述する第6章では,記録映像をクラウドストレージへアップロード・避難させる処理におけるトラブル対策ではなく,動画ファイルの作成やアップロードを続けた後にやがて生じるであろうストレージ超過トラブルに対する対策を行う.
 この第5章では,Raspberry Piのストレージ超過に備えたファイル削除の機能を実装する.削除の条件を以下に列挙する.

  • 動画ファイルと対応する.uploadedファイルが存在する:
    • クラウドストレージへの避難が済んでいない状態で,元となるRaspberry Pi上の動画ファイルを削除してしまうことを避けるため
  • 動画ファイルを指定の期間保存し,その期間を超過している:
    • 筆者がクラウドストレージとして利用しているGoogle Driveのストレージ容量は15GBであるのに対し,Raspberry Piのストレージには64GBのmicroSDカードを使用している.そのため,クラウドストレージ上にある動画ファイルの削除と同時に削除せず,少しでも記録映像を長く多く残すべく,Raspberry Pi上の動画ファイルに対しては期間の条件を設けた
    • 暫定の設定として,本稿執筆の時点では保存期間を1週間分の ”7日” とした.システム全体の開発が完了し屋外設置にまで至ったら,実際の運用状況とRaspberry Piのストレージ消費の速さから,適宜修正する予定である

 ここで,削除条件の1つである期間の捉え方について説明する.
 動画ファイルを作成してからの経過日数は,コマンドfindのオプションであるmtimeを使用し求める.これは,ファイルの最終更新日時から一定期間経過したものを抽出する.そしてこのオプションmtimeにおけるパラメータの設定の仕方と抽出対象の違いを,以下に列挙する.

  • -mtime 7:
    • 経過日数が,7[日]×24[時間]以上~8[日]×24[時間] 未満のファイルが対象
    • つまり,システムトラブル等で上記の対象期間にシステムが停止し8日以上経過したファイルが生まれた際は,削除されず残り続けてしまう
  • -mtime +7:
    • 経過日数が,8[日]×24[時間] 以上のファイルが対象
    • “+7” は,「7より大きい」を意味しているため,8日以上が対象になる
    • つまり7日間(7日間 + 23時間59分 = 191時間59分)保管し,192時間以上経過したら削除という挙動
      • 余談:「削除を実行する日数」ではなく「保管したい日数」と捉えると,このオプションを理解しやすくなると筆者は感じている

 はじめに,下記コマンドで.shファイルを作成すると共に,nanoエディタで開く.

sudo nano /usr/local/bin/security-camera-cleanup-pi.sh

 作成した.shファイルに対し,以下のコードを記述する.

#!/bin/bash

MOVIE_DIR="/home/<user_name>/SecurityCamera/logMovie" # 録画した動画ファイルがあるディレクトリ
MARKER_DIR="/home/<user_name>/SecurityCamera/logMovie/uploaded" # アップロード完了マーカを格納するディレクトリ
RETENTION_DAYS=7 # Raspberry Pi上に動画を保持する期間(日)

# 一定期間が経過した動画を検索
# find文にて削除条件に該当するファイル名を標準出力で列挙し,その出力された各ファイル名に対し,While文でループ処理している(find文自体はループしていない).
find "$MOVIE_DIR" \
    -maxdepth 1 \
    -type f \
    -name "*.mp4" \
    -mtime +"$RETENTION_DAYS" \
    -print0 |
while IFS= read -r -d '' FILE
do
    FILENAME="$(basename "$FILE")"
    MARKER="$MARKER_DIR/$FILENAME.uploaded"

    # アップロード完了マーカが存在しない場合は削除せず,この回のループを終了し,次のファイルの処理に移行する
    if [ ! -f "$MARKER" ]; then
        echo "Not uploaded, keeping: $FILE"
        continue
    fi

    echo "Deleting uploaded video: $FILE"

   # 動画ファイルを削除
    if rm -- "$FILE"; then
        echo "Deleted video: $FILE"
    else
        echo "Failed to delete video: $FILE"
        continue
    fi

    # 動画削除に成功した場合のみマーカを削除
    if rm -- "$MARKER"; then
        echo "Deleted marker: $MARKER"
    else
        echo "Failed to delete marker: $MARKER"
    fi
done

 スクリプトの作成が終わったら,下記コマンドで実行権限の付与と付与状況の確認を行う.実行結果が図2のようであれば,成功である.
 なお,図2は開発と並行しながら本稿を想定して撮ったスクリーンショットであるため,図中のファイル名が “security-camera-cleanup.sh” となっている.後述の第6章で扱うクラウドストレージ上の動画ファイル削除と区別するべく,スクリーンショット撮影後に,ファイル名を “security-camera-cleanup-pi.sh” へ修正するに至った.

sudo chmod +x /usr/local/bin/security-camera-cleanup-pi.sh
ls -l /usr/local/bin/security-camera-cleanup-pi.sh
図2 security-camera-cleanup-pi.shに対する実行権限の確認結果

 実行権限の付与まで完了したら,サービスに登録し自動化する前に,スクリプトの手動実行により,動作確認を行う.作成したスクリプトはファイル削除を扱うため,スクリプトに不備があり意図しない動作をした場合に,望まぬファイルが自動で次々に削除されてしまう事態を避けるためである.

 動作確認をするべく,最終更新から7日を超過した動画ファイルを人為的に作り出す.動作確認の環境作成から実際の実行までの手順を以下に示す.手順1~4までの実行結果を図3に示す.

  1. 既存の動画ファイルをコピーし,ファイル名を例えばtest.mp4とする
  2. 下記コマンドで,test.mp4の最終更新日を8日前の日付に設定する
touch -d "8 days ago" /home/<user_name>/SecurityCamera/logMovie/test.mp4
  1. test.mp4に対応するマーカを,下記コマンドで作成し,クラウドストレージへアップロード済みとする状況を作り出す(あるいは,第4章で実装した定期確認の機能がちょうど実行され,たまたまアップロードとマーカ作成が行われる場合も起こりうる).
touch /home//SecurityCamera/logMovie/uploaded/test.mp4.uploaded
  1. 作成した削除スクリプトを,下記コマンドで手動実行する
sudo /usr/local/bin/security-camera-cleanup-pi.sh
図3 security-camera-cleanup-pi.shに対する手動実行の結果(ファイル削除時)

 もし,7日超過しているがマーカは無い場合,つまりはクラウドストレージへのアップロードは済んでおらずRaspberri Pi上のストレージ上から削除は回避したい場合(上記手順の3.を行わなかった場合),その動作確認の結果は図4のようになる.

図4 security-camera-cleanup-pi.shに対する手動実行の結果(アップロードが済んでおらず削除対象外の場合)

 次に,スクリプトをサービスに登録し自動化するための.serviceファイルを作成する.下記コマンドで,.serviceファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-cleanup-pi.service

 作成した.serviceファイルに対し,以下のコードを記述する.

[Unit]
Description=Security Camera Uploaded Video Cleanup for Raspberry Pi

[Service]
Type=oneshot
User=<user_name>
ExecStart=/usr/local/bin/security-camera-cleanup-pi.sh

 .serviceファイル単体での実行確認はせず,後述の第4.3節で作成する.timerファイルが完成した後,第4.4節で実行・動作確認を行う.

 最後に,サービスを定期起動するための.timerファイルを作成する.下記コマンドで,.timerファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-retry.timer

 作成した.timerファイルに対し,以下のコードを記述する.以下のコードにおいては,各動画ファイルの経過日数の確認を1時間ごとに行う.

[Unit]
Description=Security Camera Uploaded Video Cleanup Timer for Raspberry Pi

[Timer]
OnBootSec=10min
OnUnitActiveSec=1h
Unit=security-camera-cleanup-pi.service

[Install]
WantedBy=timers.target

 この第5.4節では,1度サービスを起動し終了したサービスが,次の1時間後の起動に向けて待機状態になっているかを確認する.
 まずは,作成した.serviceファイルや.timerファイルに対し,下記コマンドでsystemdにその新たな設定を認識させる.

sudo systemctl daemon-reload

 設定を認識させたら,下記コマンドにて.timerファイルを有効化し,その起動と確認を行う.

sudo systemctl enable --now security-camera-cleanup-pi.timer
systemctl status security-camera-cleanup-pi.timer

# 実行結果が,Active: active (waiting) なら成功

 実行確認そのものは,上記で完了である.
 今後の運用/保守の観点で補足する.下記コマンドを用いることで,この.timerファイルが次回実行される時刻を確認することが可能である.

systemctl list-timers security-camera-cleanup-pi.timer

6. ストレージ管理~GoogleDrive上の動画ファイル削除~

 この第6章では,クラウドストレージのストレージ超過に備えたファイル削除の機能を実装する.削除の条件を以下に列挙する.

  • ストレージ使用量が一定量を超過している:
    • Google Drive(無料枠)の15GBに対し,暫定の設定として14GB以上を条件として設定した

 クラウドストレージの容量監視においては,Google Drive全体と,本システムの動画を格納しているGoogle Drive内のSecurityCameraフォルダとの2種類が,監視対象として挙げられる.
 これに対し,この第6章での実装目的は,記録映像で無料枠15GBの容量を超過しないようにすることが目的であり.また,筆者が使用しているGoogleアカウントは,この防犯カメラシステム専用として新規作成したものであるため,Google Drive全体を監視対象とした.

 Google Driveのストレージ状況は,Rcloneを用いた下記コマンドで確認ができる(図5).単位はGiB(1,024^3)である.

rclone about MyGoogleDrive:

# 直下のScurityCameraフォルダ内限定で確認・参照したい場合は,下記コマンドを用いる
# MyGoogleDrive:SecurityCamera
図5 Google Driveのストレージ状況を確認した結果

 ここで,Google Driveの単位の表記について触れる.PCや記録媒体においては,主に,人向けの表記では1GB=1,000MBを扱い,しかしPC上の認識では1GB=1,024MBで扱っており.1,000MBの記録媒体をPCに接続すると,約0.98GBとして表示される.
 つまりは,Google Driveにおける無料枠 “15GB” の ”GB” が意味しているものが,1,000^3なのか,1,024^3かによって,GiBで表記しているRcloneと,値にズレが出かねない.
 これに対し確認したところ,ブラウザ上のGoogle Driveにおいても,使用容量が1.39GBとなっており(図6),Rcloneのコマンドを介し取得した “Uesd” の使用量と同じ値を示している(図5).このことから,Rcloneでのコマンドで取得した値に基づき,ファイル削除の条件設定やストレージ管理をしても,実際のストレージ使用量と乖離することはないと言える.

図6 ブラウザ上で確認できるGoogle Driveのストレージ使用量

 Google Drive上の各ファイルサイズや更新日時の情報を含めたファイル情報の一覧は,下記コマンドで取得できる.

rclone lsl MyGoogleDrive:SecurityCamera/

 下記コマンドで.shファイルを作成すると共に,nanoエディタで開く.

sudo nano /usr/local/bin/security-camera-cleanup-cloud.sh

 作成した.shファイルに対し,以下のコードを記述する.

#!/bin/bash

# //////////////////////////////////////////////////
# 定数
# //////////////////////////////////////////////////
CLOUD_STORAGE="MyGoogleDrive:" # 容量の監視対象ディレクトリ
CLOUD_MOVIE_DIR="MyGoogleDrive:SecurityCamera" # 削除対象の動画ファイルがあるディレクトリ
MAX_STORAGE_BYTES=$((14 * 1024 * 1024 * 1024)) # 削除を実行する容量上限

# //////////////////////////////////////////////////
# Get Google Drive usage
# //////////////////////////////////////////////////
get_used_storage() {
    # jsonを用いることで,14*1024^3が指数表記になりシェル上でエラーとなることを回避
    # awkでUsedの行を抽出
    # $2は,使用容量の数値が記載された列
    # $3は,単位が記載された列
    rclone about "$CLOUD_STORAGE" --json |
        awk -F': ' '/"used":/ {
            gsub(/,/, "", $2)
            gsub(/[^0-9]/, "", $2)
            print $2
            exit
        }'
}

# //////////////////////////////////////////////////
# Main
# //////////////////////////////////////////////////
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Google Drive storage cleanup started."

# 容量上限を下回るまで,最も古いファイルを削除し続ける
while true; do
    USED_STORAGE=$(get_used_storage) # Google Drive全体の使用容量を,関数を用いて取得

    # 文字列の長さが0だった場合,削除を行わず終了
    if [ -z "$USED_STORAGE" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Failed to get Google Drive usage."
        exit 1
    fi

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Used storage: ${USED_STORAGE} bytes."

    # 使用量が14GiB以下の場合,削除を行わず終了
    if [ "$USED_STORAGE" -le "$MAX_STORAGE_BYTES" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Storage usage is within the limit."
        break
    fi

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Storage limit exceeded. Searching for the oldest video."

   # //////////////////////////////////////////////////
    # 最も古いファイル1件のファイル名を取得
    OLDEST_FILE=$(
        rclone lsl "$CLOUD_MOVIE_DIR" |
        awk '$NF ~ /\.mp4$/ {
            print $0
        }' |
        sort -k2,2 |
        head -n 1 |
        awk '{$1=""; $2=""; $3=""; sub(/^ +/, ""); print}'
    )

    # mp4ファイルが存在しない場合   
    if [ -z "$OLDEST_FILE" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Google Drive storage usage exceeds the limit, but no MP4 files are available for deletion."
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Unable to reduce Google Drive storage usage."
        exit 1
    fi
    
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deleting oldest video: $OLDEST_FILE"

    # //////////////////////////////////////////////////
    # 最も古い動画ファイル1件の削除処理
    # //////////////////////////////////////////////////
    # ゴミ箱へ移動するだけでは,使用容量は変化しないため,完全に削除する
    if rclone deletefile --drive-use-trash=false "$CLOUD_MOVIE_DIR/$OLDEST_FILE"; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deleted: $OLDEST_FILE"
    else
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Failed to delete: $OLDEST_FILE"
        exit 1
    fi
done

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Google Drive storage cleanup finished."

 スクリプトの作成が終わったら,下記コマンドで実行権限の付与と付与状況の確認を行う.

sudo chmod +x /usr/local/bin/security-camera-cleanup-cloud.sh
ls -l /usr/local/bin/security-camera-cleanup-cloud.sh

 実行権限の付与まで完了したら,サービスに登録し自動化する前に,スクリプトの手動実行により,動作確認を行う.使用量が14GiB以下の状態で下記コマンドを実行すると, ”Storage usage is within the limit”(使用量は,上限以内)の旨が表示されるだけで,ファイル削除は行われない結果となる(図7).

/usr/local/bin/security-camera-cleanup-cloud.sh
図7 security-camera-cleanup-cloud.shに対する手動実行の結果(上限以内・ファイル削除なし)

 次に,スクリプトをサービスに登録し自動化するための.serviceファイルを作成する.下記コマンドで,.serviceファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-cleanup-cloud.service

 作成した.serviceファイルに対し,以下のコードを記述する.

[Unit]
Description=Security Camera Google Drive Storage Cleanup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=<user_name>
ExecStart=/usr/local/bin/security-camera-cleanup-cloud.sh

 作成した.serviceファイルに対し,下記コマンドでsystemdにその新たな設定を認識させる.また,.serviceファイルを今すぐ起動する.

sudo systemctl daemon-reload
sudo systemctl start security-camera-cleanup-cloud.service

 systemdを経由した手動確認を行う.その際に,スクリプトを下記のように容量上限1GiBなど適宜閾値を下げておくと,閾値を下回る/上回るときの各動作確認が容易になる.

MAX_STORAGE_BYTES=$((1 * 1024 * 1024 * 1024)) # 削除を実行する容量上限

 そして.serviceの手動実行は,下記コマンドで行う.意図した通りの挙動であるならば,実行結果は ”Active: inactive (dead)” となる(図8).これは,「失敗し停止した(dead)」のではなく,「処理を1回実行し,正常に終了した(dead)」という意味である.

sudo systemctl status security-camera-cleanup-cloud.service
# 実行結果が,Active: inactive (dead) なら成功
図8 security-camera-cleanup-cloud.serviceに対する手動実行の結果

 なお,Google Driveのゴミ箱に閾値以上のファイルがある場合,該当ディレクトリ内で使用容量を閾値以下に保っていたとしても,図9のようなエラーが生じる.

図9 使用量が閾値以上の時に出るエラー内容

 最後に,サービスを定期起動するための.timerファイルを作成する.下記コマンドで,.timerファイルを作成すると共に,nanoエディタで開く.

sudo nano /etc/systemd/system/security-camera-cleanup-cloud.timer

 作成した.timerファイルに対し,以下のコードを記述する.以下のコードにおいては,古いファイルの確認と実行を1時間ごとに行う.

[Unit]
Description=Run Security Camera Google Drive Storage Cleanup Periodically

[Timer]
OnBootSec=10min
OnUnitActiveSec=1h
Unit=security-camera-cleanup-cloud.service

[Install]
WantedBy=timers.target

 ファイル削除における動作に関しては前述の第6.2章にて,systemdを経由した実行とサービスの起動状態に関しては前述の第6.3章にて,それぞれ手動確認を行った.
 この第6.4章では,1度サービスを起動し終了したサービスが,次の1時間後の起動に向けて待機状態になっているかを確認する.

 まずは作成した.timerファイルに対し,下記コマンドでsystemdにその新たな設定を認識させる.また,.timerファイルを有効化と,今すぐ起動を行う.

sudo systemctl daemon-reload
sudo systemctl enable security-camera-cleanup-cloud.timer
sudo systemctl start security-camera-cleanup-cloud.timer

 そして下記コマンドで,起動状態の確認を行う.

sudo systemctl status security-camera-cleanup-cloud.timer

# 実行結果が,Active: active (waiting) なら成功

参考文献

  1. 防犯カメラシステムの自作④~クラウドストレージへの動画ファイルの自動アップロード~, word in the world, https://word-in-the-world.com/2026/08/12/securitycamera-04/, (参照2026-8-18).
  2. 防犯カメラシステムの自作②~Raspberry PiへのPoE HATのセットアップ~, word in the world, https://word-in-the-world.com/2026/08/02/securitycamera-02/, (参照2026-8-18).