目标:esp8266 接受来自 mqtt 消息队列的信息并完成指定动作(电灯、驱动舵机等…)

MQTT 是一种轻量级的发布/订阅消息传输协议,专为低带宽、不稳定网络环境下的物联网设备通信而设计。

了解 MQTT:MQTT 核心概念 | EMQX文档

ESP8266 是一款低成本、高性能的 Wi-Fi 芯片,集成了 TCP/IP 协议栈,广泛应用于物联网设备中,能够实现无线网络连接和数据传输。

主要参考博客:使用ESP8266连接MQTT服务器!快速学习ESP8266各功能!万字长文内含示例代码(下)_esp8266 mqtt-CSDN博客

技术选型和硬件选择🛠️

  • mqtt 消息队列:EMQX (使用docker自部署)
  • mqtt 客户端:MQTTX
  • esp8266: ESP-01S安可信
  • 开发平台:Arduino
  • 依赖库:PubSubClient

安装 EMQX 和 客户端 MQTTX

使用 docker 快速部署 EMQX:

确保已安装 docker 👉:docker 和 docker-compose 安装、配置、卸载(windows+linux)-CSDN博客

参考 emqx/README-CN.md at master · emqx/emqx,在终端使用下列命令启动 emqx :

docker run -d --name emqx \
	-p 1883:1883 \
	-p 8083:8083 \
	-p 8084:8084 \
	-p 8883:8883 \
	-p 18083:18083 \
	emqx/emqx:latest

MQTTX 下载地址:MQTTX:全功能 MQTT 客户端工具

使用教程参考: 开始使用 - MQTTX 文档

配置 Arduino ESP8266 开发环境

安装 Arduino IDE 以及 ESP8266 的核心库

esp8266/Arduino: ESP8266 core for Arduino

安装教程在上面的仓库中,这里摘一下:

通过 Boards Manager 安装

从 1.6.4 版本开始,Arduino 允许使用 Boards Manager 安装第三方平台包。我们提供了适用于 Windows、Mac OS 和 Linux(32 位和 64 位)的包。

  • 下载并安装 Arduino IDE 2.x
  • 启动 Arduino 并打开 Preferences 窗口
  • 在 Arduino IDE 的 文件 > 首选项 > 其他开发板管理地址 字段中输入 https://arduino.esp8266.com/stable/package_esp8266com_index.json ,您可以添加多个 URL,用逗号分隔它们。
  • 从 工具 > 开发板 菜单中打开开发板管理器并安装 esp8266 平台(安装后别忘了从“工具”>“开发板”菜单中选择您的 ESP8266 开发板)。

安装 ESP8266 的 MQTT 库

PubSubClient - Arduino Reference

下载最新版本,在 Arduino IDE 的项目-导入库-添加.ZIP库..,选择刚刚下载好的 .zip 压缩包即可安装完成。

连接 WIFI 和 MQTT

连接 MQTT 的代码可参考:快速攻略ESP8266NodeMCU(基于Arduino IDE)(下) – 留夏的小站

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
// WiFi设置
const char* WIFISSID ="xxx";
const char* PASSWORO ="xxxx";
uint8_t wifi_flag=0;
// MQTT服务器设置
const char* mqtt_server = "xxxxx";
const int mqtt_port = 1883;
const char* mqtt_id = "esp-01";
WiFiClient espClient;
PubSubClient client(espClient);
Ticker tim0;
void setup_wifi(){
  WiFi.mode(WIFI_STA);//设置为客户端模式
  //连接Wifi
  WiFi.begin(WIFISSID, PASSWORO);
  while(WiFi.status() != WL_CONNECTED){
      delay(500);
      Serial.print(".");
  }
  Serial.println("Connected to Wi-Fi");
  Serial.println(WiFi.SSID());
  //启用自动重连
  WiFi.setAutoReconnect(true);
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(mqtt_id)) {
      Serial.println("connected");
      // 订阅主题
      client.subscribe("topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

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

void issued(){
  client.publish("test","Hello!MQTT");
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  client.setKeepAlive(15);
  tim0.attach_ms(1000, issued);
}

void loop() {
  // 持续检查连接状态
  switch(WiFi.status()){
    case WL_CONNECTED:
      if(wifi_flag == 1){
        Serial.println("Connected to Wi-Fi");
        Serial.println(WiFi.SSID());
        wifi_flag=0;
      }
      if(!client.connected()){//检查与服务器连接状态
        reconnect();
      }
      client.loop();
      break;
    case WL_DISCONNECTED:
      if(wifi_flag == 0){
         wifi_flag=1;
        Serial.println("wifi Disconnected");
      }
      break;
  }
}

程序下载失败

注意引脚定义中,需要将 IO0 引脚接 GND,使模块处于 Download 模式.

ESP8266 初始化时抛出异常后正常执行程序

安装 esp-exception-decoder 插件,将只包含地址的堆栈信息粘贴到插件中进行解析,这里报错相当长,无法正常复制粘贴到插件中。

dankeboy36/esp-exception-decoder: ESP8266/ESP32 Exception Decoder Extension for the Arduino IDE

ESP8266 无法连接至 mqtt

在 Windows 的入站规则中开放本地的 1883 端口即可。