OK Google, torneをつけて


## torne
我が家ではtorne（トルネ）でテレビを見ています。[torne公式](https://www.jp.playstation.com/nasne/torne/)
ざっくり言うと、PS3やPS4上で動作するテレビ閲覧ソフトです。ニコニコ実況と連携することができて、なんとコメントつきでテレビを見ることができます！
もうコメント無しは考えられなくなるくらいテレビが楽しくなります。

↓こんな感じです（[torneオンラインマニュアル](http://torne.scej-online.jp/contents.html)から拝借）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/322547/3815ea3a-4305-e66e-9658-3998e6f6b393.png)

しかし、torneを起動するためには
1. PS3の電源をつける
2. torneの起動アイコンまでカーソル移動
3. torne起動
4. 番組を見る
という手順を踏む必要があります。
普通のテレビであればリモコンピッで終わるところが、torneだとそうもいきません。

## やりたいこと
我が家にちょうどAlexaがいたので、こういう決まり切った仕事はやってもらうに限ります。
Alexaにtorneを起動してもらうことが目標です！

Alexaに独自の何かをしてもらうのは、カスタムスキルを作成するか、IFTTTを使えば出来るということはわかっていました。
なので
**PS3起動〜torne立ち上げ〜番組を見る**
を自動化する仕組みさえ実現できればほぼ出来たようなものです。

### torneの自動起動
偉大な先人の方がいまして、Node.jsでtorne自動起動を実現していました。
[IRKitからPS3を電源起動からtorne起動までNode.jsでやってみた - The jonki](https://www.jonki.net/entry/2014/05/11/173225)
どのようにするかというと、PS3用赤外線リモコン・IRKitを購入、PS3側に取り付けるリモコン受信部に向けてIRKitから赤外線を発信します。IRKitへはNode.jsからリクエストを送信する、という仕組みです。

ただし、PS3の電源だけは赤外線リモコンから制御できないようなので、そこだけ別に仕組みを設けます。
上記で紹介したブログでは、サーボモーターで物理的にPS3の電源ボタンを押せるようにしておき、赤外線受信によって動作するようにしていました。

私は[WioNode](http://wiki.seeedstudio.com/Wio_Node/)を使ってサーボモーターを動かすことにしました。下準備なしの状態からセットアップ5分くらいですぐにサーボモーターが使えるようになり、角度を指定してAPI叩くだけで思い通りに動かせます。大変便利です。

ここまでまとめると下記のような構成です。我が家ではRaspberryPiが常時稼働しているので、そこでNode.jsも動かしています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/322547/8851009a-a175-6bfd-19dd-3a4e9a328163.png)
赤外線リモコンのリモコンは使いません。IRKitを通して命令送信時のコマンドを取得したらあとは用済みです。

WioNodeにサーボモーターをセットアップしておき、PS3の電源ボタンを良い感じに押してくれる位置に取り付けておきます。

![ps3_power_on_with_butsuri.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322547/01bc1eee-55ea-38ed-de28-f07579003fdd.gif)


Node.jsから下記のような感じでWioNodeのAPIに向けてリクエスト2回投げて電源ボタンを押してもらっています。

```js

const request = require('request');

class Ps3Power {
  constructor(){}

  async on() {
    return this.exec_trigger();
  }

  off() {}
  current() {}

  async exec_trigger() {
    return new Promise(resolve=>{
      request.post({uri: this.servo_api_degree_by(90)}, (error, response, body)=> {
        if(response.statusCode == 200) {
          request.post({uri: this.servo_api_degree_by(0)}, (error, response, body)=> {
            resolve(response.statusCode);
          });
        }
      });
    });
  }
  servo_api_degree_by(degree) {
    return "https://us.wio.seeed.io/v1/node/GroveServoD1/angle/" + String(degree) + "?access_token=***"
  }
}
```


PS3起動後は、PS3のリモコンコマンドをIRKitに向けて送信します。リモコンコマンドは事前にIRKitに向けてリモコンのボタンを押して調べておきます。
IRKitへのリクエストの送信は`IRKit Device HTTP API`というHTTPのAPIを用意してくれているので簡単に扱えます。とてもシンプルでわかりやすいです。
[IRKit - Open Source WiFi Connected Infrared Remote Controller](http://getirkit.com/)

Node.js上では

```js
["sleep:35", "left", "sleep:1", "left", "sleep:1", "left", "sleep:1", "down", "sleep:5", "circle", "sleep:40", "circle"]
```
こんな感じで順番に処理させています。sleepは指定秒だけsleepです。left/down/circleはあらかじめそのファイル名でIRKitへ送信するコマンドを保存しておいて、ファイルを読んでIRKitへリクエストを投げるようにしています。

ちなみに最初の35秒はPS3の起動待ちで、最後の40秒はtorneの起動待ちです。PS3の世代によっては遅かったり早かったりするかと思います。


## AlexaからNode.jsに命令を送る
ローカルネットワーク内からスクリプトを実行すればtorneが自動起動できるところまで出来ました。
しかしAlexaを起点として動作させるには、カスタムスキルを作ってLambda経由にするにしても、IFTTT連携するにしても、インターネット経由で家のNode.jsを実行する必要があります。

外部からリクエストを受けられるようWebサーバ立ち上げて…という方法も考えられますが、セキュリティ面の考慮が必要になってきて面倒です。

調べたところ、出版購読モデルでメッセージをやりとりするというアプローチが見つかったので、それで実装していこうと思います。
参考にさせていただいた記事↓
[IFTTTとBeebotteを使ってGoogleHomeからRaspberryPiを操作する](https://qiita.com/msquare33/items/9f0312585bb4707c686b)

### beebotte

[beebotte](https://beebotte.com/home
)というメッセージングサービスを使用しました。
IoT向けと謳っており、REST APIやMQTT、WebSocketなどサポートしています。

> Designed to empower Internet of Things and real-time communicating applications


![image.png](https://qiita-image-store.s3.amazonaws.com/0/322547/88434e06-772c-f215-e8f1-a5197cc6efb8.png)


料金も個人ユースであれば無料枠で全く問題なしです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/322547/2b27239b-4435-57a5-7db0-2cbf3f183621.png)

使い方もとっても簡単で、チャンネルを作成したらトークンが与えられるのであとは `チャンネル` + `トークン`を使ってpublish & subscribe　するだけです！
（チャンネル作成などは前述の参考記事でとても丁寧に解説されています！）

また、公式ドキュメントはサンプルコードつきです。なんとなくの英語でもコードを見れば使い方がわかります。
Node.jsにメッセージをsubscribeするコードをサンプルを見ながら実装しました。

```javascript

const mqtt = require('mqtt');
const sleep = require('sleep');
const BEEBOTTE = {
  CHANNEL_TOKEN: "*********",
  PASS: "***"
};

const client =  mqtt.connect('mqtt://mqtt.beebotte.com',
  {username: 'token:' + BEEBOTTE.CHANNEL_TOKEN, password: BEEBOTTE.PASS} 
);

client.on('message', function (topic, message) {
  console.log(topic + '   ' + message);
  let order = "";
  message = JSON.parse(message);
  if(message.data) {
    order = message.data;
  }

  switch (order) {
    case 'ps3_power':
      Ps3.power();
      break;
    case 'ps3_start_torne':
      Ps3.start_torne();
      break;
    default: 
      break;
  }

});

client.subscribe('MySmartHome/voice');
```

beebotteのダッシュボードからメッセージのPublishを試せるので、Node.jsがきちんとsubscribeできることを確認しておきます。確認できたら、subscribe後の処理にtorne起動の処理を組み込んでおきます！上記コード中の `Ps3.start_torne()`がそれにあたります。

ここまで出来たら、npmで[forever](https://github.com/foreverjs/forever)をインストールして、デーモン起動しておきます。これで常にsubscribeし続けてくれます。

### Alexaから呼び出す
beebotteのpublishAPIにリクエストをアレクサから投げます。
IFTTTを使いました。スキルとして作成しても実現できますが、いろいろ設定するのが面倒なのでIFTTT連携のほうがはるかに楽です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/322547/7649e91e-30a9-d810-5654-133bc48c4529.png)

フレーズは「トルネ」、URLはbeebotteのダッシュボードから確認できるpublishAPI（https）、送信するjsonは`{"data":"ps3_start_torne"}`としました。

## 完成、そしてさようならAlexa
完成しました。
「アレクサ、トルネをトリガー」と呼びかければトルネが自動で立ち上がります！
やりたいことが実現できました！
「トリガー」と言わなければならないのは、AlexaでIFTTT連携する際の仕様です。

しかし、妻は「トリガーとか声にだして言うのが恥ずかしいから使わない」と言っているのです... 私もそう思います。正直恥ずかしい。


いろいろ調べていくと、なんとGoogleHomeはIFTTT連携してもこんな余分なキーワードを言う必要は無いようです。これはもうGoogleHomeを買うしかありません。
<br>
デモ動画
[![デモ動画](http://img.youtube.com/vi/UB2WTlZsqnM/0.jpg)](https://www.youtube.com/watch?v=UB2WTlZsqnM)


<br>
AlexaからGoogleHomeに乗り換えても、変更点はIFTTTの起点を変えるだけでOKです。
今では妻も「ねーGoogle,テレビをつけて！」と活用してくれています。
ありがとうGoogleHome。

## 改善点・イケてない点

- **IRKitのIPアドレスを固定にすること必須**<br>
ルータの再起動などでIPアドレスが変わると、Node.jsからのリクエストが宛先不明になります。IRKit側はDHCPしか設定不可っぽいのでルータ側で固定にする必要があります。
- **IRKitがHTTPリクエストを捌けなくなる（？）**<br>
原因がよくわからないのですが、たまにレスポンスがEmptyと返ってきてリクエストが処理されなくなります。再起動（コンセント引っこ抜いてまた挿す）すれば直りますが...。定期的にGETを投げる監視を設けてもいいかもしれません。レスポンスがおかしかったら、コンセントの間に何かON/OFFを設けておいて自動で復旧させたいですね。
- **torneの録画中は自動起動できない**<br>
torneには録画機能もあるのですが、録画中は電源ボタンを物理的に叩いてもPS3ホーム画面にはたどり着きません。（録画が終了もしませんのでその点は安心）。Xボタンを押してPSボタンを押して、PS3のホーム画面にたどり着くので、録画中の対応もできたらより便利ですね

### 余談
やけになって「アレクサ、GoogleHome！」と呼びかけました。
『Amazonで Echo dot が見つかりました。購入しますか？』ってそれお前やないか。[^1]
「購入しない！」
『購入しました』
！？
本当に購入されてたので急いでキャンセルしました。認識ミスだとは思いますが怖かったです。

[^1]: 毎回この返事をしてくれるわけではなく、『人違いです』的な回答もします。