AWS IoT Core で SORACOM Beam から来た IMSI付与のリクエストを処理する

この記事は、[SORACOM Advent Calendar 2018](https://qiita.com/advent-calendar/2018/soracom2) の12月7日にエントリーしてます。  
[SORACOM UG Hiroshima #2](https://soracomug-tokyo.connpass.com/event/95943/) の LT で話したやつの裏側で地味に悩んでしまった経験を書いてみました。

# 背景
SORACOM Beam を使った MQTTS の通信には IMSI 付与という設定があり、これを使うと簡単にどの SIM から来た情報かを判定することができます。普段から使っている人は当たり前すぎて説明無しの事が多いのですが、AWS IoT Core で判定しようと思った時にうまくググれなかったのでまとめておきます。

# 構成
* WioLTE
* SORACOM Beam
* AWS Iot Core
* AWS Lambda

# WioLTE側
今回、Things 側は WioLTE を使って Arduino IDE でスケッチを作成しました。今回はスケッチ例にある mqtt-client をそのまま使います。

https://seeedjp.github.io/Wiki/Wio_LTE_for_Arduino/Home-ja.html#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0

## スケッチ
サンプルから MQTT_SERVER_HOST と TOPIC を変えただけです。

```
#include <WioLTEforArduino.h>
#include <WioLTEClient.h>
#include <PubSubClient.h>		// https://github.com/SeeedJP/pubsubclient
#include <stdio.h>

#define APN               "soracom.io"
#define USERNAME          "sora"
#define PASSWORD          "sora"

#define MQTT_SERVER_HOST  "beam.soracom.io"
#define MQTT_SERVER_PORT  (1883)

#define ID                "WioLTE"
#define OUT_TOPIC         "device/post"
#define IN_TOPIC          "device/post"

// 以下省略（サンプルと同じ）
```

# SORACOM Beam 設定
SORACOM Beam については有名なハンズオンの資料にある手順で設定します。MQTTSの転送先の部分は、後述する AWS IoT Core の設定に変更します。
https://github.com/soracom/handson/wiki/Wio-LTE-%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3#step5

ポイントは「IMSI 付与: ON」です。こうする事で Arduino IDE 側には何も書かなくても SORACOM Beam に送るだけで自動的に IMSI が設定されます。

今回の例では

```
#define OUT_TOPIC         "device/post"
```

と書いているので、MQTT ブローカーに届く時に下記のように TOPIC が変更されます。

```
/* 123456789012345 の部分が IMSI */
device/post/123456789012345
```

プログラム側に何も書かなくても処理されるので便利ですが、SORACOM 初心者の私は気がつくまでしばらくかかりました。

# AWS IoT Core
AWS IoT の設定は SORACOM 公式の記事に従います。
https://dev.soracom.io/jp/docs/aws_iot_guide_console/

SORCOM Beam への MQTTS の転送先設定は上記の記事を参考にしてください。

# 本題
さて、準備が終わったところで本題です。  
ここまでの設定で基本的には問題なく処理されますが、AWS IoT Core のルールクエリをうまく設定する事でその先の Lambda で IMSI を使った判定ができるようになります。

## 設定するところ
ルールクエリのところに、下記の AWS IoT SQL を設定します。

```
SELECT uptime, topic() as topic FROM 'device/post/#'
```

### SELECT 句
*uptime* というのは、サンプルに元から設定されている JSON のキーです。コードでいうと下記の部分です。

```
  char data[100];
  sprintf(data, "{\"uptime\":%lu}", millis() / 1000);
  SerialUSB.print("Publish:");
  SerialUSB.print(data);
  SerialUSB.println("");
  MqttClient.publish(OUT_TOPIC, data);

```

*topic() as topic* の部分は MQTT トピックの全文を取得するために使います。AWS のリファレンスを参考にしてください。

<b>ここがこのエントリでもっとも重要な箇所</b>です。

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sql-functions.html#iot-function-topic


### FROM 句
'device/post/#' の一番後ろにある # がワイルドカードを意味します。こちらもリファレンスを読むとひっそりと書いてあります。
https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sql-from.html


### コンソール画面の様子
![image.png](https://qiita-image-store.s3.amazonaws.com/0/125488/96ebfb1d-89a6-0a17-1576-5186c68820ab.png)


# Lambda
あとは、Lambda に送られてきた値をうまく判定する事で IMSI による処理をすることができるようになります。

Lambda のイベントにはこんなペイロードが送られてきます。

```
{ uptime: 19, topic: 'device/post/123456789012345' }
```

Arduino IDE のシリアルモニターはこんな表示です。

```
--- START ---------------------------------------------------
### I/O Initialize.
### Power supply ON.
### Turn on or reset.
### Connecting to "soracom.io".
### Connecting to MQTT server "beam.soracom.io"
### Setup completed.
Publish:{"uptime":19}
```

Arduino IDE 側は送信したい情報だけを JSON に設定して送り、SORACOM Beam で IMSI を付与して転送します。それを AWS IoT Core のルールクエリで再変換することで Lambda 側で IMSI を処理できるようになりました。

# SIM の IMSI を確認する方法
SORACOM の API を使って IMSI を取得することができます。
https://dev.soracom.io/jp/docs/subscriber_status/#api

コンソールからも「SIM管理」の「詳細」ボタンで確認できます。


# まとめ
知っていれば非常に簡単な話なのですが、初回つまづいたので思い出して記録を残してみました！
2018年もあと1ヶ月を切りました。体調管理にお気をつけて来年からのイベントに備えてください！

# NT広島2019 はこちら
唐突ですが、2019年の2月2日に広島で #NT広島 というイベントが開催されます。

SORACOM を使った作品とともに、ぜひ広島に遊びにきてください！
今回初開催となるNT広島ですが、すでにNT界隈の人から好反応をいただいております。
http://wiki.nicotech.jp/nico_tech/index.php?NT%E5%BA%83%E5%B3%B62019

牡蠣の美味しい季節の広島をぜひご堪能ください！