AmazonEcho (Alexa) と RaspberryPi を連携して声だけでPS4を操作する

この記事は [ギフティ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/giftee) 22日目のエントリーです。

## はじめに

最近自室のスマート化にハマってます。
スマートリモコンと Alexa を連携してエアコンや照明を声だけで操作できるようにしたり、Slackへの通知を行ったり…。
今回は簡単な設定でできることから少し踏み込んで、かねてより使ってみたかった `RaspberryPi （以下、ラズパイ）` を使ってさらなるスマート化にチャレンジしてみたと思います。

## 要件
私の自宅ではテレビの構成が特殊で、

```
nasne(torne) -> PS4 -> PCモニター
```

といった感じになっています。
この構成だとテレビをつけようとすると、`モニターの電源ON` `PS4の電源ON` `トルネを起動` の3ステップを踏む必要があるため非常に面倒です。
そこで今回はラズパイとスマートスピーカー（`AmazonEcoh`）を使って「Alexa, テレビを点けて」と発話すると

1. ラズパイへ通信
1. `PS4` 電源ON
1. `torne` 起動

といった流れでテレビを点けることができるように頑張ってみたいと思います。

## 設計
実はPS4はWiFi経由でのリモートからの操作に標準で対応しており、スマホアプリ等から簡単にアクセスすることができます。
しかし、現時点では Alexa からのアクセスには対応していないため、Alexa と PS4 の間に何かしら処理をかませてあげる必要があります。
「何かしらの処理」について今回は以下のような構成を考えています。

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/95a4d65d-6d60-cf59-ad94-36b5ea9af7ba.png)

