# 连接 ESP8266

本文主要介绍如何在 ESP8266 项目中使用 PubSubClient ,实现客户端与 MQTT 服务器的连接、订阅、收发消息等功能。

ESP8266 (opens new window) 提供了⼀套⾼度集成的 Wi-Fi SoC 解决⽅案,其低功耗、 紧凑设计和⾼稳定性可以满⾜⽤户的需求。ESP8266 拥有完整的且⾃成体系的 Wi-Fi ⽹络功能,既能够独⽴应⽤,也可以作为从机搭载于其他主机 MCU 运⾏。

本文将分别介绍通过 TCP 端口和 SSL/TLS 端口来连接 ESP32 客户端到 MQTT 服务器,对于使用 Serverless 部署的用户,请查看 SSL/TLS 端口连接示例。TCP 端口和 SSL/TLS 端口连接在连接设置部分略有不同,发布和订阅部分代码相同。

# 前置准备

在进行连接之前,您需要准备好 MQTT 服务器和客户端。

# 获得 MQTT Broker

使用 EMQX 提供的 免费公共 MQTT 服务器 (opens new window),该服务基于 EMQX 的 MQTT 物联网云平台 (opens new window) 创建。服务器接入信息如下:

  • Broker: broker.emqx.io
  • TCP Port: 1883
  • TLS/SSL Port: 8883

您也可以自己创建部署,在部署概览下可以查看到连接相关的信息,请确保部署状态为运行中。使用 TCP 端口或 TLS/SSL 端口 测试连接到 MQTT 服务器。

如果您是自己创建部署,请设置认证鉴权,在部署控制台认证鉴权 > 认证 中设置用户名和密码,用于连接验证。

# Arduino IDE

本文中使用 Arduino IDE (opens new window)作为代码编辑和上传,Arduino 集成开发环境(或是 ArduinoIDE)包含了一个用于写代码的文本编辑器、一个消息区、一个文本控制台以及一个带有常用功能按钮和文本菜单的工具栏。软件连接 Arduino 和 Genuino 之后,能给所连接的控制板上传程序,还能与控制板相互通信。

# 安装依赖

在 Arduino IDE 中完成以下安装。

  1. 安装 ESP8266 开发板。 点击工具 -> 开发板 -> 开发板管理。搜索 ESP8266,点击安装
  2. 安装 PubSub client 库。 点击项目 -> 加载库 -> 管理库...。搜索 PubSubClient,安装 PubSubClient by Nick O’Leary。

# 通过 TCP 端口连接

本章节介绍了如何在 Arduino IDE 中通过 TCP 端口连接 ESP8266 和 MQTT 服务器。

  1. 导入 WiFi 和 PubSubClient 库。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
1
2
  1. 设置 Wi-Fi 名称和密码,以及 MQTT 服务器连接地址和端口。

示例代码将使用公共 MQTT 服务器来连接,公共 MQTT 服务器无需设置用户名和密码。如果您创建了部署,请在部署控制台找到相应的连接地址,请参考 Serverless 认证鉴权专有版 / BYOC 认证鉴权设置用户名和密码。

// WiFi
const char *ssid = "mousse"; // Enter your WiFi name
const char *password = "qweqweqwe";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "broker.emqx.io"; // broker address
const char *topic = "esp8266/test"; // define topic 
const char *mqtt_username = "emqx"; // username for authentication
const char *mqtt_password = "public"; // password for authentication
const int mqtt_port = 1883; // port of MQTT over TCP
1
2
3
4
5
6
7
8
9
10
  1. 打开串行连接,以便于输出程序的结果并且连接到 Wi-Fi 网络。
// Set software serial baud to 115200;
Serial.begin(115200);
// connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
}
1
2
3
4
5
6
7
8
  1. 使用 PubSubClient 连接到公共 MQTT Broker。
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
    String client_id = "esp8266-client-";
    client_id += String(WiFi.macAddress());
    Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
    if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
  Serial.println("Public emqx mqtt broker connected");
    } else {
        Serial.print("failed with state ");
        Serial.print(client.state());
        delay(2000);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  1. MQTT 服务器连接成功后,ESP8266 将向 MQTT 服务器发布消息和订阅主题。
// publish and subscribe
client.publish(topic, "hello emqx"); // publish to the topic
client.subscribe(topic); // subscribe from the topic
1
2
3
  1. 将主题名称打印到串行端口,然后打印收到消息的每个字节。
void callback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message arrived in topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}
1
2
3
4
5
6
7
8
9
10

