ハードウェア

ラズパイフォトフレーム v1.5.0 Google Drive/S3/ローカルフォルダ対応

この記事は約8分で読めます。

以前作成した、Raspberry PiとImmichで動くデジタルフォトフレームをアップデートしました✨
Immichだけでなく、Google Drive、S3互換ストレージ、ローカルフォルダからも写真を取得できるようになりました。

以前のポストはこちらです。

ラズパイZero 2 WでImmich対応の人感センサー付きデジタルフォトフレームを安価に作ったはずだった件
セルフホストしているImmichの写真をスライドショー表示するデジタルフォトフレームを、Raspberry Pi Zero 2 Wで自作しました。コンテナイメージ化してDockerで手軽に動かせるのでサクッと作れます。
GitHub - seizu-dev/raspi-photo-frame
Contribute to seizu-dev/raspi-photo-frame development by creating an account on GitHub.

v1.5.0で、当初想定していた機能を概ね網羅できたので、v1.0.0からの変更点をまとめておきます。
今回の主な変更点は以下のとおりです。

  1. 時間帯による省電力モードの切り替え
  2. 写真の取得元にGoogle Drive・ローカルフォルダ・S3互換ストレージを追加
  3. 安定性・表示速度の改善
  4. 大きい画面での表示調整
  5. おまけ:Linuxデスクトップ / WSLで表示するcompose
スポンサーリンク

1. 時間帯による省電力モードの切り替え

デジタルサイネージのような使い方も想定して、常時点灯にする時間帯を指定できるようにしました。

時間帯は1日1枠で、30分単位で指定できます。22:00〜翌6:00のような日を跨ぐ指定もOKです。
時間帯の外では、以下の2つから動作を選べます。

設定値 時間帯外の動作
normal これまでどおり、無操作で消灯して人感センサーかタッチで復帰
force_off 強制消灯。人感センサーでは復帰せず、タッチしたときだけ一時的に点灯

force_off は、夜間に人が通るたびに点灯するのを避けたい場合に便利です。
設定は config/settings.json の power_schedule_* か、画面の設定メニューから変更できます。
既定では無効になっているので、アップデートしても挙動は変わりません。

2. 写真の取得元を追加

v1.0.0ではImmichだけが写真の取得元でしたが、取得元の処理を抽象化して、以下の3つを追加しました。

  • Google Drive の共有フォルダ
  • デバイス上のローカルフォルダ
  • S3互換ストレージ

.env の PF_PHOTO_PROVIDER で、どれか1つを選んで使います。

追加した3つの取得元は、アルバムの扱いを共通にしています。

  • ルート直下の各サブフォルダを1つのアルバムとして扱う
  • ルート直下に直接置かれた写真は「未分類」という仮想アルバムにまとめる
  • 孫フォルダ以下は見ない
Immich以外の取得元には「お気に入り」に相当するものが無いので、使えるのはアルバム選択とデイリーピックアップだけです。

Google Drive

前回の記事では、Google Photosについて「今後は Picker API を使って対応する方法を模索したい」と書いていましたが、最終的には Google Drive API を使う形にしました。

Picker APIをやめた理由

Picker APIでは、表示したい写真を利用者がGoogleフォトのアプリで選ぶ必要があります。
つまり、写真を追加するたびに選択しなおさないといけないんですね。これが割と手間でした。

さらに、この方式だとアルバム単位の分類ができず、デイリーピックアップのような日替わり表示も使えません。
決まった写真を繰り返し表示するデジタルサイネージのような用途なら問題ないのですが、それ以外では使いづらく、限定的にしか使えなさそうでした。

それならば、フォルダに写真を入れるだけで反映されて、フォルダ単位でアルバムに分けられるGoogle Driveの方が柔軟性が高いと考えて、こちらに変更しました。

仕組み

個人のGoogleアカウントではなく、サービスアカウントで認証します。
サービスアカウントは Google Cloud(GCP) のコンソールで作成する必要があるので、プロジェクトを用意して、Google Drive APIを有効化しておいてください。
表示したいフォルダをサービスアカウントのメールアドレスに「閲覧者」権限で共有して、フォルダIDを .env に書けば準備完了です。

PF_PHOTO_PROVIDER=gdrive
GDRIVE_ROOT_FOLDER_ID=<フォルダID>

写真は、Driveが生成する縮小画像(thumbnailLink)を表示サイズで要求して取得しています。
これのおかげで、Zero 2 Wでは原本をデコードできない HEIC / HEIF も表示できます。
実機で測ったところ、48MPのHEICはデコードのピークが約602MB、20MPでも約211MBで、512MBのZero 2 Wでは割と絶望的でした。

当初は thumbnailLink をそのまま使っていたのですが、線の多いイラストで劣化とノイズが目立ちました。
表示サイズの2倍で要求して手元で縮小し、キャッシュを4:4:4で保存するようにして、PSNRで28.3dB → 33.9dBまで改善しています。

ローカルフォルダ

Immichのような写真サーバーが無くても、ホスト上のフォルダをそのまま取得元にできます。
コンテナには読み取り専用でマウントするので、写真を書き換えたり消したりすることはありません。

PF_PHOTO_PROVIDER=local
PF_LOCAL_PHOTO_DIR=/home/you/photos

