主要就是3层架构
1,设备层
配置mqtt链接
使用MQTT Broker服务器
2,中间层,用一般服务器(中间协调)
(负责协议转换与接口封装)
3,前端层(面向用户)
采用webSocket与中间层保持长链接
你可以把这个架构想象成一个新闻系统:
设备层:是各地的记者。他们用特定的方式(MQTT)将写好的新闻稿(传感器数据)发送到新闻总社(MQTT Broker)。
MQTT Broker:是新闻总社。它接收所有记者的稿件,并按照版面(主题)分类存放。
中间层:是你的新闻App的后台。它派人长期驻守在新闻总社,订阅你感兴趣的版面(比如"科技版")。一旦有新的科技新闻,它就立刻抓取过来,然后通过App的推送系统(WebSocket)发到你的手机上。
前端层:就是你手机上的新闻App界面。它和后台保持着推送连接,所以新闻一来,你的App界面就会立刻弹出通知,内容实时更新。
其实这里面比较难理解的就是,设备层(MQTT Broker服务器)和中间层的一般服务器的作用,
以下是2者的区别,
其实感觉最大的区别就是是否轻量,实时
1,一般服务器
角色:服务提供者 和 逻辑处理中心。
沟通是一对一的,并且通常是你主动发起的。
提供稳定、安全、复杂的业务服务
连接方式,短连接
典型协议。HTTP, HTTPS, TCP Socket
2,MQTT Broker:
角色:消息中转站 或 信息分发中心
沟通可以是一对多,对多个订阅者
像一个微信群群主或电台。它自己不产生消息,而是负责把某些人(发布者)发出的消息,转发给所有关心这个消息的人(订阅者)。沟通是一对多的,并且是基于兴趣的。
实现轻量级、低功耗、高实时性的机器与机器之间的通信
连接方式,长连接
典型协议 MQTT协议(基于TCP)
作用
1,消息路由与中转(核心功能)
因为板子或者传感器本身不适合处理太多逻辑,方便设备与设备之间通讯,设备与中间层通讯。
2,会话管理与离线消息当订阅者设备网络不稳定或暂时离线时,Broker可以(根据设置的服务质量等级)为它保存消息。等设备重新上线后,Broker会将这些离线期间的消息重新发送给它。
这保证了重要数据在弱网络环境下的可靠传输。
二,其实不要,"一般服务器"也行,
只不过复杂的物联网系统,还是不可或缺
"一般服务器"在物联网系统中的作用
虽然消息传递不需要它,但一个完整的物联网系统仍然离不开一般服务器。它们各司其职,协同工作。
一般服务器在物联网系统中负责 "管理"和"智能" 部分:
- 设备管理:
* 一般服务器提供一个Web界面或API,让你注册新设备、管理设备密钥。
* 它可能负责向设备和手机APP下发MQTT Broker的连接地址。- 数据持久化与智能分析:
* MQTT Broker的核心是传递消息,通常不长期保存数据。
* 这时,我们需要一个"订阅者"来将数据存入数据库。这个订阅者常常就是你的一般服务器!
* 新数据流:传感器 -> MQTT Broker -> 一般服务器(订阅者) -> 数据库
* 一般服务器存入数据后,可以进行复杂分析、生成报表、训练AI模型等。- 提供业务接口:
* 你的手机APP可能需要查看历史温度曲线。这个请求不会通过MQTT,而是直接HTTP请求到一般服务器,服务器再从数据库查询后返回。- 发送控制命令:
* 当你想通过手机远程打开空调时,手机APP可以通过HTTP请求告诉一般服务器。
* 一般服务器然后作为MQTT发布者,向主题 app/command 发布一条 "turn_on_ac" 的消息。
* 空调,作为 app/command 的订阅者,从Broker收到消息后执行开机。
三,前端层
职责:采用webSocket与中间层保持长链接
这是用户直接交互的界面,通常是一个运行在浏览器中的网页应用(Web App)。
采用WebSocket:WebSocket是一种在单个TCP连接上进行全双工通信的协议。它非常适合需要服务器主动向客户端推送数据的场景。
与中间层保持长链接:
前端通过JavaScript的 WebSocket API,与中间层建立一个持久的长连接。
一旦连接建立,中间层就可以在任何需要的时候,立即将收到的设备数据通过这个连接推送给前端,前端页面无需刷新就能实时更新显示(比如图表跳动、数字变化)。
四,mqtt Broker开发语言
- 一般服务器开发:选择开发效率高的语言(Java/PHP/Node.js/Python等)
- MQTT Broker开发:选择网络性能极致的语言(Erlang/C/Java/Go等)
五,进阶功能
进阶功能
1. OTA 远程更新
可以让 ESP32 通过 WiFi 接收代码更新,无需物理连接。
2. 低功耗模式
使用深度睡眠模式节省电量,适合电池供电场景。
3. 数据加密
使用 TLS/SSL 加密 MQTT 通信,提高安全性。
4. 断线重连机制
增强网络异常时的稳定性。
附,一个板子,接mqtt的源码
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi 配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// MQTT 配置
const char* mqtt_broker = "broker.emqx.io"; // 免费MQTT服务器
const int mqtt_port = 1883;
const char* topic = "esp32/sensor/data"; // 主题名称
const char* mqtt_username = ""; // 用户名(公共服务器通常为空)
const char* mqtt_password = ""; // 密码
// 创建客户端对象
WiFiClient espClient;
PubSubClient client(espClient);
// 设备ID(用于区分多个设备)
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
void setup() {
Serial.begin(115200);
// 1. 连接 WiFi
setup_wifi();
// 2. 配置 MQTT
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback); // 设置接收消息的回调函数
// 3. 连接 MQTT Broker
connect_mqtt();
}
void loop() {
// 保持 MQTT 连接
if (!client.connected()) {
connect_mqtt();
}
client.loop(); // 处理MQTT消息
// 每5秒发布一次数据
static unsigned long lastMsg = 0;
if (millis() - lastMsg > 5000) {
lastMsg = millis();
publish_sensor_data();
}
}
// 连接 WiFi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("连接WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi连接成功");
Serial.println("IP地址: ");
Serial.println(WiFi.localIP());
}
// 连接 MQTT Broker
void connect_mqtt() {
while (!client.connected()) {
Serial.print("连接MQTT Broker...");
if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
Serial.println("连接成功!");
// 订阅主题(如果需要接收指令)
client.subscribe("esp32/control");
} else {
Serial.print("失败, rc=");
Serial.print(client.state());
Serial.println(" 5秒后重试...");
delay(5000);
}
}
}
// 接收消息的回调函数(当收到订阅的消息时调用)
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到消息 [");
Serial.print(topic);
Serial.print("]: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// 这里可以处理接收到的控制指令
// 例如:开关LED、重启设备等
}
// 发布传感器数据
void publish_sensor_data() {
// 模拟传感器数据(实际中从这里读取真实传感器)
float temperature = random(200, 300) / 10.0; // 20.0-30.0°C
float humidity = random(400, 800) / 10.0; // 40.0-80.0%
// 创建JSON格式数据
String message = "{";
message += "\"deviceId\":\"" + clientId + "\",";
message += "\"temperature\":" + String(temperature) + ",";
message += "\"humidity\":" + String(humidity) + ",";
message += "\"timestamp\":" + String(millis());
message += "}";
// 发布消息
if (client.publish(topic, message.c_str())) {
Serial.println("数据发布成功: " + message);
} else {
Serial.println("数据发布失败");
}
}