18.从 IP 到 MQTT:STM32 用 AT 指令驱动 ESP-12F 上云的完整链路(含全套实战代码 + 踩坑清单)

这是我做 STM32F411 + ESP-12F 跑通 MQTT 上云之后的一次系统复盘。上一篇讲了「网络地基 → MQTT 模型 → AT 指令遥控」三层逻辑,有同学说想要能直接抄走跑的代码。这篇我把全套实战代码 补上:mqtt.h 头文件、mqtt.c 逐函数实现(每步为什么这么写都有注释)、main.c 调用流程,外加一节「把光照 ADC 采集值发到云端」的进阶改造。先打地基、再讲模型、然后逐行过代码,最后附上实际咬过我的易错点清单。

前言:

这篇文章是我做 STM32F411 + ESP-12F 跑通 MQTT 上云之后的一次系统复盘。

很多同学问我:"为什么我代码写得和你一样,就是连不上?"

我的回答通常是:"你写代码前,先用串口助手手动发过指令吗?"

嵌入式联网开发有一条铁律:先手动确立连通性,再写自动化代码。

这篇不仅包含完整的 mqtt.c 实战代码,更要把这个"避坑心法"讲透。

第零步:磨刀不误砍柴工------先手动跑通 AT 指令(关键!)

在打开 Keil 写代码之前,强烈建议你先拿出一个串口调试助手(如安信可、SSCOM),直接连上 ESP-12F,手动发指令测试。

为什么要这么做?

  1. 验硬件:确认 TX/RX 没接反,波特率(115200)正确,模块没坏。
  2. 验环境:确认 WiFi 密码对、路由器能上网、MQTT 服务器地址在当前网络下可达。
  3. 定逻辑 :亲眼看到发完哪条指令回 OK,发完哪条回 WIFI CONNECTED。这能让你写代码时心里非常有底。

我的测试记录(附截图)

这是我跑代码前的真实测试界面。你可以看到,我是严格按照顺序点击发送的:

解读这张图里的"通关密码":

  • 第 3 步 AT+RST:重启模块,确保状态干净。
  • 第4步AT+CWMODE:设置WiFi模式。
  • 第 6 步 AT+CWJAP :连 WiFi。注意看,如果之前连过,它可能直接回 OK 而不回 WIFI CONNECTED,这点我在代码里做了兼容。
  • 第 7 步 AT+MQTTUSERCFG :配置客户端 ID(ESP12F_2604_HH),这是你的身份证,必须唯一。
  • 第 8 步 AT+MQTTCONN :连服务器。看到 OK 或 +MQTTCONNECTED 才算成功。
  • 第 9/10 步 SUB/PUB:订阅和发布。

结论: 当你在串口助手里能完整走完这一套流程,并且收到预期的回复时,恭喜你,硬件和网络环境已经 100% 没问题了。 接下来写代码,就只是把这套动作"翻译"成 C 语言而已。

一、先打地基:上云之前必须想明白的网络常识

ESP-12F 联网,本质是让一块 MCU 借模组的 WiFi 接入 TCP/IP 网络,所以第一个绕不开的是 IP 地址。

1.1 IP = 网络号 + 主机号

IPv4 是 32 位地址,点分十进制书写(如 202.38.64.10),底层是 32 位无符号整数。二级划分:

  • 网络号 :判断两台设备是否在同一网段(局域网)。相同可直接二层互访,不同必须走网关。
  • 主机号:本网段内唯一标识一台设备,同一局域网不能重复。

按首字节分五类:A 类(1126)、B 类(128191)、C 类(192223)、D 类组播(224239)、E 类保留。嵌入式设备拿到的基本是 C 类私有地址。

1.2 几个必须记住的特殊地址

  • 0.0.0.0:服务端监听它 = 监听本机所有网卡 IP;
  • 主机号全 0(192.168.3.0):代表这个网络本身;
  • 主机号全 1(192.168.3.255):该网段广播地址;
  • 127.0.0.1:回环地址,发往它的数据包在本机 loop back。

1.3 私有地址 vs 公有地址------这是理解「上云」的关键

内网私有段只有三段:10.0.0.0~10.255.255.255、172.16.0.0~172.31.255.255、192.168.0.0~192.168.255.255。三条铁律:

  1. 公有 IP 不能直接访问私有 IP,反之亦然;
  2. 私有 IP 之间互访,必须网络号相同;
  3. 私有设备上公网靠路由器做 NAT,把内网地址映射成公网地址出去。