完整代码示例如下:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// WiFi
const char *ssid = "mousse"; // Enter your WiFi name
const char *password = "qweqweqwe";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "broker.emqx.io"; // broker address
const char *topic = "esp8266/test"; // define topic 
const char *mqtt_username = "emqx"; // username for authentication
const char *mqtt_password = "public"; // password for authentication
const int mqtt_port = 1883; // port of MQTT over TCP

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
    // Set software serial baud to 115200;
    Serial.begin(115200);
    // connecting to a WiFi network
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
    }
    Serial.println("Connected to the WiFi network");
    //connecting to a mqtt broker
    client.setServer(mqtt_broker, mqtt_port);
    client.setCallback(callback);
    while (!client.connected()) {
        String client_id = "esp8266-client-";
        client_id += String(WiFi.macAddress());
        Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
        if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Public emqx mqtt broker connected");
        } else {
            Serial.print("failed with state ");
            Serial.print(client.state());
            delay(2000);
        }
    }
    // publish and subscribe
    client.publish(topic, "hello emqx");
    client.subscribe(topic);
}

void callback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message arrived in topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}

void loop() {
    client.loop();
}
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

# 通过 TLS/SSL 端口连接

本章节介绍了如何在 Arduino IDE 中通过 TLS/SSL 端口连接 ESP8266 和 MQTT 服务器。TCP 端口和 TLS/SSL 端口连接在连接设置部分略有不同,发布和订阅部分代码相同。

  1. 导入 WiFi 和 PubSubClient 库。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
1
2
  1. 设置 Wi-Fi 名称和密码,以及 MQTT 服务器连接地址和端口。

示例代码将使用公共 MQTT 服务器来连接,公共 MQTT 服务器无需设置用户名和密码。如果您创建了部署,请在部署控制台找到相应的连接地址,请参考 Serverless 认证鉴权专有版 / BYOC 认证鉴权设置用户名和密码。。

// WiFi
const char *ssid = "[WIFI SSID]"; // Enter your WiFi name
const char *password = "[WIFI password]";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "broker.emqx.io"; // broker address
const char *topic = "esp8266/test"; // define topic 
const char *mqtt_username = "emqx"; // username for authentication
const char *mqtt_password = "public"; // password for authentication
const int mqtt_port = 8883; // port of MQTT over TLS/SSL
1
2
3
4
5
6
7
8
9
10
  1. EMQX 服务器的常见指纹,仅供参考。如果你没有使用 Serverless 部署或公共 broker、 你需要计算出你的服务器证书的 sha1 指纹并更新下面的'fingerprint'变量。
// init wifi client
WiFiClientSecure espClient;
PubSubClient client(espClient);

/*
  The common fingerprints of EMQX broker, for reference only.
  If you are not using EMQX Cloud Serverless or public EMQX broker,
  you need to calculate the sha1 fingerprint of your server certificate
  and update the 'fingerprint' variable below.
*/
// 1. fingerprint of public emqx broker. Host: broker.emqx.io
const char* fingerprint = "B6 C6 FF 82 C6 59 09 BB D6 39 80 7F E7 BC 10 C9 19 C8 21 8E";
// 2. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.com
// const char* fingerprint = "42:AE:D8:A3:42:F1:C4:1F:CD:64:9C:D7:4B:A1:EE:5B:5E:D7:E2:B5";
// 3. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.cn
// const char* fingerprint = "7E:52:D3:84:48:3C:5A:9F:A4:39:9A:8B:27:01:B1:F8:C6:AD:D4:47";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  1. 打开串行连接,以便于输出程序的结果并且连接到 Wi-Fi 网络。
// Set software serial baud to 115200;
Serial.begin(115200);
// connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
1
2
3
4
5
6
7
8
9
  1. 设置指纹并使用 PubSubClient 连接到公共 MQTT Broker。
