Advent Calendar延長戦、今日は「位置情報サービス」の話です。
Alexaで使える位置情報は
- デバイスに登録されているアカウントの住所情報を使う「デバイスアドレスAPI」
- GPS対応デバイスで使用可能な「位置情報サービス」(というか現状Alexaアプリのみ)
の2つがあります。VoiceflowではデバイスアドレスAPIには以前から対応していましたが、今回、位置情報サービスにも対応しました!ということで早速試してみたいと思います。
全体像
まず全体像はこんな感じです。何気に多いですねぇ。Flow Blockでうまくまとめておけば使いまわしもできそうですが、とりあえず。
順に説明していきます。
変数の作成
以下の通り、変数を作成します。プロジェクト変数でも良いですが、フロー変数を使いました。
各変数の意味は以下です。
変数名 |
内容 |
hasGeolocation |
位置情報サービスが使えるデバイスかどうかのチェック結果を保存します |
location |
維持情報サービスが使える場合は、JSONオブジェクトで位置情報が返ってきますので、それを保存します |
lat |
位置情報が含まれているJSONオブジェクトから緯度を取り出して保存します |
lon |
位置情報が含まれているJSONオブジェクトから経度を取り出して保存します |
スキル起動時のメッセージ
ここは難しくないですね。
位置情報サービスが使えるデバイスかどうかをチェックする
まず、Code Blockで位置情報サービスが使えるデバイスかどうかをチェックするための情報を取得します。現時点ではスマホのAlexaアプリだけで、それ以外のデバイスでは位置情報が利用できませんので、この判定を行うわけです。
以下にコードを記載します。
if (voiceflow.capabilities && ('Geolocation' in voiceflow.capabilities)) {
hasGeolocation = 1;
} else {
hasGeolocation = 0;
}
以前に画面付きデバイスの判定をやったのを覚えていますか?
基本的にやっていることは同じで、voiceflow.capabilities
というオブジェクトの中に、位置情報サービス対応デバイスの場合はGeolocation
というオブジェクトが入ってくるのでこれが存在するかどうかをチェックし、存在する=位置情報が使えるデバイスの場合はhasGeolocation
を1にします。
そして、If Blockでそれを判定します。
位置情報サービスが使えないデバイスの場合は、ここでスキルを終了させてしまいます。
位置情報サービスへのアクセス権のチェック
位置情報サービスが使えるデバイスであることが確認できたら、次はアクセス権のチェックです。位置情報サービスはユーザのアクセス許可がないとスキルからは利用ができません。そこでUser Info Blockを使って位置情報の取得を行ってみて、NGならアクセス許可をカードで促すということになります。
User Info Blockの設定に"Location Service"が選べるようになっていますね!これが位置情報になります。これが取得できれば、アクセス権が許可され、かつ、位置情報を含んだJSONオブジェクトが変数locationに入るというわけです。
取得できない場合はfailに流れますので、アクセス権を許可することを発話で促すとともに、
Permission Blockで、Location Serviceへのアクセス許可をカードで送信します。
返ってきた位置情報オブジェクトの処理
位置情報対応デバイスであることも確認した、位置情報へのアクセス権も許可されている、じゃあ位置情報取れているはず!と思いきや、それでも取れない場合がいくつかあります。例えばそもそもスマホ側でAlexaアプリに位置情報の取得を許可していない場合、などですね。そこで念のためにIf Blockでlocation変数の中にデータが入っているかを確認します。undefinedになっている場合は位置情報は空っぽということになるので、エラーでスキルを終わらせます。
しかし、以前は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を使います。
コードはこんな感じです。
lat = Number(location.coordinate.latitudeInDegrees).toFixed(6);
lon = Number(location.coordinate.longitudeInDegrees).toFixed(6);
位置情報サービスで取得できる緯度経度は結構細かく返ってくるので、それぞれ数値化して適当に小数点以下を丸めてあります。GPSなのでそもそもそんなに精度高くないと思いますし。
最後にこれをSpeak Blockで話させればOKです。
なお、位置情報のテストはAlexa開発者コンソールではできずスマホのAlexaアプリから行う必要がありますので、今回はテストは割愛します。
スマホのAlexaアプリ、あまり使われていないかもしれませんが、位置情報サービスを使うとユーザに対してリアルタイムな位置情報に基づいたカスタマイズ性の高いスキルが作れると思います。位置情報を活用したサービスやAPIなども多数ありますので、組み合わせて使ってみてはいかがでしょうか?
あと、今回のような単純な緯度経度だけならそれほど問題にはならないと思いますが、車や電車などで移動している最中の位置情報は鮮度も精度も下がったりすることが考えられますし、デバイスによって取れるもの・取れないものなどもあるようです。このあたりについては一度ドキュメントを読むことをおすすめします。
また、今回もCommunity MarketplaceにアップされているNicolasさんのデモを参考にさせていただきました。いつもありがとうございます!Thanks, Always, Nico!!!
https://airtable.com/shr36HKRwmglhZ5Lr/tblpYysnQuzqzmL0f?blocks=hide