AWS
IoT
ESP-WROOM-32

ESP32〜AWS IoTでMQTT通信して詰んだ話【ClientID】

IoTに関するAWS

  • AWS IoT
  • AWS IoT 1-click
  • AWS Greengrass Core
  • AWS FreeRTOS

いくつかある...
非常に関心があるのでいずれ使ってみようと思います。

AWS IoT

IoTデバイスをバックエンドやクラウドサービスと連携することができる。
通信はHTTPSやMQTT通信を用いることができる。

使用マイコン・環境

  • ESP-WROOM-32
  • Arduino IDE

MQTTプロトコルについて

1990年代後半に開発されたプロトコル!
TCP/IPベースに規定されたプロトコル!
MQTTは軽量で、しかも柔軟性がとても高いプロトコル!
M2M(Machine-to-Machine)を重要視するIoTにおいて、とてもぴったりなプロトコル!

利点
IoTではハードウェアやネットワークの面において、非常に厳しい環境で開発する場合がある。
- 待ち時間や帯域幅、デバイス面での条件が厳しい場合
- 双方向通信-Publish/Subscribe
- 1対多通信
- プロトコルヘッダサイズが小さく軽量(HTTP:50バイト,MQTT:2バイト)
- 電力消費量
- 非同期通信
- 負荷
- 通信量
- 頻繁な通信=>大量に送れる

欠点は信頼性ですかね。同期通信ではないですし...
サーバークライアント間がHTTPSやHTTPでなくMQTTだとやはり向いてないですよね。

クライアント証明

AWS IoTでは「モノ」「ポリシー」の登録。
最初に証明書を発行してもらい、RooTCA、Private_Key、Certificateをダウンロード!

Arduinoでのスケッチ

WiFiClientSecure.h - Wifi接続がよりSecureにできるようになるライブラリ
PubSubClient.h - Port:8883でMQTT通信ができるようになるライブラリ
これらを使っていきます。

AWS_IoT_ESP32.ino
#include <WiFiClientSecure.h>
#include <PubSubClient.h>

const char* ssid     = "[SSID]";
const char* password = "[Password]";

const char* server = "[end point]";
const int port = 8883;

const char* Root_CA = \
"-----BEGIN CERTIFICATE-----\n" \
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" \
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" \
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" \
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" \
"-----END CERTIFICATE-----\n";

const char* Client_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" \
"-----END CERTIFICATE-----\n";

const char* Client_private = \
"-----BEGIN RSA PRIVATE KEY-----\n" \
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n" \
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n" \
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n" \
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n" \
"-----END RSA PRIVATE KEY-----\n";

WiFiClientSecure client;
PubSubClient mqttClient(client);

void connectAWSIoT() {
    while (!mqttClient.connected()) {
        if (mqttClient.connect("ESP32")) {
            Serial.println("Connected.");
        } else {
            Serial.print("Failed. Error state=");
            Serial.print(mqttClient.state());
            // Wait 5 seconds before retrying
            delay(5000);
        }
    }
}

void setup()
{
  Serial.begin(115200);

  delay(10);

  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  delay(1000);

  Serial.println(Root_CA);
  Serial.println(Client_cert);
  Serial.println(Client_private);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.setCACert(Root_CA);
  client.setCertificate(Client_cert);
  client.setPrivateKey(Client_private);
  mqttClient.setServer(server, port);  
  mqttClient.setCallback(mqttCallback);

  connectAWSIoT();
}


long messageSentAt = 0;
int Value = 0;
char pubMessage[128];

void mqttCallback (char* topic, byte* payload, unsigned int length) {
    Serial.print("Received. topic=");
    Serial.println(topic);
    for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
    }
    Serial.print("\n");
}

void mqttLoop() {
    if (!mqttClient.connected()) {
        connectAWSIoT();
    }
    mqttClient.loop();
}

void loop() {
  mqttLoop();
}

こりゃダメだ

エラーコードは-1

スクリーンショット 2018-07-01 18.59.59.png

エラーの原因

MQTT_DISCONNECTED - the client is disconnected cleanly

MQTTでAWS IoTのモノまで到達できていないそう...

考えられる原因

  • 証明書が有効になってない -> アタッチ済み
  • 証明書や鍵の割り当て -> 何回か行なったが心配 ←怪しい
  • ポリシー -> 全権限許可
  • ポート -> 8883(MQTTの場合)
  • エンドポイント -> 間違いなさそう
  • AWS IoTはTLS.1.2のみ対応 -> ESP32:WifiClientSecureもTLS.1.2対応

  • PubSubClient::connectの引数 ← 怪しい

    • プログラム上では失敗してるが?

証明書をOpensslコマンドで確認

rootca2.pem - RootCA
[AWS_name]-certificate.pem - Certificate
[AWS_name]-private.pem - Private Key

Terminal
$ openssl s_client -connect [AWS_name].iot.ap-northeast-1.amazonaws.com:8443 -CAfile rootca2.pem -cert [AWS_name]-certificate.pem -key [AWS_name]-private.pem
CONNECTED(00000003)
depth=2 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 2006 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 C = US, O = Symantec Corporation, OU = Symantec Trust Network, CN = Symantec Class 3 Secure Server CA - G4
verify return:1
depth=0 C = US, ST = Washington, L = Seattle, O = "Amazon.com, Inc.", CN = *.iot.ap-northeast-1.amazonaws.com
verify return:1

接続できてるので証明書の問題ではない。
(あるとしてもコピーミス)

不可解

ところでこの接続成功はなに

スクリーンショット 2018-07-01 19.50.37.png

ということはArduinoのプログラムがやはり怪しい...

追記-接続完了!

スクリーンショット 2018-07-02 22.12.16.png

犯人はこのコード

AWS_IoT_ESP32.ino
if (mqttClient.connect("ESP32")) {
            Serial.println("Connected.");
        } else {
            Serial.print("Failed. Error state=");
            Serial.print(mqttClient.state());
            // Wait 5 seconds before retrying
            delay(5000);
 }

mqttClient.connect("ESP32")

"ESP32"というのがDocumentとにらめっこした挙句、ClientIDということがわかりました。
ClientIDはAWSのポリシーで設定しておく必要があります。
デフォルトのTopicのままだとアクセスできない状態なので、以下のようにClientに変更して設定したClientIDにアクセスできるようになる。

今回ならこんな感じ
[ESP32] -> ClientID

Policy
{
    "Version": "2018-7-1",
    "Statement": [{
        "Effect": "Allow",
        "Action": ["iot:Connect"],
        "Resource": [
            "arn:aws:iot:[us-east-1:123456789012]:client/ESP32"
        ]
    }]

mqttClient.connect("ESP32")が失敗してただけで、AWS IoTに接続はできていた。
Arduinoのコード上でdisconnectedが表記されていたのはそのため。
つまり上記は何も不可解でもなかった。

展望

ここから AWS lambdaやCognitoと連携して、サービスをつくっていく

参考文献

MQTT
- https://kfep.jp/solution/iot-mqtt/mqtt
- https://www.ibm.com/developerworks/jp/iot/library/iot-mqtt-why-good-for-iot/index.html
AWS IoT
- https://www.1ft-seabass.jp/memo/2017/07/31/esp32-developer-aws-iot-tips/
- https://blog.maripo.org/2017/07/esp32-aws-iot-troubleshooting/
- https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/protocols.html
- http://ken5owata.hatenablog.com/entry/2017/10/22/102207
エラー
- https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/basic-policy-variables.html