myThingsを使って雨が降りそうなときにGoogle Homeが自動的に教えてくれるようにする

先日登壇したSIerIoTLTでmyThingsを使ったヤフーサービスとGoogle Homeの連携について多くの方に興味を持っていただいたので、連携の仕方についてご紹介します。[myThings Developers](https://mythings-developers.yahoo.co.jp/main)を使うと様々なヤフーサービスとGoogle Homeを連携させることができます。
# この記事のゴール
今回は具体例として[myThings Developers](https://mythings-developers.yahoo.co.jp)を使ってYahoo!天気とGoole Homeを組み合わせて雨が降りそうなときにGoogle Homeが自動的に教えてくれるようにする、というのをゴールに説明していきます。

# 必要なもの
- Google Home
- Yahoo! JAPAN ID（[myThings Developers](https://mythings-developers.yahoo.co.jp)を利用するため）
- nodeがインストールされているPC（Raspberry Piでやった方が実用的なのですが、持ってない人もいると思うので今回はMacの使用を前提として説明します。）

# 手順
手順は大きく二つのパートがあります。
①発話テキストをPOSTするとGoogle Homeが話し始めるエンドポイントを作る。（1時間）
②[myThings Developers](https://mythings-developers.yahoo.co.jp)のトリガーとアクションを設定する。（30分）
スムーズにいけば2時間もかからないでできる思いますので、是非やってみてください！

# Google Homeが話し始めるエンドポイントを作る
以下Macのターミナルでのコマンドになります。

## Google Homeを喋られせるためのライブラリgoogle-home-notifierの準備
まず、Google Homeを喋らせるようにするためのnode.jsのライブラリ、[google-home-notifier](https://github.com/noelportugal/google-home-notifier)を準備します。
PCのターミナルを起動し、以下のコマンドを打ちます。

```
$ git clone https://github.com/noelportugal/google-home-notifier
$ cd google-home-notifier
$ npm install
```
ここで`npm install`をすると以下のようなエラーが出た場合は文字通りpythonのバージョンがv2.5.0 から 3.0.0の間でないとダメと怒られているので、

```
gyp ERR! configure error 
gyp ERR! stack Error: Python executable "/Users/tsubasa_oshima/.pyenv/shims/python" is v3.6.4, which is not supported by gyp.
gyp ERR! stack You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.
gyp ERR! stack     at PythonFinder.failPythonVersion (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:463:19)
```
python 2.7.10あたりを適当にインストールして

```
$ pyenv install 2.7.10
```

pythonのバージョンの切り替え（globalとすると全体に、localにするとそのカレントディレクトリに指定したバージョンが反映されます。）

```
$ pyenv local 2.7.10
```

ちゃんと切り替わったかを確認する。 2.7.10になっていればOK

```
$ python --version
Python 2.7.10
```

気を取り直して 再度`npm install`をすると先ほどのエラーが出なくなり、無事`node_modules`のインストールが完了するはずです。
## コードを書き換える
cloneしてくるとexample.jsは以下のようになっています。

```js:google-home-notifier/example.js
var express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8091; // default port

var deviceName = 'Google Home';
var ip = '192.168.1.20'; // default IP 

var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/google-home-notifier', urlencodedParser, function (req, res) {
  
  if (!req.body) return res.sendStatus(400)
  console.log(req.body);
  
  var text = req.body.text;
  
  if (req.query.ip) {
     ip = req.query.ip;
  }

  var language = 'pl'; // default language code
  if (req.query.language) {
    language;
  }

  googlehome.ip(ip, language);
  googlehome.device(deviceName,language);

  if (text){
    try {
      if (text.startsWith('http')){
        var mp3_url = text;
        googlehome.play(mp3_url, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
        });
      } else {
        googlehome.notify(text, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will say: ' + text + '\n');
        });
      }
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('Please GET "text=Hello Google Home"');
  }
})

app.get('/google-home-notifier', function (req, res) {

  console.log(req.query);

  var text = req.query.text;

  if (req.query.ip) {
     ip = req.query.ip;
  }

  var language = 'pl'; // default language code
  if (req.query.language) {
    language;
  }

  googlehome.ip(ip, language);
  googlehome.device(deviceName,language);

  if (text) {
    try {
      if (text.startsWith('http')){
        var mp3_url = text;
        googlehome.play(mp3_url, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
        });
      } else {
        googlehome.notify(text, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will say: ' + text + '\n');
        });
      }
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('Please GET "text=Hello+Google+Home"');
  }
})

app.listen(serverPort, function () {
  ngrok.connect(serverPort, function (err, url) {
    console.log('Endpoints:');
    console.log('    http://' + ip + ':' + serverPort + '/google-home-notifier');
    console.log('    ' + url + '/google-home-notifier');
    console.log('GET example:');
    console.log('curl -X GET ' + url + '/google-home-notifier?text=Hello+Google+Home');
	console.log('POST example:');
	console.log('curl -X POST -d "text=Hello Google Home" ' + url + '/google-home-notifier');
  });
})

```

この中の言語(`var language`)とGoogle HomeのIPアドレス（`var ip`）を書き換えます。
`language`は以下のように`ja`としてください。

```
var language = 'ja';
```

変更箇所がGETリクエストとPOSTリクエストの中の2箇所あるので注意してください。
（それぞれで宣言する必要もないと思うので、変数宣言を括弧の外に出してしまってもよいです。）


次にIPアドレスを自分のGoogle Homeのアドレスに書き換えます。
ipアドレスの確認の仕方はGoogle Homeアプリを開き、左上のハンバーガーメニューから「デバイス」
<img width="60%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/308fb471-c5ca-dc49-f191-ef8a5d5da6f1.png">

次に右上のマークを押す
<img width="60%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/1254eeca-efe2-05e5-9e82-b3c7efadc328.png">

設定
<img width="60%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/63436bb4-d8af-4420-7327-1811512b7368.png">

一番下までスクロールするとIPアドレスが書いてあります。
<img width="60%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/e894afd5-32ef-4a9e-f2e9-62dd5ca11caf.png">

このアドレスで書き換えます。

```
var ip = <自分のGoogle HomeのIPアドレス>;
```


## 実際にリクエストを送ってGoogle Homeを喋らせてみる。
ここまできたらあとはサーバーを起動してリクエストを送るとGoogle Homeが話し始めます。

サーバーを起動

```
node example.js
```

すると

```
Endpoints:
    http://192.168.xxxx.XXX:8091/google-home-notifier
    https://<生成されたサブドメイン>.ngrok.io/google-home-notifier
GET example:
curl -X GET https://<生成されたサブドメイン>.ngrok.io/google-home-notifier?text=Hello+Google+Home
POST example:
curl -X POST -d "text=Hello Google Home" https://<生成されたサブドメイン>.ngrok.io/google-home-notifier
```

のようにエンドポイントが生成されます。`ngrok.io`という文字列が入ったエンドポイントも同時に生成されます。
ngrokはローカル環境を簡単に外部に公開することができるツールです。詳しくは[ngrok.com](https://ngrok.com/)や[こちら](https://parashuto.com/rriver/tools/secure-tunneling-service-ngrok)をみてください。

生成されたエンドポイントに対して、GETやPOSTリクエストをしてみましょう。

```:GETリクエスト
curl -i -X GET \
 'https://<生成されたサブドメイン>.ngrok.io/google-home-notifier?text=こんにちは'
```


```:POSTリクエスト（ヘッダーをつける必要あり）
curl -i -X POST \
   -H "Content-Type:application/x-www-form-urlencoded" \
   -d \
'text=こんにちは' \
 'https://<生成されたサブドメイン>.ngrok.io/google-home-notifier'
```
するとGoogle Homeが下の動画のように喋り出すはずです！
[![GoogleHome発話デモ1](https://img.youtube.com/vi/7OXHY7hGtIQ/0.jpg)](https://youtu.be/7OXHY7hGtIQ)

## myThings Developersからのリクエストを受け取れるようにする。
myThings Developersからのリクエストは以下のような形式で送られてきます。

リクエスト内容

<dl>
  <dt>・リクエストメソッド</dt>
  <dd>POST</dd>
  <dt>・Content-Type</dt>
  <dd>application/json</dd>
  <dt>・リクエストヘッダー</dt>
  <dd>X-Secret : ＜シークレットの値＞</dd>
  <dt>・リクエストパラメーター</dt>
</dl>

|要素 |説明 |
|---|---|
|user_id|実行されたユーザーID|
|service_id|実行されたサービスID|
|mythings_id|実行された組み合わせID|
|values|トリガーから渡された値|


```json:Yahoo!天気トリガーのサンプルボディー
{
    "user_id": "<実行されたユーザーのID>",
    "service_id": "<サービスID>",
    "mythings_id": "<myTingsID>",
    "values": [
        {
            "area": "<地域>",
            "datetime": "<降雨日時>",
            "time": "<降雨時刻>",
            "date": "<降雨日>",
            "rainfall": "<降水量>",
        }
    ]
}
```
これを受け取れるように`example.js`に以下のような新たなエンドポイントを追加しましょう。

```js:google-home-notifier/example.js中に追加
var jsonParser = bodyParser.json();
app.post('/mythings/weather', jsonParser, function (req, res) {
  
  if (!req.body) return res.sendStatus(400)
  console.log(req.body);
  

  var values = req.body.values[0];
  var area = values.area;
  var time = values.time;
  var rainfall = values.rainfall;

  var text = area + "に" + time + "に1時間あたり" + rainfall + "ミリの雨がふりそうです。" ;
  
  if (req.query.ip) {
     ip = req.query.ip;
  }

  var language = 'ja';
  if (req.query.language) {
    language;
  }

  googlehome.ip(ip, language);

  if (text){
    try {
      if (text.startsWith('http')){
        var mp3_url = text;
        googlehome.play(mp3_url, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
        });
      } else {
        googlehome.notify(text, function(notifyRes) {
          console.log(notifyRes);
          res.send(deviceName + ' will say: ' + text + '\n');
        });
      }
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('textが空です');
  }
})
```

このエンドポイントにサンプルリクエストを送ってみましょう。

``` :サンプルリクエスト
curl -i -X POST \
   -H "Content-Type:application/json" \
   -d \
'{
    "mythings_id": "XXXXXXXXXX", 
    "service_id": "YYYYYYYYYYYYYYY", 
    "user_id": "ZZZZZZZZZZZZ", 
    "values": [
        {
            "area": "千代田区", 
            "time": "10:30",
            "rainfall": "10"
        }
    ]
}' \
 'https://<生成されたサブドメイン>.ngrok.io/mythings/weather'
```
するとこんな感じにGoogle Homeが喋り始めます。
[![GoogleHome発話デモ2](https://img.youtube.com/vi/HTRnpwKnBfw/0.jpg)](https://youtu.be/HTRnpwKnBfw)


これで手順①は終了です。次に手順②のmyThings Developersのトリガーとアクションを設定をします。

# [myThings Developers](https://mythings-developers.yahoo.co.jp)のトリガーとアクションを設定する。

## [myThings Developers](https://mythings-developers.yahoo.co.jp)へ登録 or ログイン
右上のから新規登録 or ログインをしてください
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/cb71a768-5cd4-6752-1122-6a6cab739a0b.png">

ログイン後、開始を押してください。
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/39f6e4ea-90b9-ab55-2a94-3f3ac3310bb7.png">

サービス登録画面が出ますので、「名称」を適当に設定してください。
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/63019047-306a-f60a-43ce-6bcd199e2405.png">


## 天気トリガーの設定
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/f96681cb-de0e-7cfb-4a8b-e814147e54bf.png">
①左下のトリガーのタブから「Yahoo!天気」を「トリガー」の丸いところまでドラッグ&ドロップ
②チャンネル設定
・トリガー 
プルダウンの中にいくつか項目がありますが、ここでは「雨が降りそうなら」を選択
・地域
好きな地域を選択
・時間
何時間以内に雨が降りそうだったら教えて欲しいかを設定
・降水量
降水量がいくつ以上だったら通知して欲しいかを設定
降水量の目安については[こちら](https://piropurin.com/event/kosuiryo)を参考にしてください。
③設定を保存ボタンを押す

ここまで完了すると「組み合わせ設定」の画面になり
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/3a0fcdb1-fed5-6b2c-f1f2-6ffffb921eef.png">
④組み合わせ設定
・組み合わせ名
好きな名前を入力
・曜日指定
この組み合わせを発火させたい曜日を選択
⑤設定を保存

## Google Homeアクションの設定
次にアクションを設定します。
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/3ab681df-faea-1b46-6461-23ed7ad48f3b.png">
①左下のアクションのタブから「カスタムアクション」を「アクション」の丸いところまでドラッグ&ドロップ
②チャンネル設定
・アクション名
好きな名前を入力

・リクエストURL
ここに手順①で生成した、Google Homeが話すためのエンドポイントを入力します。
**※ngrokのURLはサーバーを再起動するたびに変わります。サブドメインを固定させることもできますが、ngrokの有料プランとなります。なので、無料でやる場合は毎回サブドメインが変わるので、nodeサーバーを再起動させたらmyThings Developers上のリクエストURLも変更する必要があります。**

③リクエスト内容
どのようなリクエストがくるか確認できます。`values`に入るkeyを好きに使ってGoogle Homeに喋らせてください。

④設定保存ボタンを押す

## テスト実行
ここまできたらゴールは目前。
トリガーとアクションんのつなぎ込みのテストをしましょう。

テスト実行ボタンを押して
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/12a5b2cf-3200-f220-bf48-65fe9d588c20.png">

Yahoo!天気を認証して
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/935c6266-73fa-00a6-86d9-5223af45c5a9.png">

テスト実行
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/b86760cb-86c2-fde5-02a8-e40f556e7fae.png">

するとGoogle Homeが喋り出すはずです！

[![GoogleHome発話デモ3](https://img.youtube.com/vi/FOOb6awGmd0/0.jpg)](https://youtu.be/FOOb6awGmd0)
もし、失敗してしまったらリクエストURLが間違っていないかなどを確認してみてください。


## 定期実行をする

<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/d0d9453e-90c0-c9a1-48f7-a18a5c739c95.png">

組み合わせを実行したい曜日を指定して実行
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/08516622-8cd1-b260-4bbc-97b2c6c534da.png">

これで雨が降りそうな時にこの組み合わせが発動してGoogle Homeが教えてくれるようになりました！
<img width="80%" alt="ファイル名" src="https://qiita-image-store.s3.amazonaws.com/0/241871/fd5dc751-ac69-0104-e948-1d115af591c8.png">

# 他のトリガーを使っても様々なことができる
他にもトリガーとして

- ヤフオク、Yahoo!ショッピングでと組み合わせて「あるキーワードを含む商品が出品されたとき」
- Yahoo!防災速報と組み合わせて「地震情報が出たとき」「熱中症の危険度が高まったとき」
- 期限切れの間近のTポイントがあったら


などなど様々なサービスと組み合わせることができます。もちろんIFTTTでも生成したエンドポイントは使えます。
[Twitterの通知をGoogle Homeに教えてもらう](https://kotodama.today/?p=744)
IFTTTを使った例はこちらが参考になります。

是非いろいろなサービスと組み合わせて日常をハックしてみてください！！