PS4 を Google Home から音声で操作してみた

# はじめに

数ヶ月前に [Google Home Mini](https://store.google.com/product/google_home_mini) を購入しました。また、時を同じくして念願の PS4 を購入し、モンハン と [Nier: Automata](http://www.jp.square-enix.com/nierautomata/) にドハマリしております（Nier本当に面白い...）。

さて、僕は毎日PS4 を使ってテレビを見ているのですが、

1. PS4 電源つける
2. ユーザー選ぶ
3. トルネ（PS4のTVアプリ）起動

の3つの動作を取るのが非常にめんどくさい...と感じていました。その解決策として、PS4 の Remote Play 機能の応用とGoogle Home を使って、音声1発でトルネを起動する方法を構築したので紹介します。


# 準備したもの
- [Raspberry Pi3 Model B](http://amzn.asia/d/fgrmmt4)
- [Google Home Mini](https://store.google.com/product/google_home_mini)
- [Play Station 4](https://www.jp.playstation.com/ps4/)
- 設定用のスマホ（僕は iPhone 6 を使いましたが、AndroidでもOK）

4つのデバイスは同一ネットワークに接続してください（Google Home は同じじゃなくてもOK）。

Raspberry Pi のセットアップについては本記事では省略します。以下の記事などを参考にしてみてください。自分の記事ですみません...笑

[Raspberry Pi をディスプレイ/キーボードなしで初期設定する - Qiita](https://qiita.com/eup42/items/58bf6c336d325eba3ee2)

また、スマホには事前に "PS4 Second Screen" というアプリを入れておいてください。

- [「PS4 Second Screen」をApp Storeで](https://itunes.apple.com/jp/app/ps4-second-screen/id1201372796?mt=8)
- [PS4 Second Screen - Google Play のアプリ](https://play.google.com/store/apps/details?id=com.playstation.mobile2ndscreen&hl=ja)




# Raspberry Pi から PS4 を操作する
まずは、Raspberry Pi から PS4 を操作できるようにしていきます。

順番としては、まずコンソールから操作できるようにし、その後、Google Home から連携しやすいようにnode.js から制御できるようにしていきます。

![Untitled Diagram(1).png](https://qiita-image-store.s3.amazonaws.com/0/96666/98dc2d95-2def-f257-ec36-9a3ac3214f6f.png)

## コンソールから PS4 を操作する

今回は [GitHub - dhleong/ps4-waker](https://github.com/dhleong/ps4-waker) を利用させてもらいます。

まずは、`ps4-waker` をインストールします。READMEに書いてあるとおりに、以下のコマンドをラズパイで実行します。

```bash
sudo npm install ps4-waker -g
```
インストール終了後、以下のコマンドを実行してみます。

```bash
sudo ps4-waker
```
すると、以下のような表示になりますので、スマホ側の`PS4 Second Screen`の操作に移ります。

```bash
No credentials; Use the PS4 Second Screen App and try to connect to PS4-Waker
```

スマホ側で`PS4 Second Screen` を起動すると、以下の画面のようになります。リスト上の`PS4-Waker` をタップします。

<img width="30%" alt="IMG_2382.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/96666/8d46accb-1208-1c41-f2b9-40aaf69b69c7.png">

すると、コンソールには以下の内容が表示されますので、次に PS4 の操作に移ります。

```bash
Got credentials!  { 'client-type': 'i',
  'auth-type': 'C',
  'user-credential': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' }
Go to 'Settings -> PlayStation(R) App Connection Settings -> Add Device' on your PS4 to obtain the PIN code.
Pin code>
```
PS4 を起動し、`設定 > モバイルアプリ接続設定 > 機器を登録する` と進むと、以下のような画面になります。画面に表示されているPINコードをラズパイのコンソールに打ち込みます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/96666/e5939141-074a-0d2c-055a-25acfcbb023c.jpeg" width=50%>

PINコードをコンソールに打ち込むと、以下のようになります。

```bash
Pin code> 95783208
Logged into device! Future uses should succeed
```

これで、`ps4-waker` の設定は終了です。例えば、以下のコマンドをPS4がスタンバイ状態のときに実行するとPS4が起動するはずです。

```bash
sudo ps4-waker
```

なお、ラズパイからPS4への接続情報は `/root/.ps4-wake.credentials.json` に保存されています。

## Node.js から PS4 を操作する

次に、ラズパイの Node.js から PS4 を操作してみます。Node.js を使用するのは、後ほどGoogle Home との連携をする際に都合が良いからです。ここでも、`ps4-waker`を使用します。

まずは、適当なフォルダを作成し、`ps4-waker`をインストールします。また、先ほど作成したPS4への設定ファイルもユーザーのHomeディレクトリに移動します。

```bash
mkdir MySmartHome
cd MySmartHome
nmp install ps4-waker

sudo mv /root/.ps4-wake.credentials.json $HOME
```

なお、`ps4-waker`を再度インストールしたのは、Node.js から Global にインストールした `ps4-waker` モジュールを使用する方法が分からなかったためです…。また、`ps4-waker` はデフォルトでユーザーのHomeディレクトリに接続情報を探しに行くので、`$HOME` に移動しています。

では、Node.js で簡単なプログラムを書いていきます。ここでは、`PS4 電源オン -> トルネ起動` のシナリオを README を参考に書いていきます。

```javascript:index.js
const {Device} = require("ps4-waker");
var ps4 = new Device();

ps4.turnOn().then(() => ps4.startTitle("CUSA00442").then(() => ps4.close()))
```

PS4 の電源を切った状態で、以下のコマンドを実行すると PS4 が起動しトルネが立ち上がります。

```bash
node index.js
```

# Google Home への発話内容を Raspberry Pi で受け取る

次に、Google Home へ発話した内容をラズパイで受け取る仕組みを作っていきます。

![Untitled Diagram(3).png](https://qiita-image-store.s3.amazonaws.com/0/96666/b1e1f934-69af-d1d1-469d-9f2e94a320b9.png)


ここでは、

- [IFTTT](https://ifttt.com/)
- [Beebotte](https://beebotte.com)

の2つのサービスを利用していきます。

なお、Google Home と ラズパイの連携では [Firebase](https://firebase.google.com/) や [Action on Google](https://developers.google.com/actions/) などを使う方法もよく取り上げられます。

今回もそれらのサービスを検討したのですが、**Firebase** に関しては非推奨の方法でしかセキュリティが担保できそうになく、**Action on Google** に関してはテストバージョンとしての利用しかできず、一定期間でアプリが無効になってしまうようなので、今回は不採用ということにしました。以下参考。


- [GoogleHomeとiftttとDialogflowとfirebaseとLINEBOTとラズパイを使って子供と音声によるLINE交換をしてみる（後編） - Qiita](https://qiita.com/nk-tamago/items/31ee5b70c6003fb97ee4#firebase%E3%81%AErest%E3%81%AB%E3%82%88%E3%82%8B%E8%AA%8D%E8%A8%BC)
- [Actions On Googleなんちゃって中級編 - Qiita](https://qiita.com/odetarou/items/3bb06de7276fa104236f#actions-on-google%E3%81%AEdraft%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AF1%E9%80%B1%E9%96%93%E3%81%99%E3%81%8E%E3%82%8B%E3%81%A8%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%AA%E3%82%8B%E5%95%8F%E9%A1%8C)

もし、情報が古かったり、間違ったことを言っていたらご指摘いただければ幸いです。

## Beebotte の設定

以下のページを参考にさせていただきました。

[IFTTTとBeebotteを使ってGoogleHomeからRaspberryPiを操作する - Qiita](https://qiita.com/msquare33/items/9f0312585bb4707c686b)

僕はこんな感じで設定しました（綴ミスはご愛嬌）。

![Screenshot_2018-09-04 Beebotte.png](https://qiita-image-store.s3.amazonaws.com/0/96666/3160dcca-5346-a6a9-452f-c01a4739e704.png)

## IFTTT の設定

同様に

[IFTTTとBeebotteを使ってGoogleHomeからRaspberryPiを操作する - Qiita](https://qiita.com/msquare33/items/9f0312585bb4707c686b)

や

[Token Based Authentication - Beebotte](https://beebotte.com/docs/tokenauth)
[Publishing Data - Beebotte](https://beebotte.com/docs/publish)

を参考に設定。

<img src="https://qiita-image-store.s3.amazonaws.com/0/96666/42b873e3-1405-9cfd-dbb8-b46ba63ca577.png" width=30%>

ほとんど一緒なのですが、唯一`URL` の項目を、チャンネル名に `private-` という接頭辞をつけて

```bash
https://api.beebotte.com/v1/data/publish/private-MySmartHause/PS4?token=XXXX
```
としています。これについては、[Bebotteのドキュメント](https://beebotte.com/docs/publish) に

> When publishing data to a channel, the message access level is public by default.
To publish a private message, the channel name must start with private- prefix.

と記載があるため追加しています。おそらく、チャンネルがPrivate の場合に必要なのかと考えています…が、参考先の記事はそのような記載なくうまく動いているようので、よく分かっていません…（詳しい方教えてください‥）。とりあえず、本記事ではドキュメントに従って記載しようと思います。


## Google Home から Beebotte のフローの動作確認

先程の記事をまた参考にして、動作確認を行いました。

「OK, Google. PS4 つけて」と発話することで、ちゃんとデータが送られていることがわかりました。

![Screenshot_2018-09-05 Beebotte.png](https://qiita-image-store.s3.amazonaws.com/0/96666/21effe99-4f02-98f1-1f07-1fda9a376196.png)


なお、ここでも Channel名には `private-` の接頭辞をつけています。


## Raspberry Pi で Beebotte の更新情報を受け取る

続いて、Raspberry Pi 側で Beebotte の更新情報を受ける処理を書いていきます。ここでは **MQTT** というプロトコルと`Node.js` を使用してプログラムを作成します。参考にしたのは下記ページになります。

[Beebotte MQTT Support - Beebotte](https://beebotte.com/docs/mqtt)
[GitHub - mqttjs/MQTT.js](https://github.com/mqttjs/MQTT.js/)

上記を参考にしつつ作ったプログラムがこちら。

```javascript:index.js
var mqtt = require("mqtt");

client =  mqtt.connect("mqtts://mqtt.beebotte.com",
    // Authenticate with your channel token,
    // セキュアな接続を使用するため、port 8883 を明示
    // Document に従って、"username" に token を、"password" は空
    {port: "8883", username: "token:YOUR_CHANNEL_TOKEN", password: ""}
);

client.on("message", function (topic, message) {
    console.log(topic + "   " + message);
})
```

動作確認をしてみます。PS4 をスタンバイにした状態で、上のプログラムを実行します。

```bash
node index.js
```

その状態で、「PS4つけて」と発話すると以下のような出力がなされます。

```bash
MySmartHause/PS4   {"data":"つけ て","ispublic":false,"ts":1536077036975}
```

あとは、`data` の内容に従って、`ps4-waker` の任意のコマンドを実行できるようにすれば完成です。


# 完成

これまでやってきたことをまとめて、最終的にラズパイ上で動かすプログラムを作成します。

![Untitled Diagram(4).png](https://qiita-image-store.s3.amazonaws.com/0/96666/b9ed20f3-0de0-25d1-737a-e29afd13d2bb.png)

現在作成中ですが、僕のプログラムを例として掲載しておきます。日本語の文法を解析する良い方法が思いついておらず、若干汚いコードになっていますがご了承ください…。良い方法がある方は教えていただければ幸いです。

```javascript:index.js
var mqtt = require("mqtt");
const {Device} = require("ps4-waker");

client =  mqtt.connect("mqtts://mqtt.beebotte.com",
    //Authenticate with your channel token,
    {port: "8883", username: "token:XXXXXXX", password: ""}
);

client.on("message", function (topic, message) {
    // message は文字列で入ってくるので、JSONに変換する
    words = JSON.parse(message).data.split(" ");

    switch (topic) {
        case "MySmartHause/PS4":
            var ps4 = new Device();

            switch (words[0]) {
                case "つけ":
                    ps4.turnOn().then(() => ps4.close());
                case "消し":
                    ps4.turnOff().then(() => ps4.close());
                case "で":
                    switch (words[1]) {
                        case "トルネ":
                        case "テレビ":
                            if (words[3] == "つけ") ps4.turnOn().then(() => ps4.startTitle("CUSA00442").then(() => ps4.close()));
                        default:
                            // nop
                    }
                default:
                    // nop
            }

        default:
            // nop
    }
})

client.subscribe("MySmartHause/PS4");
```

ひとまず、

- PS4 の電源をつける
- 電源を消す（スタンバイ）
- トルネを起動

あたりをやってみました。今後他のコマンドも順次増やしていく予定です。


# 終わりに

今回、初めてスマートスピーカを使って家電を操作する経験をしました。**声で操作すること** は、様々な場面で有効だということがわかりました。荷物を持っているときとか着替えているとき、リモコンがなかなか見つからない時など、何かをしながら操作できることに価値を感じると思いました。

今後は、PS4以外にも色んな家電をハックしていきたいと思います。とりあえず次は赤外線リモコンにでも挑戦してみたいと思います。