データをAWS IoT経由でDynamoDBへ保存する

#はじめに
仕事上、まるっと引き継いであんまり理解できていない技術である、AWS Iotを自分で一から作成してみる。
やりたいことはタイトルの通り。まずはローカルマシン(PC)から簡単なデータをAWS Iotを使ってDynamoDBへデータを投げる部分を実装してみる。

#準備
・AWSアカウント
・ローカルマシン(mac)
・python 3.X  ※pipコマンドが使えるようにしておくこと。
・DynamoDBのテーブルは以下の通り作成しておく
　ーテーブル名：iot_test
　ーハッシュキー：time (文字列)

#システム構成図
<img width="447" alt="img_0.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/f98ce4db-b075-827d-d07d-0d22f9690be5.jpeg">

#AWS IoT側の設定
AWSにログイン後、「IOT Core」をクリックし、AWS IOTの画面を表示し、
左のメニューの「管理」をクリックし、「モノ」をクリック。

<img width="684" alt="img_1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/437e7ea9-b38a-b0f5-9d97-33d75ad6b1c0.jpeg">


モノを作成する。「単一のモノを作成する」をクリック。

<img width="442" alt="img_2.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/a19bcbb4-c3d8-8fe9-c283-5c267393639c.jpeg">


「名前」に任意の名前を入力し、「次へ」をクリック。

<img width="419" alt="img_3.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/f9a11a25-8b6a-89a3-826c-c3ee30173e0a.jpeg">


「モノに証明書を追加」画面で「1-Click 証明書作成 (推奨)」の「証明書作成」ボタンをクリック。
<img width="422" alt="img_4.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/7bd44c0f-9db0-b7ca-109c-5af13b234e1e.jpeg">


証明書が作成されるので、以下をすべてダウンロード。　　※１
・このモノの証明書
・パブリックキー
・プライベートキー
・AWS IoTのルートCA
※このファイルは以降ダウンロード出来なくなるので注意


ダウンロードが完了したら、「ポリシーをアタッチ」をクリック。

<img width="416" alt="img_5.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/f56393a3-57af-4351-08d9-5da0a678b9d7.jpeg">


ポリシーの作成を行います。
「アクション」は「iot:*」
「リソースは「＊」
※今回なんでも通す設定にしていますが、設計に応じて必要な制限をかけます。

<img width="285" alt="img_6.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/b615160f-95d0-c515-f914-bcf0512d47d8.jpeg">


「モノの登録」をクリックして。モノの登録が完了します。

登録されたモノをクリックすると、
HTTPS、MQTTのエンドポイントを確認することができます。
※管理→モノ→セキュリティ→アクションで作成したポリシーを設定しておきます。


データ送信時は「操作」からRest API エンドポイントを確認して入力します。 ★１

<img width="425" alt="img_7.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/c56edba6-5835-f2bf-ee46-e47c9319b232.jpeg">



次に、AWS IOTのホームから「ACT」をクリックし、ルールの作成を行います。

<img width="1015" alt="img_8_1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/f5ede070-fa77-ea74-c8dc-e6ae5a51e0f4.jpeg">



「名前」は任意の名前を入力し、「ルールクエリステートメント」には
「SELECT * FROM 'testRule/time'  」を入力します。
※ここで指定したクエリにより、送信データをフィルタリングすることもできる。

続いてアクションを設定します。
<img width="424" alt="img_9.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/20855a5e-05b7-3ceb-c6f4-27753298220b.jpeg">


今回はDynamoDBに直接送信データを追加ます。

「アクションの追加」を選択し、「DYNAMODBV2」を選択後、
画面下部にある「アクションの設定」ボタンをクリック。

<img width="636" alt="img_10.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/5dab3dc4-3524-8a19-c532-72207f989bb0.jpeg">


作成済みのDynamoDBを選択します。「リソースの選択」にてテーブルを選択すれば自動で入力されます。
ロールは「ロールの作成」をクリックし、新規作成し、「アクションの追加」をクリック。
以下は作成後の画面。

<img width="1021" alt="img_12_1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/8264726f-c8c9-c4e2-2076-dddf8a0d1965.jpeg">


