目录
安装 Mosquitto 作为本地 Broker,并使用 MQTTX(GUI 工具)或 Python 代码进行基本的发布/订阅测试。
进一步扩展这些功能,例如处理重连、设定遗嘱消息(Last Will and Testament)。
用 Node.js 或 ESP8266 连接 MQTT Broker 进行测试。
示例 1:用 Node.js 连接 MQTT Broker 扩展示例
示例 2:用 ESP8266(Arduino IDE)连接 MQTT Broker 扩展示例
部署一个安全的 MQTT 服务器,并用 SSL/TLS 进行加密通信。
开发一个 MQTT 可视化仪表盘,实时显示传感器数据(可以用 React + WebSocket)
用 ESP32 + MQTT 实现远程温湿度监测,并推送告警。
MQTT 是物联网(IoT)中最常用的通信协议之一,如果你想系统地学习 MQTT,从入门到精通,为你整理一个学习路径,并提供代码示例,帮助你逐步掌握 MQTT 的核心概念和应用。
📌 MQTT 学习路线
第一阶段:基础入门
🔹 了解 MQTT 是什么:轻量级的物联网消息传输协议,基于发布/订阅(Pub/Sub)模式。
🔹 MQTT 的组成部分:
-
Broker(消息代理):负责消息的转发(如 Mosquitto、EMQX、HiveMQ)。
-
Client(客户端):可以是发布者(Publisher)或订阅者(Subscriber)。
-
Topic(主题):用于分类和组织消息。
-
QoS(服务质量):0(最多一次),1(至少一次),2(仅一次)。
🔹 MQTT vs HTTP:MQTT 更适用于物联网,因为它比 HTTP 更轻量级、实时、低功耗。
推荐练习一
安装 Mosquitto 作为本地 Broker,并使用 MQTTX(GUI 工具)或 Python 代码进行基本的发布/订阅测试。
下面介绍一个完整的流程,从安装 Mosquitto 作为本地 Broker,到使用 MQTTX(图形界面工具)和 Python 代码进行基本的发布/订阅测试。
1.安装 Mosquitto Broker
(1)在 Windows 系统上
1)下载 前往 Mosquitto 官网下载页面 下载对应平台的安装包。
2)安装 双击安装程序并按照向导完成安装。记住安装目录(例如:C:\Program Files\mosquitto
)。
3)配置(可选) 若仅用于本地测试,可在配置文件 mosquitto.conf
中设置允许匿名访问(将 allow_anonymous
设置为 true
),也可直接使用默认配置。
4)启动 Broker 打开命令提示符(建议以管理员身份运行),进入 Mosquitto 安装目录,执行以下命令启动 Broker 并观察日志信息:
mosquitto -v
5) 此命令以详细模式启动,并在控制台输出连接日志。
(2)在 Linux 系统上
1)更新软件包
sudo apt-get update
2)安装 Mosquitto 和客户端工具
sudo apt-get install mosquitto mosquitto-clients
3)启动 Broker 通常 Mosquitto 会自动作为服务启动,你可以使用下面的命令检查状态:
sudo systemctl status mosquitto
4) 或者手动启动:
sudo systemctl start mosquitto
2.使用 MQTTX 进行测试
MQTTX 是一款跨平台的 MQTT 客户端工具,提供图形化操作,支持快速创建连接、订阅和发布消息。操作步骤如下:
1)创建连接
-
打开 MQTTX 后点击“New Connection”。
-
填写连接参数:
-
Host:输入
localhost
(如果 Mosquitto 运行在本机)或对应的 IP 地址。 -
Port:默认端口为
1883
。 -
若使用默认配置且允许匿名访问,则用户名和密码可留空。
-
-
点击“Connect”建立连接。
2)订阅主题
-
在已建立的连接中,点击“New Subscription”。
-
输入主题,例如:
test/topic
,然后确认订阅。
3)发布消息
-
在 MQTTX 的发布区域,输入同一主题
test/topic
及消息内容(例如“Hello MQTTX”)。 -
点击发送图标,消息将推送到 Broker,并可在订阅窗口看到接收到的消息。
第二阶段:动手实践
🔹 搭建 MQTT 服务器
-
本地部署:使用 Mosquitto(适用于轻量级测试)。
-
云端 MQTT 服务器:EMQX Cloud、AWS IoT、Google Cloud IoT、HiveMQ Cloud。
-
在树莓派等 IoT 设备上运行 MQTT Broker。
🔹 MQTT 客户端开发
-
Python(Paho MQTT 库)
-
Node.js(MQTT.js)
-
ESP8266/ESP32(Arduino-MQTT 库)
-
其他语言(Java、C++、Go)
📌 Python 客户端示例
import paho.mqtt.client as mqtt
连接回调
def on_connect(client, userdata, flags, rc):
print(f"Connected with result code {rc}")
client.subscribe("home/temperature")
消息接收回调
def on_message(client, userdata, msg):
print(f"Received: {msg.topic} -> {msg.payload.decode()}")
创建 MQTT 客户端
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.emqx.io", 1883, 60) # 连接 MQTT 服务器
client.loop_forever() # 进入循环等待消息
推荐练习二
用 Python 发送和接收 MQTT 消息
下面提供一个简单示例,展示如何使用 Python 的 Paho MQTT 库实现消息的发布与接收。首先请确保安装了 Paho MQTT 库:
pip install paho-mqtt
1.订阅客户端(接收消息)
以下代码演示了如何创建一个 MQTT 订阅者,连接到 Broker 后订阅某个主题,并在收到消息时打印输出:
import paho.mqtt.client as mqtt
连接成功后的回调函数
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("成功连接到 MQTT Broker!")
# 订阅主题 'test/topic'
client.subscribe("test/topic")
else:
print("连接失败,错误码:", rc)
收到消息时的回调函数
def on_message(client, userdata, msg):
print(f"接收到主题 {msg.topic} 的消息: {msg.payload.decode()}")
创建 MQTT 客户端实例
client = mqtt.Client()
指定回调函数
client.on_connect = on_connect
client.on_message = on_message
连接到本地 Broker(也可以替换为其他服务器地址)
client.connect("localhost", 1883, 60)
启动网络循环,保持连接并等待消息
client.loop_forever()
2.发布客户端(发送消息)
下面代码用于创建一个 MQTT 发布者,连接到 Broker 后向指定主题发布一条消息:
import paho.mqtt.client as mqtt
import time
创建 MQTT 客户端实例
client = mqtt.Client()
连接到 Broker
client.connect("localhost", 1883, 60)
启动网络循环(这里使用非阻塞模式)
client.loop_start()
发布消息到主题 'test/topic'
message = "Hello MQTT from Python!"
client.publish("test/topic", message)
print(f"已向主题 test/topic 发送消息: {message}")
稍作延时后关闭循环(确保消息已发送完成)
time.sleep(2)
client.loop_stop()
说明
-
订阅客户端中,我们在
on_connect
回调中调用了client.subscribe("test/topic")
订阅指定主题,收到消息时由on_message
回调处理并打印消息内容。 -
发布客户端中,通过
client.publish("test/topic", message)
向同一主题发布消息,确保发布者与订阅者都能接收到消息。
这种发布/订阅模式是 MQTT 协议的核心机制,非常适合物联网等场景下的设备间通信。
扩展功能:设置用户名/密码、配置 QoS、使用 TLS 。
下面的示例演示了如何在 Python 中使用 Paho MQTT 库实现扩展功能,包括设置用户名/密码、指定 QoS 和使用 TLS 加密连接。
请确保已安装 Paho MQTT 库:
pip install paho-mqtt
示例 1:订阅客户端(带用户名/密码、TLS 和 QoS)
import paho.mqtt.client as mqtt
import ssl
连接成功后的回调函数
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("成功连接到 MQTT Broker!")
# 订阅主题 "test/topic",QoS 设为 1
client.subscribe("test/topic", qos=1)
else:
print("连接失败,错误码:", rc)
收到消息时的回调函数
def on_message(client, userdata, msg):
print(f"接收到主题 {msg.topic} 的消息: {msg.payload.decode()}")
创建 MQTT 客户端实例,并指定客户端 ID
client = mqtt.Client(client_id="extended-subscriber")
设置用户名和密码(替换为实际值)
client.username_pw_set("your_username", "your_password")
配置 TLS 加密(替换证书路径为实际路径)
client.tls_set(
ca_certs="path/to/ca.crt", # CA 证书
certfile="path/to/client.crt", # 客户端证书(如果需要)
keyfile="path/to/client.key", # 客户端密钥(如果需要)
tls_version=ssl.PROTOCOL_TLSv1_2 # 指定 TLS 版本
)
client.on_connect = on_connect
client.on_message = on_message
连接到支持 TLS 的 MQTT Broker,端口一般为 8883
client.connect("broker.example.com", 8883, 60)
启动网络循环,等待消息
client.loop_forever()
示例 2:发布客户端(带用户名/密码、TLS 和 QoS)
import paho.mqtt.client as mqtt
import ssl
import time
创建 MQTT 客户端实例,并指定客户端 ID
client = mqtt.Client(client_id="extended-publisher")
设置用户名和密码(替换为实际值)
client.username_pw_set("your_username", "your_password")
配置 TLS 加密(替换证书路径为实际路径)
client.tls_set(
ca_certs="path/to/ca.crt",
certfile="path/to/client.crt",
keyfile="path/to/client.key",
tls_version=ssl.PROTOCOL_TLSv1_2
)
连接到 MQTT Broker(TLS 端口 8883)
client.connect("broker.example.com", 8883, 60)
使用非阻塞网络循环
client.loop_start()
发布消息到主题 "test/topic",QoS 设为 1
message = "Hello with TLS and QoS!"
client.publish("test/topic", payload=message, qos=1)
print(f"已向主题 test/topic 发送消息: {message}")
等待一段时间,确保消息发送完成
time.sleep(2)
client.loop_stop()
说明
-
用户名/密码:通过调用
client.username_pw_set("your_username", "your_password")
指定认证信息。 -
TLS 加密:使用
client.tls_set()
方法配置 CA 证书、客户端证书与密钥(如服务器要求双向认证),并指定 TLS 协议版本。 -
QoS 设置:在订阅时通过参数
qos=1
指定消息服务质量;发布消息时也可通过qos=1
保证至少一次交付。 -
连接端口:使用 TLS 时通常连接端口为 8883(请根据实际 Broker 配置调整)。
这些扩展配置使得 MQTT 客户端更加安全和可靠,适用于生产环境中的物联网通信场景。
进一步扩展这些功能,例如处理重连、设定遗嘱消息(Last Will and Testament)。
下面的示例扩展了之前的代码,不仅设置了用户名/密码、TLS 与 QoS,还添加了自动重连和遗嘱消息(Last Will and Testament)的配置。该示例适用于发布和订阅场景,可以帮助你更好地处理网络断连等异常情况。
import paho.mqtt.client as mqtt
import ssl
import time
当连接成功时的回调函数
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("成功连接到 MQTT Broker!")
# 连接成功后订阅指定主题,QoS 设为 1
client.subscribe("test/topic", qos=1)
else:
print("连接失败,错误码:", rc)
当断开连接时的回调函数
def on_disconnect(client, userdata, rc):
print("断开连接,返回码:", rc)
# 如果是非正常断开(rc != 0),则尝试自动重连
if rc != 0:
print("非正常断开,尝试重连...")
try:
client.reconnect()
except Exception as e:
print("重连失败:", e)
收到消息时的回调函数
def on_message(client, userdata, msg):
print(f"接收到主题 {msg.topic} 的消息: {msg.payload.decode()}")
创建 MQTT 客户端实例,并指定客户端 ID
client = mqtt.Client(client_id="extended-client")
设置用户名和密码(请替换为实际的认证信息)
client.username_pw_set("your_username", "your_password")
配置 TLS 加密(请替换证书路径,若不需要 TLS 可忽略此步骤)
client.tls_set(
ca_certs="path/to/ca.crt", # CA 证书路径
certfile="path/to/client.crt", # 客户端证书(如果需要)
keyfile="path/to/client.key", # 客户端密钥(如果需要)
tls_version=ssl.PROTOCOL_TLSv1_2
)
设置遗嘱消息(Last Will and Testament)
当客户端意外断开连接时,Broker 将向主题 "test/will" 发布该消息
client.will_set("test/will", payload="Client disconnected unexpectedly", qos=1, retain=False)
设置回调函数
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_message = on_message
配置自动重连延迟,最小 1 秒,最大 120 秒
client.reconnect_delay_set(min_delay=1, max_delay=120)
连接到支持 TLS 的 MQTT Broker(此处以 8883 端口为例,请根据实际情况修改)
client.connect("broker.example.com", 8883, 60)
启动网络循环(非阻塞模式)
client.loop_start()
示例:每隔 5 秒发布一条消息到 "test/topic",QoS 设为 1
try:
while True:
message = "Hello with LWT, QoS 1!"
result = client.publish("test/topic", payload=message, qos=1)
status = result[0]
if status == 0:
print(f"已发布消息到主题 test/topic: {message}")
else:
print(f"发布消息失败,错误码: {status}")
time.sleep(5)
except KeyboardInterrupt:
print("退出程序...")
finally:
client.loop_stop()
client.disconnect()
说明
-
用户名/密码:通过
client.username_pw_set("your_username", "your_password")
设置认证信息。 -
TLS 加密:使用
client.tls_set(...)
配置了 CA 证书、客户端证书及密钥,并指定了 TLS 版本。 -
遗嘱消息:调用
client.will_set("test/will", payload="...", qos=1, retain=False)
,在客户端意外断连时,Broker 将自动发布该消息给订阅了test/will
主题的客户端。 -
自动重连:在
on_disconnect
回调中检测非正常断连,并调用client.reconnect()
尝试重连。同时,通过client.reconnect_delay_set()
配置了重连延迟参数,使重连更加平滑。 -
QoS:在发布和订阅时均设置了 QoS 为 1,以保证至少一次的消息交付。
这种扩展的代码能够应对生产环境中常见的网络异常,并保证消息的可靠传递,同时利用遗嘱消息提醒其他客户端注意异常断连情况,非常适合物联网应用中的实际需求。
扩展练习三
用 Node.js 或 ESP8266 连接 MQTT Broker 进行测试。
下面给出两个示例,一个是用 Node.js 连接 MQTT Broker 进行测试,另一个是用 ESP8266(基于 Arduino IDE)连接 MQTT Broker 进行测试。
示例 1:用 Node.js 连接 MQTT Broker
我们使用 Node.js 的 mqtt 库来建立连接、订阅和发布消息。 首先安装 mqtt 模块:
npm install mqtt
下面是一段简单的代码示例:
const mqtt = require('mqtt')
// 连接到 Broker(这里以公共 Broker 为例,也可替换为你的服务器)
const client = mqtt.connect('mqtt://broker.hivemq.com')
client.on('connect', function () {
console.log('已成功连接到 MQTT Broker!')
// 订阅主题 'test/topic',QoS 设置为 1
client.subscribe('test/topic', { qos: 1 }, (err) => {
if (!err) {
// 发布消息到 'test/topic'
client.publish('test/topic', 'Hello Node.js MQTT!', { qos: 1 })
} else {
console.error('订阅失败:', err)
}
})
})
// 接收消息
client.on('message', function (topic, message) {
// message 为 Buffer 类型,转换为字符串
console.log(
收到主题 ${topic} 的消息: ${message.toString()}
)
// 根据需要可以结束连接
// client.end()
})
说明
-
连接:使用
mqtt.connect()
传入 Broker 地址建立连接。 -
订阅:调用
client.subscribe()
并指定主题和 QoS 参数。 -
发布:在连接成功后调用
client.publish()
向同一主题发布消息。 -
回调:
on('message', ...)
用于接收并处理消息。
示例 2:用 ESP8266 连接 MQTT Broker
ESP8266 上通常使用 Arduino IDE 开发,可以借助 PubSubClient 库来连接 MQTT Broker。下面是一段简单的代码示例:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// 替换为你的 WiFi SSID 和密码
const char* ssid = "your_SSID";
const char* wifi_password = "your_WiFi_password";
// 替换为你的 MQTT Broker 地址(这里以公共 Broker 为例)
const char* mqtt_server = "broker.hivemq.com";
WiFiClient espClient;
PubSubClient client(espClient);
// MQTT 消息到达回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到主题 [");
Serial.print(topic);
Serial.print("] 的消息: ");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
// 尝试重连 MQTT Broker
void reconnect() {
// 循环直到连接成功
while (!client.connected()) {
Serial.print("尝试连接 MQTT Broker...");
// 使用一个唯一的客户端 ID
if (client.connect("ESP8266Client")) {
Serial.println("连接成功");
// 订阅主题
client.subscribe("test/topic", 1);
} else {
Serial.print("连接失败,状态码=");
Serial.print(client.state());
Serial.println(",5 秒后重试");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
delay(10);
// 连接 WiFi
Serial.println();
Serial.print("连接 WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 连接成功");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 每 5 秒发布一条消息到主题 'test/topic'
static unsigned long lastPublish = 0;
if (millis() - lastPublish > 5000) {
lastPublish = millis();
Serial.println("发布消息到主题 test/topic");
client.publish("test/topic", "Hello from ESP8266!", 1);
}
}
说明
-
WiFi 连接:在
setup()
中连接到 WiFi 网络。 -
MQTT 连接:调用
client.setServer()
配置 Broker 地址,并在reconnect()
函数中实现自动重连。 -
订阅:连接成功后订阅主题
test/topic
,QoS 设置为 1。 -
发布:在
loop()
中定时调用client.publish()
向主题发布消息。 -
回调:
callback()
用于接收并打印从 Broker 传来的消息。
这两个示例展示了如何分别使用 Node.js 和 ESP8266 连接 MQTT Broker 进行测试。
扩展功能:自动重连、遗嘱消息、保留消息、交互逻辑
下面提供两个扩展示例代码,分别适用于 Node.js 和 ESP8266(基于 Arduino IDE),示例中加入了以下扩展功能:
-
自动重连:当连接断开时自动尝试重连。
-
遗嘱消息(Last Will and Testament):在异常断连时,Broker 会自动向指定主题发布遗嘱消息。
-
保留消息:在发布消息时设置保留标识,Broker 会保存最后一条保留消息供新订阅者接收。
-
交互逻辑:例如在收到特定命令(如 "ping")时回复 "pong"。
示例 1:用 Node.js 连接 MQTT Broker 扩展示例
首先安装 Node.js 的 mqtt 模块:
npm install mqtt
然后使用以下代码实现扩展功能:
const mqtt = require('mqtt')
// 连接选项,包含用户名、密码、自动重连、遗嘱消息等配置
const options = {
clientId: 'nodejs-advanced-client-' + Math.random().toString(16).substr(2, 8),
username: 'your_username', // 替换为实际用户名
password: 'your_password', // 替换为实际密码
keepalive: 60,
reconnectPeriod: 5000, // 每 5 秒自动重连一次
will: {
topic: 'test/will',
payload: 'Node.js client disconnected unexpectedly',
qos: 1,
retain: false,
}
}
// 连接到 Broker(这里以公共 Broker 为例,或替换为你的服务器地址)
const client = mqtt.connect('mqtt://broker.hivemq.com', options)
client.on('connect', () => {
console.log('已成功连接到 MQTT Broker!')
// 订阅主题 'test/advanced',QoS 设为 1
client.subscribe('test/advanced', { qos: 1 }, (err) => {
if (!err) {
console.log('已订阅主题 test/advanced')
// 发布一条保留消息
client.publish('test/advanced', 'Hello with retained message', { qos: 1, retain: true })
} else {
console.error('订阅失败:', err)
}
})
})
client.on('reconnect', () => {
console.log('正在重连 MQTT Broker...')
})
client.on('offline', () => {
console.log('客户端处于离线状态')
})
client.on('error', (err) => {
console.error('MQTT 错误:', err)
})
// 接收消息并实现简单交互逻辑
client.on('message', (topic, message) => {
const msg = message.toString()
console.log(
收到主题 ${topic} 的消息: ${msg}
)
// 示例:如果收到 "ping" 消息,回复 "pong"
if (topic === 'test/advanced' && msg === 'ping') {
client.publish('test/advanced', 'pong', { qos: 1, retain: false })
console.log('回复 pong')
}
})
// 定时发布 "ping" 命令,每 10 秒一次
setInterval(() => {
client.publish('test/advanced', 'ping', { qos: 1, retain: false })
console.log('发布 ping 消息')
}, 10000)
说明
-
自动重连:通过
reconnectPeriod
配置,客户端会每 5 秒尝试重连。 -
遗嘱消息:配置项
will
在客户端异常断连时由 Broker 发布到test/will
主题。 -
保留消息:发布消息时设置
retain: true
,Broker 会保存最后一条保留消息。 -
交互逻辑:当收到主题
test/advanced
上的 "ping" 消息时,回复 "pong"。
示例 2:用 ESP8266(Arduino IDE)连接 MQTT Broker 扩展示例
在 Arduino IDE 中,使用 PubSubClient 库实现扩展功能。请先安装 ESP8266 开发板和 PubSubClient 库。
下面代码展示了如何配置自动重连、遗嘱消息、保留消息以及简单的交互逻辑(收到 "ping" 回复 "pong"):
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// WiFi 配置(请替换为你的 WiFi SSID 与密码)
const char* ssid = "your_SSID";
const char* wifi_password = "your_WiFi_password";
// MQTT Broker 配置(这里以公共 Broker 为例,可替换为你的服务器)
const char* mqttServer = "broker.hivemq.com";
const int mqttPort = 1883;
// MQTT 用户名和密码(若需要认证,否则可省略)
const char* mqttUser = "your_username";
const char* mqttPassword = "your_password";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastPublish = 0;
void setupWiFi() {
Serial.begin(115200);
delay(10);
Serial.println();
Serial.print("连接到 WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi 已连接,IP: ");
Serial.println(WiFi.localIP());
}
// MQTT 消息回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到主题 [");
Serial.print(topic);
Serial.print("] 的消息: ");
String msg;
for (unsigned int i = 0; i < length; i++) {
msg += (char)payload[i];
}
Serial.println(msg);
// 如果收到 "ping" 消息,回复 "pong"
if (String(topic) == "test/advanced" && msg == "ping") {
client.publish("test/advanced", "pong", 1, false);
Serial.println("回复 pong");
}
}
void reconnect() {
// 如果未连接,循环尝试重连
while (!client.connected()) {
Serial.print("尝试连接 MQTT Broker...");
// 使用遗嘱消息,当连接失败时会自动通知 Broker
if (client.connect("ESP8266Client", mqttUser, mqttPassword, "test/will", 1, false, "ESP8266 disconnected unexpectedly")) {
Serial.println("连接成功");
// 订阅主题,QoS 设为 1
client.subscribe("test/advanced", 1);
} else {
Serial.print("连接失败,状态码: ");
Serial.print(client.state());
Serial.println(",5 秒后重试");
delay(5000);
}
}
}
void setup() {
setupWiFi();
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
// 尝试连接 MQTT Broker
reconnect();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 每 10 秒发布 "ping" 消息到主题 "test/advanced"
if (millis() - lastPublish > 10000) {
lastPublish = millis();
client.publish("test/advanced", "ping", 1, false);
Serial.println("发布 ping 消息");
}
// 每 30 秒发布一条保留消息
static unsigned long lastRetained = 0;
if (millis() - lastRetained > 30000) {
lastRetained = millis();
client.publish("test/advanced", "Retained message from ESP8266", 1, true);
Serial.println("发布保留消息");
}
}
说明
-
自动重连:在
loop()
中检测 MQTT 连接状态,若断开则调用reconnect()
函数重连。 -
遗嘱消息:在
client.connect()
时设置了遗嘱消息,当客户端异常断开时,Broker 将向test/will
主题发布消息。 -
保留消息:使用
client.publish()
时,最后一个参数设置为true
表示该消息为保留消息。 -
交互逻辑:在回调函数
callback()
中,如果收到 "ping" 消息,则回复 "pong"。
这两个扩展示例分别展示了如何在 Node.js 与 ESP8266 上实现更复杂的 MQTT 交互逻辑,涵盖了自动重连、遗嘱消息、保留消息以及简单的指令交互。
第三阶段:进阶与优化
🔹 高级 MQTT 功能
-
持久会话(Persistent Session)
-
遗嘱消息(Last Will Testament,LWT)
-
保留消息(Retained Messages)
-
负载均衡和集群(MQTT 集群化部署)
🔹 安全与认证
-
使用 SSL/TLS 加密传输 MQTT 消息。
-
用户名/密码认证(如 Mosquitto 用户数据库)。
-
ACL(访问控制列表) 限制访问权限。
🔹 结合 Web 开发
-
使用 WebSocket 让 MQTT 与 Web 应用交互(例如:使用 MQTT.js 在网页上接收 MQTT 数据)。
-
在前端 React/Vue 中使用 MQTT 进行实时数据更新。
推荐练习四
部署一个安全的 MQTT 服务器,并用 SSL/TLS 进行加密通信。
下面介绍如何使用 Mosquitto 部署一个安全的 MQTT 服务器,并配置 SSL/TLS 加密通信。整体流程包括:生成证书、配置 Mosquitto 使用证书、启动 Broker 以及配置客户端连接。以下为详细步骤和示例配置。
1.生成 SSL/TLS 证书
使用 OpenSSL 生成自签名证书(也可以使用受信任 CA 签发的证书)。
2.生成 CA 私钥和自签名证书:
生成 CA 私钥
openssl genrsa -out ca.key 2048
生成自签名的 CA 证书(有效期 10 年)
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
3.生成服务器私钥和证书签名请求 (CSR):
生成服务器私钥
openssl genrsa -out server.key 2048
生成证书签名请求(按提示输入相关信息,如国家、省份、组织名称等)
openssl req -new -key server.key -out server.csr
4.使用 CA 签署服务器证书:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
生成的文件:
-
ca.crt
:CA 证书 -
server.crt
:服务器证书 -
server.key
:服务器私钥
5.配置 Mosquitto 使用 SSL/TLS
将生成的证书文件放入合适的目录(例如 /etc/mosquitto/certs/
),然后编辑 Mosquitto 的配置文件(通常是 /etc/mosquitto/mosquitto.conf
或在 /etc/mosquitto/conf.d/
下新建一个配置文件)。
以下是一个示例配置文件内容:
设置 TLS 监听端口(一般使用 8883)
listener 8883
指定 CA 证书、服务器证书和私钥路径
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
指定 TLS 协议版本(这里使用 TLSv1.2)
tls_version tlsv1.2
可选:禁用匿名访问,启用用户认证
allow_anonymous false
password_file /etc/mosquitto/passwd
注: 如果需要实现客户端双向认证,可以将 require_certificate
设置为 true
,并提供客户端证书验证相关配置。
6.启动 Mosquitto Broker
保存配置文件后,通过以下命令启动 Mosquitto Broker:
sudo mosquitto -c /etc/mosquitto/mosquitto.conf -v
你应该会看到日志显示 Broker 正在 8883 端口监听,并启用了 SSL/TLS 加密。
7.配置客户端连接
客户端在连接时需要指定使用 TLS。例如,在 Python 中可以使用 Paho MQTT 库进行连接:
import paho.mqtt.client as mqtt
import ssl
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("成功连接到安全的 MQTT Broker")
client.subscribe("test/topic", qos=1)
else:
print("连接失败,返回码:", rc)
client = mqtt.Client(client_id="python_tls_client")
如需要设置用户名/密码,请调用 username_pw_set()
client.username_pw_set("your_username", "your_password")
配置 TLS 参数(ca_certs 指向你的 CA 证书)
client.tls_set(
ca_certs="/etc/mosquitto/certs/ca.crt",
tls_version=ssl.PROTOCOL_TLSv1_2
)
client.on_connect = on_connect
client.connect("your_broker_host", 8883, 60)
client.loop_forever()
同理,其他客户端(如 Node.js、ESP8266 等)也需要配置 TLS 参数来确保连接安全。
总结
-
证书生成:使用 OpenSSL 创建 CA 证书、服务器私钥和证书,然后由 CA 签署服务器证书。
-
配置 Broker:在 mosquitto.conf 中配置 listener、证书文件路径、TLS 版本以及(可选)用户认证。
-
启动 Broker:启动时加载配置文件,确保 Broker 监听 8883 端口。
-
客户端配置:在连接时使用 TLS 参数,并连接到加密端口 8883,从而实现安全通信。
这样部署的 MQTT 服务器就可以为设备间提供加密通信,保障消息的安全性与数据隐私。
推荐练习五
开发一个 MQTT 可视化仪表盘,实时显示传感器数据(可以用 React + WebSocket)。
下面介绍一个完整的实现方案,将 MQTT 消息通过 Node.js 后端转发给前端 React 页面,实时显示传感器数据。整体架构如下:
1.MQTT Broker 传感器数据发布到 MQTT Broker(例如 Mosquitto、EMQX 等)。
2.Node.js 后端(桥接层) 后端使用 MQTT 客户端库(如 mqtt)订阅指定的传感器数据主题,然后利用 WebSocket(例如通过 socket.io)将消息实时转发给前端。
3.React 前端仪表盘 前端使用 WebSocket 客户端(例如 socket.io-client 或浏览器内置的 WebSocket API)接收实时数据,并使用图表库(如 Chart.js 或 Recharts)展示传感器数据。
Node.js 后端示例
安装所需依赖:
npm install mqtt socket.io express
下面是一个示例代码,后端订阅 MQTT 数据并通过 socket.io 广播给所有连接的前端客户端:
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mqtt = require('mqtt');
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
// MQTT Broker 连接配置(替换为你的 Broker 地址)
const mqttOptions = {
clientId: 'nodejs_bridge_' + Math.random().toString(16).substr(2, 8),
// 若需要认证可配置 username、password 等
};
const mqttBrokerUrl = 'mqtt://broker.emqx.io';
const mqttClient = mqtt.connect(mqttBrokerUrl, mqttOptions);
// 订阅的主题(例如传感器数据主题)
const sensorTopic = 'sensor/data';
// 当 MQTT 连接成功
mqttClient.on('connect', () => {
console.log('已连接到 MQTT Broker');
mqttClient.subscribe(sensorTopic, { qos: 1 }, (err) => {
if (err) {
console.error('订阅主题失败:', err);
} else {
console.log(
已订阅主题 ${sensorTopic}
);
}
});
});
// 当收到 MQTT 消息时,将消息广播给所有 WebSocket 客户端
mqttClient.on('message', (topic, message) => {
console.log(
收到 MQTT 主题 ${topic} 的消息: ${message.toString()}
);
// 这里可以做数据预处理
io.emit('sensorData', { topic, message: message.toString() });
});
// WebSocket 连接处理
io.on('connection', (socket) => {
console.log('前端客户端已连接');
socket.on('disconnect', () => {
console.log('前端客户端断开连接');
});
});
// 启动 HTTP 服务(WebSocket 会依托该服务)
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(
服务器运行在 http://localhost:${PORT}
);
});
React 前端示例
在 React 项目中,安装 socket.io-client:
npm install socket.io-client recharts
下面是一个简单的示例,利用 Recharts 显示传感器数据,并通过 socket.io-client 实时接收数据:
// App.jsx
import React, { useEffect, useState } from 'react';
import io from 'socket.io-client';
import { LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid } from 'recharts';
// 连接到后端 WebSocket 服务器(请确保地址和端口正确)
const socket = io('http://localhost:3000');
function App() {
const [data, setData] = useState([]);
useEffect(() => {
// 监听 'sensorData' 消息
socket.on('sensorData', (msg) => {
console.log('接收到数据:', msg);
// 假设 msg.message 是数字型传感器数据,这里构造一个时间戳数据点
const newData = {
time: new Date().toLocaleTimeString(),
value: parseFloat(msg.message) || 0,
};
setData(prev => [...prev, newData].slice(-20)); // 只保留最近20个数据点
});
// 清理监听器
return () => socket.off('sensorData');
}, []);
return (
<div style={{ textAlign: 'center' }}>
<h2>实时传感器数据仪表盘</h2>
<LineChart width={600} height={300} data={data}>
<XAxis dataKey="time" />
<YAxis />
<Tooltip />
<CartesianGrid stroke="#f5f5f5" />
<Line type="monotone" dataKey="value" stroke="#ff7300" />
</LineChart>
</div>
);
}
export default App;
说明
-
后端 Node.js 部分 通过 MQTT 客户端订阅传感器数据主题,并利用 socket.io 将收到的数据广播给所有连接的前端客户端。
-
前端 React 部分 使用 socket.io-client 连接后端服务,监听
sensorData
事件,将接收到的数据存入 state,然后使用 Recharts 绘制折线图,实现实时数据可视化。 -
扩展 根据实际需求,你可以进一步处理数据格式、添加多个图表、支持更多交互功能(例如过滤、历史数据回放等)。
这种方案可以实现一个全栈的 MQTT 数据可视化仪表盘,从传感器数据采集、MQTT 通信到前端实时显示,能够满足大多数物联网应用的数据监控需求。
第四阶段:物联网实战项目
🔹 智能家居系统
-
使用 ESP8266 + MQTT 控制 LED 灯、风扇等家电。
-
开发一个 Web 控制面板(React + MQTT.js)。
🔹 环境监测系统
-
通过 MQTT 传输传感器数据(如温湿度传感器)。
-
在 Grafana/Dashboard 上实时可视化数据。
🔹 工业物联网(IIoT)
-
通过 MQTT 监控生产设备状态,实现远程控制。
-
结合数据库(如 InfluxDB)存储 MQTT 传输的数据。
推荐练习六
用 MQTT + React 开发一个 IoT 控制面板。
下面提供一个完整的方案,展示如何使用 MQTT 与 React 构建一个 IoT 控制面板。整体架构如下:
1.MQTT Broker
负责设备间消息传输(可以使用 Mosquitto、EMQX 等)。
2.Node.js 后端(桥接层,可选)
用于连接 MQTT Broker 并提供 REST API 或 WebSocket 转发消息到前端。
3.React 前端
通过 WebSocket 或 REST API 接收 MQTT 消息,并向设备发送控制命令。
下面以直接在 React 前端使用 WebSocket 连接到后端 Node.js 服务为例,展示一个简单的 IoT 控制面板示例。
4.Node.js 后端示例
安装依赖:
npm install express socket.io mqtt
编写 server.js
代码,实现 MQTT 订阅与 WebSocket 转发:
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mqtt = require('mqtt');
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
// MQTT Broker 配置(替换为你的 Broker 地址及认证信息)
const mqttOptions = {
clientId: 'nodejs-bridge-' + Math.random().toString(16).substr(2, 8),
// username: 'your_username',
// password: 'your_password',
keepalive: 60,
reconnectPeriod: 5000,
};
const mqttBrokerUrl = 'mqtt://broker.emqx.io';
const mqttClient = mqtt.connect(mqttBrokerUrl, mqttOptions);
// 控制面板主题(传感器数据、设备控制)
const sensorTopic = 'iot/sensor';
const controlTopic = 'iot/control';
mqttClient.on('connect', () => {
console.log('已连接到 MQTT Broker');
// 订阅传感器数据主题
mqttClient.subscribe(sensorTopic, { qos: 1 }, (err) => {
if (err) console.error('订阅失败:', err);
else console.log(
已订阅主题 ${sensorTopic}
);
});
});
// 当收到 MQTT 消息时,通过 Socket.IO 转发到前端
mqttClient.on('message', (topic, message) => {
console.log(
收到 MQTT ${topic} 消息: ${message.toString()}
);
io.emit('mqttMessage', { topic, message: message.toString() });
});
// 当收到前端控制命令时,发布到 MQTT Broker
io.on('connection', (socket) => {
console.log('前端客户端已连接');
socket.on('controlCommand', (data) => {
console.log('收到控制命令:', data);
mqttClient.publish(controlTopic, JSON.stringify(data), { qos: 1 });
});
socket.on('disconnect', () => {
console.log('前端客户端断开连接');
});
});
// 静态文件服务(用于前端)
app.use(express.static('public'));
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(
服务器运行在 http://localhost:${PORT}
);
});
该示例中,后端订阅主题
iot/sensor
(设备发送的传感器数据),并将数据通过 Socket.IO 广播给前端。同时,当前端发送控制命令时,后端将消息发布到iot/control
主题,设备可订阅该主题接收控制指令。
5.React 前端示例
假设在 public
文件夹下创建 React 应用构建后的静态文件,下面是一个简单示例代码(可用 Create React App 搭建项目):
// App.jsx
import React, { useEffect, useState } from 'react';
import io from 'socket.io-client';
const socket = io(); // 默认连接当前服务器
function App() {
const [sensorData, setSensorData] = useState([]);
const [command, setCommand] = useState('');
useEffect(() => {
socket.on('mqttMessage', (data) => {
if (data.topic === 'iot/sensor') {
// 假设传感器数据为 JSON 格式
const parsed = JSON.parse(data.message);
setSensorData((prev) => [...prev, parsed].slice(-20)); // 保存最近20条数据
}
});
return () => {
socket.off('mqttMessage');
};
}, []);
// 发送控制命令
const sendCommand = () => {
// 这里构造一个控制命令,例如开关灯
const cmd = { device: 'lamp', action: command };
socket.emit('controlCommand', cmd);
setCommand('');
};
return (
<div style={{ padding: 20 }}>
<h2>IoT 控制面板</h2>
<div style={{ marginBottom: 20 }}>
<h4>传感器数据</h4>
<ul>
{sensorData.map((item, index) => (
<li key={index}>
{item.timestamp}: {item.value}
</li>
))}
</ul>
</div>
<div>
<h4>发送控制命令</h4>
<input
type="text"
placeholder="例如 ON 或 OFF"
value={command}
onChange={(e) => setCommand(e.target.value)}
/>
<button onClick={sendCommand}>发送</button>
</div>
</div>
);
}
export default App;
说明
-
实时数据展示:前端通过 socket.io-client 接收
mqttMessage
事件,并根据主题iot/sensor
解析数据,显示最近的传感器数据。 -
控制命令:输入框允许用户输入控制命令(例如 "ON" 或 "OFF"),点击发送按钮后,通过 socket 发送
controlCommand
事件,后端收到后发布到 MQTT Broker,设备订阅iot/control
即可获取指令。 -
构建与部署:前端项目构建后的静态文件放入后端
public
目录,Node.js Express 提供静态文件服务。
总结
这套方案使用 MQTT 作为设备通信协议,通过 Node.js 作为桥接层实现 MQTT 与前端的消息转发,React 前端实时显示传感器数据并发送控制命令,实现一个简单的 IoT 控制面板。你可以根据实际需求进一步扩展功能,例如增加用户身份认证、图表展示、历史数据查询等。
这就是一个使用 MQTT + React 构建 IoT 控制面板的基本实现方案。
推荐练习七
用 ESP32 + MQTT 实现远程温湿度监测,并推送告警。
使用 ESP32 和 MQTT 实现远程温湿度监测并推送告警是一个典型的物联网(IoT)应用场景。以下是详细的实现步骤:
1. 概述
-
目标:通过 ESP32 采集温湿度数据,并通过 MQTT 协议将数据发送到远程服务器(MQTT Broker)。当温湿度超过设定阈值时,推送告警消息。
-
硬件:
-
ESP32 开发板
-
温湿度传感器(如 DHT11 或 DHT22)
-
-
软件:
-
Arduino IDE 或 PlatformIO
-
MQTT Broker(如 Mosquitto、EMQX 或云服务如 AWS IoT、阿里云 IoT)
-
MQTT 客户端工具(如 MQTT Explorer、MQTT.fx
-
2. 硬件连接
将 DHT11/DHT22 传感器连接到 ESP32:
-
VCC → 3.3V
-
GND → GND
-
DATA → GPIO 引脚(如 GPIO4)
3. 软件实现
(1)安装依赖库
在 Arduino IDE 中安装以下库:
-
PubSubClient:用于 MQTT 通信。
-
DHT:用于读取 DHT11/DHT22 传感器的数据。
(2)编写代码
以下是完整的 ESP32 代码示例:
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// WiFi 配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// MQTT 配置
const char* mqtt_server = "MQTT Broker 地址"; // 例如 "test.mosquitto.org"
const int mqtt_port = 1883; // MQTT 端口
const char* mqtt_user = "MQTT 用户名"; // 如果没有用户名和密码,可以留空
const char* mqtt_password = "MQTT 密码";
// 温湿度传感器配置
#define DHTPIN 4 // DHT 数据引脚
#define DHTTYPE DHT22 // DHT22 或 DHT11
DHT dht(DHTPIN, DHTTYPE);
// 告警阈值
const float temp_threshold = 30.0; // 温度阈值
const float humidity_threshold = 70.0; // 湿度阈值
// MQTT 主题
const char* temp_topic = "esp32/temperature";
const char* humidity_topic = "esp32/humidity";
const char* alert_topic = "esp32/alert";
WiFiClient espClient;
PubSubClient client(espClient);
// 连接 WiFi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
// 连接 MQTT Broker
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP32Client", mqtt_user, mqtt_password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
// 初始化
void setup() {
Serial.begin(115200);
dht.begin();
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
}
// 主循环
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 读取温湿度数据
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// 检查数据是否有效
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// 发布温湿度数据到 MQTT
char temp_msg[10];
char humidity_msg[10];
snprintf(temp_msg, 10, "%.2f", temperature);
snprintf(humidity_msg, 10, "%.2f", humidity);
client.publish(temp_topic, temp_msg);
client.publish(humidity_topic, humidity_msg);
// 检查是否超过阈值并推送告警
if (temperature > temp_threshold) {
client.publish(alert_topic, "Temperature exceeds threshold!");
}
if (humidity > humidity_threshold) {
client.publish(alert_topic, "Humidity exceeds threshold!");
}
// 每隔 5 秒发送一次数据
delay(5000);
}
4. 配置 MQTT Broker
-
如果你使用本地 Broker(如 Mosquitto),确保 Broker 已启动并监听正确端口。
-
如果你使用云服务(如 AWS IoT 或阿里云 IoT),按照服务提供商的文档配置设备证书和权限。
5. 测试与调试
(1)将代码上传到 ESP32。
(2)使用 MQTT 客户端工具(如 MQTT Explorer)订阅以下主题:
-
esp32/temperature
:接收温度数据。 -
esp32/humidity
:接收湿度数据。 -
esp32/alert
:接收告警消息。
(3)观察数据是否正常发布,并测试告警功能。
6. 扩展功能
-
数据持久化:将温湿度数据存储到数据库(如 InfluxDB、MySQL)。
-
可视化:使用 Grafana 或 Node-RED 创建实时数据仪表盘。
-
OTA 升级:通过 WiFi 实现 ESP32 的固件远程升级。
-
多设备支持:扩展系统以支持多个 ESP32 设备。
7. 注意事项
-
网络稳定性:确保 ESP32 连接的 WiFi 网络稳定。
-
MQTT Broker 性能:如果设备数量较多,选择高性能的 Broker(如 EMQX)。
-
安全性:启用 TLS/SSL 加密 MQTT 通信,防止数据泄露。
通过以上步骤,可以成功实现基于 ESP32 和 MQTT 的远程温湿度监测与告警系统。
💡 总结
学习阶段 | 内容 | 练习 |
入门 | MQTT 基础概念、架构、安装 | 运行 Mosquitto,使用 Python 发布/订阅 |
实践 | 部署 MQTT 服务器,编写客户端 | 用 Python/Node.js/ESP8266 连接 MQTT |
进阶 | 安全、优化、MQTT WebSocket | 用 SSL/TLS 加密,创建 MQTT 可视化仪表盘 |
实战 | 智能家居、环境监测 | 开发 IoT 项目,连接 Web 应用k |
扩展阅读
物联网开发者必备工具:6款实用MQTT调试工具推荐 | 物联网开发者必备工具:6款实用MQTT调试工具推荐-优快云博客 |
MQTT 实战手册:从初学者到高级开发者的进阶之路 | https://blog.youkuaiyun.com/moton2017/article/details/146458533 |
MQTT开发者指南:15个实战问题全解析 | https://blog.youkuaiyun.com/moton2017/article/details/146459682 |