基于Arduino将ESP8266(Nodemcu) MQTT使用TLS接入物联网平台

本文基于UCloud的物联通信云平台给出具体示例,并附上示例代码。
模块是用ESP8266的NodeMCU。

1. TLS的概述

关于TLS的具体理论可以参考下面5篇文章:
HTTPS协议详解(一):HTTPS基础知识
HTTPS协议详解(二):TLS/SSL工作原理
HTTPS协议详解(三):PKI 体系
HTTPS协议详解(四):TLS/SSL握手过程
HTTPS协议详解(五):HTTPS性能与优化

本文虽然不介绍具体的TLS的具体只是,大概讲解下TCP、MQTT、TLS三者之间的关系。

MQTT是一个应用层协议,可以理解为和HTTP相对应的一层协议,MQTT是目前物联网平台广泛支持的一种用于物联网通信的协议,他的优势是开销小,实现标准,目前主流的云厂商AWS、Aliyun、UCloud的物联网平台都是基于MQTT标准进行通信。MQTT的4层连接协议仍然是TCP,所以是可靠的连接,TLS是在TCP和MQTT之间将MQTT数据包加密再通过TCP传输加密数据。所以MQTT over TLS一般叫做MQTTS。

层级关系:
MQTT
---------
TLS
---------
TCP

2. ESP8266 的Arduino库官方TLS库

ESP8266-Aruino使用的是BearSSL库(ESP32使用的是embedTLS库),具体介绍可以参考文档 ESP8266-Aruino的官方介绍文档和TLS and HTTPS Basics。
基于Arduino将ESP8266(Nodemcu) MQTT使用TLS接入物联网平台_第1张图片
BearSSL官方文档

3. 接入物联网平台准备工作

本文物联网平台使用UCloud物联网通信云平台,目前处于公测阶段是免费使用的,参考文档

1) 创建产品、创建设备

2) MQTT连接参数

  • clientID:zzau1wz5blfzgltp.zpzqzz98lk8yrvmp
  • Username: zzau1wz5blfzgltp|zpzqzz98lk8yrvmp|1
  • Password: 90apiwl2txbo9gn6

3) MQTT连接

  • Broker address: mqtt-cn-sh2.iot.ucloud.cn
  • Port: 8883
  • CA证书:下载CA证书(自签名)

4. 实现代码

#include 
#include 
#include 
#include 
#include "FS.h"


const char *logo_img = \
{
    "`],`].   =@@@^  ,/@@@@@@@^ =@@@^      ,@@@@@@@@@`   @@@O    =@@@. =@@@@@@@@@@` \n"\
    " \\=@O.   =@@@^ ,@@@@.      =@@@^     =@@@^   =@@@^  @@@O    =@@@.         =@@@`\n"\
    " O@@O.   =@@@^ O@@@.       =@@@^     O@@O.    O@@@  @@@O    =@@@. =@@@^   .@@@\\\n"\
    " O@@O.   =@@@^.O@@O        =@@@^    .O@@O     =@@@. @@@O    =@@@. =@@@^   .O@@O\n"\
    " O@@O.   =@@@^ O@@@.       =@@@^     O@@O.    O@@@  @@@O    =@@@. =@@@^   .@@@O\n"\
    " =@@@^  .O@@@. ,@@@@`      ,@@@@].   =@@@\\  ./@@@^  \\@@@`  ,@@@@  =@@@^  ./@@@^\n"\
    "  ,@@@@@@@@/    .\\@@@@@@@^  ,\\@@@@@@O ,\\@@@@@@@O`    ,@@@@@@@@/   =@@@@@@@@@O` \n"\
};