他にも [IFTTT](https://ifttt.com/) から [Firebase](https://firebase.google.com/) function をフックしてラズパイを操作するアプローチもあるのですが、その場合「Alexa、〇〇をトリガー」と話しかければならず、ダサさが勝ったので `Node-Red` を使用しました。

## 用意するもの
今回はこちらの機器を使用します。

- [Amazon Echo 第３世代](https://www.amazon.co.jp/dp/B07P86XC4P/ref=cm_sw_r_tw_dp_U_x_luX.Db88ATRWE)
- [Raspberry Pi3 B+ コンプリートスターターキット](https://www.amazon.co.jp/gp/product/B07CRY1JC1/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1)
- PS4 Pro
- nasne（PS4用TVチューナー）

## 実装
### Node-Red Alexa Home Skill Bridge の設定
![スクリーンショット 2019-12-22 16.30.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/4a1bf616-e9f4-084d-c25d-12348d56a099.png)

まず Alexa とラズパイの連携を可能にする [Node-RED Alexa Home Skill Bridge](https://alexa-node-red.bm.hardill.me.uk/) のアカウント作成からデバイス作成までを行います。

【公式ドキュメント】https://alexa-node-red.bm.hardill.me.uk/docs

1. TOP画面の`Register`からアカウントを登録
2. `Device`タブの`Add Device`を押下
<img width="1167" alt="スクリーンショット 2019-12-22 16.34.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/50366685-4c36-b752-b972-4e72194b954d.png">
3. `Add New Device` ポップアップの`Name`, `Actions`を設定する  
  - `Name` - Alexaに話しかける際にトリガーとなる言葉。「Alexa、PS４を〇〇して」  
  - `On, Off` - Deviceを操作するアクション。「Alexa、〇〇を点けて」「Alexa、〇〇を消して」など
<img width="1171" alt="スクリーンショット 2019-12-22 16.36.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/f26cc130-0764-a1e0-28fe-570c7cdb8147.png">

### Amazon Echo の設定
ここまで設定できたら登録したデバイスがAlexaで認識できるようになります。

1. Alexaアプリでスキル[node-red](https://www.amazon.co.jp/Ben-Hardill-Node-RED/dp/B01N0D97FZ)を有効にする
2. 有効後に `node-red` アカウントでのログインを求められるので、「Node-Red Alexa Home Skill Bridge の設定」で登録したアカウントでログインする
3. Alexa「デバイスの検出」で先程 `Node-Red Alexa Home Skill Bridge` で登録したDeviceが検出できるので登録しておく
![alexa_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/948b3585-ac07-dfb4-6621-a05a86ccb07e.png)

※この時点ではデバイスの登録だけで操作はできません。

### ラズパイの設定

![IMG_20191221_154313.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/9022ccc6-f639-9f39-ece2-280e4204ef75.jpeg)
今回は [Raspberry Pi3 B+ コンプリートスターターキット](https://www.amazon.co.jp/gp/product/B07CRY1JC1/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1) を購入しました。写真は購入したラズパイちゃん。
ラズパイは最初に `Raspbian` というラズパイ専用OSをSDカードに突っ込んでインストールする必要があるのですが、スターターキットだとプリインストールされたSDカードも付属するので初期設定が楽でおすすめです（おうちに大量のSDカードがある人はそれ使ったほうがいいかも）。

※ RaspberryPi の初期設定や `Raspbian`（OS）の導入方法は割愛します。

ラズパイが起動したらコンソールを開き、 `Node-RED` をインストールしていきます。
【公式ドキュメント】https://nodered.jp/docs/getting-started/raspberrypi

##### Node-RED の導入
Node-REDは公式のインストール用スクリプトをダウンロードして実行します。
※ [スクリプトはこちら](https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

```console
$ bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```

スクリプトを実行すると進行状況が表示されます。

```console
Running Node-RED install for user pi at /home/pi on raspbian


This can take 20-30 minutes on the slower Pi versions - please wait.

  Stop Node-RED                       ✔
  Remove old version of Node-RED      ✔
  Remove old version of Node.js       -
  Leave existing Node.js              -   Node v12.14.0   Npm 6.13.4
  Clean npm cache                     -
  Install Node-RED core               
  Move global nodes to local          
  Install extra Pi nodes              
  Npm rebuild existing nodes          
  Add shortcut commands               
  Update systemd script               
                                      

Any errors will be logged to   /var/log/nodered-install.log
```
実はラズパイには `Node-RED` と `Node.js` が標準でインストールされているのですがこのスクリプトを実行して最新のバージョンをインストールしています。
※ `npm` はインストールされていないので本スクリプトで初めてインストールされます。

### ps4-waker の導入
`ps4-waker` とはネットワーク経由でコンソール上からPS4を操作できる npm パッケージです。
こちらのインストールは `npm` を使用します。（`Node-RED` 導入時に `npm` がインストールされているのでここでは `npm` 自体をインストールする必要はありません）

```console
$ npm install -g ps4-waker
```

ダウンロードできたら早速実行します。

```console
$ ps4-waker
No credentials; Use Playstation App and try to connect to PS4-Waker
```

クレデンシャルがねぇよ！！と怒られるので、スマホアプリの「PS4 Second Screen」（[iOS](https://apps.apple.com/jp/app/ps4-second-screen/id1201372796) , [Android](https://play.google.com/store/apps/details?id=com.playstation.mobile2ndscreen)） を使用してクレデンシャル情報を取得します。

![secound_screen.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/9233f568-37f0-f2a7-1a07-05e9c74f514d.jpeg)

「PS4-Waker」をタップするとコンソール側に以下のクレデンシャル情報が表示され、PS4から出力されたPINコードを打ち込むよう要求されます。

```console
Got credentials!  { 'client-type': 'i',
  'auth-type': 'C',
  'user-credential': 'credentials' }
Go to 'Settings -> Mobile App Connection Settings -> Add Device' on your PS4 to obtain the PIN code
Pin code> xxxxxxx
```

PS4の `設定` -> `モバイルアプリ接続設定` -> `機器を登録する` で表示されたPINコードを入力。
![IMG_20191222_175133.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/f384e22e-d7da-60f0-06e9-90cbae9c51e9.jpeg)

```console
Pin code> #[your ps4 pin code]
Logged into device! Future uses should succeed
```

上記メッセージが表示されれば `PS4-Waker` でPS4を操作する準備が整った証拠です。
実際にPS4をスタンバイモードにしてラズパイ側で操作してみましょう。

```console
$ ps4-waker start
```

`standby` でスタンバイモードへ

```console
$ ps4-waker standby
```

##### ps4-waker でできること

`ps4-waker` では起動、スタンバイモード以外に色々なことが実行できます。

|コマンド|実行内容|備考|
|:--|:--|:--|
|start|スタンバイモードから起動|
|start [titleID]|特定のアプリを起動|PS Store のURL等から取得|
|remote [key-name...]|[key-name]に対応した操作を行う|`up`（上キー）、`ps`（PSボタン）など|
|search|起動しているアプリの情報を表示する|
|standby|スタンバイモードへ|

上記以外にも様々なことができますが、詳しくは [公式のREADME](https://www.npmjs.com/package/ps4-waker) を参照ください。

今回はスタンバイ状態からトルネを起動するため、トルネの `titleID` を `start` コマンドに付与してあげます。

```console
$ ps4-waker start CUSA00442
```

`titleID` は [PS Store](https://store.playstation.com/ja-jp/home/games) のURL等から取得できます。

```
https://store.playstation.com/ja-jp/product/JA0003-CUSA00442_00-TORNEPS400000000
```

これでスタンバイ状態からトルネを起動させる準備が整いました。

#### Node-RED の実行
次に `Node-RED` を起動させておきます。
ラズパイの少ないメモリを素早く開放するため、 `node-red-pi` コマンドを利用し、かつ `--max-old-space-size` として未使用メモリ開放の最大サイズを引数として渡してあげます。

```console
$ node-red-pi --max-old-space-size=256
```

これでラズパイ側の設定は完了です。

### Node-RED エディタで処理フローを作成する

さて、機器側の設定が完了したので最後に `Node-RED` で【Alexaで「トルネをつけて」と発話したらPS4を起動してトルネを実行する】という処理フローを作成していきます。

Node-REDはGUIで処理フローを作成できます。
エディタはラズパイのブラウザで `Node-RED` 起動時に表示されているポートにアクセスすると開くことができます。

```console
Server now running at http://127.0.0.1:1880/
```

ラズパイ側ではなく別途用意してあるPCから操作したい場合はラズパイのIPを指定してアクセスできます。

```console
http://<ip-address>:1880
```

ラズパイ側のIPアドレスを調べる際は `hostname -I` を実行しましょう。

```console
$ hostname -I
192.168.X.XX XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX

http://192.168.X.XX:1880
```

アクセスすると下記エディターが表示されます。
<img width="1994" alt="スクリーンショット 2019-12-22 18.21.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/156a0a54-bde3-980f-d0e1-05771d5023e0.png">
今回は以下のようなフローを作成しました。
#### PS4起動フロー
<img width="768" alt="スクリーンショット 2019-12-22 18.26.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/473f87cb-2d3b-aa06-89c5-e4360e0e5d8e.png">
1. 「Alexa、PS4をつけて」または「Alexa、PS4を消して」と発話する
2. 「つけて」「消して」の発話の違いによって `ps4-waker` で実行するコマンドを変更する
3. 変更されたコマンドを付与して `ps4-waker` を実行する

#### トルネ起動フロー
<img width="811" alt="スクリーンショット 2019-12-22 18.22.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/980558f0-8e61-31c1-3ef1-e6ab82ee8e79.png">
1. 「Alexa、トルネをつけて」または「Alexa、トルネを消して」と発話する
2. 「つけて」「消して」の発話の違いによって `ps4-waker` で実行するコマンドを変更する
3. 「つけて」の場合はトルネの `titleID` である `CUSA00442` も付与する
4. 変更されたコマンドを付与して `ps4-waker` を実行する

2つの違いは入力のデバイス名の違いとトルネの場合に `titleID` を付与するかどうかだけです。
トルネのフローを応用すればプレイしたいゲームを即座に起動させることもできます。

#### 各チャネルの詳細
せっかくなので各ノードの設定を説明していきます。

##### Alexa Home ノード　<img width="157" alt="スクリーンショット 2019-12-22 18.34.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/497fcdb2-2a31-d1fa-5114-1a6d51687c7a.png">
`Node-Red Alexa Home Skill Bridge` で登録、 `Alexa アプリ` でデバイス登録した機器を取り扱うノードです。
「Alexa、〇〇（登録機器名）を〇〇（登録したアクション名）。」と発話すると処理がスタートします。

こちらのノードを取り扱うには以下の初期設定が必要です。

- `Node-RED` 本体に `node-red-contrib-alexa-home-skill` ノードを追加
- ノードの設定にて `Node-Red Alexa Home Skill Bridge` のアカウントを設定
- Alexaに登録してあるデバイスの一覧を取得する

まず、右上の `メニュー（≡）` -> `設定` からユーザー設定を開き、 `パレット` タブ ->　`ノードを追加` タブを選択。
`node-red-contrib-alexa-home-skill` を追加します。
<img width="710" alt="スクリーンショット 2019-12-22 18.38.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/a67fae80-7f2b-f8b4-4f2b-6426ae5f0619.png">

メニューを閉じ、左のノード一覧から `alexa home` をドラッグしてエディタ上に置きます。
置かれたノードをダブルクリックして設定画面を開きます。
<img width="513" alt="スクリーンショット 2019-12-22 18.34.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/82aa7c2f-e04e-9e11-3a59-717702ca83e2.png">
👆Accountのえんぴつマークを押下してアカウント情報を設定する画面に遷移。
<img width="514" alt="スクリーンショット 2019-12-22 18.34.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/df065f9b-7a97-3295-6b21-ddf41df1cfb7.png">
👆`Node-Red Alexa Home Skill Bridge` で登録したユーザの `Username` , `Password` を入力して「追加」ボタンを押下する。
<img width="517" alt="スクリーンショット 2019-12-22 18.34.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/b6bee2ad-dc46-837d-733d-24e8f11e7e4c.png">
👆`Device` のリフレッシュマークを押下してデバイス一覧を取得する。

上記設定を行い、デバイスを選択すると無事発話したデバイスのフローが作成できるようになります。

##### switch ノード <img width="126" alt="スクリーンショット 2019-12-22 18.47.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/19ef7da1-dc9e-3225-6b2c-c7fa3bc1791d.png">
直前のノードから渡されたパラメータによって処理を分岐させます。
今回はAlexaに発話した際のアクションが入る `msg.command` の文字列によって分岐させています。
簡単に「ON、OFF」のみのアクションなので `TurnOnRequest` , `TurnOffRequest` のみの分岐。
<img width="509" alt="スクリーンショット 2019-12-22 18.49.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/4d93d777-f75a-4cfc-d7e2-89c29dbbd093.png">

※ `Node-Red Alexa Home Skill Bridge` による `msg.command` の文字列は [公式ドキュメント](https://alexa-node-red.bm.hardill.me.uk/docs) を参照。

##### change ノード <img width="120" alt="スクリーンショット 2019-12-22 18.55.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/5499e6e3-1a1f-734b-1eaa-3694cb687c7f.png">　<img width="136" alt="スクリーンショット 2019-12-22 18.55.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/919cb531-c6b4-8f8b-035c-958c45ccfdf3.png">
渡された値に代入したり、削除したり、置換したりすることができるノードです。
今回は `switch` ノードの分岐から処理が走るので、 `msg.payload` に `ps4-waker` のコマンドを代入しています。
`msg.payload` に代入した値は次のノードにより以下のように実行されます。

```console
$ ps4-waker <msg.payload>
```
<img width="504" alt="スクリーンショット 2019-12-22 18.58.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/6f4d3bac-1ed2-16d2-f33a-8240cdbafe5b.png">
トルネを起動する場合などは `start` の後に`titleID`を記述してあげましょう。

```console
$ ps4-waker start CUSA00442
```

##### exec ノード <img width="152" alt="スクリーンショット 2019-12-22 19.01.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/631563d5-827a-19ba-767d-9df299e10c51.png">
シェルのコマンドを実行します。
引数に標準で `msg.payload` を与えることができるので、 `change` ノードで代入した値をそのままコマンドとして使えます。
<img width="505" alt="スクリーンショット 2019-12-22 19.02.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/e2858f53-998e-ef1c-ac4a-eed1afab5947.png">


---

以上で `Node-RED` の処理フローの作成が完了しました。
エディター右上の「デプロイ」を押してラズパイにデプロイしましょう！
<img width="1994" alt="スクリーンショット 2019-12-22 19.03.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184697/0a93e79a-fcd2-9bd2-5bdf-58d48a35c9a3.png">

### Node-RED の自動起動設定
いちいちラズパイ起動後にコンソールで `Node-RED` を起動するのは面倒なので自動起動の設定をしておきます。

```console
sudo systemctl enable nodered.service
```
これでラズパイの電源を入れると自動で `Node-RED` が起動するようになりました。

## デモ
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ついでにデスストも立ち上がるようにしてみました。アプリ→アプリのスイッチングにも対応してます。 <a href="https://t.co/p0w0drXcUd">pic.twitter.com/p0w0drXcUd</a></p>&mdash; ごはん (@okomeshino) <a href="https://twitter.com/okomeshino/status/1208703631890870272?ref_src=twsrc%5Etfw">December 22, 2019</a></blockquote>

:tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: 

## さいごに

今回特に難しい技術は利用しておらず、比較的簡単に `Alexa` , `Raspberry Pi` の連携ができました :tada: 
お部屋のスマート化はモチベーションに繋がりやすいので是非挑戦してみたください。

ただ、今回の `Node-RED` を使用するやり方だだといちいちデバイスを１から登録する必要があるため、トルネ以外のアプリケーションも立ち上げようとした際にとても面倒です。
このあたりは Alexa のスキルを作成したり `Firebase` などを利用して動的にコマンドを変えることもできそうなので、試行錯誤して再チャレンジしてみたいと思います。

## 参考
- [Alexaでスマートホーム化した話](https://qiita.com/SugiC/items/9088f79b6aa11437b0ef)
- [PS4 を Google Home から音声で操作してみた](https://qiita.com/eup42/items/98c2c3df55211d5b0202)
- [わがやのスマートホーム化](https://qiita.com/negiboudu/items/0045ee38904eea59833a)

偉大なる先人たちの知恵に感謝 :pray: