日別アーカイブ: 2017年11月16日

GoogleHomeで潮汐情報 その7

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からだと、沓形が一番近いのかな?

場所を東京にして見ます。

いい感じにできました!