RT-Thread中使用Mqtt(ESP8266+AT)

环境:

开发板:Panduola(stm32L475)
KEIL5 开发环境
rtthread 4.0.3内核
使用ENV 配置Rtt


MQTT

1.MQTT介绍
客户端 Client

  • 使用MQTT的程序或设备。客户端总是通过网络连接到服务端。
  • 它可以发布应用消息给其它相关的客户端。
  • 订阅以请求接受相关的应用消息。
  • 取消订阅以移除接受应用消息的请求。
  • 从服务端断开连接。服务端 Server一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。

服务端

  • 接受来自客户端的网络连接。

  • 接受客户端发布的应用消息。

  • 处理客户端的订阅和取消订阅请求。

  • 转发应用消息给符合条件的已订阅客户端。

订阅 Subscription

  • 订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅与单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。

  • QoS0,At most once,至多一次;Sender 发送的一条消息,Receiver 最多能收到一次,如果发送失败,也就算了。

  • QoS1,At least once,至少一次;Sender 发送的一条消息,Receiver 至少能收到一次,如果发送失败,会继续重试,直到 Receiver 收到消息为止,但Receiver 有可能会收到重复的消息

  • QoS2,Exactly once,确保只有一次。Sender 尽力向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。
    2.MQTT协议数据包结构

一个MQTT数据包由:固定头(Fixed header)、可变头(Variable header)、有效载荷(payload)三部分构成。

(1) 固定头(Fixed header)。存在于所有MQTT数据包中,表示数据包类型及数据包的分组类标识。
(2)可变头(Variable header)。存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容。
(3)有效载荷(Payload)。存在于部分MQTT数据包中,表示客户端收到的具体内容。

操作:

0.添加AT指令部分,使用ESP8266连接网络:

//8266AT层支持
RT-Thread online packages  --->
  IoT - internet of things  --->
  [*] AT DEVICE: RT-Thread AT component porting or samples for different device
  [*]   Espressif ESP8266  --->

//AT命令启用BSD Socket API支持
//bsd socketbsd socket, 是UNIX系统中通用的网络接口,它不仅支持各种不同的网络类型,而且也是一种内部进程之间的通信机制。
RT-Thread Components 
	→ Network
		 → AT commands
		 		 [*]Enable BSD Socket API support by AT commnads

在这里插入图片描述
在这里插入图片描述

1. 添加RTT组件包:

MQTT
在这里插入图片描述

CJSON

在这里插入图片描述

AHT10:使用AHT10还需要打开I2c的驱动部分,使用旧版本1.0的AHT驱动,可以避免使用Sensor的框架

在这里插入图片描述

启用I2c总线:

在这里插入图片描述
三个组件包的版本:

在这里插入图片描述

2.使用scons --target=mdk5生成mdk工程

在这里插入图片描述

3.使用MQtt客户端:

修改连接参数:

#define MQTT_URI “tcp://192.168.1.110:1883”
#define MQTT_USERNAME “panduola”
#define MQTT_PASSWORD “panduola”
#define MQTT_SUBTOPIC “/test/topic2”
#define MQTT_PUBTOPIC “/test/topic1”

可在rtconfig.h中修改wifi连接参数:
在这里插入图片描述

  1. 创建一个客户端:
    static MQTTClient client;

  2. 初始化客户端:


