提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本系列将以0基础新手视角,完整演示Arduino+ESP8266连接OneNET云平台的全流程,涵盖ESP8266固件烧录、物模型的模型设计、MQTT协议配置及代码实现。建议搭配Arduino IDE 2.0+和Arduino开发板使用。
(三)本文为arduino连接ESP8266(ESP-01S)的 优化版
优化了,上传的格式,(二)中的转义符过于复杂,改用 Raw
可不看(二),直接看(三)
一、前期准备
1.1 硬件配置
需准备Arduino开发板 和 ESP8266
1.2 软件环境配置
安装Arduino IDE 2.0.2
安装 EspSoftwareSerial 库(工具→库管理→搜索EspSoftwareSerial→安装)
二、接线
注:arduino的 5V 给ESP8266的3.3V 供电,不然电压可能不够。
代码中的这句话是指 arduino的软串口,RX为9,TX为10;此时我们用ESP8266的TX接9,RX接10
SoftwareSerial espSerial(9, 10); // RX=9, TX=10 注意前面的是指arduino的TRX,连线时候ESP8266的TX应接9,RX接10
arduino uno | ESP8266 |
---|---|
5V | 3.3V 和 EN(即CH_PD) |
10 | RX |
9 | TX |
GND | GND |
再从 引脚5 引出一根导线,连接 小电阻→LED灯→GND
以备之后测试云平台下发
三、核心代码
3.1 总代码
替换
const char* WIFI_SSID = "Xiaomi 15";
const char* WIFI_PWD = "147258369";
// OneNET参数
#define PRODUCT_ID "1SX9Lm39T5"
#define DEVICE_NAME "arduino"
#define TOKEN "version=2018-10-31&res=products%2F1SX
相较于上个版本,我修改了上传格式,更为简洁,若还是不明白添加或者减少 上传数量 的格式,可用ai辅助。
并且注意代码中的标识符和定义和云平台的已经对不上了,要根据实际去修改。包括回调函数里面的标识符
代码:
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
/*
若发现上传一直error,从第一次上传开始就error,则需要,
将上传的函数注释掉两个,也就是只上传一个函数,这时会成功。
然后再取消另外两个函数的注释,就都可以上传成功,
*/
// 网络配置
const char* WIFI_SSID = "Xiaomi 15";
const char* WIFI_PWD = "147258369";
const char* MQTT_SERVER = "mqtts.heclouds.com";
// OneNET 物联参数
const int MQTT_PORT = 1883;
#define PRODUCT_ID "1SX9Lm39T5"
#define DEVICE_NAME "arduino"
#define TOKEN "version=2018-10-31&res=products%2F1SX9Lm39T5%2Fdevices%2Farduino&et=2059472864&method=md5&sign=F5DI%2FHUhIdIeZx1CUsR%2ByQ%3D%3D"
// 硬件配置
SoftwareSerial espSerial(9, 10); // RX=9, TX=10 注意前面的是指arduino的TRX,连线时候ESP8266的TX应接9,RX接10
#define TLED_PIN 5 // LED控制引脚
// 全局变量
const unsigned long readInterval = 3000;// 数据上报周期(ms)
int postMsgId = 0; // 消息序列号
float temp_test = 20.25; // 温度值
bool TLED_state = true; // LED开关状态
//前置函数声明
bool sendATCommand(const char* cmd, const char* ack, unsigned int timeout);
void initESP8266();
void initSwitch();
void Post_Sensor();
void Post_Switch();
void setup() {
Serial.begin(9600); // 调试串口
espSerial.begin(9600); // ESP8266通信
initESP8266();
initSwitch();
}
void loop() {
handleMQTTMessage();
// 定时上传数据
static unsigned long lastPost = 0;
if (millis() - lastPost >= readInterval) {
Post_Switch();
// Post_Sensor();
lastPost = millis();
}
}
// AT指令发送函数(带超时检测)
bool sendATCommand(const char* cmd, const char* ack, unsigned int timeout) {
espSerial.println(cmd);
unsigned long start = millis();
String response;
while (millis() - start < timeout) {
while (espSerial.available()) {
char c = espSerial.read();
response += c;
}
if (response.indexOf(ack) != -1) {
Serial.print("[SUCCESS] ");
Serial.println(cmd);
return true;
}
}
Serial.print("[ERROR] ");
Serial.print(cmd);
Serial.println(" 未收到预期响应");
return false;
}
void initESP8266(){
// 初始化ESP8266
sendATCommand("AT", "OK", 2000);
// sendATCommand("AT+RST", "ready", 8000);
sendATCommand("AT+CWMODE=1", "OK", 1000);
sendATCommand("AT+CWDHCP=1,1", "OK", 1000);
// 连接WiFi
String cmd = "AT+CWJAP=\"" + String(WIFI_SSID) + "\",\"" + String(WIFI_PWD) + "\"";
sendATCommand(cmd.c_str(), "OK", 5000);\
// 配置MQTT
String mqttCfg = "AT+MQTTUSERCFG=0,1,\"" + String(DEVICE_NAME) + "\",\"" + String(PRODUCT_ID) + "\",\"" + String(TOKEN) + "\",0,0,\"\"";
sendATCommand(mqttCfg.c_str(), "OK", 5000);
// 连接服务器
String connCmd = "AT+MQTTCONN=0,\"" + String(MQTT_SERVER) + "\"," + String(MQTT_PORT) + ",1";
sendATCommand(connCmd.c_str(), "OK", 5000);
// 添加订阅命令(在MQTT连接成功后)
String subscribeCmd = "AT+MQTTSUB=0,\"$sys/" + String(PRODUCT_ID) + "/" + String(DEVICE_NAME) + "/thing/property/set\",1";
sendATCommand(subscribeCmd.c_str(), "OK", 2000);
}
void initSwitch(){
pinMode(TLED_PIN, OUTPUT);
digitalWrite(TLED_PIN, TLED_state);
}
void Post_Sensor() {
postMsgId++;
// 使用原始字符串构造JSON(无需转义符)
String jsonPayload = "{";
jsonPayload += "\"id\":\"" + String(postMsgId) + "\",";
jsonPayload += "\"version\":\"1.0\",";
jsonPayload += "\"params\":{";
jsonPayload += "\"t1\":{\"value\":" + String(t1) + "},";
jsonPayload += "\"t2\":{\"value\":" + String(t2) + "}";
jsonPayload += "}}";
// 构造MQTT二进制发布指令(规避转义问题)
String pubCmd = "AT+MQTTPUBRAW=0,\"$sys/" + String(PRODUCT_ID) + "/"
+ String(DEVICE_NAME) + "/thing/property/post\","
+ String(jsonPayload.length()) + ",0,0";
// 发送指令和JSON数据(分两步)
sendATCommand(pubCmd.c_str(), ">", 1000); // 等待">"提示符
delay(50);
sendATCommand(jsonPayload.c_str(), "OK", 3000);
}
void Post_Switch() {
postMsgId++;
// 直接构建合法JSON字符串(无需手动转义双引号)
String jsonPayload = "{";
jsonPayload += "\"id\":\"" + String(postMsgId) + "\",";
jsonPayload += "\"version\":\"1.0\",";
jsonPayload += "\"params\":{";
jsonPayload += "\"T\":{\"value\":" + String(TLED_state ? "true" : "false") + "},";
jsonPayload += "\"H\":{\"value\":" + String(Heating_state ? "true" : "false") + "},";
jsonPayload += "\"A\":{\"value\":" + String(AddHeating_state ? "true" : "false") + "}";
jsonPayload += "}}"; // 闭合外层JSON结构
// 构造MQTT二进制发布指令(规避转义问题)
String pubCmd = "AT+MQTTPUBRAW=0,\"$sys/" + String(PRODUCT_ID) + "/"
+ String(DEVICE_NAME) + "/thing/property/post\","
+ String(jsonPayload.length()) + ",0,0";
// 分两步发送:先发送指令头,再发送原始JSON数据
sendATCommand(pubCmd.c_str(), ">", 1000); // 等待">"提示符
delay(50); // 确保模块准备好接收数据
sendATCommand(jsonPayload.c_str(), "OK", 3000); // 发送JSON内容
}
// 接收数据函数 ▼
void handleMQTTMessage() {
while (espSerial.available()) {
String message = espSerial.readStringUntil('\n');
if (message.indexOf("+MQTTSUBRECV:") != -1) { // 检测到新消息
Serial.print("收到原始消息:");
Serial.println(message); // 调试输出
// 提取JSON部分
int jsonStart = message.indexOf('{');
String jsonStr = message.substring(jsonStart);
JsonDocument doc;
DeserializationError error = deserializeJson(doc, jsonStr);
if (!error) {
if (doc["params"]["TLED"].as<bool>()) {
digitalWrite(TLED_PIN, HIGH);
TLED_state = true;
Serial.println("✅ 已开灯");
} else {
digitalWrite(TLED_PIN, LOW);
TLED_state = false;
Serial.println("✅ 已关灯");
}
// 回复 set 指令
int id = doc["id"] | 0; // 取出id进行回复(可选)
String replyJson = String("{\\\"id\\\":\\\"") + id + "\\\",\\\"code\\\":200}";
String cmd = "AT+MQTTPUB=0,\"$sys/" + String(PRODUCT_ID) + "/" + String(DEVICE_NAME) + "/thing/property/set/reply\",\"" + replyJson + "\",0,0";
sendATCommand(cmd.c_str(), "OK", 1000);
}
else {
Serial.println("[ERROR] JSON解析失败");
}
}
}
}
三、最终效果
串口上,会出现几个error,属于正常情况,如响应超时等
后续出现的success,就代表上传成功
若有问题,则重复上篇文章,使用USB转TTL,进行AT指令测试
总结
本文搭建了 基于Arduino的ESP8266连接OneNET云平台(MQTT协议 物模型)。