Google Homeを使って娘のオムツの情報をGoogle Spreadsheetに記録する

ことの発端は下記のTweet。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Google Homeいつの間にか夫が買ってたのでてぃばちゃんがやってたみたいなムスメの💩記録できるようにしたいなー。「ねぇ、グーグル。娘が💩したんだけど！」「💩はどんな状態でしたか？」「ゆるめだった」「記録しました」と言うのを目指したい</p>&mdash; あひる (@ahiru_z) <a href="https://twitter.com/ahiru_z/status/940495374472507392?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

我が家もIFTTTでやろうかと思ったけど上の要件を満たせないようで結局python＋heloku+dialogflowを使ってやることに。
pythonとhelokuを使用してwebhookを作成、Dialogflowを介して音声入力したものをグーグルスプレッドシートに記録するのが目標。
[この記事](https://qiita.com/kotatu_km/items/c06f45c6692dceb9258d)を全体の流れの参考にした。
超ざっくりやったことを書いていく。
（pythonもhelokuも初めて触ったからあんまりわかってない）

# DialogFlowに登録
[上記記事](https://qiita.com/kotatu_km/items/c06f45c6692dceb9258d) を参考にしつつDialogFlowに記入していく
登録中、途中心が折れそうになるがコツコツとバリエーションを登録。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">なんだかなぁって気分になってきた <a href="https://t.co/dkxYI3LVaw">pic.twitter.com/dkxYI3LVaw</a></p>&mdash; あひる (@ahiru_z) <a href="https://twitter.com/ahiru_z/status/942929269084192768?ref_src=twsrc%5Etfw">2017年12月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Intentsの設定はこんな感じにした。
ResponseにGoogle homeに返してもらいたい言葉を入れる。
今回は「記録しました」とした。
Fulfillmentの項目は「Use webhook」にチェック。
Google Assistantの項目は会話を続ける必要が無いので「End conversation」にもチェックを入れた。
![FireShot Capture 6 - Dialogflow_ - https___console.dialogflow.com_api-.png](https://qiita-image-store.s3.amazonaws.com/0/226500/d8feb10d-5bbd-a68d-c26f-5b7eb6ac6772.png)

## 「うんこ」のときはその状態の記録を必須にしたい
「うんこした」とコチラが言った場合、「その状態を教えてください」というようなリアクションが欲しかった。
なので、Intentsを登録する際に"REQUIRED"にチェックを入れ、入力がなかった場合に質問を返すように「PROMPTS」にコメントを登録する
<img width="719" alt="スクリーンショット 2017-12-24 17.04.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/226500/ff289a3a-b1dd-4aee-68a8-926b9be98dfd.png">


# pythonでコードを書いてhelokuにPushする
下記を参考にしまくりながらコピペプログラミングでpythonをなんとなく書いてみる

- gspredsheetへの書き込みの参考  
http://temcee.hatenablog.com/entry/gspread_python
- webhookの参考  
https://github.com/dialogflow/fulfillment-webhook-weather-python/

helokuにPushする際に気をつけたいのはpython内で使用したライブラリ群を同ディレクトリ内にrequirements.txtと名前をつけて保存する必要が有ること。
下記コマンドで一覧が作れる
```pip freeze > requirements.txt
```
これを作っておけばローカルでもお手軽にライブラリをまとめてインストールすることが出来る
```pip install -r requirements.txt  
```
helokuのPush成功したら `heroku open` を実行するとBrowserが立ち上がる。
立ち上がったURLの後に/webhook/とつけたものが今回はwebhookのURLになる。

helokuのログを監視は下記。
```heroku logs --tail  
```

コピペプログラミングのcodeを一応貼っておく。

```python3
#!/usr/bin/env python
# -*- coding: utf-8 -*-


from __future__ import print_function
from future.standard_library import install_aliases
install_aliases()

# URL を開くためのライブラリ
from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import json
import os

# ウェブアプリケーションフレームワーク
from flask import Flask
from flask import request
from flask import make_response

#googleSpreadsheet用のライブラリ
import gspread

#OAuth 2.0で保護されたリソースにアクセスするためのライブラリ
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds']

#現在日時のdatetimeオブジェクトを取得するためのライブラリ
from datetime import datetime
from pytz import timezone




# Flask app should start in global layout
app = Flask(__name__)


@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = processRequest(req)
    # return返さないとエラーになる
    return "SUCCESS"

def processRequest(req):
    if req.get("result").get("action") != "writeSpreadSheet":
        return {}
    if req.get("result").get("parameters").get("called-pee") == "pee":
        pee = u"💧"
    else:
        pee = u"-"
    if req.get("result").get("parameters").get("called-poo") == "poo":
        poo = u"💩"
        pooStatus = req.get("result").get("parameters").get("state-poo")
    else:
        poo = u"-"
        pooStatus = u"-"
    #ダウンロードしたjsonファイルを同じフォルダに格納して指定する
    credentials = ServiceAccountCredentials.from_json_keyfile_name('hogehoge.json', scope)
    gc = gspread.authorize(credentials)
    # 共有設定したスプレッドシートの名前を指定する
    worksheet = gc.open("hogehoge").sheet1

    print(worksheet.cell(1,1))
    utc_now = datetime.now(timezone('UTC'))
    jst_now = utc_now.astimezone(timezone('Asia/Tokyo'))

    # シートに行を追加して記入
    worksheet.append_row([jst_now.strftime("%Y/%m/%d %H:%M:%S"),pee,poo,pooStatus]);


if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print("Starting app on port %d" % port)

    app.run(debug=False, port=port, host='0.0.0.0')

```

# webhookのURLをDialogflowに設定する
DialogflowのメニューでFulfillmentを選択し、helokuのurlを指定する
![スクリーンショット 2017-12-25 9.38.34.png](https://qiita-image-store.s3.amazonaws.com/0/226500/6feb8811-f264-4972-f960-1d6977b3ba14.png)

# DialogflowのIntegrationを有効にする
google assistantの項目をClickして使用するIntentsを設定していく
![スクリーンショット 2017-12-26 12.58.11.png](https://qiita-image-store.s3.amazonaws.com/0/226500/33663e05-508e-712d-7942-c0020df8e3d6.png)
Explicit invocationには、google homeでアプリを呼び出したときに呼び出されるIntentsを入れるっぽいのでResponseに「こんにちは、オムツの管理です」とだけ入れたIntentsを用意した(いい文言が思いつかなかった)
![スクリーンショット 2017-12-26 13.02.23.png](https://qiita-image-store.s3.amazonaws.com/0/226500/e4732f6d-6eea-5d34-cbb0-52b9b6750fc4.png)




右したのMANAGEMENT ASSISTANT APPをクリックするとAction on Googleに飛ばされる
項目を埋めて「SUBMIT DRAFT FOR REVIEW」を押すとAPPが世界に公開されるはずだが今回は超個人的なものなので公開はしない。
公開する場合は[この記事](https://qiita.com/miso_develop/items/c56fd334f333160a9130)が参考になりそう
テキトウに入力してからSUBMIT DRAFT FOR REVIEW **ではなく「TEST DRAFT」**をクリックする
![スクリーンショット 2017-12-26 12.49.54.png](https://qiita-image-store.s3.amazonaws.com/0/226500/99c04c94-6920-5488-f33f-820618d3938f.png)

シミュレーターが起動するのでテストしてみる
![スクリーンショット 2017-12-26 12.55.50.png](https://qiita-image-store.s3.amazonaws.com/0/226500/958cb069-7a35-ad07-6a1d-0cf0468ef013.png)


スプレッドシートに記録されました！
ヤッタネー！
![スクリーンショット 2017-12-25 9.50.10.png](https://qiita-image-store.s3.amazonaws.com/0/226500/f40ade63-498e-808d-54f1-fa3004bd12e1.png)

Action on Googleでアプリ名を入れておけば、アカウントと紐付いたgoogle homeに向かって「omutukanriにつないで」といえばシミュレーターと同じような挙動になる