这直接解释了代码里最关键的现象 :板子连家里 WiFi(私有 192.168.x.x)却能连公网 broker.emqx.io------不是设备被公网直接访问,而是我主动从内网向外发起 TCP 连接,经路由器 NAT 出去。这也回答了「两个不同局域网设备 A、B 怎么通信」:都去连公网上的中转服务器(MQTT Broker),由 Broker 转发。这正是 MQTT 架构存在的网络学理由。

1.4 TCP 还是 UDP?MQTT 选了 TCP

协议 优点 缺点 典型场景
TCP 有连接、可靠:确认/重传/CRC,不丢不重不乱序 慢、开销大 表单提交、即时消息、文件传输
UDP 快、轻 不可靠、易丢包 视频通话、直播

MQTT 构建在 TCP/IP 之上,天生继承 TCP 可靠性,再在应用层用 QoS 补一层消息级保证。

1.5 顺带:虚拟机 NAT/桥接 与 ping

  • NAT 模式 :虚拟机 IP 由宿主虚拟 DHCP 分配,网段不定甚至撞 IP,虚拟机间默认不能互访;
  • 桥接模式:IP 由真实路由器分配,地位与宿主机平级------联网实验用真实局域网身份就选桥接;
  • ping :测连通、由域名解析 IP、看 TTL 估算跳数(每过一路由器减 1,到 0 丢包)。连不上网第一步永远是同 WiFi 的电脑 ping broker.emqx.io,先排除环境问题。

二、中间层:MQTT 的发布/订阅模型

MQTT(消息队列遥测传输)是 IBM 1999 年提出、构建在 TCP/IP 上的轻量级发布/订阅 协议,专为低带宽、不稳定网络的物联网场景设计。它和写 Web 服务器最大的不同:Broker 只负责转发,不负责存储业务数据和应答处理,重点是订阅、发布、转发过程。

三个角色:代理 Broker (中心服务器,做消息路由,如 EMQX/Mosquitto/broker.emqx.io)、发布者 Publisher (往某 Topic 发消息)、订阅者 Subscriber (注册对某 Topic 的兴趣)。发布订阅者彼此不直连,全靠 Topic 字符串匹配、Broker 撮合------这就是它能解决「两个局域网设备通信」的原因。

概念 含义 我项目取值
Topic 主题 消息频道,字符串匹配,支持 / 分层 2604/topic-HH(自发自收同一主题)
QoS 服务质量 0 最多一次 / 1 至少一次 / 2 恰好一次 1(至少一次,可能重复)
Retain 保留消息 置 1 时 Broker 存最后一条,新订阅者上线即收到 MQTTPUB 末位 0,不保留
Client ID Broker 区分设备的唯一标识,重复会互踢 ESP12F_2604_HH
keepalive 心跳 维持 TCP 长连接的探活间隔 由模组固件维持

调试阶段可先用 MQTT.fx 当「假设备」:填 Broker + 端口(1883,TLS 是 8883)+ 唯一 Client ID 连上,右侧变绿即成功;再开第二个客户端,一个订阅、一个发布,肉眼验证消息在 Broker 转发------先确认协议和服务器没问题,再怀疑单片机代码。

三、最上层:STM32 用 AT 指令「遥控」ESP-12F

架构职责先分清------MQTT 协议栈整个跑在 ESP-12F 里 (ESP8266 固件已内置 TCP/IP + LwIP + MQTT 3.1.1)。STM32 自己压根不碰网络,它只是个通过串口发 AT 指令的遥控器。

复制代码
STM32(F411) --USART2/AT指令--> ESP-12F --WiFi--> 路由器 --NAT/公网--> Broker(broker.emqx.io:1883)
     |                             ^                                        |
     +------USART1 打印<-----------+<------- 订阅回推 +MQTTSUBRECV ----------+

整条工程 = 一条主线 + 一个统一模式 :每条指令都是「发指令 → 收应答 → strstr 找关键字」三件套。下面直接上全套代码。

四、实战代码(完整可编译)

4.1 头文件 mqtt.h

把对外接口集中在头文件,main.c 只需要包含它即可。

