GPSマルチユニットSORACOM Editionと簡易位置情報

# これは

GPSマルチユニットSORACOM EditionとSORACOM Air/特定地域向け IoT SIM (plan-KM1) を組み合わせて使ってみて気がついたことをまとめました。

# GPSマルチユニットSORACOM Editionとは

[GPSマルチユニットSORACOM Edition](https://dev.soracom.io/jp/gps_multiunit/what-is-gps_multiunit/)は、(株)ソラコムが販売している、GPS/温度/湿度/加速度を計測する4つのセンサーとバッテリーを内蔵しているガジェットです。

SORACOM Air(plan-D、plan-KM1)のSIMを挿すことでSORACOMのサービスと連携し、非常に簡単にデータを取得することができます。

2020年3月の発売以来各地で絶賛されていたので気にはなっていたものの、多忙でなかなか入手する機会に恵まれず、ようやく5月のキャンペーン期間に特価で購入して試すことが出来ました。

# WFHとGPSと私

2020年5月26日にオンラインで開催された[SORACOM UG Tokyo Online #15](https://soracomug-tokyo.connpass.com/event/174374/)に参加し、[max](https://qiita.com/ma2shita)の発表を聞きながらその内容に従って開封したGPSマルチユニットに同封のSIM(plan-D)を挿し、手順通りサクサクとSIMグループとデバイスの設定をしていきます。

なるほど、クラウド側で行ったデバイスの設定をデバイスに同期させるのは[SORACOM Air メタデータサービス](https://dev.soracom.io/jp/start/metadata/)で実装してるのね～などとあれこれ見つつ発表を聞いているうちに、無事Harvestでデータが確認できました。

![gpsmultiunit-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59415/9368881a-5ce7-6e25-361c-fc2a2ded197f.png)

しかし、ここで気がつきました。

**・・・あれ、GPS情報取れてないよね？**

実際のpayloadを見ても、latとlonがnullになってます。

```json
{"value":"{\"lat\":null,\"lon\":null,\"bat\":-1,\"rs\":4,\"temp\":36.1,\"humi\":35.6,\"x\":64.0,\"y\":64.0,\"z\":-960.0,\"type\":0}"}
```

おりしも先日からの非常事態宣言とWFH(Work From Home)の流れでユーザグループのイベントもオンライン開催になり、今日は家の中から参加中。室内からではGPSの衛星を見つけられず情報が取得できないのも仕方ないところです。

とはいえ、じゃあWFHが続く限りGPSマルチユニットの面白さは半減(位置情報が面白さの半分かと言われるとアレですが)？もしくは室内設置では位置情報は絶望的？

ちょうどそのタイミングで聞いていたUGの発表でこの「室内だとGPS拾えない」という話が出たのですが、それを受けてMaxがこんなツイートをしました。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">plan-KM1を使うと、、、ふふふ (簡易位置測位機能が！) <a href="https://twitter.com/hashtag/soracomug?src=hash&amp;ref_src=twsrc%5Etfw">#soracomug</a> <a href="https://t.co/PZUfiM65Y4">https://t.co/PZUfiM65Y4</a></p>&mdash; 松下享平 《IoTの事例や技術を紹介》(Max@ソラコム) (@ma2shita) <a href="https://twitter.com/ma2shita/status/1265227901537931269?ref_src=twsrc%5Etfw">May 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

言われてみれば確かに！これは是非やってみねば！

・・というのが今回の記事の趣旨です(話が長い)

# 簡易位置測位機能

[簡易位置測位機能](https://dev.soracom.io/jp/docs/location_service/)は、SIMの通信時に使った基地局の位置を用いておおよその位置情報を取得する機能です。使い方は簡単で、コンソールの「SIMグループ設定」→「SORACOM Air」から該当の機能をONにするだけです。

これだけでBeam/Funnel/Funkなどで連携する際に簡易位置情報が渡るようになります。

ただし、これはSORACOM Airのプランが**plan-KM1のみ**対応とあります。あれ、けどplan-DのSIMでもコンソールのSIMの情報の所に地図が出てるしいけるんじゃね？と思ってさっそくデータをダンプするだけのBeamを仕立てて接続してみます。

詳細は省略しますが、以下のコードのLambdaを準備してAPI Gatewayから接続するように設定し、BeamでこちらのAPIに接続するように設定します。BeamではなくFunkで連携する場合はAPI Gatewayは不要ですが、位置情報はcontext.client_context.customの方に入ってますのでご注意ください。

```python

import json

def lambda_handler(event, context):
    # TODO implement
    print(json.dumps(event))
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

出力も省略しますが、残念ながら位置情報は出てきませんでした。

理由は色々推測も出来ますがここは公式ドキュメントの通り、**plan-KM1でしか使えない**ということだと思っておきましょう。

検証用にplan-KM1を発注して到着を待ちます。

# plan-KM1到着！

2日後には無事plan-KM1のSIMが届きましたので、GPSマルチユニットのSIMを差し替え、ボタンをポチッとします。さて、肝心のLambdaに渡った情報は・・・

```json

    "headers": {
        "content-length": "150",
        "content-type": "application/json",
        "host": "******.execute-api.ap-northeast-1.amazonaws.com",
        "user-agent": "SORACOM Beam",
        "x-amzn-trace-id": "Root=***************************",
        "x-forwarded-for": "***.***.***.***",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https",
        "x-soracom-geo-position": "**.***********;***.**********",
        "x-soracom-geo-position-query-result": "success",
        "x-soracom-imei": "***************",
        "x-soracom-imsi": "***************"
    },
```

ヘッダ部分のみ抜粋し、重要情報は伏せてますが、ちゃんと「x-soracom-geo-position」ヘッダで取れてます。

これでWFH中はもちろん、実用上も移動中にGPSがうまく取れなかったときに簡易とはいえおおよその位置は取得できるので色々便利そうですね！

・・・これでお話が終わると良かったのですが(その場合blog的には情報少なすぎますが)、残念ながらとある事件が待っていました。

# 簡易位置情報が更新されない！？

全国的に緊急事態宣言が解除された最初の週末。ちょっと用事があって車で移動することがあったのでこれ幸いとGPSマルチユニットを持ってお出かけし、出先でボタンを押してみました。

で、その情報(もちろん値はダミーです)を出先から確認してみると・・・

- 自宅で押したときのデータ

```json

{"value":"{\"lat\":null,\"lon\":null,\"bat\":3,\"rs\":4,\"temp\":29.9,\"humi\":45.2,\"x\":256.0,\"y\":0.0,\"z\":-960.0,\"type\":0}","$metadata":{"locationQueryResult":"success","location":{"lat":33.AA***********,"lon":130.BB***************}}}
```

- 車で20kmほど離れたところまで移動して押したときのデータ

```json
{"value":"{\"lat\":null,\"lon\":null,\"bat\":3,\"rs\":1,\"temp\":35.1,\"humi\":35.5,\"x\":512.0,\"y\":-64.0,\"z\":-832.0,\"type\":1}","$metadata":{"locationQueryResult":"success","location":{"lat":33.AA***********,"lon":130.BB***************}}}
```

・・・マジか。数字をお見せできないのが残念ですが、完全に一致しています。けっしてコピペミスではありません。

20kmも離れればさすがにLTE-Mの基地局が同一と言うことは考えにくいです。そうすると何かのキャッシュ？バグ？

あれこれ考えてる中で、ふと思いついて再度[簡易位置測位機能の説明ページ](https://dev.soracom.io/jp/docs/location_service/)を確認し、その手がかりを発見しました。

> 簡易位置測位機能は LTE 通信のセッション確立時点でのおおよその位置情報を取得し

そう、**「セッション確立時点」**と書いてあります。これより「セッションが切り替わっていないのではないか？」という仮説を立てました。

仮説を立てたら、次はそれを確かめます。幸い、SORACOM Airのセッションはコンソールから簡単に調べられます(SIM管理→SIMにチェックを入れて「詳細」クリック→「セッション詳細」タブ)。

抜粋するとこんな感じです。

|日時|イベント|エリアコード|セルID|備考|
|:---|:---|:---|:---|:---|
|2020/5/29 18:43:21|Created|49AAA|136BBBBBB|SIMを挿して家で動作確認|
|2020/5/30 09:07:39|Modified|49AAA|136BBBBBB|出かける前にボタンを押した|
|2020/5/30 13:20:10|Modified|49AAA|136BBBBBB|出先でボタンを押した|

これまた一部データは伏せていますが、基地局を示す(たぶん)エリアコードとセルIDが更新されていません。また、イベントが「Modified」となっており、半日以上経ってもセッションが維持されているようです。これで先ほどの仮説は合っているようだと確信が持てました。

この間、GPSマルチユニットは動作モードを「定期送信無し」としており通信は行っていませんが、電源が入ってスリープモードに入っている間はできるだけセッションを維持しようとしているように見えます。

そこでボタンを長押しして一旦電源を切り、再度入れてみたところ以下の通りセッションが削除→開始となり、この時に基地局情報が変更されて無事に位置情報も変更されました。

|日時|イベント|エリアコード|セルID|備考|
|:---|:---|:---|:---|:---|
|2020/5/30 14:17:16|Deleted|49AAA|136BBBBBB|電源OFF|
|2020/5/30 14:17:33|Created|49CCC|134DDDDDD|電源ON|

```json
{"value":"{\"lat\":null,\"lon\":null,\"bat\":3,\"rs\":4,\"temp\":28.7,\"humi\":32.9,\"x\":-384.0,\"y\":-640.0,\"z\":-640.0,\"type\":1}","$metadata":{"locationQueryResult":"success","location":{"lat":33.CC***********,"lon":130.DD***************}}}
```

# まとめ　そして解決へ

今回分かったことは以下の通りです。

- GPSマルチユニットにplan-KM1のSIMを挿すことで簡易位置測位機能を利用できる
- GPSマルチユニットは、電源が入っている間はできるだけSIMの通信セッションを維持しようとする
- 簡易位置測位機能は「セッション開始時の情報」に基づいて位置を返す

このため、GPSマルチユニットで簡易位置測位機能を用いる場合、送られてきた簡易位置情報は「通信時の現在位置」ではなく「スイッチを入れて最初に通信された場所」になっている可能性が高い(「セッション開始時の場所」なので途中で何らかの原因でセッションが途切れて再開されていればその場所)という結論になります。
これを解決するには都度GPSマルチユニットの電源を入れ直すか、コンソールの「SIM管理」からセッションを切断する必要がありますが、それは結構面倒ですね・・・。

というわけで、こちらの解決方法については次の解決編に続きます！(2020/5/31 12:00現在、鋭意執筆中なのでしばしお待ちを・・・)

(2020/6/6 15:50追記)
[解決編](https://qiita.com/kkimura/items/97729471d87ec9151a13)をアップしました！

# 補足

[plan-KM1の通信費は上り下りとも0.5 円 / KB](https://soracom.jp/services/air/cellular/price_specific_area_sim/#plan-km1)です。
正確に観測はしてませんが、GPS以外のデータ全てを送信するように設定して1回ボタン押すと上り下り合計で3KBほど利用していましたので、これで1.5円です。

皆さん、plan-KM1でのボタンの押しすぎには注意しましょう・・・。送るデータを最小限になるように設定するのも大事ですね！