Google Homeに話しかけてテレビの電源を操作してみる


# はじめに
[前回記事(Google Homeに話しかけてPS4を操作してみる)](https://qiita.com/miso_develop/items/0175c5f45a1e90464234)にてPS4を音声操作できるよにしましたが、テレビの電源を消せない事がネックでした。
なので今回はHDMI CECを用いてテレビの電源を音声操作してみます。



# 処理の流れ
![image](https://qiita-image-store.s3.amazonaws.com/0/207109/1ffd9dbf-f77b-aba7-ff50-8270c63b8663.png)



# 環境
- Google Home
- Raspberry Pi3 (Raspbian Lite 9.1)
    - Node.js (v8.6.0)
- SONY Bravia (KDL-32EX420)



# テレビの電源操作
冒頭にて書いたとおりテレビの電源操作にはHDMI CEC(Consumer Electronics Control)を利用します。
HDMI CECとはテレビとかレコーダーとかのHDMI対応機器間での制御信号をやりとりするため規格です。
Google HomeとChromecastを繋いで「テレビつけて」と言うとテレビがつくのもこのHDMI CECのおかげです。

## cec-clientのインストール
HDMI CECでの制御なのでまずはラズパイとテレビをHDMI接続します。
両方起動してテレビの画面からラズパイが見えるようにしておいて下さい。

そしてラズパイからHDMI CECを制御できる`cec-client`をインストールします。

```
$ sudo apt-get install git vim cec-utils -y
```

インストールできたらHDMI信号をチェックしてみましょう。
以下のコマンドを実行してテレビの電源をオンオフしてみて下さい。

```
$ cec-client -m -d 8 -b -r
```

電源をオフった時に`0f:36`とか出てきたと思います。
あと定期的に`0e:83`とか出てると思いますが、これはヘルスチェックみたいなもんぽいです。
このMACアドレスっぽいのがHDMIの制御信号で、各バイトごとに意味を持っています。

どのコードがどんな意味かは以下のサイトから確認できます。
[CEC-O-MATIC](http://www.cec-o-matic.com/)

## cec-clientによるテレビの制御
続いてcec-clientにてテレビを制御してみましょう。
まず以下のコマンドを実行してHDMIデバイスの一覧を取得します。

```
$ echo "scan" | cec-client -d 1 -s
log level set to 1
opening a connection to the CEC adapter...
requesting CEC bus information ...
CEC bus information
===================
device #0: TV
address:       0.0.0.0
active source: no
vendor:        Sony
osd string:    TV
CEC version:   1.4
power status:  on
language:      jpn


device #1: Recorder 1
address:       3.0.0.0
active source: yes
vendor:        Pulse Eight
osd string:    CECTester
CEC version:   1.4
power status:  on
language:      eng


device #4: Playback 1
address:       1.0.0.0
active source: no
vendor:        Sony
osd string:    PlayStation 4
CEC version:   1.3a
power status:  standby
language:      ???


currently active source: Recorder 1 (1)
```

私はテレビに対しラズパイとPS4を接続しています。
上記の結果の場合`device #0`がテレビ、`device #1`がラズパイ、`device #4`がPS4となります。
このテレビのdevice値はHDMIの論理アドレスとなっており、テレビのオンオフコマンドにて使用します。

では実際にテレビをオフってみましょう。
以下のコマンドの`0`の部分が対象デバイスの番号になります。
上記コマンドの実行結果のテレビのdevice値に変えて実行してみて下さい。

```
$ echo "standby 0" | cec-client -s -d 1
```

どうでしょうか。
テレビがオフられましたか？

次はテレビをつけてみましょう。
以下のコマンドを同様に実行してみて下さい。

```
$ echo "on 0" | cec-client -s -d 1
```

ちなみにdevice値を他のデバイスの値に変えれば対象のデバイスを操作できます。
例えば私の環境ですとdevice値を`4`とすればPS4の電源をオンオフできます。

※テレビによっては上記コマンドで起動できない場合があるようです。
　これは電源オフ時にスタンバイ状態ではなく完全に電源がオフられた状態となっているためと思われます。
　テレビの設定により電源オフ時にスタンバイになるよう設定できる場合もあります。
　VIERAの場合ですとコメント欄にてtamotsu416さんが記載頂いた方法でスタンバイにできるのでもし起動がうまくいかない場合はお試し下さい。

ついでに以下のコマンドで音量の操作も可能です。

```
$ echo "volup" | cec-client -d 1 -s
$ echo "voldown" | cec-client -d 1 -s
```

他にも`echo "tx xx:xx:xx:xx" | cec-client -d 1 -s`といった感じでバイトコードを直接投げられるようです。
これを利用すれば色んなリモコン操作も出来るんじゃないかと思いますが、まだ制御コードを詳しく見れてなく未検証です。
時間がとれたらここも調べてみたいと思います。

## ラズパイのHDMI連動をオフる
ラズパイとテレビをHDMI接続してると、ラズパイの起動に合わせテレビも連動して起動してしまいます。
これはちょっと微妙なので、ラズパイのHDMI設定にて連動をオフります。
設定方法は`/boot/config.txt`に以下の記述を追加して再起動します。

```
hdmi_ignore_cec_init=1
```

ちなみにこの設定をした状態でHDMIを抜き差しするとcec-clientコマンドが効かなくなります。
その場合は上記の記述を一度コメントアウトしてから再起動し、コマンドが効くことを確認してから再度設定し直して下さい。

## Google Homeから音声操作
ここから先は前回記事を参考によしなにしてみて下さい。
以下のリンク部から進めてもらえれば大体おっけーです。

ひとつ注意点として、IFTTTで操作ワードを指定する際に「テレビ $」とかやっちゃうとダメです。
「テレビつけて」とかってワードはChromecastの操作として認識されてしまうからです（Chromecastささってなくても）。
なので私は「ブラビア $」にしています。

[FirebaseのDatabase定義](https://qiita.com/miso_develop/items/c2008235cb4a8567cfa9#firebase%E3%81%AE%E8%A8%AD%E5%AE%9A)

あと一応`index.js`への追記部を記載しておきます。

```js:index.js
      ...
      
      //TV
      "tv": () => {
        const command = 'echo "%OPTION%" | cec-client -s -d 1';
        const word = value.split(" ")[1];
        let option=  getJsonData(word, {
          "起動": "on 0",
          "軌道": "on 0",
          "つけ": "on 0",
          "オン": "on 0",
          "スタンバイ": "standby 0",
          "消し": "standby 0",
          "けし": "standby 0",
          "止め": "standby 0",
          "とめ": "standby 0",
          "停止": "standby 0",
          "音量": () => {
            return getJsonData(value.split(" ")[2], {
              "上げ": "volup",
              "あげ": "volup",
              "アップ": "volup",
              "下げ": "voldown",
              "さげ": "voldown",
              "ダウン": "voldown",
              "default": false
            });
          },
          "default": false
        });
        //
        if (typeof option === "function") option = option()
        return option ? command.replace("%OPTION%", option) : option;
      },
      
      ...
```



# おわりに
電源つながりでメインPCとして使ってるWindowsのオンオフも一緒に書こうと思ってましたが、テレビだけで意外と文量とってしまったのでここで一旦区切ります。
Windowsの方はWOL(Wake On Lan)による起動と、Node.jsをサービス化させてラズパイでのFirebaseフックと同じ方法でスリープをさせてみます。

※2017/10/31追記　投稿しました↓
[Google Homeに話しかけてWindowsを操作してみる](https://qiita.com/miso_develop/items/7a02908aad2a5cf192d0)



# 参考記事
[Raspberry PiとテレビをHDMI接続してテレビのON/OFFを確認する](https://qiita.com/mascii/items/132c064c30e321dea911)