Geolocation を使うAlexaスキルを作ってみた


2019年4月6日に神戸で行われたAlexa Day2019、その中の「神戸スキルコンテスト」に出撃して、[玉砕してきました。](https://note.mu/sitopp/n/nbe644084ad41)この記事では、スキルを作る時に気づいたTipsを書いていきます。

ストア申請してないので、この形で一般公開できるかはわかりません。
もしリリースできたらGeolocation使用国内初になるのかな。。いやまさか。
まだまだ申請できるとこまで作れてないので、もし出せたらまたエントリ書きます。

### 参考にさせていただいた記事

スキルを手探りでつくってる時に、大変参考にさせていただきました！(^o^) ありがとうございます！


Alexaから位置情報を取得可能になったので試してみた
https://alexa.wp-kyoto.net/archives/1364/

[Alexa] 位置情報サービスを使ってスキルからモバイルデバイスの位置情報を取得する
https://dev.classmethod.jp/voice-assistant/amazon-alexa/get-geo-location-using-location-services/



# スキル概要

![スクリーンショット 2019-05-02 21.00.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173392/ccc323d5-37dc-59bc-7007-515bfaf8af1f.png)
（Lambda関数のランタイム：Node.js8.0）

- **スマホのAlexaアプリ**(注1)でスキルを起動すると、Lambdaにrequestが飛んでくる。
- このrequestに緯度経度(Geolocation)が入っている。
- Lambda関数の中から「ぐるなびAPI」を呼び、付近のお店を検索する。
- ページネーションのために必要な部分をセッションIDと紐づけてDynamoDBに書く。
- アレクサスキルに結果を返却して、読み上げてもらう。

(注1)
スマホのAlexaアプリというのは、Echo Dotなどの画面なし端末をセットアップする時に必須だったアレです。
iOS：https://itunes.apple.com/jp/app/amazon-alexa/id944011620?mt=8
Android：https://play.google.com/store/apps/details?id=com.amazon.dee.app&hl=ja
Echo Spotなど画面付き端末では、こやつらを使わなくてもAlexaが使えるので、存在を知らない人もいるようですが。。(^^;)

# Tips

## その１. パーミションや動作環境について

### Alexaスキルの「アクセス権限」の設定


Alexa Developer consoleで該当Alexaスキルの「位置情報サービス」を有効にしておくこと。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173392/8244ad79-dc19-a810-1988-740c6687f7a0.png">


### ユーザーパーミション

該当Alexaスキルを「有効」にするとき、位置情報サービスをOnにしてもらわないと、Geolocationはとれません。


<img width="200" alt="IMG_3116.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173392/9ff02981-38af-7b84-018b-b683347168ad.png">

### 機種判別
Geolocationが取得できるかどうか、試してみたところ、以下のようになりました。

- Echo dot：取得NG
- Echo Show：取得NG
- Echo input：取得NG
- iOS/AndroidのAlexaアプリ：取得OK

そこで、このスキルの起動時に、機種判別のようなものをする必要があります。
しかし対応機種が明確に公開されてないのと、ユーザーエージェント(?)の取り方がよくわからないので、LaunchRequestHandlerでレスポンスに入ってくるかどうかで判別をしました。

```index.js 
const Alexa = require('ask-sdk');

//中略

  //LaunchRequestHandlerの中
  if ('Geolocation' in handlerInput.requestEnvelope.context) {
    var speechText = 'Alexaアプリの緯度経度を使い、近くのお店を検索します。和食、洋食、中華、スイーツ、のどれにしますか？';
    var withShouldEndSession = false;
  } else {
    var speechText = 'このスキルは、現在地の位置情報を使うため、スマホのAlexaアプリから起動する必要があります。お使いのデバイスでは対応しておりません。ご了承ください。'
    var withShouldEndSession = true;
  }
  return handlerInput.responseBuilder
    .speak(speechText)
    .reprompt(speechText)
    .withShouldEndSession(withShouldEndSession)
    .getResponse();


```

## その2. Geolocationの取り方について

### requestのjsonからとれます

handlerInput.requestEnvelope.context の中に格納されています。

```index.js

const Alexa = require('ask-sdk');
//中略

  //それぞれのIntentHandlerの中
  if ('Geolocation' in handlerInput.requestEnvelope.context) {
    //緯度
    var lat = handlerInput.requestEnvelope.context.Geolocation.coordinate.latitudeInDegrees;
    //経度
  　var long = handlerInput.requestEnvelope.context.Geolocation.coordinate.longitudeInDegrees;
  }
```


### 取得できるGeolocationの中身

現在地の緯度経度、高度、方向、移動スピードが取得できます。
以下はスキルのRequestの抜粋です。
気になる精度ですが、私のiPhone6では充分に**自宅の住所を検出しちゃってた**のでフェイクにしてます。


```json
    "Geolocation": {
      "timestamp": "2019-05-01T10:07:04Z",
      "coordinate": {
        "latitudeInDegrees": 35.1234567(フェイク。実際は小数点以下14桁),
        "longitudeInDegrees": 139.1234567(フェイク。実際は小数点以下14桁),
        "accuracyInMeters": 10
      },
      "altitude": {
        "altitudeInMeters": 28.1234567(フェイク。実際は小数点以下15桁),
        "accuracyInMeters": 10
      },
      "heading": {
        "directionInDegrees": 172.59243774414062
      },
      "speed": {
        "speedInMetersPerSecond": 1
      }
    }
```


なおGoogleMapも採用している10進数表記の緯度経度の場合、小数点以下四桁で10m、五桁で1m単位の精度となります。
それなのに、14桁って。。
スマホのOSは、まだこんな精度で位置情報を出せませんので、アマゾンさんの計算の都合で生じちゃったのだと思います。

なおaccuracyInMetersという値が「10」になってるので、いくら小数点以下14桁の緯度経度を出していても、東西南北どっちかに10m以内でずれてるやで、という意味になります。

### バッテリー消費量について

ところで、「accuracyInMeters」の「10」という値は、
iOSのdesiredAccuracyを"kCLLocationAccuracyNearestTenMeters"に指定した時の値と同じですね。偶然ではないでしょう。
10mだとすると、iOSの最高精度ではないにしても5段階中2番目ですので精度は高いほうです。

desiredAccuracy：
　kCLLocationAccuracyBest：最高精度
　kCLLocationAccuracyNearestTenMeters：10ｍ
　kCLLocationAccuracyHundredMeters：100ｍ
　kCLLocationAccuracyKilometer：1ｋｍ
　kCLLocationAccuracyThreeKilometers：3ｋｍ

iOSの人は、Alexaアプリの位置情報設定をオンにするときは、「アプリを使用中のみ」にして置くのが良いかもしれませんね。。


## その3.ぐるなびAPIについて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173392/8498529c-01da-d13a-e168-9402c4519665.png)

[APIの仕様書](https://api.gnavi.co.jp/api/)はこちら。
無料です。
ぐるなびさん太っ腹(^o^)！

自分は[「レストラン検索API」](https://api.gnavi.co.jp/api/manual/restsearch/)を使いました。
緯度経度を指定して呼び出すと、付近のお店を教えてくれます。
飲食店のカテゴリも指定できるので、和食洋食中華スイーツなどと分けました。

当初は「応援口コミAPI」も使って、口コミの点数を平均をだそうかなとしたのですが、Alexa Dayには間に合わず、あとでぽちぽちいじってたところ、ぐるなびの口コミの点数は別サービスと連携してるらしく、webサイトでは口コミの乗ってるどのお店も、返却データには点数がなく。。見送りました。

なお、アカウント作成の申請には1〜2日かかると思います。
[@imajoriri さんが「幹事くん」というLINE Botを作られたという記事](https://note.mu/inasirooo/n/n564cfbda7075)を読み、密かに自分も何かに使いてえなーと思って、開発者アカウントを取得してたので、すぐ使えました。よかったよかった。(^o^)






# おまけ

去年の年末、Alexaアプリに、「location Routines」という機能が追加されました。
日本版のAlexaアプリにはまだ来てないですが、USでは動画をアップしてる方がいらっしゃいました。
https://www.youtube.com/watch?v=o4hAr6M4exg

自宅とか職場のまわりに円形のナワバリを指定して、Alexaアプリの入ったスマホを持ってそこに入ったり出たりした時に、何かを起こすという機能だそうです。たとえば毎週火曜、「家」に着いたら「ゴミを捨てる」というリマインダーをAmazon Echoに送るとか、毎日「家」に帰るとき、Hueをつけるとか。

このlocationは、iOS/AndroidのGeofenceだと思います。IFTTTでも人気のトリガーですね（[私も使ってます(^o^)](https://note.mu/sitopp/n/nd0956bff77dc)）

desiredAccuracyが10だとすると、バッテリー消費量はまぁまぁ高いでしょうから、
ずっと起動しっぱなしだと、バッテリーが心配かも。。
車のバッテリーチャージャーで給電しながら使う、というUXだったら受け入れられる気がします。echo auto早く来ないかなぁ〜。




以上となります！