RaspberryからAWS IoT にsubscribeする


モチベーション

Raspberry Pi カメラ画像をS3へアッロードでは、ラズパイから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種のルート証明書がダウンロードできるのだが、どれが最適なのか、正直不明。

デバイスつまりラズパイ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)

ポリシを作成して証明書にアタッチ

安全性→ポリシー→作成

  • 名前:RasPi3BPolicy
  • アクション:iot:*
  • リソース ARN:* 要ははiotの操作は何でも許す設定にして、作成

証明書に今作成したポリシをアタッチする。

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→ソフトウェア→設定 からエンドポイントを確認

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を入力して、「トピックを発行」

メッセージが受信され、登録してあった処理が呼ばれることが分かる。
無限ループにしているので、最後に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

次回

ラズパイからトピックを発行したかったのに、逆のことをしてしまいました。
次回当初したかったことをトライします。