// set fingerprint
espClient.setFingerprint(fingerprint);
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
    String client_id = "esp8266-client-";
    client_id += String(WiFi.macAddress());
    Serial.printf("The client %s connects to the mqtt broker\n", client_id.c_str());
    if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
        Serial.println("Connected to MQTT broker.");
    } else {
        Serial.print("Failed to connect to MQTT broker, rc=");
        Serial.print(client.state());
        Serial.println(" Retrying in 5 seconds.");
        delay(5000);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  1. MQTT 服务器连接成功后,ESP8266 将向 MQTT 服务器发布消息和订阅主题。
// publish and subscribe
client.publish(topic, "hello emqx"); // publish message to a topic
client.subscribe(topic); // subscribe message from the topic
1
2
3
  1. 将主题名称打印到串行端口,然后打印收到消息的每个字节。
void callback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message arrived in topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}
1
2
3
4
5
6
7
8
9
10

完整代码示例如下:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// WiFi
const char *ssid = "[WIFI SSID]"; // Enter your WiFi name
const char *password = "[WIFI password]";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "broker.emqx.io"; // broker address
const char *topic = "esp8266/test"; // define topic 
const char *mqtt_username = "emqx"; // username for authentication
const char *mqtt_password = "public"; // password for authentication
const int mqtt_port = 8883; // port of MQTT over TLS/SSL

// init wifi client
WiFiClientSecure espClient;
PubSubClient client(espClient);

/*
  The common fingerprints of EMQX broker, for reference only.
  If you are not using EMQX Cloud Serverless or public EMQX broker,
  you need to calculate the sha1 fingerprint of your server certificate
  and update the 'fingerprint' variable below.
*/
// 1. fingerprint of public emqx broker. Host: broker.emqx.io
const char* fingerprint = "B6 C6 FF 82 C6 59 09 BB D6 39 80 7F E7 BC 10 C9 19 C8 21 8E";
// 2. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.com
// const char* fingerprint = "42:AE:D8:A3:42:F1:C4:1F:CD:64:9C:D7:4B:A1:EE:5B:5E:D7:E2:B5";
// 3. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.cn
// const char* fingerprint = "7E:52:D3:84:48:3C:5A:9F:A4:39:9A:8B:27:01:B1:F8:C6:AD:D4:47";


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to the WiFi network");

  // set fingerprint
  espClient.setFingerprint(fingerprint);
  client.setServer(mqtt_broker, mqtt_port);
  client.setCallback(callback);
  while (!client.connected()) {
    String client_id = "esp8266-client-";
    client_id += String(WiFi.macAddress());
    Serial.printf("The client %s connects to the mqtt broker\n", client_id.c_str());
    if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
        Serial.println("Connected to MQTT broker.");
    } else {
        Serial.print("Failed to connect to MQTT broker, rc=");
        Serial.print(client.state());
        Serial.println(" Retrying in 5 seconds.");
        delay(5000);
    }
  }

    // publish and subscribe
    client.publish(topic, "hello emqx"); // publish message to the topic
    client.subscribe(topic); // subscribe message from the topic
}

void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Message arrived in topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}
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

# 测试连接

在成功连接 MQTT 服务器后,您可以使用 Arduino IDE 和 MQTT X 测试连接。

  1. 请使用 Arduino IDE 将完整代码上传到 ESP8266,并打开串口监视器。 esp8266_connection
  2. 建立 MQTT X 客户端 与 MQTT 服务器的连接, 并向 ESP8266 发送消息。 esp8266_mqttx
  3. 在串口监视器查看 ESP8266 接收到的消息。 esp8266_receive

# 更多内容

综上所述,我们实现了在 ESP8266 项目中创建 MQTT 连接,模拟了使用客户端与 MQTT 服务器进行连接、订阅、收发消息的场景。可以在 这里 (opens new window) 下载到示例的源码,同时也可以在 GitHub (opens new window) 上找到更多其他语言的 Demo 示例。