static const char mqtt_ca_crt[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDsjCCApoCCQCudOie27G3QDANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC
Q04xETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UE
CgwGVUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3
dy51Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24w
HhcNMTkwNzI5MTIyMDQxWhcNMzkwNzI0MTIyMDQxWjCBmjELMAkGA1UEBhMCQ04x
ETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UECgwG
VUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3dy51
Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0g9bzkQBipln/nRsUKeQcwAkU
ZUk/VMWrg5AzBislYW9hujCGZHWXUknVHPSQM2Pk30tPeIdmupSkOJllYtFplI6U
6kqHpVsyPn925H5zz4uP5Ty0hkkNK+rIR/YjbEjGn8loTqWk++/o6qST5QOrZLUR
vxaWvshpce0QUcYU9xMfUPzLa6/ZfmaNHgn1aWExYMJAWDyBCyw4OxeSMUyH+ydh
egW7VHNQuVHOYdnXiC+VYImNJ8+QAyCIZ88lP0nqVPSKTt1XXmGW6vXrWSl+/XhO
GaHNMzlwb1kqlFx/ZagTQoQ0hpmqSUKtqPgKSqGPxY9go1Rda1m2rYc8k3gJAgMB
AAEwDQYJKoZIhvcNAQELBQADggEBAHU0KKqEbR7uoY1tlE+MDsfx/2zXNk9gYw44
O+xGVdbvTC298Ko4uUEwc1C+l9FaMmN/2qUPSXWsSrAYDGMS63rzaxqNuADTgmo9
QY0ITtTf0lZTkUahVSqAxzMFaaPzSfFeP9/EaUu14T5RPQbUZMVOAEPKDNmfK4rD
06R6dnO12be4Qlha14o67+ojaNtyZ7/ESePXA/RjO9YMkeQAoa4BdnsJCZgCFmXf
iKvGM+50+L/qSbH5F//byLGTO1t3TWCCdBE5/Mc/QLYEXDmZM6LMHyEAw4VuinIa
I8m1P/ceVO0RjNNBG0pDH9PH4OA7ikY81c63PBCQaYMKaiksCzs=
-----END CERTIFICATE-----
)EOF";

const char *ssid = "your-ssid";
const char *pass = "your-wifi-password";

//uiot-core server
const char*  mqtt_server = "mqtt-cn-sh2.iot.ucloud.cn";

PubSubClient mqttclient;


BearSSL::WiFiClientSecure wifiClient;
/* set SSL/TLS certificate */
BearSSL::X509List mqttcert(mqtt_ca_crt);

//WiFiClient wifiClient;



/* auth topic */
#define PRODUCT_SN              "poau1wz5blfzgltp"
#define DEVICE_SN               "f94sszx6nue2zhkc"
#define CLIENT_ID               PRODUCT_SN"."DEVICE_SN
#define DYNAMIC_USERNAME        PRODUCT_SN"|"DEVICE_SN"|2"
#define STATIC_USERNAME         PRODUCT_SN"|"DEVICE_SN"|1"
#define DYNAMIC_PASSWORD        "tq1vwjhxbpw78g0l"
#define STATIC_PASSWORD         "4n60vhi2rub3g5r3"
#define PASSWRD_TOPIC           "/$system/"PRODUCT_SN"/"DEVICE_SN"/password"
#define PASSWORD_REPLY_TOPIC    "/$system/"PRODUCT_SN"/"DEVICE_SN"/password_reply"
// Topic
#define uplink                  "/"PRODUCT_SN"/"DEVICE_SN"/upload"
#define downlink                "/"PRODUCT_SN"/"DEVICE_SN"/set"

#define CURRENT_VERSION                     "0.0.1"


// Set time via NTP, as required for x.509 validation
void setClock()
{
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2)
  {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
}


void receivedCallback(char* topic, byte* payload, unsigned int length)
{

  Serial.print("Message received: ");
  Serial.println(topic);

  Serial.print("payload: ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
}


void setup()
{
  Serial.printf("%s", logo_img);
  Serial.printf("\nCurrent Version = %s\n", CURRENT_VERSION);

  // STEP1: Configure Hardware-UART0 for YB48, SoftwareSerial as Serial;
  Serial.begin(115200);
  Serial.printf("\n%s", logo_img);
  Serial.printf("\nCurrent Version = %s\n", CURRENT_VERSION);

  // STEP2: Do SmartConifg and connecting to a WiFi network
  Serial.printf("Connecting to %s\n", ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

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

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

  // STEP3: Set CA Certification for TLS
  wifiClient.setTrustAnchors(&mqttcert);
  setClock();
  // if no check the CA Certification
  wifiClient.setInsecure();

  // STEP4: Set MQTT Parameters
  mqttclient.setClient(wifiClient);
  // configure the MQTT server with IPaddress and port, and the subscribe callback
  mqttclient.setServer(mqtt_server, 8883);
  mqttclient.setCallback(receivedCallback);

  // STEP5: Connect to UCloud MQTT Broker
  if (mqttclient.connect(CLIENT_ID, STATIC_USERNAME, STATIC_PASSWORD))
  {
    Serial.println("static connected");
    mqttclient.subscribe(downlink);
  }
  else
  {
    Serial.printf("static connect failed, status code = %d\n", mqttclient.state());
    // Wait 5 seconds before retrying
    delay(5000);
  }

}


void loop()
{
  if (WiFi.status() != WL_CONNECTED)
  {
    WiFi.begin(ssid, pass);
    Serial.println("wifi reconnected!");
  }

  // this function will listen for incomming subscribed topic-process-invoke receivedCallback
  if (!mqttclient.loop())
  {
    Serial.println("mqttclient.loop fail!");
  }

}

你可能感兴趣的:(物联网平台)