复制代码
#ifndef __MQTT_H
#define __MQTT_H

#include "stm32f4xx_hal.h"
#include <stdint.h>

/* ===== 对用户开放的接口 ===== */
uint8_t Mqtt_Server_Init(void);   // 一键上云:上电延时→关回显→连WiFi→配MQTT→连Broker→订阅
void    outputMsg(void);          // 主循环:周期性发布 + 打印云端回推
uint8_t MqttSub(void);            // 订阅主题(也用于断线后重新订阅)

#endif

注意 Mqtt_Server_Init 返回类型要写一致(原代码声明带参数、定义不带,编译会告警);这里统一为 uint8_t Mqtt_Server_Init(void)。

4.2 实现文件 mqtt.c(逐函数完整实现)

复制代码
/**
 *******************************************************
 *  文件名称 : mqtt.c
 *  作    者 : huanghuai
 *  版    本 : V1.0
 *  编写日期 : 2026.10.13
 *  功    能 : 通过 ESP-12F 完成 MQTT 发布/订阅
 *******************************************************
 */

/* 包含头文件 ------------------------------------------ */
#include "stm32f4xx_hal.h"
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "usart.h"
#include "mqtt.h"

/* 1. 宏定义区 ----------------------------------------- */
#define MQTT_SSID       "7"           // WiFi 名称(根据自己网络/热点设置)
#define MQTT_PWD        "66668888"    // WiFi 密码(根据自己网络/热点设置)
#define MQTT_BROKER     "broker.emqx.io"
#define MQTT_PORT       1883
#define MQTT_CLIENTID   "ESP12F_2604_HH"   // 客户端ID:全局唯一!
#define MQTT_TOPIC      "2604/topic-HH"    // 自发自收的主题

/* 2. 全局变量区 --------------------------------------- */
// strstr 的返回值暂存(判断应答里是否含关键字)
char const *pos;
// 订阅消息共享缓冲区:MqttPub 收到的回推数据也转存到这里,由 outputMsg 统一打印
uint8_t subRecvBuf[256] = {0};

/* 3. 私有函数声明区 ----------------------------------- */
static uint8_t setEchoOff(void);
static uint8_t setWifiMode(uint8_t mode);
static uint8_t connectWifi(const char *ssid, const char *pwd);
static uint8_t setMqttPara(void);
static uint8_t MqttConn(void);
static uint8_t MqttPub(const char *msg);

/* 4. 全局函数定义区 ----------------------------------- */

// 一键上云:严格按「延时→关回显→WiFi→MQTT参数→连Broker→订阅」顺序
uint8_t Mqtt_Server_Init(void)
{
    // ① 等 ESP-12F 上电启动完成。ESP 启动比 STM32 慢 1~2 秒,
    //    启动期间串口吐日志,必须就绪后再发指令,否则首条指令被冲掉。
    HAL_Delay(3000);

    // ② 关回显:后续一切 strstr 判断可靠的前提(见易错点8)
    setEchoOff();

    // ③ 设 Station 模式,连接其他热点
    setWifiMode(1);

    // ④ 连接 WiFi
    connectWifi(MQTT_SSID, MQTT_PWD);

    // ⑤ 配置 MQTT 客户端身份
    setMqttPara();

    // ⑥ 连接 MQTT 服务器
    MqttConn();

    // ⑦ 订阅主题
    MqttSub();

    return HAL_OK;
}

// 主循环:周期性发布 + 打印云端回推
void outputMsg(void)
{
    uint8_t retData[256] = {0};
    uint8_t i = 0;
    while (1)
    {
        // 发布一条消息(实际项目里把 msg 换成传感器数据即可)
        MqttPub("Hello 2604-HH");

        // 打印自发自收、在发布接收窗口内到达的回推数据
        if (subRecvBuf[0] != 0)
        {
            printf("retData:%s\r\n", (char *)subRecvBuf);
            memset(subRecvBuf, 0, 256);
        }

        // 持续轮询接收约 2 秒:20 个 100ms 小窗口,几乎不留「没人接收」空窗
        for (i = 0; i < 20; i++)
        {
            HAL_UART_Receive(&huart2, retData, 256, 100);
            if (retData[0] != 0)
            {
                printf("retData:%s\r\n", (char *)retData);
                memset(retData, 0, 256);
            }
        }
    }
}

