Google Homeにドコモのバイクシェアの空き状況を確認してもらう

#目的
都内の移動に便利な[ドコモ・バイクシェア](http://www.d-bikeshare.com/)のヘビーユーザーなのだけど、ユーザー数増加につれて、ポート（駐輪場）に行っても品切れで借りられない状態が増えてきた。特に朝は競争率が高い。

ポートに自転車があるのとないので、玄関を出たあと右に曲がるか左に曲がるかが違ってくるので、朝、家を出る前に自転車の残りの台数を把握したい。それもさくっと。

![IMG_20160521_153548.jpg](https://qiita-image-store.s3.amazonaws.com/0/64523/5d9baa14-7e51-4352-9fd2-45046099b031.jpeg)

#現状
[公式スマホアプリ](https://play.google.com/store/apps/details?id=com.d_bikeshare&hl=ja)からのみ、リアルタイムで残りの台数を確認可能。

アプリ起動→現在地取得→地図から最寄りのポートを選択→台数が表示される…という流れ。

外出先などで最寄りのポートを探すときはとても便利なアプリなのだけど、自宅の最寄りなどいつも決まったポートを調べるには若干手間がかかる。

特に朝バタバタしてるときは、このちょっとした操作も煩わしかったりする。



#やったこと
Google Homeから残りの自転車の台数を調べられるようにした。
これで朝仕度をしながら「ねぇグーグル」とすれば、最寄りのポートに、今残り何台あるのかを教えてくれる。0台なら玄関を出て右に曲がり駅に向かう。

#手順

1. [Charles](https://www.charlesproxy.com/)を使って、公式アプリのリクエスト内容をキャプチャ

1. キャプチャした内容をもとに、アプリの代わりにサーバーからリクエストして、レスポンスを取得できるようにする

1. Google HomeからWebhookでサーバーのデータを取得


##1. 通信内容をキャプチャ
[Charles](https://www.charlesproxy.com/)を使うと、自分のPCやスマホがどういった通信をしているかをキャプチャできる。

スマホアプリの通信内容のキャプチャについて、詳しい使い方は以下を参考にした。
[【Charles】アプリの通信をキャプチャする](https://qiita.com/KokiEnomoto/items/7f386352176ce049dffc)
※自分の環境は、Mac + Android

大まかには、
Charlesのインストール
　↓
Charlesのメニューから Proxy -> SSL Proxying Settingsで、「Host： * 」をAdd
　↓
Charlesのメニューから Help > SSL Proxying > Install Charles Root Certificate
　↓
Macのキーチェーンアクセスが自動で開くので、「Charles Proxy CA」をダブルクリック > 「信頼」 > 「この証明書を使用するとき」 > 「常に信頼」を選択
　↓
Mac と スマホを同じWifiにつなぎ、スマホのWifi設定から、「手動」（機種によっては「詳細設定」）で、MacのローカルIPとポート8888に接続。
MacのローカルIPは、「システム環境設定」 > 「ネットワーク」 > 「詳細」 > 「TCP/IP」で確認できる。
　↓
接続後、スマホのブラウザなどでどこでもいいので通信したとき、Charlesの画面に反応があれば成功。

---

この状態で、バイクシェア公式アプリを開き、各ポートの画面を開くと、以下のリクエストがキャプチャできるはず。

※以下、普通にキャプチャできる内容とはいえ、公式にアナウンスされているAPIではないので、念のため一部伏字。もし使用する時は、大量リクエストなど想定外の負荷となる使用方法は避けて、自己責任で。

```
POST /cgi-bin/xxxx/yyyy HTTP/1.1
Content-Type: application/xml; charset=utf-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.0; xxxxx)
Host: tcc.docomo-cycle.jp
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 203

<?xml version="1.0" encoding="UTF-8"?>
<csreq>
<msgtype>3</msgtype>
<aplcode>xxxxxxxxxxxxxxxxxx</aplcode>
<park_id>00000123</park_id>
<get_num>100</get_num>
<get_start_no>1</get_start_no>
</csreq>

```

つまり、
`https://tcc.docomo-cycle.jp/cgi-bin/xxxx/yyyy`
に対して、XMLをPOSTすれば、データを取得できるはず。

XMLにある、park_idタグの数字（ここでは、00000123）が、各ポート固有のIDと思われる。

##2.サーバーからデータを取得する

###データを取得してJSONで返す
以下は、上記のURLに、XMLをPOSTして、レスポンスをJSONで返すPHPサンプル。

```
<?php

function getBikeData () 
{
	$url = "https://tcc.docomo-cycle.jp/xxxx/yyyy";

	$content = array(
		'<?xml version="1.0" encoding="UTF-8"?>',
		'<csreq>',
		'<msgtype>3</msgtype>',
		'<aplcode>xxxxxxxxxxxxxxxxxx</aplcode>',
		'<park_id>00000123</park_id>',
		'<get_num>100</get_num>',
		'<get_start_no>1</get_start_no>',
		'</csreq>',
	);
	$content = implode($content);

	$headers = array(
		'Content-Type: application/xml; charset=utf-8',
		'Content-Length:'.strlen($content),
	);
	$headers = implode("\n", $headers);

	$context = array(
		'http' => array(
			'method'  => 'POST',
			'header'  => $headers,
			'content' => $content,
		)
	);

	return file_get_contents($url, false, stream_context_create($context));
}

$response = getParkData();
$simpleXML = simplexml_load_string($response);
$json = json_encode($simpleXML);

echo($json); 

```
これで、park_idが"00000123"のポートの情報が取得できる。
※ ここで取得できるのはあくまで台数情報が主で、ポートの名前や位置情報などは別DBで管理しているぽい

###JSONをGoogle Homeが読める形にする
次に、レスポンスするJSONのフォーマットを、「Dialogflow」というGoogle Homeで使用する言語解析エンジンに対応した形式にする。
最低限、以下ふたつを記述したJSONを返すのであればなんでもよい様子。
※ 今回は、V1 APIを使用。

```
{
    “speech”: “喋らせたい文章”,
    “displayText”: “画面上で表示させたい文章”
}
```
displayTextは、Googleアシスタントで表示される文章。
詳しくは、[Webhook requirements](https://dialogflow.com/docs/fulfillment)。

また、今回必要な情報は、「残り台数（total_num）」だけなので、シンプルにこの数字だけを返すようにする。

先ほどのPHPの後半部分を少しだけ変更。

```
<?php

function getParkData () {
　　　　...
}

$response = getParkData();
$simpleXML = simplexml_load_string($response);
$totalNum = intval($simpleXML->total_num);

$arr = array(
	'speech' => $totalNum."台、空いています。", 
	'displayText' => $totalNum."台、空いています。"
);
echo json_encode($arr);

```

このPHPを適当なサーバーにおいて、無事レスポンスを確認できたら、Google Homeの作業へ。

##3. Google Homeの設定

Google Homeでは、「Actions on Google」と「Dialog Flow」を使えば、デフォルトで対応している以外の会話もできるようになる。

詳しい手順は、別で書いた。
[Google Homeからサーバーにアクセスして結果を喋らせる](https://qiita.com/YuYuYuYoYoYo/items/57d2e85ab42cce40d67a)

この記事の「下準備：サーバーを用意する」が、上で書いたバイクシェアにアクセスするPHPとなる。

あとは、Webhookに設定するURLをこのPHPの場所にして、トリガーとなるワードや、Google アシスタントアプリの名前を埋めていけば完成。

<img width="351" alt="スクリーンショット 2018-02-25 19.22.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/64523/9548c6d3-5319-1b13-da99-e91b4756d670.png">


#自分向けアシスタントアプリをつくるときの考え方（感想）
ちゃんと一般公開を想定するアプリだとしたら、
「渋谷駅前ポートの、残りの自転車の台数を教えて」
と、内容が明確なコマンドにしたほうがよいし、
ポートの名前をパラメータ化したほうが汎用性があるだろう。

ただ、せっかく自分だけのアシスタントを作るのであれば、そこは、「あ」といえば「うん」みたいな、「あのときのあいつのあれがあれでさー」で会話が通じてしまうような、そんな関係でいてほしい。

今回でいえば、ポート自体は沢山あるけど、「朝、自分が知りたいポート」は常にひとつなので、「自転車ー？」と言うだけで、「今10台あいてるよー！」と直で返ってくるほうが、家の中の会話としては自然。

なので、ホームアシスタントデバイスで自分専用アプリをつくるときには、「いろんなパラメーターを処理できるフレキシブルなAPI」とは対照的な、「自分にしかわからない1対1対応のショートカットコマンド」をひたすら増やしていく考え方が向いているのかな、という感想。


以上