GoogleHomeに潮汐情報をしゃべらせるようにして満足はしていたのですが、使っていると面倒なことも出てくるもので・・・
大きくは二つです
・明日の名古屋は?ときいても、2017年11月10日の・・・みたいに言われて長い。
・そもそも、今いるところに近いところの情報が聞きたいわけで、名古屋は?とか面倒。
一つ目は、「明日の」と聞いているので、そのまま「明日の」としゃべってもらえればよいです。リクエストのJSONを見てみると
["result"]=> object(stdClass)#15 (10) { ["source"]=> string(5) "agent" ["resolvedQuery"]=> string(27) "明日の名古屋の潮は" ["speech"]=> string(0) "" ["action"]=> string(9) "calc_tide" ["actionIncomplete"]=> bool(false) ["parameters"]=> object(stdClass)#16 (2) { ["date"]=> string(10) "2017-11-10" ["geocity"]=> string(9) "名古屋" } ["contexts"]=> array(3) { [0]=> object(stdClass)#17 (3) { ["name"]=> string(32) "actions_capability_screen_output" ["parameters"]=> object(stdClass)#18 (4) { ["date"]=> string(10) "2017-11-10" ["date.original"]=> string(6) "明日" ["geocity.original"]=> string(9) "名古屋" ["geocity"]=> string(9) "名古屋" } ["lifespan"]=> int(0) }
result->contexts[0]->parameters->date.originalに情報があるので、それが使えそうです。収集してそれを出すように変えます。
if($action == "calc_tide") { $date = $json->result->parameters->date; list($year, $month, $day) = split("-", $date); $portName = $json->result->parameters->geocity; $dateStr = $json->result->contexts[0]->parameters->{'date.original'}; $message = createTideMessage($year, $month, $day, $dateStr, $portName); speak($message); }
これは簡単ですね。
次に、位置情報です。位置情報はFirebaseを使う場合のサンプルはあるのですが、JSONを自分で触る時の情報は全然ないのですよね・・・
まず、Default Welcome IntentをWebHookを使うようにします。Defaukl Welcome Intentは、プログラム側で受ける場合には、input.welcomというアクションになるのですが、これで緯度経度を取得したいという権限がほしいというJSONを返すようにします。
if($action == "calc_tide") { $date = $json->result->parameters->date; list($year, $month, $day) = split("-", $date); $portName = $json->result->parameters->geocity; $dateStr = $json->result->contexts[0]->parameters->{'date.original'}; $message = createTideMessage($year, $month, $day, $dateStr, $portName); speak($message); } else if($action == "input.welcome") { echo ' { "speech": "PLACEHOLDER_FOR_PERMISSION", "data": { "google": { "expectUserResponse": true, "isSsml": false, "noInputPrompts": [], "systemIntent": { "intent": "actions.intent.PERMISSION", "data": { "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec", "optContext": "近くの港を検索するため", "permissions": [ "DEVICE_PRECISE_LOCATION" ] } } } } } '; }
返すJSONについては、この辺りが詳しいです。
今回は緯度経度だけなので、DEVICE_PRECISE_LOCATIONを指定していますが、NAMEを指定すると名前が、DEVICE_COARSE_LOCATIONを指定すると住所が取得できます。
これで、Google Assistantに接続したときに、情報を取得してよいか?というメッセージが表示されます。
IntentでDefault Welcome IntentのFollowUp Intentを作ります。このFollowUp Intentで、情報取得してよいか?の結果を受け取ります。Default Wlecome Intentの右の方にカーソルを持っていくと、Add follow-up intentというのが表示されますので、それをクリックします。
クリックするとメニューが表示されますので、fallbackを選択します。
中を変更する必要はありません。必要であれば、WebHookを呼んでサーバ側に登録するというのもありかもしれません。
次に、内部的には、actions_intent_PERMISSION上記の結果を受けるIntentを追加します。
Eventsにactions_intent_PERMISSIONというイベントを追加します。
これにもWebhookを追加しておきます。
このイベントは、action名を、set_locationとしておくことにします。
これで、接続(action:input.welcome) →パーミッション取得 → パーミッション取得イベント(action: set_location)という流れができました。
PHP側にもコードを追加します。
if($action == "calc_tide") { $date = $json->result->parameters->date; list($year, $month, $day) = split("-", $date); $portName = $json->result->parameters->geocity; $dateStr = $json->result->contexts[0]->parameters->{'date.original'}; $message = createTideMessage($year, $month, $day, $dateStr, $portName); speak($message); } else if($action == "input.welcome") { echo ' { "speech": "PLACEHOLDER_FOR_PERMISSION", "data": { "google": { "expectUserResponse": true, "isSsml": false, "noInputPrompts": [], "systemIntent": { "intent": "actions.intent.PERMISSION", "data": { "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec", "optContext": "近くの港を検索するため", "permissions": [ "DEVICE_PRECISE_LOCATION" ] } } } } } '; } else if($action == "set_location") { $tide = new tide_base(); if(isset($json->originalRequest->data->device)) { $lat = $json->originalRequest->data->device->location->coordinates->latitude; $lng = $json->originalRequest->data->device->location->coordinates->longitude; $nearPort = $tide->getNearPort($lat, $lng); $nearPortAll = $tide->getNearPortAll($lat, $lng); $port = $tide->minatoAll; $nearPortName = $port[$nearPort][0]; $nearPortNameAll = $port[$nearPortAll][0]; if($nearPort == $nearPortAll) { $message = "一番近い港は" . $nearPortName . "です。"; $message = createTideMessage($year, $month, $day, "今日", $nearPortName); } else { $message = "一番近い港は" . $nearPortNameAll . "ですが主要4分潮の計算しかできません。60分潮>の計算ができる一番近い港は" . $nearPort + "です。"; $message = createTideMessage($year, $month, $day, "今日", $nearPortNameAll); } } else { $message = "登録なしで進めます。"; } speak($message); }
さてテストしてみましょう。
沓形ってどこ?
画面上小さくなっているため見えないのですが、デフォルトではシミュレーターの場所が、MountainViewになっていますね。右上のLocationで変更してやります。
ちなみに、MountainViewからだと、沓形が一番近いのかな?
場所を東京にして見ます。
いい感じにできました!