// 订阅主题:AT+MQTTSUB=0,"topic",QoS
uint8_t MqttSub(void)
{
    pos = 0;
    uint8_t cmd[] = "AT+MQTTSUB=0,\"2604/topic-HH\",1\r\n";
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    HAL_UART_Receive(&huart2, retData, 64, 1000);   // 1秒超时,绝不无限等

    pos = strstr((char *)retData, "OK");
    if (pos) { printf("MqttSub : OK!!!\r\n");   return HAL_OK; }
    else     { printf("MqttSub : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

/* 5. 私有函数定义区 ----------------------------------- */

// 关闭 ESP 指令回显。默认回显会把指令原样回发,一条占几十上百字节,
// 64字节缓冲区被回显塞满后真正的 OK 还没进来就超时返回,导致 strstr 误判。
static uint8_t setEchoOff(void)
{
    uint8_t cmd[] = "ATE0\r\n";
    pos = 0;
    uint8_t retData[64] = {0};
    uint8_t tryCnt = 0;

    // 这是后续所有步骤的前提,失败最多重试3次(偶尔丢字节会回 ERROR)
    for (tryCnt = 0; tryCnt < 3; tryCnt++)
    {
        memset(retData, 0, 64);
        HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
        HAL_UART_Receive(&huart2, retData, 64, 1000);
        pos = strstr((char *)retData, "OK");
        if (pos) break;
    }
    if (pos) { printf("setEchoOff : OK!!!\r\n"); return HAL_OK; }
    else     { printf("setEchoOff : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

// 设 WiFi 模式:1=Station(连别人热点)
static uint8_t setWifiMode(uint8_t mode)
{
    pos = 0;
    (void)mode;   // 样例固定为1;要灵活可拼接成 AT+CWMODE=%d
    uint8_t cmd[] = "AT+CWMODE=1\r\n";
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    HAL_UART_Receive(&huart2, retData, 64, 1000);

    pos = strstr((char *)retData, "OK");
    if (pos) { printf("setWifiMode:OK!!!\r\n"); return HAL_OK; }
    else     { printf("setWifiMode:FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

// 连接 WiFi:AT+CWJAP="ssid","pwd"。连接慢,给 10 秒超时。
static uint8_t connectWifi(const char *ssid, const char *pwd)
{
    pos = 0;
    (void)ssid; (void)pwd;   // 样例指令里固定写死;要灵活用 sprintf 拼接
    uint8_t cmd[] = "AT+CWJAP=\"7\",\"66668888\"\r\n";
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    HAL_UART_Receive(&huart2, retData, 64, 10000);   // 连 WiFi 慢,10 秒

    // 注意:已连过该热点时可能不再回 "WIFI CONNECTED",判断成功认 "OK"
    pos = strstr((char *)retData, "OK");
    if (pos) { printf("connectWifi : OK!!!\r\n"); return HAL_OK; }
    else     { printf("connectWifi : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

// 配置 MQTT 客户端身份:AT+MQTTUSERCFG=linkID,ver,clientID,user,pwd,clean,ssl,willTopic
static uint8_t setMqttPara(void)
{
    /*
      参数:① 0 LinkID(固定0)
            ② 1 MQTT版本(1=3.1.1)
            ③ "ESP12F_2604_HH" 客户端ID(必须全局唯一!)
            ④ "" 用户名  ⑤ "" 密码
            ⑥ 0 不清除会话  ⑦ 0 不用SSL  ⑧ "" 遗嘱主题(留空=不用)
    */
    pos = 0;
    uint8_t cmd[] = "AT+MQTTUSERCFG=0,1,\"ESP12F_2604_HH\",\"\",\"\",0,0,\"\"\r\n";
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    HAL_UART_Receive(&huart2, retData, 64, 1000);

    pos = strstr((char *)retData, "OK");
    if (pos) { printf("setMqttPara : OK!!!\r\n"); return HAL_OK; }
    else     { printf("setMqttPara : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

// 连接 Broker:AT+MQTTCONN=linkID,"host",port,reconnect。末位1=启用自动重连
static uint8_t MqttConn(void)
{
    pos = 0;
    uint8_t cmd[] = "AT+MQTTCONN=0,\"broker.emqx.io\",1883,1\r\n";
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    HAL_UART_Receive(&huart2, retData, 64, 5000);   // 连服务器慢,5秒

    // 成功有两种应答:首次连接回 OK,重连场景可能直接回 +MQTTCONNECTED
    if (strstr((char *)retData, "OK") || strstr((char *)retData, "+MQTTCONNECTED"))
    { printf("MqttConn : OK!!!\r\n"); return HAL_OK; }
    else { printf("MqttConn : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

// 发布消息:AT+MQTTPUB=linkID,"topic","msg",QoS,retain
static uint8_t MqttPub(const char *msg)
{
    pos = 0;
    // 用 msg 拼出发布指令(保留样例的固定主题)
    uint8_t cmd[128] = {0};
    sprintf((char *)cmd, "AT+MQTTPUB=0,\"%s\",\"%s\",1,0\r\n", MQTT_TOPIC, msg);
    uint8_t retData[64] = {0};

    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), HAL_MAX_DELAY);
    // 发布是异步的:发完不立刻死等应答,回推数据由接收窗口自然到达
    pos = strstr((char *)retData, "OK");
    if (pos)
    {
        printf("MqttPub : OK!!!\r\n");
        // 自发自收回推往往落在这次接收里,转存共享缓冲,由 outputMsg 统一打印
        strncpy((char *)subRecvBuf, (char *)retData, 255);
        return HAL_OK;
    }
    else { printf("MqttPub : FAIL,recv:%s\r\n", (char*)retData); return HAL_ERROR; }
}

4.3 主程序 main.c 调用流程

复制代码
#include "main.h"
#include "mqtt.h"

int main(void)
{
    HAL_Init();
    SystemClock_Config();     // CubeMX 生成
    MX_GPIO_Init();
    MX_USART1_UART_Init();    // 调试打印口
    MX_USART2_UART_Init();    // 接 ESP-12F,115200-8-N-1
    // 若进阶要做传感器数据,这里再初始化 ADC:MX_ADC1_Init();

    // 上电一键上云
    Mqtt_Server_Init();

    // 进入发布/接收主循环(内部 while(1))
    outputMsg();
}

4.4 进阶:把光照 ADC 采集值发到云端(闭环改造)

把之前那个光敏电阻 ADC 项目接进来,让「Hello World」变成真正会报数的物联网终端。ADC 侧沿用 12 位满量程 4095、vref=3.3V:

复制代码
// ADC 原始值转电压
static float adc_to_voltage(uint32_t adc_value, float vref)
{
    return (adc_value * vref) / 4095.0f;
}

// 读一次光敏电阻电压
static uint32_t Read_Light_Sensor(void)
{
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);
    return HAL_ADC_GetValue(&hadc1);
}

// 在 outputMsg 主循环里,把固定字符串换成实测数据:
void outputMsg_with_sensor(void)
{
    uint8_t retData[256] = {0}, i = 0;
    char payload[64];
    while (1)
    {
        float v = adc_to_voltage(Read_Light_Sensor(), 3.3f);
        sprintf(payload, "light=%.2fV", v);   // 例如 light=1.87V
        MqttPub(payload);                     // 发布光照电压到 2604/topic-HH

        if (subRecvBuf[0] != 0) { printf("retData:%s\r\n",(char*)subRecvBuf); memset(subRecvBuf,0,256);}
        for (i = 0; i < 20; i++)
        {
            HAL_UART_Receive(&huart2, retData, 256, 100);
            if (retData[0] != 0) { printf("retData:%s\r\n",(char*)retData); memset(retData,0,256);}
        }
    }
}

这样 PC 端 MQTT.fx 只要订阅 2604/topic-HH,就能实时看到板子报上来的 light=x.xxV,一个「采集 → 上云 → 远程可视化」的最小闭环就成立了。

五、易错点清单(血泪复盘)

网络底层类

  1. 私有 IP 不能直接访问另一台私有 IP,两个局域网设备互通必须靠公网中转(Broker),别幻想用内网 IP 直连。
  2. 连不上网先 ping :同 WiFi 电脑 ping broker.emqx.io,先排除环境(路由器没联网、密码错、外网被墙),再查代码。
  3. 虚拟机默认 NAT 不能互访/网段不定,要真实局域网身份改桥接。

MQTT 协议类

  1. Client ID 必须全局唯一,公共 Broker 上重名会互相踢下线,现象是「连上几秒被踢、反复掉线」。
  2. QoS 1 = 至少一次 ≠ 恰好一次,可能重复投递,业务要「只处理一次」得自己做去重。
  3. 端口别填错 :MQTT over TCP 是 1883,over TLS/SSL 是 8883,用 SSL 时 MQTTUSERCFG 的 SSL 位也要置 1。

AT 指令时序类(最容易翻车)

  1. ESP-12F 上电启动比 STM32 慢 1~2 秒 ,不加 HAL_Delay(3000),第一条指令被启动日志冲掉、不收 OK,全链路连环失败。
  2. 忘关回显 ATE0 = 最隐蔽的坑 :回显撑爆 64 字节缓冲区,真正的 OK 还没进缓冲区就超时返回,strstr 误判失败。放在最前面 + 3 次重试,是「从全不通到全通」的分水岭。
  3. 收应答绝不能用 HAL_MAX_DELAY:ESP 没回就死在那行。给有限超时------普通 1s、连 WiFi 10s、连服务器 5s。
  4. WiFi 连接成功别死盯 WIFI CONNECTED ,已连过时可能只回 OK/ALREADY CONNECTED,判断认 OK。
  5. MQTTCONN 成功有两种应答 :OK 或 +MQTTCONNECTED,两种都要认。
  6. AT 指令格式细节 :必须大写、必须 \r\n(CRLF) 结尾、字符串参数带双引号、默认 115200 波特率,漏一个 ESP 直接不回或回 ERROR。
  7. 发布是否成功以「订阅端收到回推」为准,发布是异步的,端到端跑通的真正证据是自发自收能打印出回推内容。

六、总结

这个项目代码量小,却把网络基础、MQTT 协议、AT 指令交互串成一条完整因果链,核心体会三条:

第一,上云是分层的事,卡住了分层定位。 最底层 IP/TCP------先想清「私有 IP 上公网靠 NAT 主动外连」,连不通先 ping;中间层 MQTT 的 Pub/Sub、Topic 匹配、QoS、Client ID 唯一性;最上层才是 AT 逐条交互。绝大多数「上云失败」根因在网络底层或 AT 时序,而不在 MQTT 本身。

第二,AT 指令交互本质是异步串口协议,难点全在时序和缓冲区。 上电等模组就绪、先关回显避免 strstr 误判、收应答设有限超时不死等、连接判据兼容多种应答。守住这条时序纪律,链路稳一大半。

第三,先跑通再工程化。 用 MQTT.fx 当假设备先验证协议和服务器,用轮询版跑通自发自收,正式项目再迁 DMA + 空闲中断 解决丢消息、补 keepalive 心跳与断线重连提升健壮性,并把发布内容换成真实传感器数据,从「Hello World」升级为真正的物联网终端。

相关推荐
霖霖7141 小时前
【ESP32笔记】SmartConfig一键配网
笔记·单片机·mcu·物联网
霖霖7141 小时前
【ESP32笔记】WIFI连接—STA模式
笔记·单片机·mcu·物联网
重生之高冷汉堡包1 小时前
JavaScript 网络爬虫教程(2026)
大数据·网络·爬虫·安全
HRTOS1 小时前
HRTOS 4.0 实测:时间片模式与调度位模式的任务切换性能对比
经验分享·单片机·嵌入式硬件·51单片机
深圳市恒锐丰科技杨生1 小时前
LR048N10SM3 / LR046N10SM2 N 沟道 SGT‑MOSFET|Long‑Tek 龙夏电子
嵌入式硬件·硬件工程
独孤九剑打醒他1 小时前
【原创开源·2.0 版】太阳能水闭环氢能源汽车:动态制氢、动能回收与副产物商业闭环
前端·嵌入式硬件·汽车·硬件工程·能源
Raas1001 小时前
AI网关怎么选?MAI Gateway(魔芋企业级AI网关)入选2026年企业级AI网关推荐清单
大数据·网络·人工智能·gateway·mai gateway
我先去打把游戏先2 小时前
Git-Rebase使用指南-从原理到实战
服务器·git·嵌入式硬件·物联网·ubuntu
白帽攻防录2 小时前
SRC 挖洞:MSMQ 端口上的 UAF 炸弹,9.8 分网络 RCE 怎么打到 SYSTEM
网络·网络安全·src漏洞挖掘