yamamoWorks

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

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

今回はチャンネルを変える機能の実装です。前回はCEC(Consumer Electronics Control)で電源ON/OFFを制御しましたが、CECは繋いだHDMI機器の連動規格なのでボリュームUP/DOWNや入力切替は出来ますが、チャンネルの切替は対応していません。そこで、テレビに実装されているAPIを利用します。

※全体像および各関連記事へのリンクはこちらから

BRAVIAの新旧API

BRAVIAにはリモコンと同じ操作をHTTPリクエストで実行できるAPIが備わっています。 「BRAVIA nodejs」でググれば waynehaffenden/bravia とか alanreid/bravia といった便利なライブラリを使った実装方法が出てくるのですが、6年前くらいのモデルであるHX850では動作しません。 最近のモデルはPSK(Pre-Shared Key)による認証が実装されているのですが、古いモデルは認証がなくリクエスト先のパスも異なります。
以下は古いモデルの内容になります。比較的新しいモデルをお持ちの方は上記のライブラリを使用するのがよいでしょう。

API仕様

BRAVIAの古いモデルのAPI仕様は以下のURLにXML形式でリモコンのコードをPOSTする方式です。

URL

http://{テレビのIPアドレス}/IRCC

POST Body

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1">
            <IRCCCode>{制御コード}</IRCCCode>
        </u:X_SendIRCC>
    </s:Body>
</s:Envelope>

制御コードの一部を抜粋して載せます。

Control Code
Home AAAAAQAAAAEAAABgAw==
Options AAAAAgAAAJcAAAA2Aw==
Num1 AAAAAQAAAAEAAAAAAw==
Num2 AAAAAQAAAAEAAAABAw==
: :
Num11 AAAAAQAAAAEAAAAKAw==
Num12 AAAAAQAAAAEAAAALAw==
VolumeUp AAAAAQAAAAEAAAASAw==
VolumeDown AAAAAQAAAAEAAAATAw==
Mute AAAAAQAAAAEAAAAUAw==
Yellow AAAAAgAAAJcAAAAnAw==
Blue AAAAAgAAAJcAAAAkAw==
Red AAAAAgAAAJcAAAAlAw==
Green AAAAAgAAAJcAAAAmAw==
Play AAAAAgAAAJcAAAAaAw==
Stop AAAAAgAAAJcAAAAYAw==
Pause AAAAAgAAAJcAAAAZAw==
ChannelUp AAAAAQAAAAEAAAAQAw==
ChannelDown AAAAAQAAAAEAAAARAw==
Digital AAAAAgAAAJcAAAAyAw==
BS AAAAAgAAAJcAAAAsAw==
CS AAAAAgAAAJcAAAArAw==
TenKey AAAAAgAAAJcAAAAMAw==

※参考 https://gist.github.com/joshluongo/51dcfbe5a44ee723dd32

IFTTTの設定

今回は先にIFTTTの設定を見ていきましょう。
IFTTT編ではGoogle Assistantアプレットの「Say a simple phrase」を使って「Netfilxを起動して」、「モンハンを起動して」のようにPS4のアプリケーション毎にアプレットを作りましたが、チャンネルの数だけアプレットを作るのは大変なので「Say a phrase with a text ingredient」を使って「テレビを○○に変えて」という1つのアプレットを作成します。

「○○」の部分は$で表現します。
f:id:yamamoWorks:20181008120142p:plain

WebHookでPOSTする内容は以下とします。

{
  "endpoint": "https://{IoT Hub名}.azure-devices.net/twins/raspi/methods?api-version=2016-11-14",
  "policyName": "service",
  "sharedAccessKey": "{IoT Hubの共有アクセスポリシー「service」の共有アクセスキー}",
  "data": {
    "methodName": "sendChannelCommand",
    "payload": {
      "name": "{チャンネル名}"
    }
  }
}

Google Assistantアプレットで聞き取った$の部分は、WebHookアプレットで{{TextField}}として参照できます。なお「Add ingredient」 ボタンを押すと利用可能な変数が表示されます。
f:id:yamamoWorks:20181008154945p:plain

プログラムの修正

上記のAPI仕様を実装したbravia.jsを用意します。

IFTTT→Azure Functions→IoT Hub経由でpayload.nameでチャンネル名を受け取るよう設定したので、プログラム側でチャンネル名からBRAVIAに送信する制御コードを変換します。
NHKならリモコンの「地デジ」ボタン→「1」ボタンを、1~10に割り当てきれない衛生放送などは3桁の数字で指定するので「BS」ボタン→「10キー」ボタン→「1」「9」「3」と定義しておきます。
なお、Google Assistantで$に入ったテキストは先頭に空白文字が入るのと「{space}フジ{space}テレビ」のように単語が分割される場合があるので、プログラム側で空白除去を行い「NHK BS 1」でも「NHKBS1」のように定義しておきます。

const channels = {
    "NHK": ["Digital", "Num1"],
    "Eテレ": ["Digital", "Num2"],
    "日テレ": ["Digital", "Num4"],
    "テレ朝": ["Digital", "Num5"],
    "TBS": ["Digital", "Num6"],
    "テレ東": ["Digital", "Num7"],
    "フジテレビ": ["Digital", "Num8"],

    "NHKBS1": ["BS", "TenKey", "Num1", "Num0", "Num1"],
    "NHKBSプレミアム": ["BS", "TenKey", "Num1", "Num0", "Num3"],
    "BS日テレ": ["BS", "TenKey", "Num1", "Num4", "Num1"],
    "BS朝日": ["BS", "TenKey", "Num1", "Num5", "Num1"],
    "BSTBS": ["BS", "TenKey", "Num1", "Num6", "Num1"],
    "BSテレ東": ["BS", "TenKey", "Num1", "Num7", "Num1"],
    "BSフジ": ["BS", "TenKey", "Num1", "Num8", "Num1"],
    "WOWOWプライム": ["BS", "TenKey", "Num1", "Num9", "Num1"],
    "WOWOWライブ": ["BS", "TenKey", "Num1", "Num9", "Num2"],
    "WOWOWシネマ": ["BS", "TenKey", "Num1", "Num9", "Num3"]
};

あとはチャンネル名を上記でコマンドに変換し送信する関数を追加し、これまでと同様にIoT Hubのダイレクトメソッドと紐づけます。

const onSendChannelCommand = (request, response) => {
    console.log(request.payload);
    let name = request.payload.name.replace(/\s+/g, "");
    let commands = channels[name];
    console.log(commands);

    if (commands) {
        let client = new Bravia(braviaIpAddress);
        commands.forEach(cmd => {
            client.sendIrccCommand(cmd);
        });
    }
};

client.openAsync()
    .then(() => {
        console.log("iot-hub client opened.");
        client.onDeviceMethod("sendPS4Command", onSendPS4Command);
        client.onDeviceMethod("sendCecCommand", onSendCecCommand);
        client.onDeviceMethod("sendChannelCommand", onSendChannelCommand);  // ★追加★
    })
    .catch(err => console.error(`could not open iot-hub client. ${err.toString()}`));

これで「OK Google、テレビをNHKに変えて」でチャンネルが変わるようになりました。

随分と長い時間をかけてしましましたが「Google HomeとAzure IoT HubとRaspberry PiでTVとPS4をコントロール」の連載は終了となります!