#目的
都内の移動に便利なドコモ・バイクシェアのヘビーユーザーなのだけど、ユーザー数増加につれて、ポート(駐輪場)に行っても品切れで借りられない状態が増えてきた。特に朝は競争率が高い。
ポートに自転車があるのとないので、玄関を出たあと右に曲がるか左に曲がるかが違ってくるので、朝、家を出る前に自転車の残りの台数を把握したい。それもさくっと。
#現状
公式スマホアプリからのみ、リアルタイムで残りの台数を確認可能。
アプリ起動→現在地取得→地図から最寄りのポートを選択→台数が表示される…という流れ。
外出先などで最寄りのポートを探すときはとても便利なアプリなのだけど、自宅の最寄りなどいつも決まったポートを調べるには若干手間がかかる。
特に朝バタバタしてるときは、このちょっとした操作も煩わしかったりする。
#やったこと
Google Homeから残りの自転車の台数を調べられるようにした。
これで朝仕度をしながら「ねぇグーグル」とすれば、最寄りのポートに、今残り何台あるのかを教えてくれる。0台なら玄関を出て右に曲がり駅に向かう。
#手順
-
Charlesを使って、公式アプリのリクエスト内容をキャプチャ
-
キャプチャした内容をもとに、アプリの代わりにサーバーからリクエストして、レスポンスを取得できるようにする
-
Google HomeからWebhookでサーバーのデータを取得
##1. 通信内容をキャプチャ
Charlesを使うと、自分のPCやスマホがどういった通信をしているかをキャプチャできる。
スマホアプリの通信内容のキャプチャについて、詳しい使い方は以下を参考にした。
【Charles】アプリの通信をキャプチャする
※自分の環境は、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。
また、今回必要な情報は、「残り台数(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からサーバーにアクセスして結果を喋らせる
この記事の「下準備:サーバーを用意する」が、上で書いたバイクシェアにアクセスするPHPとなる。
あとは、Webhookに設定するURLをこのPHPの場所にして、トリガーとなるワードや、Google アシスタントアプリの名前を埋めていけば完成。
#自分向けアシスタントアプリをつくるときの考え方(感想)
ちゃんと一般公開を想定するアプリだとしたら、
「渋谷駅前ポートの、残りの自転車の台数を教えて」
と、内容が明確なコマンドにしたほうがよいし、
ポートの名前をパラメータ化したほうが汎用性があるだろう。
ただ、せっかく自分だけのアシスタントを作るのであれば、そこは、「あ」といえば「うん」みたいな、「あのときのあいつのあれがあれでさー」で会話が通じてしまうような、そんな関係でいてほしい。
今回でいえば、ポート自体は沢山あるけど、「朝、自分が知りたいポート」は常にひとつなので、「自転車ー?」と言うだけで、「今10台あいてるよー!」と直で返ってくるほうが、家の中の会話としては自然。
なので、ホームアシスタントデバイスで自分専用アプリをつくるときには、「いろんなパラメーターを処理できるフレキシブルなAPI」とは対照的な、「自分にしかわからない1対1対応のショートカットコマンド」をひたすら増やしていく考え方が向いているのかな、という感想。
以上