【AWS IoT】カメラ画像をIoT CoreへMQTT送信してS3に保存してみた

AWS IoT にデータを送る場合、画像ファイルのような大きなデータはAWS STSで一時的なTokenを取得し、S3に直接書き込むといったやり方があると思います。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp.html

今回はそれを使わず、MQTTで画像を送ってみる　という事を試してみました。
エッジデバイスはJetsonを使っています。

クラスメソッドさんの
[ [AWS IoT] RaspberryPiからMQTTで画像をS3にアップロードしてみました](https://dev.classmethod.jp/articles/aws-iot-binary-upload-to-s3/) を参考にさせていただきました。


#前提
+ 送信元デバイスは　NVIDIA Jetson Nano 開発者キット B01　を利用
+ AWS IoT Core のコンパネで「モノ」を作成して、「モノ」用の証明書も作成してデバイスに保存
+ デバイスにはAWS IoT Device SDK をインストール
+ 送信用のpythonのコードと、lambdaプログラムコードは [ [AWS IoT] RaspberryPiからMQTTで画像をS3にアップロードしてみました](https://dev.classmethod.jp/articles/aws-iot-binary-upload-to-s3/) を参考にさせていただきました。
+ 送信した画像はこれ(物体検出 を試していた時のもの）

![send_picture2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/45b3c0d1-c068-d100-2e18-7091ab4fc1e5.jpeg)


## 構成
![Qiita記事用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/e8ae5074-7656-efce-b9a0-2e9da2e5ea35.png)

##1. S3バケット作成

`jetson-nano-tsumida-image`というバケットを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/f476b6de-f5d4-eba2-3380-c805067c44b7.png)

##2. LambdaからS3へのアクセスロール作成
試して消すので、一旦S3のフルアクセスを付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/149e1fc8-0e7c-9fc4-441b-34f1541097d5.png)

lambdaの実行権限も付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/14f40785-cdb3-ef03-8bd8-a66495f85d4e.png)

ロール名は`jetson-nano-tsumida-image-lambda`という名前で作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/b8907bda-c689-b21c-c8f8-1e85b131e585.png)


##3.IoT Core rule action の設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/cf7881f9-ec7c-d8a2-4d8a-79b5a6abfc31.png)

 + ルール名 `jetson-nano-tsumida-image` とした
 + クエリ 

```SQL
 SELECT * FROM 'data/jetson-nano-tsumida-image'
```

 + アクション
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/45bd9d96-5dc9-9ce1-f2f8-20ebdd6cab43.png)

 + 新しいlambda関数を作成を押してlambdaを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/2fe6f7a1-4660-05db-ec6b-c06e763ff963.png)


##4. lambda

 + 一から作成
 + 関数名は`jetson-nano-tsumida-image`とした

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/e025b684-2889-a17b-8991-d9516b23acb4.png)

 + アクセス権限はデフォルトの実行ロールの変更　で「既存のロールを使用する」で、2. LambdaからS3へのアクセスロール作成 で作ったものを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/586859a1-3895-7381-7343-08aab86f109f.png)


できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/0fd60cf9-251b-cd97-5654-343fa02036da.png)


 + lambda_function.py に以下コードを入れてDeployを押す。

```python
import json
import os
import boto3
from datetime import datetime
from io import BytesIO
from base64 import b64decode

def lambda_handler(event, context):
    print("event",event)

    img = event["img"]
    bucket = event["bucket"]
    key = event["key"]

    # デコード base64 => binary
    img_binary = b64decode(img)

    s3 = boto3.resource('s3')
    obj = s3.Object(bucket, key)
    obj.put(Body=BytesIO(img_binary),ContentType="image/jpg")

    return 0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/a2c73aeb-d422-21de-c3f6-8f19915dcaa2.png)


 + アクションで「バージョンの発行」を押す

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/ad3d3439-eb16-07bb-8c44-221f91c500bd.png)

 + IoT Core ルールの画面に戻り作ったLambdaを選択して、アクション追加、ルール作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/94296228-8162-3946-d775-d4e1c83127f7.png)


 + Lambda のトリガーにIoT Coreが追加されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/75c3c4ad-ebf4-53d7-d093-d620b9be93a7.png)
 

##5. Client 

 + デバイスの証明書は `./certs/` に保存してある前提
 + 画像は`./image/send_picture.jpg` として保存した。


####クライアントプログラム

送信用のpythonのコードは [ [AWS IoT] RaspberryPiからMQTTで画像をS3にアップロードしてみました](https://dev.classmethod.jp/articles/aws-iot-binary-upload-to-s3/) を使わせていただきました。


 + 画像ファイルは`./image/send_picture.jpg` に書き換えてます。

実行

```
$ python3 index.py
```

結果

```
$ python3 index.py
[30/Jun/2021 22:42:37] INFO - MqttCore initialized
[30/Jun/2021 22:42:37] INFO - Client id: jetson-nano-tsumida
[30/Jun/2021 22:42:37] INFO - Protocol version: MQTTv3.1.1
[30/Jun/2021 22:42:37] INFO - Authentication type: TLSv1.2 certificate based Mutual Auth.
[30/Jun/2021 22:42:37] INFO - Configuring endpoint...
[30/Jun/2021 22:42:37] INFO - Configuring certificates...
[30/Jun/2021 22:42:37] INFO - Configuring reconnect back off timing...
[30/Jun/2021 22:42:37] INFO - Base quiet time: 1.000000 sec
[30/Jun/2021 22:42:37] INFO - Max quiet time: 32.000000 sec
[30/Jun/2021 22:42:37] INFO - Stable connection time: 20.000000 sec
[30/Jun/2021 22:42:37] INFO - Configuring offline requests queueing: max queue size: -1
[30/Jun/2021 22:42:37] INFO - Configuring offline requests queue draining interval: 0.500000 sec
[30/Jun/2021 22:42:37] INFO - Configuring connect/disconnect time out: 10.000000 sec
[30/Jun/2021 22:42:37] INFO - Configuring MQTT operation time out: 5.000000 sec
[30/Jun/2021 22:42:37] INFO - Performing sync connect...
[30/Jun/2021 22:42:37] INFO - Performing async connect...
[30/Jun/2021 22:42:37] INFO - Keep-alive: 600.000000 sec
[30/Jun/2021 22:42:38] INFO - Performing sync publish...
publish: 224238.jpg
[30/Jun/2021 22:42:43] INFO - Performing sync publish...
publish: 224243.jpg
[30/Jun/2021 22:42:52] INFO - Performing sync publish...
publish: 224252.jpg
```



##6. S3の確認

無事保存されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/bec56031-16e0-5cb0-594f-4a787a1231d9.png)

ダウンロードしてみた画像
![224238.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001712/99e4bf5b-4c1b-99e4-ddac-30ab4dcdf876.jpeg)

ちゃんと行けました。


補足
画像のサイズが大きすぎるとtimeoutエラーを起こすため、25Kくらいのサイズにしてから送りました。

```
AWSIoTPythonSDK.exception.AWSIoTExceptions.publishTimeoutException
```