kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

Voiceflow TIPS #37 位置情報サービスを使う

Advent Calendar延長戦、今日は「位置情報サービス」の話です。

Alexaで使える位置情報は

  • バイスに登録されているアカウントの住所情報を使う「デバイスアドレスAPI
  • GPS対応デバイスで使用可能な「位置情報サービス」(というか現状Alexaアプリのみ)

の2つがあります。VoiceflowではデバイスアドレスAPIには以前から対応していましたが、今回、位置情報サービスにも対応しました!ということで早速試してみたいと思います。

全体像

まず全体像はこんな感じです。何気に多いですねぇ。Flow Blockでうまくまとめておけば使いまわしもできそうですが、とりあえず。

f:id:kun432:20191129235521p:plain

順に説明していきます。

変数の作成

以下の通り、変数を作成します。プロジェクト変数でも良いですが、フロー変数を使いました。

f:id:kun432:20191130000530p:plain

各変数の意味は以下です。

変数名 内容
hasGeolocation 位置情報サービスが使えるデバイスかどうかのチェック結果を保存します
location 維持情報サービスが使える場合は、JSONオブジェクトで位置情報が返ってきますので、それを保存します
lat 位置情報が含まれているJSONオブジェクトから緯度を取り出して保存します
lon 位置情報が含まれているJSONオブジェクトから経度を取り出して保存します

スキル起動時のメッセージ

ここは難しくないですね。

f:id:kun432:20191130001130p:plain

位置情報サービスが使えるデバイスかどうかをチェックする

まず、Code Blockで位置情報サービスが使えるデバイスかどうかをチェックするための情報を取得します。現時点ではスマホのAlexaアプリだけで、それ以外のデバイスでは位置情報が利用できませんので、この判定を行うわけです。

f:id:kun432:20191130001347p:plain

以下にコードを記載します。

if (voiceflow.capabilities && ('Geolocation' in voiceflow.capabilities)) {
  hasGeolocation = 1;
} else {
  hasGeolocation = 0;
}

以前に画面付きデバイスの判定をやったのを覚えていますか?

基本的にやっていることは同じで、voiceflow.capabilitiesというオブジェクトの中に、位置情報サービス対応デバイスの場合はGeolocationというオブジェクトが入ってくるのでこれが存在するかどうかをチェックし、存在する=位置情報が使えるデバイスの場合はhasGeolocationを1にします。

そして、If Blockでそれを判定します。

f:id:kun432:20191130001838p:plain

位置情報サービスが使えないデバイスの場合は、ここでスキルを終了させてしまいます。

f:id:kun432:20191130002053p:plain

位置情報サービスへのアクセス権のチェック

位置情報サービスが使えるデバイスであることが確認できたら、次はアクセス権のチェックです。位置情報サービスはユーザのアクセス許可がないとスキルからは利用ができません。そこでUser Info Blockを使って位置情報の取得を行ってみて、NGならアクセス許可をカードで促すということになります。

User Info Blockの設定に"Location Service"が選べるようになっていますね!これが位置情報になります。これが取得できれば、アクセス権が許可され、かつ、位置情報を含んだJSONオブジェクトが変数locationに入るというわけです。

f:id:kun432:20191130002416p:plain

取得できない場合はfailに流れますので、アクセス権を許可することを発話で促すとともに、

f:id:kun432:20191130002841p:plain

Permission Blockで、Location Serviceへのアクセス許可をカードで送信します。

f:id:kun432:20191130002930p:plain

返ってきた位置情報オブジェクトの処理

位置情報対応デバイスであることも確認した、位置情報へのアクセス権も許可されている、じゃあ位置情報取れているはず!と思いきや、それでも取れない場合がいくつかあります。例えばそもそもスマホ側でAlexaアプリに位置情報の取得を許可していない場合、などですね。そこで念のためにIf Blockでlocation変数の中にデータが入っているかを確認します。undefinedになっている場合は位置情報は空っぽということになるので、エラーでスキルを終わらせます。

f:id:kun432:20191130004022p:plain

f:id:kun432:20191130004036p:plain

しかし、以前はnullとかundefinedとかのチェックはIf Blockでこんな書き方ではできなかったと思うんですが、ちょっと変更されたのかもしれませんね。

それはさておき、これで位置情報データは正しく取れました。ちなみに位置情報データ配下のようなJSONオブジェクトになっています。

{
    "location":{
        "locationServices":{
            "status":"RUNNING",
            "access":"ENABLED"
        },
        "timestamp":"2019-11-29T12:29:42Z",
        "coordinate":{
            "latitudeInDegrees":34.6826XXXXXXXXXX,
            "longitudeInDegrees":135.1867XXXXXXXXX,
            "accuracyInMeters":10
        },
        "altitude":{
            "altitudeInMeters":8.5653XXXXXXXXXXX,
            "accuracyInMeters":10
        },
        "speed":{
            "speedInMetersPerSecond":1
        }
    }
}

各オブジェクトの詳細はドキュメントを見ていただくとして、シンプルに緯度と経度を取るならば、

  • location.coordinate.latitudeInDegrees が緯度
  • location.coordinate.longtitudeInDegrees が経度

になるので、この値だけを取得すればOKです。Code Blockを使います。

f:id:kun432:20191130005506p:plain

コードはこんな感じです。

lat = Number(location.coordinate.latitudeInDegrees).toFixed(6);
lon = Number(location.coordinate.longitudeInDegrees).toFixed(6);

位置情報サービスで取得できる緯度経度は結構細かく返ってくるので、それぞれ数値化して適当に小数点以下を丸めてあります。GPSなのでそもそもそんなに精度高くないと思いますし。

最後にこれをSpeak Blockで話させればOKです。

f:id:kun432:20191130010041p:plain

なお、位置情報のテストはAlexa開発者コンソールではできずスマホのAlexaアプリから行う必要がありますので、今回はテストは割愛します。


スマホのAlexaアプリ、あまり使われていないかもしれませんが、位置情報サービスを使うとユーザに対してリアルタイムな位置情報に基づいたカスタマイズ性の高いスキルが作れると思います。位置情報を活用したサービスやAPIなども多数ありますので、組み合わせて使ってみてはいかがでしょうか?

あと、今回のような単純な緯度経度だけならそれほど問題にはならないと思いますが、車や電車などで移動している最中の位置情報は鮮度も精度も下がったりすることが考えられますし、デバイスによって取れるもの・取れないものなどもあるようです。このあたりについては一度ドキュメントを読むことをおすすめします。

また、今回もCommunity MarketplaceにアップされているNicolasさんのデモを参考にさせていただきました。いつもありがとうございます!Thanks, Always, Nico!!!

https://airtable.com/shr36HKRwmglhZ5Lr/tblpYysnQuzqzmL0f?blocks=hide