yamamoWorks

.NET技術を中心に気まぐれに更新していきます

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【PS4後編】

前回はps4-wakerをセットアップしコマンド実行でPS4を制御しました。今回はプログラムからps4-wakerのライブラリを呼び出す方法の紹介と、IoT Hubからダイレクトメソッド呼び出しされてPS4を制御する部分の実装を行います。

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【概要編】
Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【IoT Hub編】
Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【PS4前編】

ps4-waker

ps4-wakeを使ってNode.jsからPS4を制御するコードは簡単です。スタンバイモードから復帰してNetflixを起動する場合は下記のようになります。ps4-wakerのメソッドはPromiseパターン(?)で実装されているのでコールバック地獄にならずにスラッと記述できます。

const Device = require("ps4-waker").Device;
var ps4 = new Device();
ps4.turnOn()
   .then(() => startTitle('CUSA02988'))
   .then(() => ps4.close());

SmartHome Client

IoT Hubに接続してダイレクトメソッド呼び出しを受けたらPS4を制御するコードを実装します。ps4-wakerがPromiseパターンなのでIoT Hub ClientもBluebirdを使ってPromise化しています。またIoT Hubの接続文字列は環境変数「IOTHUB_CONNECTION_STRING」から取得するようにしています。
なおNode.js初心者なのでベストな実装かどうかは分かりません(´・ω・`)

"use strict";

const Bluebird = require("bluebird");
const Mqtt = require("azure-iot-device-mqtt").Mqtt;
const Client = require("azure-iot-device").Client;
const Device = require("ps4-waker").Device;

const connectionString = process.env.IOTHUB_CONNECTION_STRING;
const client = Bluebird.promisifyAll(Client.fromConnectionString(connectionString, Mqtt));


const onSendPS4Command = (request, response) => {
    console.log(request.payload);
    let command = request.payload.command;
    let titleId = request.payload.titleId;

    var res = Bluebird.promisifyAll(response);
    let ps4 = new Device({
        bindAddress: process.argv[2]
    });

    Promise.resolve()
        .then(() => command == "standby" ? ps4.turnOff() : ps4.turnOn())
        .then(() => command == "start" ? ps4.startTitle(titleId) : null)
        .then(() => ps4.close())
        .then(() => res.sendAsync(200, "success"))
        .catch(err => {
            console.error(err.toString());
            res.sendAsync(500, err.toString());
        });
};

client.openAsync()
    .then(() => {
        console.log("iot-hub client opened.");
        client.onDeviceMethod("sendPS4Command", onSendPS4Command);
    })
    .catch(err => console.error(`could not open iot-hub client. ${err.toString()}`));

次回はGoogle Home(Assistant)からIoT Hub経由でダイレクトメソッドを呼び出す部分を実装します。

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【PS4前編】

前回までに全体像とAzure IoT Hubの設定まで行いました。今回はPlayStation 4の制御とIoT Hubとの連携を実装します。最終的にはRaspberry Piで実行しますが先ずはWindows上のNode.jsで実装してみます。

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【概要編】
Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【IoT Hub編】

PS4の制御

PS4の制御には「ps4-waker」というライブラリを使います。このライブラリでは同一LAN上のPS4に対して以下の事が可能です。

  • 起動(スタンバイモードから)
  • スタンバイ
  • アプリの起動
  • キー送信(up, down, left, right, enter, back, option, ps)
  • テキスト送信

ps4-wakerの導入

プログラムを作る前に、PS4にアクセスするにはPINコードでの認証が必要なので以下の手順で先に済ませておきます。なお作業にはPS4 Second ScreenというiPhone/Androidアプリが必要となります。 (PS4 Second ScreenはPlayStation Appのセカンドスクリーン機能が別アプリとして切り出されたものです)

PSN | PlayStation App | プレイステーション
※PS4 Second Screenは「PlayStation関連アプリ」にあります

まずPowerShellかコマンドプロンプトからps4-wakerをインストールします。

PS > npm install -g ps4-waker

インストールが完了したらコマンドを実行します。すると認証情報が無いのでPS4 Second Screen Appで接続しろと表示されます。

PS > npx ps4-waker
No credentials; Use the PS4 Second Screen App and try to connect to PS4-Waker

実行している端末にネットワークインターフェイスが複数ある場合は、PS4と同一LAN上のインターフェイス(IPアドレス)を--bind 192.168.0.1のように指定する必要があります。

この状態のまま、同一LAN上にあるスマホでPS4 Second Screenを起動すると「PS4-Waker」が見つかるので選択します。
f:id:yamamoWorks:20180318233559p:plain:w300

するとps4-wakerがPINコード入力待ち状態になります。 この時点でPS4 Second Screenは終了しても構いません。

Got credentials!  { 'client-type': 'i',
  'auth-type': 'C',
  'user-credential': 'xxxxxxxxxxxxxxxxxxxxxxxx' }
Go to 'Settings -> PlayStation(R) App Connection Settings -> Add Device' on your PS4 to obtain the PIN code.
Pin code> 

次にPS4側で[設定] - [モバイルアプリ接続設定] - [機器を登録する]と進み、表示されたPINコードをps4-wakerに入力します。
f:id:yamamoWorks:20180318164306p:plain:w300 f:id:yamamoWorks:20180318164323p:plain:w300

Pin code> 00000000
Logged into device! Future uses should succeed

以上でps4-wakerを実行している端末からPS4の制御が可能となりました。

認証情報はHOMEディレクトリに.ps4-wake.credentials.jsonファイルとして保存されます。Linux系/macOSなら~/ですが、Windowsだと実行時のカレントドライブ+%HOMEPATH%のようです。

動作確認

試しにコマンドを送ってみましょう。

PS > npx ps4-waker standby

PS4がスタンバイモードになれば成功です。

アプリを起動する場合は以下のようなコマンドになります。スタンバイモードになっていても自動的にPS4が起動します。

PS > npx ps4-waker start CUSA02988

ここで「CUSA02988」はNetflixアプリを表すTitle Idと呼ばれるコードです。
※Title Idは同じアプリでも国・地域によって値が異なります。

Application Title Id (JP) Title Id (US) Title Id (EU)
Netflix CUSA02988 CUSA00129 CUSA00127
YouTube CUSA01065 CUSA01015 CUSA01116
Amazon Video CUSA03099 CUSA00130 CUSA00126

Title Idを調べるには、PS4で目的のアプリを起動した状態でsearchコマンドを送信、表示された応答のrunning-app-titleidを確認します。

{
  "type": "device",
  "statusLine": "200 Ok",
        (省略)
  "running-app-name": "Spotify",
  "running-app-titleid": "CUSA01780",
  "address": "192.168.0.2"
}

次回はPS4にコマンドを送信するプログラムを作成します。

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【Iot Hub編】

前回は「概要編」ということで、これから作る全体像を示しました。今回からは各パーツの設定や作成を行っていきます。

IoT Hub作成

最初は同じくAzureのEvent Hubで構想していたのですが、Freeプランがありデバイスにダイレクトメソッド呼び出しができるIoT Hubで作ることにします。

Azure Portalより、リソースの作成「+」ボタンで「IoT Hub」を探して「作成」
f:id:yamamoWorks:20180305221832p:plain

「名前」は公開されるURLの一部(xxxxx.azure-devices.net)になるので既に使われている名前はつけられません。 「価格とスケールティア」は 今回の用途では1日に8000メッセージを処理できる「F1 Free」で十分ですね。 後は「サブスクリプション」と「リソースグループ」を選び「作成」ボタンを押します。
f:id:yamamoWorks:20180305221828p:plain:w300

デバイス登録

次にRaspberry Piをデバイスとして登録します。 作成したIoT Hubを開き「デバイスエクスプローラー」の「+追加」ボタンを押し、任意のデバイスIDを入力して「保存」ボタンを押します。
f:id:yamamoWorks:20180306000805p:plain:w400

接続テスト

公式ドキュメントを参考に、クラウドから呼び出すことができるダイレクトメソッドを持つデバイス側のプログラムと、IoT Hub を介してデバイス側のダイレクトメソッドを呼び出すプログラムをNode.jsで作成しWindows上で実行します。 「シミュレーション対象デバイス アプリの作成」以下を手順通りに実施するだけなので詳細は省きますが、指定する接続文字列について触れておきます。

SimulatedDevice.js で指定する {device connection string} は先程ポータルで作成したデバイスの詳細にある文字列です。
f:id:yamamoWorks:20180312232222p:plain:w400

CallMethodOnDevice.js で指定する {iothub connection string} は「共有アクセスポリシー」-「service」の詳細にある接続文字列です。
f:id:yamamoWorks:20180312232605p:plain:w400

IoT Hubを介してデバイス側のメソッドを呼び出す事が出来ました。
f:id:yamamoWorks:20180312234546g:plain

次回はPS4の制御方法を解説します。

Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール【概要編】

Google Home miniを購入したので様々な家電のコントロールを実現したいと思い赤外線リモコンの信号を制御するeRemote miniを買いましたが、Amazon EchoやGoogle Homeでスマート家電として認識できるのは現状では照明のみでテレビやエアコンのコントロールはできません。 *1

出来ないなら自前で作ろう、という事でテレビ周りのコントロールを出来るようにしてみます。様々な実現方法がありますが、今回は以下の条件で進めます。

実現したいこと

  • 「OK Google、プレステを起動して」で、PS4を起動する
  • 「OK Google、プレステを消して」で、PS4をスタンバイモードにする
  • 「OK Google、torneを起動して」で、PS4を起動してtorneを開く
  • 「OK Google、Netflixを起動して」で、PS4を起動してNetflixを開く
  • 「OK Google、テレビBRAVIAをつけて」で、テレビの電源をONにする *2
  • 「OK Google、テレビBRAVIAを消して」で、テレビの電源をOFFにする
  • 「OK Google、NHKに変えて」で、テレビのチャンネルを変える

持ってるもの

  • Sony BRAVIA HX850
  • PlayStation 4
  • Raspberry Pi 2 Model B
  • eRemote (今回は使わない)

Chromecastがあればテレビのコントロールは簡単ですが買わない方向で。

アーキテクチャ

f:id:yamamoWorks:20180301013529p:plain

Google Home(というかAssistant)はIFTTTと連携しているので、Google Assistantをトリガーとした処理を定義できます。

機器のコントロールについては、BRAVIAもPS4もLAN経由でコントロールが可能である事が分かったので、眠っていたRaspberry Piを活用し信号を送るプログラムを作成することにします。 但しBRAVIAの電源ONについてはLAN経由では出来ないのでHDMI対応機器間での制御信号をやりとりする規格であるHDMI-CECを用いることにします。なのでRaspberry PiとテレビをHDMIケーブルで繋げます。

次にGoogle HomeでトリガーされたコマンドをRaspberry Piまで伝達する方法ですが、ググるとGoogleのMBaaSであるFirebaseを使う例が殆どなので、同じことをやっても面白くないのでAzure IoT Hubを使うことにします。

Raspberry Pi上には、IoT Hubに接続し受信したイベントに従ってPS4やBRAVIAに信号を送るプログラムをNode.jsで作成します。※自分のNode.jsの勉強を兼ねて

今回はここまで。次回から各部分を実際に作っていきます。

 


  1. テレビを照明として登録する裏ワザ的な使い方はありますが…

  2. 「テレビをつけて」はChromecastデバイスの制御として認識されるのでテレビのブランド名で呼ぶ事にします

認証済みアプリ/サービスの削除ページリンク集

すぐ分からなくなるのでメモ。

「Googleアカウントでログイン」みたいなやつで承認した外部サービスやアプリの認証を削除するページへのリンク集。