/* 创建与配置 mqtt 客户端 */
static void mq_start(void)
{
   
   
    /* 初始 condata 参数 */
    MQTTPacket_connectData condata = MQTTPacket_connectData_initializer;
    static char cid[20] = {
   
   0};

    static int is_started = 0;
    if (is_started)
    {
   
   
        return;
    }
    /* 配置 MQTT 文本参数 */
    {
   
   
        client.isconnected = 0;
        client.uri = MQTT_URI;

        /* 生成随机客户端 ID */
        rt_snprintf(cid, sizeof(cid), "rtthread%d", rt_tick_get());

        // rt_snprintf(sup_pub_topic, sizeof(sup_pub_topic), "%s%s", MQTT_PUBTOPIC, cid);
        /* 配置连接参数 */
        memcpy(sup_pub_topic, MQTT_SUBTOPIC, sizeof(MQTT_SUBTOPIC));
        memcpy(&client.condata, &condata, sizeof(condata));
        client.condata.clientID.cstring = cid;
        client.condata.keepAliveInterval = 60;
        client.condata.cleansession = 1;
        client.condata.username.cstring = MQTT_USERNAME;
        client.condata.password.cstring = MQTT_PASSWORD;

        /* 配置 mqtt 参数 */
        client.condata.willFlag = 0;
        client.condata.will.qos = 1;
        client.condata.will.retained = 0;
        client.condata.will.topicName.cstring = sup_pub_topic;

        client.buf_size = client.readbuf_size = 1024;
        client.buf = malloc(client.buf_size);
        client.readbuf = malloc(client.readbuf_size);
        if (!(client.buf && client.readbuf))
        {
   
   
            LOG_E("no memory for MQTT client buffer!");
            goto _exit;
        }

        /* 设置事件回调 */
        client.connect_callback = mqtt_connect_callback;
        client.online_callback = mqtt_online_callback;
        client.offline_callback = mqtt_offline_callback;
        /* 设置要订阅的 topic 和 topic 对应的回调函数 */
        client.messageHandlers[0].topicFilter = MQTT_SUBTOPIC;
        client.messageHandlers[0].callback = mqtt_sub_callback;
        client.messageHandlers[0].qos = QOS1;

        /* 设置默认订阅回调函数 */
        client.defaultMessageHandler = mqtt_sub_default_callback;
    }

    /* 启动 MQTT 客户端 */
    LOG_D("Start mqtt client and subscribe topic:%s", sup_pub_topic);
    paho_mqtt_start(&client);
    is_started = 1;

_exit:
    return;
}

  1. 设置收到信息后的回调:
static void mqtt_sub_callback(MQTTClient *c, MessageData *msg_data)
{
   
   
    printf("Receive message ,Topic: %.*s,payload:\n", msg_data->topicName->lenstring.len,msg_data->topicName->lenstring.data);
    // 解析JSON消息
    cJSON *json_obj = cJSON_Parse((const char *)msg_data->message->payload);
    if (json_obj == NULL)
    {
   
   
        printf("Failed to parse JSON message\n");
        return;
    }
    cJSON *object = RT_NULL;
    object = cJSON_GetObjectItem(json_obj, "location");
    if (object != NULL)
    {
   
   

        printf("Location: %s\n", object->valuestring);
    }
    object = cJSON_GetObjectItem(json_obj, "led");
    if (object != NULL)
    {
   
   
        if(object->type == cJSON_True)
        printf("led: ture\n");
        else
        printf("led: false\n");
    }

    cJSON_Delete(json_obj);

    return;
}
  1. 发布消息:

/* MQTT 消息发布函数 */
static void mq_publish(const char *send_str)
{
   
   
    MQTTMessage message;
    const char *msg_str = send_str;
    const char *topic = MQTT_PUBTOPIC;
    message.qos = QOS1;
    message.retained = 0;
    message.payload = (void *)msg_str;
    message.payloadlen = strlen(message.payload);

    MQTTPublish(&client, topic, &message);

    return;
}

常用的cjson函数

void cJSON_Delete(cJSON *c)

删除 cJSON 指针,释放空间

char *cJSON_Print(cJSON *item)

cJSON数据解析成JSON字符串,并会在堆中开辟一块char *的内存空间,存放JSON字符串。
函数成功后会返回一个char *指针,该指针指向位于堆中JSON字符串。

cJSON *cJSON_Parse(const char *value)

将一个JSON数据包,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体
返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL

cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)

获取JSON字符串字段值,成功返回一个指向cJSON类型的结构体指针,失败返回NULL

常用的mqtt的API

