SORACOM LTE-M Button for Enterpriseで位置情報を取得してみた

SORACOM LTE-M Button for Enterpriseで位置情報が取得できるようになったので早速使ってみました
まずはSORACOMユーザーコンソールからSORACOM LTE-M Button for Enterpriseを発注
見た目はシールの貼ってないLTE-M Button powered by AWSですね...

#1. SIMグループ
SIMグループを適当に作成して、そのグループにButtonを所属させます
![sora1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/ff8858a8-b02c-96ad-b2f9-5f329c10a6d2.jpeg)

#2. 簡易位置測位機能を使うための設定
SIMグループの基本設定から、SORACOM Air for Cellular設定を開いて簡易位置測位機能をONにします
![sora2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/daf2f728-bf45-cda0-d17f-07d939e6eb02.jpeg)

さらにバイナリパーサー機能を有効化し、フォーマットに@buttonと入力しておきます
![sora5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/b4638a55-4786-90f7-b45a-4bf406287277.jpeg)

SORACOM HervestをONにします
この状態でボタンを押すとHervestにデータが登録されます
Hervestで見ると↓のような感じでデータが登録されてました

|データ|一次処理済みデータ|
|---|---|
|{"clickType":2,"clickTypeName":"DOUBLE","batteryLevel":1,"binaryParserEnabled":true}|{"clickType":2,"clickTypeName":"DOUBLE","batteryLevel":1,"binaryParserEnabled":true,"$metadata":{"locationQueryResult":"success","location":{"lat":35.980014321805754,"lon":139.75467681884766}}}|

#3. SORACOM FUNKの設定
SIMグループの基本設定からSORACOM FunkをONにしてみます
AWS Lambdaにデータが飛ぶように↓のように設定してみました
![sora3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/fca2157e-8d4d-4c53-99a7-ae57f3f60370.jpeg)

認証情報はプルダウンメニューから新規作成で作成します
![sora4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/52946fe9-de8f-5bcb-8175-80e4da644e52.jpeg)

関数のARNにはFunkから呼び出したいAWS LambdaのARNを入力します
Lambda関数を作成するとAPNが表示されるので、その値をコピーして入力します

Lambdaで以下のようなコードを書いてみました

```python
from __future__ import print_function
import boto3
import os
import json
import logging
import dateutil.parser
from datetime import datetime, timedelta
import xml.etree.ElementTree as ET
import urllib.request

logger = logging.getLogger()
logger.setLevel(logging.INFO)
ses = boto3.client('ses')
from_address = "送信元のメールアドレス"
to_address = []
to_address.append("送信先メールアドレス")

def lambda_handler(event, context):
    # Hervestのデータに相当する部分はeventに入ってるようです
    clickType = event["clickTypeName"]
    batteryLevel = event["batteryLevel"]
    # 位置情報を含めた細かい値はcontext.client_context.customに入るみたいです
    lat = context.client_context.custom["location"]["lat"]
    lon = context.client_context.custom["location"]["lon"]
    imsi = context.client_context.custom['imsi']

    # 取得した位置情報をyahoo Mapに渡して該当する場所を取得してみました
    apiUrl = 'https://map.yahooapis.jp/geoapi/V1/reverseGeoCoder?lat=' + str(lat) + '&lon=' + str(lon) + '&appid=' + os.environ['yahooMapApi']
    response = urllib.request.Request(apiUrl)
    with urllib.request.urlopen(response) as res:
        data = res.read()
    root = ET.fromstring(data)
    titl = root[1][0][1].text
    # googleマップ用のURLも生成してみました
    mapUrl = 'http://maps.google.co.jp/maps?q=' + str(lat) + ',' + str(lon)
    body = "\n" + titl + " にいます\n" + mapUrl

    # ボタンから送られるデータには時刻情報がないみたいなのでLambda実行時の時間を使っています
    ts = datetime.now() + timedelta(hours=9)
    ts = ts.strftime('%Y/%m/%d %H:%M:%S')
    
    # clickTypeによって処理の条件わけができます
    if (clickType == 'SINGLE'):
        subject = 'SINGLE'
        body = str(ts) + body
    elif (clickType == 'DOUBLE'):
        subject = 'DOUBLE'
        body = str(ts) + body
    elif (clickType == 'LONG'):
        subject = 'LONG'
        body = str(ts) + body
    else:
        subject = 'failed'
        body = 'failed'

    # 例えばSES経由で位置情報を送信できます
    ses.send_email(Source=from_address,
        Destination={'ToAddresses': to_address},
        Message={'Subject': {'Data': subject}, 'Body': {'Text': {'Data': body}}})
```

確認用にスマホのGPSの位置情報と比較してみました
携帯基地局の多い場所ならそれほど大きなズレはなさそうな気がします
簡易的ですがGPS無しで大まかな位置がわかるので便利だと思います

|場所|スマホ(moto g7 power)のGPSデータ|ボタンの簡易位置測位機能のデータ|
|---|----------------------|--------------------------|
|春日部駅|35.9801048556836,<br>139.7520915232467|35.980014321805754,<br>139.75467681884766|