今回の内容
前回からの続きで、3回目となります。(長くなってスミマセン・・・)
これまでの2回でプラットフォームへデータが送信できることを確認できましたので、今回と次回の2回に渡ってデバイスに取り付けたセンサーで取得したデータを、Amazon S3に保存するところまでやってみたいと思います。
トポロジ
アプリケーションサーバ側は下図のように、API Gateway
、Kinessis Firehose
(以下、Firehose)、S3
を使って構築します。
AWS側の準備
クラスメソッドさんが解りやすい情報を公開していましたので、その情報にある「AWSサービスプロキシ」方式に倣って設定してみます。
尚、クラスメソッドさんが情報を公開した時点では、東京リージョンでのFirehose利用はできませんでしたが、現在は利用できますので、AWS側は全て東京リージョンで構成することにしました。
Firehose
Delivery stream name
に任意のストリーム名を入力、Source
にDirect PUT or other sources
が選択されていることを確認し、ページ下部のNext
をクリック
Destination
にAmazon S3
を選択、S3 bucket
は任意のバケット(既存、またはCreate new
をクリックして新しいバケットを作成)を選択し、Next
をクリック
Buffer interval
を60
に変更し、IAM role
にあるCreate new, or Choose
ボタンをクリック
IAMロールページが閉じて元のページに戻るので、
IAM role
に上記で作成したロール名が表示されていることを確認し、Next
をクリック
以上の手順で、FirehoseがS3を操作するためのIAM Roleと、Firehoseストリーム、S3バケット(新規作成した場合)が作成されます。
またFirehoseストリームに対して、次のようなIAM Role(lorawan_delivery_role
)が作成されています。
信頼関係(Trust Relationships)
Firehose に対し、AssumeRoleすることを許可するポリシードキュメント
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "<アカウントID>"
}
}
}
]
}
アクセス権限(Permissions)
S3やAmazon Lambda、Logs、Kinesisに対して、操作を許可するインラインポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::<バケット名>",
"arn:aws:s3:::<バケット名>/*",
"arn:aws:s3:::%FIREHOSE_BUCKET_NAME%",
"arn:aws:s3:::%FIREHOSE_BUCKET_NAME%/*"
]
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"lambda:GetFunctionConfiguration"
],
"Resource": "arn:aws:lambda:ap-northeast-1:<アカウントID>:function:%FIREHOSE_DEFAULT_FUNCTION%:%FIREHOSE_DEFAULT_VERSION%"
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-northeast-1:<アカウントID>:log-group:/aws/kinesisfirehose/lorawan:log-stream:*"
]
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"kinesis:DescribeStream",
"kinesis:GetShardIterator",
"kinesis:GetRecords"
],
"Resource": "arn:aws:kinesis:ap-northeast-1:<アカウントID>:stream/%FIREHOSE_STREAM_NAME%"
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:region:accountid:key/%SSE_KEY_ARN%"
],
"Condition": {
"StringEquals": {
"kms:ViaService": "kinesis.%REGION_NAME%.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:aws:kinesis:arn": "arn:aws:kinesis:%REGION_NAME%:<アカウントID>:stream/%FIREHOSE_STREAM_NAME%"
}
}
}
]
}
API Gateway向けIAMロール作成
API Gatewayのメソッド作成時に指定するIAMロールを、新たに作成します。
今回はfirehose_for_lorawan
という名前で作成しました。
信頼関係(Trust Relationships)
API GatewayがAssumeRoleすることを許可するポリシードキュメント
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
アクセス権限(Permissions)
Firehoseにデータレコードを書き込むAPI(PutRecord
、PutRecordBatch
)を許可するインラインポリシー
- PutRecord
- 単一のデータレコードをストリームに書き込む
- PutRecordBatch
- 1回の呼出しで複数のデータレコードをストリームに書き込む
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt",
"Effect": "Allow",
"Action": [
"firehose:PutRecord",
"firehose:PutRecordBatch"
],
"Resource": [
"*"
]
}
]
}
API Gateway作成
AWSマネジメントコンソールから
API Gateway
を開き、APIの作成
をクリック、更に新しいAPI
を選択し、API名
に任意の名称を入力してAPIの作成
をクリック
リソース名に
api
を入力し、リソースの作成
をクリック(リソースパス
は、デフォルトでリソース名と同一文字が自動入力される)
-
項目 設定値 統合タイプ AWSサービス AWSリージョン Firehoseを作成したリージョン ※今回は東京リージョンなので ap-northeast-1
AWSサービス Firehose HTTPメソッド POST アクション PutRecord 実行ロール API Gateway向けIAMロール( firehose_for_lorawan
) 本文マッピングテンプレート
をクリックして展開し、リクエストが定義されていない場合
を選択、更にマッピングテンプレートの追加
をクリックし、Content-Type
にapplication/json
と入力して確定アイコンをクリック
-
テンプレートの生成
欄が表示されるので、以下のコードを入力し、保存
ボタンをクリック{ "DeliveryStreamName": "lorawan_stream", "Record": { "Data": "$util.base64Encode($input.json('$.DevEUI_uplink'))" } }
[補足] マッピングテンプレートについて
公式ドキュメントを確認すると、Firehoseに単一のデータレコードを書き込むPutRecord
APIは、次のフォーマットになります。{ "DeliveryStreamName": "string", "Record": { "Data": blob } }
また、LoRaWANプラットフォーム(ThingPark)からAPI GatewayにPOST送信されるJSONオブジェクトは、次のようなフォーマットです。
{ "DevEUI_uplink": { "Time": "2017-11-02T08:48:47.595+01:00", "DevEUI": "47XXXXXXXXXXXXXX", "FPort": "8", "FCntUp": "35", "ADRbit": "1", "MType": "4", "FCntDn": "40", "payload_hex": "1b1083202fd06b8c5410350c16b5", "mic_hex": "41293adb", "Lrcid": "01234567", "LrrRSSI": "-116.000000", "LrrSNR": "-5.000000", "SpFact": "9", "SubBand": "G0", "Channel": "LC4", "DevLrrCnt": "1", "Lrrid": "65XXXXXX", "Late": "0", "LrrLAT": "33.588463", "LrrLON": "130.397446", "Lrrs": { "Lrr": [ { "Lrrid": "65XXXXXX", "Chain": "0", "LrrRSSI": "-116.000000", "LrrSNR": "-5.000000", "LrrESP": "-122.193314" } ] }, "CustomerID": "100008500", "CustomerData": { "alr": { "pro": "LORA/Generic", "ver": "1" } }, "ModelCfg": "0", "DevAddr": "01XXXXXX" } }
つまり、プラットフォームから送られてくるJSONオブジェクトの最上位メンバー
DevEUI_uplink
を、PutRecord APIのData
メンバーにマッピングするすることで、DevEUI_uplink
メンバー内のデータを、Firehoseストリームに書き込む仕組みとなっています。
更に、PutRecord APIのData
メンバーの値(上記APIフォーマットのblob
)は、Base64でエンコードする必要があるため、組み込み関数base64Encode()
を利用しています。
マッピングテンプレートのその他組み込み関数については、こちらに詳しく説明があります。
ここまでの手順で、AWS側の設定作業は完了です。
API Gatewayテスト
以下の手順で、API Gatewayのテストを行ってみます。
(背後でFirehoseストリームと連動していますので、実質AWS側の統合テストになります)
-
リクエスト本文
に以下のJSONコードを入力し、テスト
をクリック{ "DevEUI_uplink" : "Fukuoka City LoRaWAN" }
(レスポンスの)
ステータス
が200
になっているか確認
※ステータスが200
でない場合、表示されているログからエラー内容を確認できます。
-
S3バケットを確認し、データを確認
バケットに保存されたデータの中身"Fukuoka City LoRaWAN"
API Gatewayデプロイ
以下の手順で、作成したAPIをユーザーが呼び出せるようにデプロイします。
ステージエディタが表示されればデプロイ完了
尚、URLの呼び出し
に記載されたURLに続けてリソースパスを指定したアドレス(今回の場合、https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/api/vi
)が、プラットフォーム側で設定するアプリケーションサーバのアドレスになります。(=>前回のアプリケーションサーバの登録を参照)
次回
LoRaWANデバイスにセンサーを取り付け、送信してみます。