RaspberryPi+MagicMirror2で超簡単にGoogleフォトフレームをつくる

**([2024/3/30補足] [古いWindows10タブレットを再活用！MagicMirror2を稼働してGoogleフォトフレームを作ろう！](https://qiita.com/tonasuzuki/items/ce4e075904170e7d71b7) 記事を書きました。最近、RaspberryPIよりお安い中古Windowsタブレットが出回っておりますので、MagicMirror2をインストールして遊んでみてください！ )**


# はじめに
[RaspberryPi](https://jp.rs-online.com/web/generalDisplay.html?id=raspberrypi)でフォトフレームを作るのはよくあるネタですが、えいっとPythonでコード書いて作っても、しばらくすると写真を選ぶのメンドクサイとか、ついでに天気予報を横に出したいとか、日常で使い出すことを考えると、コードメンテがタイヘンになってきます。

そこでオープンソースの[MagicMirror2](https://magicmirror.builders/)を使って、簡単に(設定は1つの設定ファイルと1つのcssファイルだけ、そして若干のコマンド入力だけです)、そしてメンテも最小(ssh経由でモジュールのアップデートと設定修正くらい)、普通に日常で使えそうなフォトフレームを作ってみました。

![photoframe.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/7e4052ef-08f5-d28b-98ad-1acca8248609.jpeg)
RaspberryPiを買ったけど机の中に入れっぱなしになっている、なんとなく高性能なフォトフレームをさりげなく家のリビングに置いて家族に自慢したい、実家に置いて子供の成長を見せたい、なーんてお父さんにオススメです。
※補足:既存のオープンソース[MagicMirror2](https://magicmirror.builders/)を使うだけなのでカンタンですが、タダでさえ説明が長いのに、もっと長くなると読むのがめんどくさくなりますので、RaspberryPiでなんとなく遊んでみて、SSH経由でコマンドがある程度入力できる方を対象にしています。

# MagicMirror2を設定する
 [MagicMirror2](https://magicmirror.builders/)は、今ハヤりのElectronを使い、表示画面をhtmlで生成してChromiumで表示する仕組みです。画面構成をcssでカスタマイズできるので楽ちんです。

 [MagicMirror2](https://magicmirror.builders/)は、もともと鏡の裏に液晶ディスプレイを仕込んでおいて、鏡を見ながら今日の予定を確認したり、天気や交通情報を表示したりする、未来っぽい仕組みを作る仕組み、だそうです。構築環境やモジュールが揃っており、組み合わせれば超簡単に便利なフォトフレームになります。
 
 ここでは、以下機能を設定してみます。

- Google Photoの指定したアルバムを表示する。
    - Google Photoのアルバム機能は地味に便利で、普通に好きな写真を選んでアルバムを作ってもいいのですが、特定の人物が写っている・特定の地域などをフィルタ設定して、勝手にアルバムを作成する機能があります。これで、例えば家の子供を設定すると、写真を選ばずに、子供だけ出てくるステキなフォトフレームができあがります。
- 時計を表示してGoogleカレンダーと連携する。
    - Googleカレンダーから直近の予定を出せば、便利かもしれません。
- 天気予報を表示する。
    - ベタですがいつも表示されており、すぐに確認できるといいですよね。
- 近くに誰かいるときだけ画面が表示される。
    - PIRセンサ(人感センサー)をつないで、近くに誰かいるときのみ、画面表示します。ずっと画面が表示されっぱなしになるのを防ぎます。

出来上がるとこんな感じに表示されるフォトフレームが完成します。(画面をデジカメで撮影したので見にくいですが…)
![screen-img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/386ef9a4-808a-6858-f54f-7514ff360299.jpeg)

## 必要な環境
- Raspberry Pi(2以上)
    - ゼイタクにElectronで動いているので、Raspberry Pi2以上でないと動かないようです。ネットワークに接続するので、無線LANのある3以上のほうが楽でしょう。
    - SDカードは、それほど容量はいらないので、8GB以上で十分かと思います。
- HDMI接続の液晶ディスプレイ
    - この記事では、解像度800x480のHDMIディスプレイを使っていますので、解像度が異なる場合はテキトウに修正してください。
    - SPI接続などHDMI以外の液晶ディスプレイだと、画面描画が遅いので不向きです。
    - このページの最後に、その昔ドコモがばらまいていたフォトフレームの液晶をHDMIディスプレイにするビンボウネタも載せましたので、ご参照ください。
- PIRセンサー(人感センサー)(必要であれば)
    - 人が近くにいるとONになるセンサーです。「HC-SR501」と呼ばれるPIRセンサーユニットは、RaspberryPiに直接接続できるので便利です。[秋月電子で400円で売っています](http://akizukidenshi.com/catalog/g/gM-09627/)。AmazonやAliexpressでも同様の部品が売っているので、テキトウに選んでください。
- SSHでログインしたりファイルを修正したりするPC
    - Raspberry Piにキーボードを繋いでもいいのですが、実際にフォトフレームとしてリビングなどに置き始めると、とてもめんどくなりますので、PCにSSHでコンソールとファイル転送できる環境があると楽です。自分は、コンソールに[Windows Terminal](https://www.microsoft.com/ja-jp/p/windows-terminal/9n0dx20hk701)、ファイル転送に[WinSCP](http://winscp.net/jp/)を使っています。

## APIキーを取得する
- 天気予報は[OpenWeather](https://openweathermap.org/)を使うので、[無償のAPIキーを取得](https://openweathermap.org/appid)しておきます。
- Google Photoをアクセスするためには、Google Photos Library APIのクライアントキーを取得する必要があります。利用する[MMM-GooglePhotos](https://github.com/hermanho/MMM-GooglePhotos)モジュールの「Get token.json」の説明を見て、`client_secret_xxxx...xxx.json`ファイルを取得して`credentials.json`にリネームしておきます。

## MagicMirror2のインストール
- Xを使うので、[Raspberry Pi OS(Raspbian)](https://www.raspberrypi.org/downloads/raspberry-pi-os/) のDesktop版をインストールしてください。 `sudo raspi-config` などでネットワークやSSHを有効の設定を行い、普通に使える状態にします。今後は、最初から設定されている pi ユーザを使って作業を行います。
- MagicMirror2のインストールは、[ドキュメント](https://docs.magicmirror.builders/getting-started/installation.html)のAutomatic Installation Scripts項目に書いてある、[MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)が簡単です。具体的には、piユーザでログインしたら、そのまま以下スクリプトを実行します。

```
bash -c "$(curl -sL https://raw.githubusercontent.com/sdetweil/MagicMirror_scripts/master/raspberry.sh)"
```
- これで、電源を入れれば勝手にMagicMirror2が起動します。

## MagicMirror2の標準モジュールを設定する

設定ファイルは、`~/MagicMirror/modules//config/config.js`だけです。存在しなければ、`cp ~/MagicMirror/config/config.js.sample ~/MagicMirror/config/config.js`でサンプルファイルをコピーして使います。

MagicMirror2はこの設定ファイルを監視しており、更新するとMagicMirror2を再起動して反映しますので、ファイル転送ソフトで手元のPCから修正すると楽です。

設定ファイルはjavascriptでconfig配列変数を設定しているだけですので、カッコやカンマなど記述に注意しながら修正します。

MagicMirror2は、モジュールを追加することで、いろいろな情報を画面に表示することができます。まずは標準モジュール設定を設定して、天気予報と予定を表示しましょう。詳しくは、[MagicMirror2 Documentation](https://docs.magicmirror.builders/modules/introduction.html)を参照してください。

- 表示を日本語に **([2021/7/13更新]2.16.0に合わせました。)**

```
    language: "ja",
    locale: "ja_JP.UTF-8",
```
- ログを残さないように **(2021/4/12に追加しました)**
  - 未記入だと `logLevel: ["INFO", "LOG", "WARN", "ERROR"], ` になるようです。ログは`~/.pm2/logs/`に残ります。このまま運用すると、ログが溜まってしまいますので、完成したらこの設定に変更しましょう。(SDカードへの書き込みを抑えられます。)

```
    logLevel: [], 
```


- complimentsモジュールを非表示にします。

```
    {
        module: "compliments",
        disabled: true,
        position: "lower_third"
    },
```
- 標準の天気予報モジュール「weather」を設定します。`"YOUR_OPENWEATHER_API_KEY"`の部分に、先程取得したOpenWeatherのAPIキーを取得します。locationIDに、表示したい場所のIDを記載します。(調べ方はconfig.js.sampleに書いてあります)
  - **([2021/7/13更新]標準の天気予報モジュール変更(weather)に伴い修正しました。)**

```
    {
        module: "weather",
        position: "top_right",
        config: {
            weatherProvider: "openweathermap",
            type: "current",
            location: "Fuji-kawaguchiko",
            locationID: "7281819", 
            updateInterval: 1200000 , 
            apiKey: "YOUR_OPENWEATHER_API_KEY"
        }
    },
    {
        module: "weather",
        position: "top_right",
        header: "Weather Forecast",
        config: {
            weatherProvider: "openweathermap",
            type: "forecast",
            location: "Fuji-kawaguchiko",
            locationID: "7281819", 
            updateInterval: 1200000 , 
            apiKey: "YOUR_OPENWEATHER_API_KEY"
        }
    },
```
- 標準モジュールの「calendar」で、iCal形式の予定を表示できます。例えばGoogleカレンダーの予定を表示したい場合は、Googleカレンダー設定画面の「マイカレンダーの設定」にある「iCal形式の非公開URL」を使います。例えば以下のように修正します。

```
		{
			module: "calendar",
			header: "予定",
			position: "top_left",
			config: {
					colored: true,
					coloredSymbolOnly: true,
					// Interval 120min
					fetchInterval: 7200000, 
					dateFormat: "YYYY MM DD" ,
					fade: false,
					timeFormat: "absolute" , //absolute or relative or dateheaders
					calendars: [
					{
						color:  "#4169e1",
						symbol: "user",
						url: "ここにGoogleカレンダーのiCal形式の非公開URLを挿入します"
					}
				]
			}
		},
```


## GooglePhotoの写真を表示するモジュールをインストールする

  - **([2023/2/17更新][MMM-GooglePhotos](https://github.com/hermanho/MMM-GooglePhotos)モジュールの更新に伴い修正しました。)**

  [MagicMirror2](https://magicmirror.builders/)は、モジュールを追加することで、いろいろな情報を画面に表示することができます。まずは、Google Photoの写真を背景に表示する[MMM-GooglePhotos](https://github.com/hermanho/MMM-GooglePhotos)モジュールを入れてみましょう。

他のモジュールも、基本的には同じ方法でインストールできます(詳細は各モジュールのドキュメントを参照してください)。piユーザでログインして、以下コマンドを入力します。

```
cd ~/MagicMirror/modules/ #←モジュールを入れるディレクトリに移動
git clone https://github.com/hermanho/MMM-GooglePhotos.git #←モジュールのURL+.gitでgithubから取得
cd MMM-GooglePhotos   #←取得したモジュールのディレクトリに移動
npm install #←インストール
```
- Google Photos Library APIのクライアントキーをコピーします。「APIキーを取得する」項目で取得した`credentials.json`を`~/MagicMirror/modules/MMM-GooglePhotos/`にコピーします。そして、実機上で(SSHなどリモートログインせずに)以下コマンドを実行します。
    - 以下コマンドを実行するとブラウザが起動し、Googleの認証ページが開きます。そのため、実機上で実行する必要があります。

```
cd ~/MagicMirror/modules/MMM-GooglePhotos
node generate_token_v2.js
```


- 設定ファイルを修正します。先程の天気予報モジュールと同じような体裁で、設定ファイル`~/MagicMirror/config/config.js`の`modules: [ … ]`の中に以下を挿入します。

```
		{
			module: "MMM-GooglePhotos",
			position: "fullscreen_below",
			config: {
				// Set your album name. 
				//like ["My wedding", "family share", "Travle to Paris"]
				albums: ["表示したいアルバムの名前"], 
				// Interval 90 seconds.
				updateInterval: 90 * 1000, 
				sort: "random", // "new", "old", "random"
				uploadAlbum: null, // Only album created by `create_uploadable_album.js`.
				condition: {
					fromDate: null, // Or "2018-03", RFC ... format available
					toDate: null, // Or "2019-12-25",
					minWidth: null, // Or 400
					maxWidth: null, // Or 8000
					minHeight: null, // Or 400
					maxHeight: null, // Or 8000
					minWHRatio: null,
					maxWHRatio: null,
					// WHRatio = Width/Height ratio ( ==1 : Squared Photo,   < 1 : Portraited Photo, > 1 : Landscaped Photo)
				},
				// These values will be used for quality of downloaded photos to show. real size to show in your MagicMirror region is recommended.
				showWidth: 800, 
                showHeight: 480,
				//timeFormat: "YYYY/MM/DD HH:mm", // Or `relative` can be used.
				timeFormat: "YYYY/MM/DD",
				autoInfoPosition: false,
			}
		},
```
  - showWidthとshowHeightは、接続するディスプレイの解像度を設定します。
  - Google Photoのアルバム名は、日本語も使えますが、UTF-8で記載しているか確認しましょう。アルバムを複数記入すると、順に表示されます。細かい設定は、[MMM-GooglePhotos](https://github.com/hermanho/MMM-GooglePhotos)モジュールの説明を参照してください。
    - Google Photoのアルバムにそれなりの数の写真が保存されていると(数千枚以上)、写真を表示しなくなります…。アルバムは最大で数百枚程度にしましょう。
    - アルバムの写真登録数に比例して、最初の写真が表示されるまでに時間がかかります。試しに数枚程度のアルバムを作成して、動作確認しましょう。

## PIRセンサーで画面を節電するモジュールをインストールする
**([2022/7/3更新]MagicMirror 2.18.0以降では [MMM-PIR-Sensor](https://github.com/paviro/MMM-PIR-Sensor) モジュールが動作しないため、 [MMM-PIR-Sensor-Lite](https://github.com/grenagit/MMM-PIR-Sensor-Lite) モジュールに変更しました。)**
PIRセンサー(HC-SR501)を使って、誰かいるときだけ画面が表示されるように設定します。センサは、例えば以下のように接続します。

|HC-SR501側|RaspberryPi側|
|---|---|
|VCC|2 (5V) |
|Out|15 (GPIO22) |
|GND|6 (GND) |

- モジュールのインストール
モジュールは、[MMM-PIR-Sensor-Lite](https://github.com/grenagit/MMM-PIR-Sensor-Lite) を使います。モジュールのインストールは、piユーザでログインして、以下コマンドを入力します。

```
cd ~/MagicMirror/modules/
git clone https://github.com/grenagit/MMM-PIR-Sensor-Lite
cd MMM-PIR-Sensor-Lite
npm install
```
- GPIOを使用するため、以下権限を追加します。(「pi」はユーザ名)

```
sudo usermod -a -G gpio pi
```

- 設定ファイル`~/MagicMirror/config/config.js`の`modules: [ … ]`の中に以下を挿入します。[MMM-PIR-Sensor-Lite](https://github.com/grenagit/MMM-PIR-Sensor-Lite) のExampleほぼそのままです。

```
		{
			module: "MMM-PIR-Sensor-Lite",
			position: "bottom_right",
			config: {
				sensorPin: 22, // GPIO pin
				deactivateDelay: 60 * 1000, 
				title: "",     
				showCountDown: false,
				showDetection: true 
			}
		},
```
- 設定について
    - `deactivateDelay`は、センサが未感知状態になった後、設定したミリ秒数が経過した後にディスプレイをOFFにします。
    - `showCountDown`を true にすると、何秒後にディスプレイをOFFにするか、カウントダウンが表示されます。まずはtrueにして、動作を確認するのが良いでしょう。


## 画面デザインをカスタマイズする
  `~/MagicMirror/css/custom.css`を新規作成し、そこにスタイルシートを記載すると、設定を上書きすることができます。`~/MagicMirror/css/main.css`やモジュール内のcssファイルを修正すると、バージョンアップ時に上書きされてしまいますので、元のcssファイルを見ながら、修正したい項目をcustom.cssにコピーして修正します。
  いくつか自分が追加した例を載せますので、custom.cssに追加してみてください。

- 画面いっぱいに表示する。(ディスプレイが低解像度の場合オススメです。)

```
body {
  margin: 0px;
  padding: 0px;
  height: 100%;
  width:  100%;
}
.region.fullscreen {
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  pointer-events: none;
}
.region.fullscreen.below {
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
}
```

- ぼかした背景を表示しない。([MMM-GooglePhotos](https://github.com/hermanho/MMM-GooglePhotos)モジュールのTipに載っています。)

```
#GPHOTO_BACK {
	display:none;
}
```

- GooglePhotoの写真を画面いっぱいに表示する。(画面と縦横比が異なる場合は、切り取って表示します。切り取りたくない場合は、`background-size:auto;`に変更します(画面と縦横比が異なる場合、黒い未表示部分ができます))。

```
#GPHOTO_CURRENT {
    background-size:cover;
    position: absolute;
    top:   0px;
    left:  0px;
    right: 0px;
    bottom:0px;
}
```

- 時計や天気予報の文字を黒色で縁取りして、写真と重なった文字を見やすくします。
  - **([2021/7/13更新]標準の天気予報モジュール変更(weather)に伴い修正しました。)**


```
.clock {
    text-shadow:
        1px  1px 2px black , -1px  1px 2px black ,
        1px -1px 2px black , -1px -1px 2px black ;
}

.weather {
    text-shadow:
        1px  1px 2px black , -1px  1px 2px black ,
        1px -1px 2px black , -1px -1px 2px black ;
}

.calendar {
    text-shadow:
        1px  1px 2px black , -1px  1px 2px black ,
        1px -1px 2px black , -1px -1px 2px black ;
    font-weight: 700;
}
```

## 表示フォントを変更する
デフォルトのフォントデザインは簡体字に寄っていて読みにくいので、フォントをインストールして変更します。個人的に好きなMigMix 1Pに変えてみます。

- フォントのインストール

```
sudo apt-get install fonts-migmix
```

- `~/MagicMirror/css/custom.css`に追加します。

```
body {
  font-family: "MigMix 1P", "Roboto Condensed", sans-serif;
}
.light {
  font-family: "MigMix 1P", "Roboto Condensed", sans-serif;
  font-weight: 300;
}
.regular {
  font-family: "MigMix 1P", "Roboto Condensed", sans-serif;
  font-weight: 400;
}
.bold {
  font-family: "MigMix 1P", "Roboto Condensed", sans-serif;
  font-weight: 700;
}
```

## アップデートする
時々画面上部に「アップデートしたよ」(実際には英語です)と出たら、アップデートしましょう。
以下アップデートを実行するときは、`pm2 stop all`コマンドを入力して、MagicMirrorを停止しておきます。(停止しておかないと、アップデートに失敗します…)

- [MagicMirror2](https://magicmirror.builders/)をアップデートする。
    - インストールで使った[MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)のアップデートスクリプトを使うのが簡単です。具体的には、piユーザでログインしたら、そのまま以下スクリプトを実行します。

```
bash -c "$(curl -sL https://raw.githubusercontent.com/sdetweil/MagicMirror_scripts/master/upgrade-script.sh)" apply
```

- モジュールをアップデートする。
    - piユーザでログインしたら、以下スクリプトを実行します。「モジュール名」の部分に、アップデートしたいモジュール名を入れます。

```
cd ~/MagicMirror/modules/「モジュール名」
git pull
npm install
```

- npmをアップデートする。

```
    New patch version of npm available! 6.14.5 → 6.14.7     
 Changelog: https://github.com/npm/cli/releases/tag/v6.14.7  
             Run npm install -g npm to update!               
```

モジュールをアップデート後などで、上記のようなメッセージが出てきた場合は、以下のようにrootでアップデートします。

```
sudo npm install -g npm
```


## Magicmirror2 を停止・再起動する
Magicmirror2は、[PM2](https://pm2.keymetrics.io/)を使ってプロセスを管理しています。モジュールのアップデートなどでMagicmirror2を再起動したい場合は、以下コマンドを入力します。

- Magicmirror2を再起動

```
pm2 restart all
```

- Magicmirror2を停止

```
pm2 stop all
```

- Magicmirror2を起動

```
pm2 start all
```

# おまけ。Docomoフォトフレーム02の液晶を再利用する。
数年前、Docomoのケータイやスマホを契約しようとすると、なぜかDocomoフォトフレーム02を契約料だけで持っていってくれ、という謎の勧誘を受けてしまい、1台持って帰って押し入れに入れっぱなしにしておりました。これを今回のディスプレイに再利用しました。

このDocomoフォトフレーム02は、9インチ800x480の解像度を持つ「AT090TN12」が入っています。恐ろしいことにAliexpressには、この液晶を[HDMI接続するためのボード](https://ja.aliexpress.com/item/4000244379190.html)が売っています。これを買って、液晶を取り出して接続すると、お安くフォトフレームが完成します。

- 中国から届いたボード
![HDMI-board.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/fe2ada42-a466-9abd-0fdd-7c92364295d1.jpeg)

- 試しにHDMI接続してみました
![HDMI-out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679798/214ec290-efa2-aee0-a052-434cadf7130c.jpeg)

- ちなみに、このDocomoフォトフレーム02は、HUAWEI(ファーウェイ)製で、中のマザーボードの出来がとても良いです…。シールドやプリント基板の構成に無駄がなく、モデムにQualcomm製チップセット、SOCは自社(HiSilicon)製と、部品もゼイタクで、HUAWEIなんだかんだ言って開発力高すぎです。ただ、なぜか中のソフトは、とても使い勝手が悪すぎなのがアンバランスで面白いです。