間が空きましたが、以前の記事でBRAVIAをネットワーク経由で制御する方法をまとめました。Node.jsサーバーを建てて、alanreidさんのGitHubにある制御スクリプトをクローンして設置すると、
|
http://192.168.0.???:xxxx/WakeUp |
という感じでNode.jsスクリプトを叩けるAPIが構築できます。WakeUpの部分がBRAVIAリモコンのボタンに対応づいていて、
|
PowerOn Num1 Num2 Num3 Num4 Num5 Num6 Num7 Num8 Num9 Num0 Num11 Num12 Enter GGuide ChannelUp ChannelDown VolumeUp VolumeDown Mute TvPower Audio MediaAudioTrack Tv Input TvInput TvAntennaCable WakeUp PowerOff Sleep Right Left SleepTimer Analog2 TvAnalog Display Jump PicOff PictureOff Teletext Video1 Video2 AnalogRgb1 Home Exit PictureMode Confirm Up Down ClosedCaption Component1 Component2 Wide EPG PAP TenKey BSCS Ddata Stop Pause Play Rewind Forward DOT Rec Return Blue Red Green Yellow SubTitle CS BS Digital Options Media Prev Next DpadCenter CursorUp CursorDown CursorLeft CursorRight ShopRemoteControlForcedDynamic FlashPlus FlashMinus AudioQualityMode DemoMode Analog Mode3D DigitalToggle DemoSurround *AD AudioMixUp AudioMixDown PhotoFrame Tv_Radio SyncMenu Hdmi1 Hdmi2 Hdmi3 Hdmi4 TopMenu PopUpMenu OneTouchTimeRec OneTouchView DUX FootballMode iManual Netflix Assists ActionMenu Help TvSatellite WirelessSubwoofer |
といったコマンドが使えるようです。
後はこれをポート開放してインターネットから叩けるようにすれば、ブラウザはもちろん、IFTTTのWebHookから呼び出すことが出来、つまるところGoogle Homeに向かって「OK Google、NHKにして」と言ったら、
|
http://(Node.jsサーバーのグローバルIPアドレス):xxxx/Num1 |
を叩くようなレシピが書けるわけです。
ただし、実際に使ってみるとこれだけでは不十分だと気付きます。Num1は数字キーの1に相当しますが、試せばわかるように、例えばホーム画面が出ている時にNum1を押してもNHK(関東の場合)にはならないのです。あるいはBSを見ている時にNum1したらBS1になってしまいます。これらはあくまでリモコンのボタンと同等の機能しかもっていないので、実際にある目的の状態に遷移させるには複数のボタンをマクロで動作させる必要があります。例えば、ホーム画面にいることを想定すると、Exit(戻る)->Digital(地デジ)->Num1(数字キー1)を押す必要があります。これはIFTTT側では対応できません。そこで、あるGETパラメーターに対して連続的に上記コマンドを発行する別スクリプトを作りました。統一性に欠けますが個人的に使い慣れたPHPで書いています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
<?php header('Content-type: text/plain; charset=utf-8'); function send($cmd) { echo "Sending Command: {$cmd}\n"; $url = "http://192.168.0.xxx:(ポート番号)/{$cmd}"; echo $url."\n"; $result = file_get_contents($url); echo $result."\n\n"; } $cmd = filter_input(INPUT_GET, 'cmd', FILTER_SANITIZE_SPECIAL_CHARS); echo "Received Command:{$cmd}\n"; switch ($cmd) { case 'wakeup': send('WakeUp'); break; case 'sleep': send('Sleep'); break; case 'tv': send('WakeUp'); send('Digital'); break; case 'voldown': for ($i=0;$i<5;$i++) { send('VolumeDown'); } break; case 'volup': for ($i=0;$i<5;$i++) { send('VolumeUp'); } break; case 'netflix': send('WakeUp'); sleep(1); send('Netflix'); break; case 'nhk': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num1'); break; case 'etv': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num2'); break; case 'tvtokyo': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num7'); break; case 'tvk': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num3'); break; case 'fuji': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num8'); break; case 'tbs': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num6'); break; case 'mx': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num9'); break; case 'asahi': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num5'); break; case 'nihontv': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num4'); break; case 'bs1': send('Exit'); sleep(1); send('BS'); sleep(1); send('Num1'); break; case 'bs11': send('Exit'); sleep(1); send('BS'); sleep(1); send('Num11'); break; Default: send($cmd); break; } |
仕組みは簡単です。冒頭の関数send()が実際にNode.jsサーバーのAPIを叩く部分です。自宅内のNode.jsサーバーのIPアドレスとポート番号を適宜書き換えます。本PHPスクリプトを動かすサーバーと同じでも良いですし、別でもいいです。外部にポート公開するのは本PHPスクリプトを動かすApacheなどのポートのみでOKです。安全の為、Node.js側のポートは閉じておいた方が良いでしょう。
例えばApacheのDocumentRootに本スクリプトをindex.phpなどという名前で配置した場合、呼び出し方は、
|
http://(グローバルIPアドレス):xxxx/index.php?cmd=(cmdコード) |
という感じになります。cmdコードはswitch文の中で色々と定義できます。例えば、先ほど書いたNHKの部分は、
|
case 'nhk': send('Exit'); sleep(1); send('Digital'); sleep(1); send('Num1'); break; |
なので、sleep(1)で1秒ずつ間隔を置きながら、Exit、Digital、Num1を発していることになります。これでホーム画面にいてもBSを見ていても地デジの1チャンネルとなるので、IFTTT側で「NHKにして」と言われたらWebHookで
|
http://(グローバルIPアドレス):xxxx/index.php?cmd=nhk |
を叩くようにすればOKです。MethodはGET、Content Typeはtext/plainでOKです。BSチャンネルの場合はDigitalの代わりにBSを指定します。
他にも、音量アップダウンは、
|
case 'voldown': for ($i=0;$i<5;$i++) { send('VolumeDown'); } |
のようにして、同じ操作を5回繰り返して1単位としています。ここはsleep挟まなくてもいけてるぽいです。
なお、Netflixだけはリモコンにダイレクトボタンがあるのでcmd=Netflixで一発起動できます。うまくマクロを組めばユーザ選択くらいまでは自動化できるかも知れません。しかし他のYoutubeやAmazonプライムビデオといったアプリは対応できません。頑張ってHome、↓、↓、→、決定みたいなマクロを書けばできるかも知れませんが未検証です。
■セキュリティ的な配慮
caseのどれにも当てはまらない場合はDefaultセクションでそのまま送信することになっています。つまり、個別のボタンを直接叩くこともできます。可能性は低いと思いますがいたずらのリスクを抑えるのであれば、Defaultセクションは消しておいて、自分が定義したマクロ以外は無視するようにしてもいいかも知れません。電源はGoogle Homeから直接Chromecastエミュレーションでオンにできると思うので、電源だけはこのスクリプトからオンできなくしておくとか(あれ、でもNum1とかで電源はいっちゃうかな?)。その他、
- パスを深くする
- POSTにする
- パラメーターで暗号キーを一緒に渡してチェックする
- ソースIPをIFTTTのものに限定する
くらいの配慮はできるかもですが、IFTTTのWebHookから利用することを考えるとその辺りが限界でしょうか。Node.jsスクリプトを直接インターネットに公開するよりはマシかなとは思います。いずれにせよ本PHPスクリプトはあくまで実証スクリプトということで、ご利用は自己責任で。自宅アドレスを含むIFTTTレシピをそのまま共有しないようご注意ください(笑)。
■IFTTTのGoogleアシスタント用コマンドにチャンネル名を使う
以前の記事で固有名詞がGoogleアシスタントのコマンドに向かないよということを書きましたが、あれはあくまで自分のペットの名前などマイナーな固有名詞についてです。日本の代表的なテレビ局名くらいはきちんとGoogle側の辞書に入っているので、特に問題なく認識されると思います。「日テレ」などの略称でも大丈夫でした。「tvk」「MX」なども不安でしたが大丈夫なようです。Googleアシスタントアプリで確認したところ「ティーヴィーケー」と言うと「TVK」と出るので、そこは大文字でコマンドを定義しました。適宜Googleアシスタントアプリで聞き取り方を確認しつつIFTTTを設定してみてください。
■「?」を使ったレシピ集約
今回は主要チャンネルの数だけレシピを作ってしまいましたが結構手間です。IFTTTのGoogleアシスタントレシピでは「?」(「Say a phrase with a text ingredient」)を使って聞き取った文字列の一部をWebHookスクリプトにそのまま文字列として渡すことができますので、「チャンネルを ? にして」のようなレシピ1つで、あとはスクリプト側で分岐させる手もあると思います。そこら辺はAVアンプ制御編でチャレンジしてまうので、そちらも合わせてご覧ください。