STM32+ESP8266接入OneNET的环境监测系统实现全解析
简介基于STM32C8T6与ESP8266的实时环境监测系统设计完整工程包面向嵌入式初学者、STM32开发者和物联网爱好者也适用于毕业设计、课程实验、学科竞赛等场景解决环境参数采集、本地显示与云平台远程监控的核心问题。压缩包共278个文件总大小约7.87MB核心内容包含C源码、H头文件、Keil工程.uvprojx、编译生成的AXF/HEX烧录文件以及工程备份、说明文档等可直接打开工程编译烧录并支持后续二次开发。系统集成DHT11温湿度、MQ-2可燃气体、GY302光照传感器经0.96英寸OLED屏实时显示支持串口与蓝牙透传交互并通过ESP8266以MQTT协议接入OneNET平台实现数据上云与远程查看。资料内的代码均经过功能验证还提供面包板加杜邦线的简易硬件搭建方案便于初学者快速复现完整工程结构也可作为项目开发、实验报告、竞赛答辩的重要参考。已有105人浏览学习。1. 实时环境监测系统为什么这条“STM32采集ESP8266上云OneNET展示”链路最省事做实验室温湿度记录、小型温室监控或者车间烟雾报警时基于STM32与ESP8266接入OneNET平台的实时环境监测系统设计是目前最典型的一条链路STM32把传感器数据采回来ESP8266把数据送上网OneNET把数据存起来再画成可视化曲线。整套方案不需要自建服务器也不用维护数据库手机和浏览器打开就能看实时值硬件成本几十块钱。它特别适合做毕业设计、课程设计或者给产品做功能原型验证。我按这个方向完整搭过一遍下面把硬件选型、驱动代码和平台接入参数一次讲透你不用再来回翻十几篇帖子。2. 硬件架构与选型从传感器到云端的器件清单和引脚规划2.1 数据流向DHT11/MQ-2 采集在 STM32传输在 ESP8266这套系统的数据流其实很短传感器输出物理量STM32通过GPIO或ADC把物理量读成数字拼成一段JSON文本然后通过串口把JSON交给ESP8266ESP8266以MQTT协议发布到OneNET云平台平台侧再按字段名拆成温湿度、烟雾浓度数据流供可视化图表调用。这里有个常见的理解误区很多人以为ESP8266自己也能读传感器为什么非要让STM32先采一遍原因是ESP8266的GPIO少、ADC精度差而且它的WiFi协议栈和用户代码跑在同一颗芯片上读取DHT11这种对时序敏感的设备时很容易被网络中断干扰导致读到的数据偶发跳变。STM32做主控ESP8266只做数据透传两边职责分开系统稳定性会好很多。工程文件里最常见的组织方式也是这么划分的STM32工程负责传感器驱动、数据组包和串口收发ESP8266只跑AT固件。2.2 器件清单与选型理由为什么是 STM32F103 ESP8266 而不是 51 或 W5500具体器件我按最常见、最容易买到的来列。绝大多数毕设和原型验证用的是一块STM32F103C8T6核心板也就是常说的BluePill。这颗芯片主频72MHz、Flash 64KB、RAM 20KB跑两个串口加一个ADC、一个GPIO时序采集完全够用价格也便宜。赶上活动十几块钱就能拿到而且HAL库代码可以直接移植到F103系列其它型号。WiFi模块我推荐ESP8266-01S或ESP12F。前者引脚少、体积小适合毕设这种固定场景后者天线性能更好适合经常挪动的设备。如果对成本不敏感、又想省掉AT指令的调试麻烦也可以直接给ESP8266刷NodeMCU固件让它在内部跑MQTT但那就不是今天这套“STM32AT指令”的框架了。顺带提一句如果现场有网线用W5500硬件协议栈接入OneNET也是成熟方案但W5500是纯TCP协议栈MQTT报文还需要自己在单片机上拼比ESP8266走AT指令要抽象得多不建议新手入门直接上。传感器部分我选了DHT11和MQ-2覆盖温湿度和可燃气体浓度三个环境指标足够撑起一个“实时环境监测”的演示。DHT11精度一般但便宜、资料多适合入门MQ-2是模拟量输出接STM32的ADC引脚就能读。如果还想测光照加一个BH1750走I2C代码模式类似不改变整体架构。2.3 接线表与 3.3V 供电规划ESP8266 峰值电流不容忽视下面这张接线表是我自己习惯用的引脚分配和大多数源码工程的默认工程文件一致你可以直接照抄。注意串口一定要交叉连接STM32的TX接ESP8266的RXSTM32的RX接ESP8266的TX。模块引脚接到 STM32F103C8T6ESP8266-01SVCC3.3V独立供电不直挂板载LDOESP8266-01SGNDGND与STM32共地ESP8266-01SRXPA2USART2_TXESP8266-01STXPA3USART2_RXESP8266-01SCH_PD/EN3.3V使能引脚必须拉高DHT11DATAPB12MQ-2AOUTPA0ADC1_IN0MQ-2DOUT可选PA1用于阈值报警供电是整个系统翻车率最高的地方。ESP8266在WiFi发射瞬间峰值电流可以冲到300mA以上如果直接把它的VCC接到核心板上那颗小小的LDO后面电压一旦掉到3.3V以下模块就会重启、串口打印乱码、AT指令无响应。我一般用一个AMS1117-3.3单独给ESP8266供电或者用手机充电头加DC-DC模块但无论怎么供都必须和STM32的GND共地否则串口电平完全没有参考点通信必定失败。3. STM32 端传感器采集DHT11 驱动、ADC 采样与 JSON 拼接3.1 DHT11 温湿度读取时序、信号宽度与校验代码DHT11的驱动难点不在通信协议本身而在时序。它是单总线设备主机先把总线拉低至少18ms然后释放DHT11会回一个80us左右的低电平响应接着连续发送40位数据每一位都以50us低电平开始后面高电平的持续时间决定它是0还是1。高电平26~28us是070us是1。主控必须在这几十微秒内完成采样判断所以用HAL_Delay肯定不行需要微秒级延时。我这里的工程文件里用DWT内核定时器做微秒延时比for循环空转精确也不受编译器优化影响。下面这段是完整的读取函数/* dht11.c - 基于 STM32F103 HAL 库 */ #include dht11.h #define DHT11_PORT GPIOB #define DHT11_PIN GPIO_PIN_12 /* 初始化 DWT 延时在 main 里调用一次 */ void DWT_Delay_Init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; } static void delay_us(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000UL); while ((DWT-CYCCNT - start) ticks); } /* 读取 DHT11成功返回 1失败返回 0 */ uint8_t DHT11_Read(float *temperature, float *humidity) { uint8_t data[5] {0}; uint8_t bits[40] {0}; GPIO_InitTypeDef gpio {0}; /* 配置为开漏输出外部上拉拉低至少 18ms 触发 DHT11 */ gpio.Pin DHT11_PIN; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(DHT11_PORT, gpio); HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET); HAL_Delay(20); HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); /* 切换为输入模式等待 DHT11 响应 */ gpio.Mode GPIO_MODE_INPUT; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(DHT11_PORT, gpio); delay_us(30); if (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET) { return 0; /* 没有低电平响应 */ } while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_RESET); while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET); /* 读取 40 位数据低电平 50us 后高电平宽度决定 0/1 */ for (int i 0; i 40; i) { while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_RESET); delay_us(28); bits[i] (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET) ? 1 : 0; while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET); } for (int i 0; i 5; i) { for (int j 0; j 8; j) { data[i] (data[i] 1) | bits[i * 8 j]; } } /* 校验前四个字节累加和等于第五字节 */ if ((uint8_t)(data[0] data[1] data[2] data[3]) ! data[4]) { return 0; } *humidity (float)data[0]; *temperature (float)data[2]; return 1; }代码里最关键的是读取每一位时的delay_us(28)。这个28us是判断0和1的分水岭采样点放在高电平开始后的第28us如果读到高电平说明高电平持续超过28us这一位是1如果是低电平说明高电平已经结束这一位是0。你把采样点放到40us也能工作但越往后越容易被干扰这是我调过不少板子之后的血泪经验。另外注意GPIO要配成开漏输出。DHT11数据线空闲时靠上拉电阻维持高电平开漏模式可以避免推挽输出时两片芯片互相打架。如果你的板子外部没有上拉电阻就在PB12和3.3V之间焊一个4.7kΩ电阻这点别省。3.2 烟雾传感器 ADC 采集通道切换与滑动平均滤波MQ-2传感器上电后内部加热丝需要几十秒才能稳定刚上电读到的电压会持续漂移。它的模拟输出接在PA0上对应ADC1的通道0。STM32F103的ADC是12位参考电压取3.3V所以读到的原始值乘以3.3再除以4095就是电压。浓度越高输出电压越高但我不建议大家拿这个电压直接当线性浓度MQ-2的灵敏度曲线本身就不是线性的实际工程里要用标定数据做查表或拟合。毕设演示时直接把电压值报上去即可说明里讲清楚单位是电压就能过。ADC读取时有个很容易踩的坑多通道切换。如果你只是静态读PA0每次转换前调用一次HAL_ADC_ConfigChannel就行但如果你后面加了PA1读取另一个通道必须注意——先HAL_ADC_Stop停掉上一次转换重新配置通道后再HAL_ADC_Start。我见过不少人在STM32 ADC切换通道上翻车表现是切换通道后读到的值一直不变其实就是上一次转换没有停止ADC还在按旧通道转换。/* 读取 MQ-2 电压连续采 10 次滑动平均返回单位V */ float MQ2_ReadVoltage(void) { ADC_ChannelConfTypeDef sConfig {0}; uint32_t sum 0; sConfig.Channel ADC_CHANNEL_0; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_239CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); for (int i 0; i 10; i) { HAL_ADC_Start(hadc1); if (HAL_ADC_PollForConversion(hadc1, 10) HAL_OK) { sum HAL_ADC_GetValue(hadc1); } HAL_ADC_Stop(hadc1); HAL_Delay(2); } return (sum / 10.0f) * 3.3f / 4095.0f; }这里的HAL_ADC_Stop在每次采样后都调用就是为了避免上面说到的通道“粘连”问题。采样时间我选239CYCLES_5对高内阻的传感器输出更稳一点。如果你用的是PA1做数字量报警输出那不需要ADC直接配一个GPIO输入读高低电平就完事。3.3 把温湿度、烟雾值拼成 JSON缓冲区设计与发送接口数据采回来之后要拼成OneNET能识别的JSON字符串。这里建议用一个全局字符数组做缓冲区不要每次在栈上开大数组因为STM32的栈空间本来就紧张。我一般开128字节格式如下{temp:26.3,hum:60.2,smoke:0.45}。浮点格式化成一位小数省空间也够看。/* data_report.c */ extern UART_HandleTypeDef huart2; extern void ESP8266_Publish(const char *topic, const char *payload); char mqtt_payload[128]; void Report_EnvData(float temp, float hum, float smoke) { int len snprintf(mqtt_payload, sizeof(mqtt_payload), {\temp\:%.1f,\hum\:%.1f,\smoke\:%.2f}, temp, hum, smoke); if (len 0 len (int)sizeof(mqtt_payload)) { ESP8266_Publish($dp, mqtt_payload); } }注意snprintf的返回值需要做边界判断如果返回负数或超过缓冲区大小说明数据格式出错这时候直接丢弃这一帧不要让半截JSON发到云端。OneNET解析JSON是按字段名匹配数据流的哪怕你少了一个右括号整个数据点都会解析失败平台侧就会显示设备在线但没有数据。这会在后面的避坑章节里再细说。4. 接入 OneNET 云平台创建产品设备、MQTT 连接与数据上报4.1 在 OneNET 控制台创建产品与设备三个关键参数到手在OneNET云平台上接入流程是先在控制台创建一个产品再在产品下添加设备。以老版OneNET开放平台的多协议接入为例进入控制台后找到“多协议接入”选择MQTT协议创建一个新的产品。创建成功后你会拿到一个产品ID也就是product_id。然后在产品下添加设备设备类型选择“MQTT协议”注册方式可以选手动。设备添加成功后控制台会显示设备IDdevice_id和APIKeyapi_key。这三个参数就是后面MQTT连接的三个身份凭证。有的教程里还会让你配置一个token新版OneNET Studio的鉴权方式和老版不太一样但连接公式是同一个套路服务器地址、端口、设备ID、用户名、密码。区别只在密码字段怎么算老版直接填api_key新版可能要求填token签名。你以自己控制台“设备详情”页显示的信息为准代码框架不用变。一个建议在控制台把产品里的“数据流”提前规划好。比如你上报的JSON里有temp、hum、smoke三个字段就在数据流模板里分别建这三个名字字段名必须和JSON的key完全一致大小写都不能差。这个不强制但先建好数据流后面可视化面板拉图表时会省很多事。4.2 给 ESP8266 准备带 MQTT 功能的 AT 固件并初始化网络ESP8266买回来默认的AT固件不一定会带MQTT指令。乐鑫的AT固件是从ESP8266 NONOS开发环境编译出来的版本不同支持的指令集也不同。老版本AT固件只有ATCIPSTART、ATCIPSEND这些TCP/IP指令要发MQTT报文得自己拼协议包非常痛苦。我建议你刷一个带MQTT指令的AT固件例如基于NONOS SDK 2.2.0编译的AT 2.2.0以上版本用ATGMR查看版本号确认返回信息正常后再继续。初始化网络时的指令很简单但要注意几个参数细节// 设置为 Station 模式连接路由器 ATCWMODE1 // 连接 WiFi注意 SSID 和密码都要 ASCII 字符 ATCWJAPTP-LINK_TEST,12345678 // 查询本机 IP确认已拿到地址 ATCIFSRATCWMODE有三个值1是Station连接外部路由器2是SoftAP自己开热点3是双模式。我们这边必须用1。ATCWJAP连接成功后模块会主动上报WIFI CONNECTED和WIFI GOT IP然后再返回OK。如果你的路由器开了5GHz频段或者开启了AP隔离、MAC过滤都会导致连接失败这点放到避坑章节里讲。4.3 跑通 MQTT 连接与数据上报AT 命令序列和 STM32 发送函数WiFi通了之后接着就是MQTT连接。OneNET的MQTT接入地址是老平台常用的183.230.40.40端口1883。连接指令格式如下ATMQTTCONN0,183.230.40.40,1883,device_id,product_id,api_key,60这个命令里第一个0是链路ID固定用一个就行device_id是控制台里的设备IDproduct_id是产品IDapi_key是设备APIKey最后一个60是MQTT心跳周期单位秒。OneNET要求客户端定期发送心跳保活60秒是常见配置。连接成功后返回OK这时OneNET控制台里设备状态会变成“在线”。连接成功后上报数据用发布命令主题填$dp这是老版OneNET接收数据点的特殊主题ATMQTTPUB0,$dp,{\temp\:26.3,\hum\:60.2,\smoke\:0.45},0,0注意$dp主题里JSON的引号在AT指令中要么用反斜杠转义要么按下面代码里我的做法把payload转成十六进制字符串发送避免引号和逗号被AT指令解析器截断。这个坑很多人踩过表现为串口调试助手能看到命令发出去但OneNET平台收不到数据点。STM32侧我封了一个通用发送函数/* esp8266.c - STM32 通过 USART2 与 ESP8266 通信 */ #include stdio.h #include string.h #include usart.h extern UART_HandleTypeDef huart2; /* 发送一条 AT 命令等待 OK 返回超时退出 */ uint8_t ESP8266_SendCmd(const char *cmd, uint16_t timeout_ms) { uint8_t rx_buf[128]; uint16_t rx_len 0; uint32_t start HAL_GetTick(); HAL_UART_Transmit(huart2, (uint8_t *)cmd, strlen(cmd), 200); while (HAL_GetTick() - start timeout_ms) { if (HAL_UART_Receive(huart2, rx_buf[rx_len], 1, 20) HAL_OK) { rx_len; if (rx_len 127) break; rx_buf[rx_len] \0; if (strstr((char *)rx_buf, OK) ! NULL) return 1; if (strstr((char *)rx_buf, ERROR) ! NULL) return 0; } } return 0; } /* 将字符串转成十六进制字符串用于 MQTTPUB 数据段 */ static void StrToHex(const char *src, char *dst) { const char hex[] 0123456789ABCDEF; while (*src) { *dst hex[(*src 4) 0x0F]; *dst hex[*src 0x0F]; src; } *dst \0; } void ESP8266_Publish(const char *topic, const char *payload) { char cmd[256]; char hex_buf[128]; StrToHex(payload, hex_buf); snprintf(cmd, sizeof(cmd), ATMQTTPUB0,\%s\,%d,0,0,%s\r\n, topic, (int)strlen(payload), hex_buf); ESP8266_SendCmd(cmd, 3000); }代码里的StrToHex就是避开引号转义的关键操作。ATMQTTPUB的长格式是linkID,topic,data_len,qos,retain,datadata_len用原始payload字节数data用十六进制串。这个格式在带MQTT指令的AT固件上都是支持的比直接拼JSON进去稳得多。4.4 云端命令下发订阅主题与数据解析思路OneNET云平台下发命令是环境监测系统里容易被人忽略的一块。比如温度超标时你想让平台远程控制一个继电器或风扇就需要ESP8266订阅某个主题来接收下行消息。在老版OneNET上平台下发的数据会通过MQTT主题推给设备设备侧要先订阅这个主题然后解析收到的消息。乐鑫AT固件里订阅命令格式如下ATMQTTSUB0,topic_name,0STM32收到数据后在串口中断回调里判断MQTTSUB开头的异步消息再把内容拆出来。这里我建议的做法是收到数据先放一个环形缓冲区主循环里再解析不要在中断里做耗时操作。命令下发的实际主题名在OneNET控制台产品“Topic”页里可以看到不同版本平台差异比较大但订阅和收包的流程是通用的。毕设阶段能把上行数据流跑通、可视化面板看到曲线再做一个下行命令控制LED亮灭这套系统的完整度就很高了。5. 调试避坑与排查五类翻车现场的现象、原因与解决方案5.1 供电不足导致 ESP8266 反复重启、串口乱码现象按下电源键后系统开始几秒工作正常然后ESP8266指示灯突然熄灭串口打印乱码或者AT指令时好时坏。拿万用表量ESP8266的VCC发现电压一直在3.0V到3.3V之间跳。原因ESP8266发射WiFi信号时电流峰值接近300mA核心板板载LDO的压降和散热能力不够电流一上来电压就崩。解决给ESP8266独立供电用AMS1117-3.3从5V输入转出3.3V或者在ESP8266的VCC和GND之间跨接一个470uF电解电容再并一个100nF瓷片电容只有共地线接STM32的GND。注意独立供电芯片的输入端别跟STM32的3.3V串在一起否则等于没隔离。5.2 ATMQTTCONN 返回 ERROR先分清是固件还是参数问题现象STM32串口指令窗口里发ATMQTTCONN0,183.230.40.40,1883,device_id,product_id,api_key,60模块立刻回ERROR不是OK。反复检查设备ID和APIKey都没问题。原因常见的不是参数错而是ESP8266的AT固件压根不支持MQTT指令或者服务器地址和端口填写与平台实际要求不匹配。老版本AT固件不识别ATMQTTCONN会直接当成非法指令返回ERROR。解决先用PC串口助手单独连接ESP8266输入ATGMR查看固件版本如果输出里没有MQTT相关字段先刷带MQTT功能的NONOS SD版本固件。然后手工输入ATMQTTCONN验证刚才的地址端口和参数一条一条排除。不要一上来就怀疑STM32代码很多时候串口助手先能调通问题就出在固件。5.3 WiFi 连接不稳定2.4G 信道、天线位置与重连机制现象ATCWJAP经常连不上或者连接成功后几十秒自动断开ESP8266的IP地址消失。原因ESP8266只支持2.4GHz频段如果你手机开了5GHz热点或者路由器启用了“Smart Connect”把2.4G和5G合并成一个SSIDESP8266可能反复在信道之间跳动。另外ESP8266-01S用的是PCB天线靠金属外壳、电机或者液晶屏太近都会掉线。解决路由器单独开一个2.4G SSID信道固定到1、6或11关闭AP隔离和“WiFi增强”类功能。天线尽量悬空。STM32程序里要做掉线重连不要启动时连一次就完事主循环里定期用ATCIICR或者轻量ATCIPSTATUS检查链路状态断线后重新走一遍CWMODE→CWJAP→MQTTCONN。5.4 DHT11 数据跳变或恒为 255时序细节和上拉电阻的玄学现象温度读数一直在正常值和65、255之间跳或者DHT11刚上电读一次正常后续全都失败。用示波器看数据线波形上升沿明显变缓。原因数据线过长、没有上拉电阻、或者主控在读取过程中被中断打断。STM32的HAL库定时器中断、串口中断如果和DHT11的40位数据读取重叠某一位的采样点就会错判。至于恒为255这通常是校验失败后我在代码里返回了初始值你看到255要意识到是读取失败而不是传感器坏了。解决数据线控制在10cm以内4.7kΩ上拉电阻必须加读DHT11时临时关闭可屏蔽的中断。更稳妥的做法是连续读三次取三次都成功的中间值或者至少两次一致的读数再使用。我在工程文件里就写了“三次读取投票”的逻辑你如果嫌麻烦至少也要做一次失败重试。5.5 OneNET 设备在线但看不到数据点$dp 主题与 JSON 映射现象OneNET控制台显示设备已经在线但数据流页面一个点都没有可视化曲线是空的请求数据API也返回空列表。原因这几乎是老版OneNET最容易踩的坑。很多人在AT指令里直接把数据发到了自定义topic但OneNET的数据点接收必须走$dp这个特殊主题而且payload必须是规范JSON字段名要和控制台数据流名称一致。缺少右括号、字段名写成大写、用了单引号都会静默失败平台不会给你报错。解决先把AT指令里topic确认成$dp然后在本地串口助手手动发一次完整JSON形如{temp:26.3,hum:60.2,smoke:0.45}立刻去控制台看数据流有没有新增数据点。如果有问题在程序里JSON拼装如果没有把payload改成纯ASCII数字再试逐步缩小范围。还有一个隐蔽问题如果你的AT指令用了十六进制格式十六进制串里不能有多余空格我见过有人生成的hex串每个字节之间加了空格OneNET收到后整条解析失败这个只靠眼睛很难看出来建议打印原始串排查。6. 验证链路与进阶玩法先手工打一遍 AT 命令再上整机联调整个系统联调我建议按“三段式”验证不要一上来就把STM32、ESP8266、OneNET三方同时跑起来出了问题根本不知道在哪一段。第一段PC上用USB转TTL接ESP8266串口助手波特率115200手工输入ATCWJAP和ATMQTTCONN确认WiFi和MQTT都能通。第二段用同一个串口助手下发ATMQTTPUB发一条手工拼好的JSON去OneNET控制台看数据流是否新增数据点。第三段再把STM32的USART2接上让STM32串口打印出它发出去的AT指令和收到的响应对比前两段的手工指令看哪一步不一致。这个三段式看起来多花了半小时但能帮你把“硬件问题、固件问题、代码问题”切成三类来定位。我现在的习惯是每次做这种联网项目先在串口助手里把链路敲通再写STM32代码最后才讨论软件逻辑。特别是MQTT这类带状态的协议一旦AT固件版本或平台参数换了一个前面的经验全部清零手工验证几乎是唯一可靠的排错手段。进阶方向有几个值得玩一是用OneNET的触发器功能温度超过阈值时平台主动发邮件或推送这个在控制台界面就能配不写一行代码。二是用平台的数据可视化面板把温度、湿度、烟雾浓度三条曲线关联合并成一张实时大屏这也是OneNET可视化最常用的卖点。三是如果你后面做产品化部署把ESP8266换成ESP32模块代码里只需要改串口速率的AT指令和WiFi配置传感器驱动和JSON拼装逻辑完全不用动因为ESP32也兼容乐鑫AT指令集。最后提醒一点MQTT心跳参数别设太短有些固件把心跳设成10秒反而会被平台判定为频繁连接而踢下线。我一般设60秒既保活又不打扰服务端。这套系统做下来你会对“采集、传输、平台解析”整条数据链路有非常清晰的感觉以后再接LoRa、NB-IoT或者别的云平台其实就是把中间这一段换掉而已。希望这篇笔记帮到你少走几步弯路。本文还有配套的精品资源点击获取