Để có thể làm được phần này, các bạn cần nắm rõ và làm qua các bước thiết lập ban đầu như: tạo Thing, tạo chứng chỉ xác thực, kích hoạt chứng chỉ cho thiết bị, khởi tạo và liên kết Policy với chứng chỉ cũng như đính kèm chứng chỉ xác thực cho Thing. Đồng thời các bạn cũng cần hiểu mô hình mà AWS IoTs đưa ra cho việc tương tác giữa các thiết bị và ứng dụng với Device Shadow Service sử dụng giao thức MQTT. Những nội dung này đã được trình bày ở các phần trước:
Xem lại phần 1: Hướng dẫn tạo Thing, Device Certificate và Policy
Xem lại phần 2: Tương tác với Device Shadow sử dụng giao thức MQTT
Phần cuối: Kết nối ESP32 Dev Kit và AWS IoT sử dụng giao thức MQTT
- Cài đặt các thư viện cần thiết
Hai thư viện chính cần sử dụng là:
- WiFiClientSecure (cho ESP32)
- PubSubClient
Để ESP32 có thể kết nối tới AWS IoT chúng ta sử dụng thư viện WiFiClientSecure (Đây là thư viện built-in của ESP32). Lưu ý phiên bản cũ của thư viện WiFiClientSecure không hỗ trợ cho việc gửi chứng chỉ gốc CA. Nếu bạn gặp lỗi WiFiClientSecure::setCACert() not found thì bạn cần phải nâng cấp lên phiên bản mới nhất.
Để ESP32 có thể tương tác với AWS IoT thông qua giao thức MQTT như một client thì chúng ta sẽ sử dụng thư viện có tên PubSubClient. Các bạn có thể tải thư viện ở đây.
Sau khi đã cài đặt xong thư viện, có một thay đổi nhỏ cực kì quan trọng mà chúng ta cần lưu ý nằm trong thư viện PubSubClient. Ở thư mục chứa thư viện PubSubClient, mở file PubSubClient.h ra sẽ tìm thấy định nghĩa:
1 |
#define MQTT_MAX_PACKET_SIZE 128 |
Việc cấu hình mặc định này sẽ gây ra một lỗi khi nhận dữ liệu trả về từ AWS thông qua các topic. Bởi vì kích thước tối đa của gói tin khi gửi tới các topic như shadow/update/delta, shadow/update/accepted,… có thể lên tới 128KB trong khi thư viện PubSubClient lại định nghĩa kích thước tối đa của gói tin chỉ vỏn vẹn có 128Byte… nên nếu dữ liệu trả về lớn hơn 128Byte có thể làm mất dữ liệu. Để khắc phục vấn đề này chúng ta sẽ tăng giá trị của biến MQTT_MAX_PACK_SIZE lên như sau:
1 |
#define MQTT_MAX_PACKET_SIZE 1024 |
2. Viết chương trình kết nối ESP32 đến AWS endpoint
Chương trình chính của chúng ta sẽ tuần tự thực hiện các bước như sau:
- Cài đặt và kết nối WiFi
- Cài đặt các chứng chỉ và privateKey trong thư viện WiFiClientSecure
- WiFiClientSecure::setCACert()
- WiFiClientSecure::setCertificate()
- WiFiClientSecure::setPrivateKey()
- Khởi tạo MQTT Client để kết nối tới AWS IoT Broker
- Port là 8883 (TLS)
- AWS IoT endpoint với định dạng iot.us-west-2.amazonaws.com
- Subscribe, publish các topic để truyền nhận dữ liệu
Để lấy được Certificate, privatekey cũng như rootCA các bạn lưu ý đọc lại phần 1. Sau đó lấy endpoint bằng cách làm theo các bước sau:
Các bạn chọn Thing mà mình muốn tương tác, ở đây mình ví dụ một Thing tên là LIGHT đã tạo từ trước. Chúng ta nhấn đúp để chọn, lập tức console sẽ chuyển hướng tới trang quản lý Thing này. Tiếp tục thực hiện như sau sẽ lấy được endpoint của Thing:
Sau khi đã cài đặt xong thư viện cũng như lấy được các thông tin cần thiết, chúng ta sẽ viết chương trình kết nối cho ESP32 theo đoạn chương trình mẫu dưới đây:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include <WiFiClientSecure.h> #include <PubSubClient.h> void connectAWSIoT(); void mqttCallback (char* topic, byte* payload, unsigned int length); char *ssid = "<YOUR_SSID>"; char *password = "<YOUR_WIFI_PASSWORD>"; const char *endpoint = "<AWS_IOT_ENDPOINT>"; // Example: xxxxxxxxxxxxxx.iot.us-west-2.amazonaws.com const int port = 8883; char *pubTopic = "$aws/things/<DEVICE_NAME>/shadow/update"; char *subTopic = "$aws/things/<DEVICE_NAME>/shadow/update/delta"; const char* rootCA = "-----BEGIN CERTIFICATE-----\n" "......" "-----END CERTIFICATE-----\n"; const char* certificate = "-----BEGIN CERTIFICATE-----\n" "......" "-----END CERTIFICATE-----\n"; const char* privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" "......" "-----END RSA PRIVATE KEY-----\n"; WiFiClientSecure httpsClient; PubSubClient mqttClient(httpsClient); void setup() { delay(1000); Serial.begin(115200); // Start WiFi Serial.println("Connecting to "); Serial.print(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to WiFi."); // Configure MQTT Client httpsClient.setCACert(rootCA); httpsClient.setCertificate(certificate); httpsClient.setPrivateKey(privateKey); mqttClient.setServer(endpoint, port); mqttClient.setCallback(mqttCallback); connectAWSIoT(); } void connectAWSIoT() { while (!mqttClient.connected()) { if (mqttClient.connect("ESP32_device")) { Serial.println("Connected to AWS IoT."); int qos = 0; mqttClient.subscribe(subTopic, qos); Serial.println("Subscribed to topics."); } else { Serial.print("Failed. Error state="); Serial.print(mqttClient.state()); // Wait 5 seconds before retrying delay(5000); } } } long messageSentAt = 0; int dummyValue = 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(); long now = millis(); if (now - messageSentAt > 5000) { messageSentAt = now; sprintf(pubMessage, "{\"state\": {\"desired\":{\"foo\":\"%d\"}}}", dummyValue++); Serial.print("Publishing message to topic "); Serial.println(pubTopic); Serial.println(pubMessage); mqttClient.publish(pubTopic, pubMessage); Serial.println("Published."); } } void loop() { mqttLoop(); } |
*Lưu ý: Nếu các bạn sao chép trực tiếp các file rootCA, certificate và privateKey vào các biến tương ứng sẽ gây ra lỗi. Để tránh lỗi xảy ra, định dạng của các biến này bắt buộc phải thỏa mãn các điều kiện sau:
- Mỗi dòng phải kết thúc bởi 1 kí hiệu \n
- Mỗi dòng được bao bởi cặp dấu “ ”
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
const char* rootCA = "-----BEGIN CERTIFICATE-----\n" "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" "rqXRfboQnoZsG4q5WTP468SQvvG5\n" "-----END CERTIFICATE-----\n"; |
Giải thích chương trình: Sau mỗi 5 giây, ESP32 sẽ publish một chuỗi có định dạng JSON tới trường desired của topic $aws/things/<Your_Device_ID>/shadow/update. Đồng thời chúng ta cũng sẽ subscribe topic $aws/things/<Your_Device_ID>/shadow/update/delta để có thể nhận được dữ liệu trả về từ AWS Broker khi có sự sai khác dữ liệu giữa trường desired và reported trong topic $aws/…/shadow/update. Các bạn đọc thêm ở phần 2 để hiểu thêm về cách sử dụng và tương tác với wildcards topic của AWS IoT.
Sau khi nạp code thành công chúng ta mở Serial Monitor trong Arduino IDE ra để quan sát (Lưu ý cài đặt mức baudrate là 115200). Dữ liệu nhận được sẽ như sau:
Như vậy là ở phần này chúng ta đã hoàn thành kết nối ESP32 tới AWS thông qua giao thức MQTT (tích hợp bảo mật TLS). Hy vọng thông qua chuỗi bài hướng dẫn “Xây dựng hệ thống Internet of Things sử dụng nền tảng AWS IoTs” sẽ giúp các bạn có được những kiến thức căn bản nhất để có thể xây dựng được các ứng dụng Internet of Things kết hợp với nền tảng AWS IoT cho riêng mình nhé.
Chúc các bạn thành công!
Xem thêm: Tổng hợp hướng dẫn Internet of Things với NodeMCU ESP8266 và ESP32
Nhóm TAPIT IoTs