写真の出し入れは、scp や rsync、Samba共有などでホスト側から行います。

また、ホスト側でNASの共有フォルダをネットワーク経由でマウントしておけば、NAS上の写真をそのまま表示することもできます。
NASで写真を管理している場合は、Immichを立てなくても手軽に連携できるのが利点ですね。
追加・削除した写真は、次に写真リストを読み込むとき(起動時、アルバム変更時、日付が変わったとき)に反映されます。

原本をデバイス上でデコードするので、HEIC / HEIFは非対応です。
また、メモリの都合で、12MPを超えるPNGと8MPを超えるWebPも表示されません。

S3互換ストレージ

バケット(またはその中のプレフィックス)直下のフォルダをアルバムとして読み込みます。
依存を増やしたくなかったので、SigV4の署名は自前で実装して、requests だけで動くようにしています。
動作はGoogle Cloud StorageのXML APIで確認しました。

PF_PHOTO_PROVIDER=s3
S3_ENDPOINT_URL=<エンドポイントのURL>
S3_BUCKET=<バケット名>
S3_PREFIX=photos/
S3_ACCESS_KEY_ID=<アクセスキー>
S3_SECRET_ACCESS_KEY=<シークレットキー>

対応形式はローカルフォルダと同じくJPEG / PNG / WebPで、URLはpath-styleのみ対応です。

3. 安定性・表示速度の改善

取得元を増やしたことで、Immichでは表に出なかった問題がいくつか見つかったので、合わせて直しています。

  • 先読みの失敗でスライドショーが止まる問題(v1.3.0)
    表示できない写真が1枚あると、同じ写真のまま止まっていました。失敗した写真は飛ばすようにしました。
  • WebPのメモリ使用量(v1.3.1)
    Pillowが静止画のWebPでも多くのメモリを使っていたので(8MPで約121MB増)、静止画は軽い経路でデコードするようにしました。
  • 自動送りが長時間止まる問題(v1.3.2)
    キャッシュの容量チェックが先読みを止めていて、実機で74〜92秒止まることがありました。チェックをバックグラウンドで行うようにしました。
  • 先読みの高速化(v1.4.0)
    描画ループが先読みのダウンロードを邪魔していました。描画の直前に4msだけ譲るようにしたところ、1枚あたり約2.8秒 → 約0.5〜0.6秒になりました。
  • カウントダウンゲージの挙動(v1.4.1)
    次の写真が間に合わないとき、ゲージが0%に戻ってループしていました。95%で止めて待ち、読み込めたらすぐ送るようにしました。

4. 大きい画面での表示調整

これまではRaspberry Pi向けの1024×600程度の画面を前提にしていたので、3840×2160のような写真より大きい画面では、写真が画面より小さく表示されていました。

v1.5.0では、既定の表示方法(photo_fit が contain)でも、写真が画面より小さいときは比率を保ったまま画面に合わせて拡大するようにしました。
拡大はキャッシュを作るときに行うので、表示時の処理は増えていません。
画面より大きい写真はこれまでどおり縮小するだけなので、小さい画面での表示は変わりません。

Immichでは、普段は軽いプレビュー画像を取得していますが、プレビューでは画面に足りないときだけ原寸の画像を取り直すようにしています。
原寸の方が画素数が多くない場合や、画素数の上限を超える場合などは、プレビューをそのまま使います。

5. おまけ:Linuxデスクトップ / WSLで表示するcompose

おまけとして、コンテナからLinuxデスクトップ(X11)やWSL(WSLg)の画面へ直接表示するcomposeファイルを追加しました。
本番用の docker-compose.yml とは独立しているので、Raspberry Pi側の構成には影響しません。

ファイル 表示先
docker-compose.desktop.yml LinuxデスクトップのX11セッション
docker-compose.wsl.yml Windows(WSL2 + WSLg、Docker Desktop)
# Linuxデスクトップ(事前にXの接続を許可しておく)
xhost +SI:localuser:$(id -un)
docker compose -f docker-compose.desktop.yml up --build

# WSL
docker compose -f docker-compose.wsl.yml up --build
WSL版は、WSLgのソケットなどのマウント元にDocker DesktopのVMから見たパスを既定にしています。
環境に合わない場合は、.env の PF_WSLG_DIR / PF_WSL_LIB_DIR / PF_WORKSPACE_DIR で上書きしてください。

特に利用ケースを考えて作ったものではないのですが、即席でPCをサイネージ代わりにしたい時に使えると思います。

タッチに対応したノートPCで表示している例

今後の課題

ローカルフォルダとS3互換ストレージは、原本をデバイス上でデコードしているので、以下の写真が表示できません。

  • HEIC / HEIF
  • 画素数や容量の大きな画像

iPhoneで撮った写真をそのまま置けないのは、割と不便なところです。
今のところ策が見つかっていませんが、Zero 2 Wのメモリでも扱える方法を探して、対応していきたいと思います。

おわりに

Immichをセルフホストしていなくても、Google Driveやローカルフォルダで手軽に使えるようになったので、だいぶ間口が広がったと思います。
詳しくはリポジトリのREADMEを参照してください。

以上!

コメント

タイトルとURLをコピーしました