<think>好的,用户的问题是关于如何在RT-Thread操作系统中通过ESP8266模块连接到云平台,需要教程指导。首先,我需要回忆一下RT-Thread的相关知识,特别是关于AT设备框架、软件包管理以及云平台连接的步骤。 根据用户提供的引用内容,特别是引用[1]和引用[2],他们提到了使用AT设备配置、添加mpu6xx软件包,以及ESP8266与OneNet平台的连接。用户可能需要详细的步骤,比如开发环境配置、软件包添加、设备初始化、云平台设置和数据上传等。 首先,用户需要安装RT-Thread Studio,并创建项目。这部分需要检查是否支持他们的开发板型号,比如STM32F7或者其他。然后,配置AT设备框架和ESP8266软件包是关键步骤,因为AT指令是通过串口与模块通信的。接下来,配置OneNet软件包,确保数据能正确上传。 用户可能遇到的困难包括串口配置不正确、AT指令无法响应、网络连接问题或者数据上传失败。需要提醒他们检查硬件连接,比如串口引脚是否正确,供电是否稳定。软件配置方面,注意I2C或UART的配置,尤其是在使用不同MCU时的注意事项,如引用[4]提到的BSP配置。 另外,引用[1]中提到将虚拟温度改为读取六轴传感器数据,所以可能需要指导如何修改数据采集部分,替换传感器相关的代码。同时,引用[3]提到了调试命令,可以建议用户开启ESP8266的调试信息,帮助排查问题。 最后,用户可能需要优化网络稳定性,比如心跳包机制或重连逻辑,以及了解如何扩展其他云平台,如腾讯云,如引用[3]和引用[2]所示。需要总结常见问题,比如软件包版本兼容性、网络配置错误,并给出参考资料和社区链接,方便用户深入学习和解决问题。</think>### RT-Thread通过ESP8266连接云平台教程 本教程以连接中国移动OneNET云平台为例,详细说明基于RT-Thread Studio的开发流程: #### 一、开发环境配置 1. 安装RT-Thread Studio(最新版建议4.1.3+) 2. 新建项目选择对应BSP(如STM32F407系列) 3. 在`RT-Thread Settings`中启用以下组件: - AT设备框架 - ESP8266软件包 - OneNET软件包 - SAL套接字抽象层 #### 二、硬件连接 ```c ESP8266模块接线示例: VCC -> 3.3V GND -> GND TX -> MCU_UART2_RX RX -> MCU_UART2_TX EN -> 3.3V(使能端) ``` #### 三、软件配置流程 1. **AT设备配置**: 在`board.h`中配置UART2参数: ```c #define BSP_USING_UART2 #define BSP_UART2_TX_PIN "PA2" #define BSP_UART2_RX_PIN "PA3" #define BSP_UART2_BAUD_RATE 115200 ``` 在`at_device`软件包中启用`ESP8266`模块配置[^2] 2. **OneNET配置**: ```c /* 添加设备三元组 */ #define ONENET_DEVICE_ID "your_device_id" #define ONENET_API_KEY "your_api_key" #define ONENET_PROJECT_ID "your_project_id" ``` 3. **网络初始化代码**: ```c int esp8266_init(void) { rt_pin_mode(ESP8266_PWR_PIN, PIN_MODE_OUTPUT); rt_pin_write(ESP8266_PWR_PIN, PIN_HIGH); return RT_EOK; } INIT_APP_EXPORT(esp8266_init); ``` #### 四、数据上传实现 ```c void upload_sensor_data(float acc_x, float acc_y, float acc_z) { cJSON *root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "acc_x", acc_x); cJSON_AddNumberToObject(root, "acc_y", acc_y); cJSON_AddNumberToObject(root, "acc_z", acc_z); onenet_mqtt_publish("$sys/device/upload", cJSON_Print(root)); cJSON_Delete(root); } ``` #### 五、调试技巧 1. 使用`ifconfig`命令查看网络状态 2. 通过`ping www.baidu.com`测试网络连通性 3. 开启ESP8266调试模式: ```shell msh > at_cli esp8266> AT+CWMODE=1 esp8266> AT+CWJAP="SSID","password" ``` #### 六、注意事项 1. ESP8266固件需支持MQTT协议(建议使用安信可AT固件V1.7+) 2. OneNET设备需开启`多协议接入`模式 3. 数据点上传频率不宜超过1次/秒 4. 建议添加看门狗防止网络异常导致死机
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想和我重名?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值