RaspberryからAWS IoT にsubscribeする

##モチベーション
[Raspberry Pi カメラ画像をS3へアッロード](https://qiita.com/atmaru/items/8caa8d15246dbfe4ae4a)では、ラズパイからAWSのアクセスはAWS SDK for Python (Boto3) を使用している。
AWS IoTを使うのと何が違うんだろ？ということでAWS IoT Coreを試す。

ラズパイ→boto3→AWS S3→xxx
ラズパイ→AWSIoTPythonSDK→AWSIoTMQTTClient→AWS IoT Core→xxx

##AWS IoTにRaspberryPiを登録

###モノの作成
https://console.aws.amazon.com/iot/home?region=us-east-1#/home
- 開始方法→管理→モノ→作成→単一のモノを登録する
- 名前：RasPi3B
- 次へ
- 証明書の作成
このモノの証明書	xxxxxcert.pem→ダウンロード
パブリックキー	xxxxx.public.key→ダウンロード
プライベートキー	xxxxx.private.key→ダウンロード
AWS IoT のルート CA→ダウンロードをリンク先へ、この5種のルート証明書がダウンロードできるのだが、どれが最適なのか、正直不明。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/cf7df3ce-4199-25a0-ab0a-a722b2cf7b08.png)
デバイスつまりラズパイRSAベースなのか、ECCベースなのかで選べばよいみたい。
一旦全部ダウンロードしてみる。

どうも、Aug 29, 2018まではVeriSignの証明書へのリンクが張られていたのが、変更になった模様。VeriSignの証明書が使えなくなるためAWSが独自の証明書である Amazon Trust Sevices (ATS)を提供開始したため。（理由は下記ページからの私の推測です
https://aws.amazon.com/jp/about-aws/whats-new/2018/08/aws-iot-core-adds-new-endpoints-serving-amazon-trust-services-signed-certificates-to-help-customers-avoid-symantec-distrust-issue）


###ポリシを作成して証明書にアタッチ
安全性→ポリシー→作成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/5c907657-0faf-8613-926e-f6b4dbf3ca4f.png)

- 名前：RasPi3BPolicy
- アクション：iot:*
- リソース ARN:*
要ははiotの操作は何でも許す設定にして、作成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/7892ef3b-524b-3a90-1fe4-68dee00aa884.png)

証明書に今作成したポリシをアタッチする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/29768d46-5528-dd3d-5f4d-9a667dc64ccd.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/59681359-beca-a7e2-e67b-1d753bbac1af.png)


###AWSIoTPythonSDKのインストール(AWSIoTPythonSDK-1.4.4)

```
pi@raspberrypi:~ $ pip install AWSIoTPythonSDK
Collecting AWSIoTPythonSDK
  Downloading https://files.pythonhosted.org/packages/95/1d/40c13828f8cec38b4ca4213b9815d19f4776de17bb82f9680b9297925ca9/AWSIoTPythonSDK-1.4.4.tar.gz (79kB)
    100% |████████████████████████████████| 81kB 989kB/s
Building wheels for collected packages: AWSIoTPythonSDK
  Running setup.py bdist_wheel for AWSIoTPythonSDK ... done
  Stored in directory: /home/pi/.cache/pip/wheels/f6/f9/4c/8959a65e4a45bdf0dd5f0e062a93b30b5221a4fffea7f85a2a
Successfully built AWSIoTPythonSDK
Installing collected packages: AWSIoTPythonSDK
Successfully installed AWSIoTPythonSDK-1.4.4
```

###RESTエンドポイントの確認
AWS IoT→ソフトウェア→設定 からエンドポイントを確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/bccec0ce-1fac-3679-e563-fe369ac0921e.png)

###Subscribeするpythonコード

```mqttclient.py
# coding: utf-8
import time
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient

CLIENT_ID = "test_client_id"
ENDPOINT = "xxx-ats.iot.us-east-1.amazonaws.com"
# MQTTでは、標準で1883/TCPポート
# SSL（TLS）による暗号化を行う場合には8883/TCPポートを使用。
PORT = 8883
ROOT_CA = "./cert/AmazonRootCA1.pem"
PRIVATE_KEY = "./cert/xxx-private.pem.key"
CERTIFICATE = "./cert/xxx-certificate.pem.crt"

TOPIC = "RasPi3B/sample"

def main():
    # https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/sphinx/html/index.html
    # setting for MQTT
    client = AWSIoTMQTTClient(CLIENT_ID)
    client.configureEndpoint(ENDPOINT, PORT)
    client.configureCredentials(ROOT_CA, PRIVATE_KEY, CERTIFICATE)
    # AWSIoTMQTTClient connection configuration
    client.configureAutoReconnectBackoffTime(1, 32, 20)
    # -1:infinite
    client.configureOfflinePublishQueueing(-1)
    # Draining: 2 Hz
    client.configureDrainingFrequency(2)
    # 10 sec
    client.configureConnectDisconnectTimeout(10)
    # 5 sec
    client.configureMQTTOperationTimeout(5)
    # Connect to AWS IoT with default keepalive set to 600 seconds 
    # keepAliveIntervalSecond : Time in seconds for interval of sending MQTT ping request. Default set to 600 seconds.
    client.connect()
    # TOPICが起動したら呼ばれる関数を登録するQoS(Quality of Service)=1
    # QoS=0:投げっぱなし,QoS=1:少なくとも1回は確実にBrokerにメッセージが届く
    client.subscribe(TOPIC, 1, mycallback)
#    time.sleep(5)
    #無限ループ
    while True:
        time.sleep(5)

def mycallback(client, userdata, message):
    print("Received a new message: ")
    print(message.payload)
    print("from topic: ")
    print(message.topic)
    print("--------------\n\n")


if __name__ == "__main__":
    main()
```

コード実行

```
pi@raspberrypi:~ $ python mqttclient.py
```

##テスト機能を使ってトピックを発行(publish)
AWS IoT→テスト
RasPi3B/sampleを入力して、「トピックを発行」
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29032/bdd015c2-c164-3e05-c864-f87568ab74b0.png)

メッセージが受信され、登録してあった処理が呼ばれることが分かる。
無限ループにしているので、最後にCtrl-Zでループを抜ける。

```
pi@raspberrypi:~ $ python mqttclient.py
Received a new message:
{
  "message": "Hello from AWS IoT atsmaru"
}
from topic:
RasPi3B/sample
--------------

^Z
[3]+  停止                  python mqttclient.py

```
##最後に
できたことを図示するとこんな感じ。

```
モノRasPi3B
├ 証明書
│  └ ポリシー
├ エンドポイント
├ トピック：RasPi3B/sample ← Publish ← test
                          ← subscribe ← ラズパイのpython
```
##次回
ラズパイからトピックを発行したかったのに、逆のことをしてしまいました。
次回当初したかったことをトライします。