#ローカルマシン側の設定

任意のディレクトリを作成し、※１のファイルをすべて配置する。

ディレクトリには以下の様になる。
・XXX.crt
・XXX-private.pem.key
・XXX-public.pem.key
・AmazonRootCA1.pem
・test.py  ←　実行ファイル

pipコマンドを実行
pip install AWSIoTPythonSDK

test.pyのソース

```ruby:test.py
'''
Send Time Sample
'''

from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import time
import json
import datetime
import logging

# select Debug mode
_DEBUG_ = 'PC'
#_DEBUG_ = 'Raspberry'

# Setup Param
host = "XXXXXX-ats.iot.us-west-2.amazonaws.com"　★１を入力

if _DEBUG_ == 'PC':
    #for PC
    rootCAPath = "XXXXX/AmazonRootCA1.pem"　　※ダウンロードしたKeyを入力
    certificatePath = "XXXXXX/XXXX-certificate.pem.crt"　　※任意のディレクトリに保管する。
    privateKeyPath = "XXXX/XXXX-private.pem.key"
else:
    #for Raspberry Pi
    rootCAPath = "/cert/AmazonRootCA1.pem"
    certificatePath = "/cert/xxxxxxxxx-certificate.pem.crt"
    privateKeyPath = "/cert/xxxxxxxxx-private.pem.key"

useWebsocket = False
clientId = "testRule"
topic = "testRule/time"
deviceNo = "10001"

# Configure logging
logger = logging.getLogger("AWSIoTPythonSDK.core")
logger.setLevel(logging.DEBUG)
streamHandler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
streamHandler.setFormatter(formatter)
logger.addHandler(streamHandler)

# Init AWSIoTMQTTClient
myAWSIoTMQTTClient = None
if useWebsocket:
    myAWSIoTMQTTClient = AWSIoTMQTTClient(clientId, useWebsocket=True)
    myAWSIoTMQTTClient.configureEndpoint(host, 443)
    myAWSIoTMQTTClient.configureCredentials(rootCAPath)
else:
    myAWSIoTMQTTClient = AWSIoTMQTTClient(clientId)
    myAWSIoTMQTTClient.configureEndpoint(host, 8883)
    myAWSIoTMQTTClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

# AWSIoTMQTTClient connection configuration
myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1)      # Infinite offline Publish queueing
myAWSIoTMQTTClient.configureDrainingFrequency(2)            # Draining: 2 Hz
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)    # 10 sec
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)         # 5 sec

# Connect and subscribe to AWS IoT
myAWSIoTMQTTClient.connect()
time.sleep(2)
# Initial

try:
    while True:
        nowtime = datetime.datetime.now()
        nowsettime = int(time.mktime(nowtime.timetuple()))  # UNIX Time
        #send Command
        message = {}
        message['time'] = nowtime.strftime('%Y/%m/%d %H:%M:%S')
        message['deviceNo'] = deviceNo
        message['ttl']  = nowsettime + 2592000
        messageJson = json.dumps(message)
        print (messageJson)
        myAWSIoTMQTTClient.publish(topic, messageJson, 1)
        time.sleep(10)
except:
    import traceback
    traceback.print_exc()

print ("Terminated")

```
動きとしては、数秒おきにサンプルで作成したデータをDynamoDBへ送信し続けます。


実行ログ
<img width="1045" alt="img_13_1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/15f2b5cd-3e5b-02f1-0d54-db6ef2746f7b.jpeg">


DynamoDB（テーブル名はiot_test)
<img width="845" alt="img_14.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/367782/5feb50bd-3ef5-e814-2af6-ae95ddbebd42.jpeg">



#まとめ

ひとまず、データをデバイス → AWS IoT → DBへ保存 という流れを一通り再現することができたのと、データを送信するまでのAWS IoTの必要な設定項目、必要なファイルも確認できたので、理解が深まった。

次はデバイスをPCではなく、raspberry piなどで実際の生データを送る部分や、
送ったデータを可視化（クラフ表示）できるようなところを触ってみたいと思います。