AliYun平台

Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.


AliYun简介

阿里云是阿里巴巴旗下自研云计算服务平台,依托自研飞天云计算操作系统,涵盖云计算、存储、物联网、数据库等全栈云产品体系阿里云。平台配套物联网IoT平台,支持MQTT等主流通信协议接入各类嵌入式硬件,实现设备安全鉴权、上下线管理、数据上报与云端指令下发,可无缝联动云服务器、时序数据库等产品,是设备云端接入、数据存储与远程管控的依托载体。

资源准备

硬件准备

  • 一块移远通信提供的 pico开发板介绍 开发板。(下文以该开发板为例)

  • USB数据线(USB-A转USB-C)。

  • PC(Windows 10/Windows 11)。

软件准备

  • unirtos-toolchain.exe:编译工具链安装程序,点此获取

  • Python:用于运行unirtos-cli工具,需使用3.9及更高版本。安装步骤详见 环境搭建

  • Git:unirtos-cli使用该工具拉取SDK、依赖库等,需使用2.20及更高版本。安装步骤详见 环境搭建

  • unirtos-cli:UniRTOS的命令行工具,用于一键拉取SDK、快速创建工程。安装步骤详见 环境搭建

  • USB驱动:用于PC识别模块的USB枚举接口,点此获取

  • QFlash.exe:模块固件烧录程序,用于烧录UniRTOS编译生成的固件,点此获取

  • EPAT工具:芯片厂商提供的日志抓取工具,用于查看模块运行日志以分析应用程序执行情况,点此获取

  • QCOM工具:移远通信提供的串口调试工具,用于执行和验证AT命令,点此获取

  • 程序源码:位于UniRTOS的官方github仓库,点此查看,示例可通过unirtos-cli直接拉取 。

  • 关于如何拉取示例程序、编译和烧录固件,请参考 快速上手

AliYun连接参数获取

获取产品证书

  1. 在AliYun控制台新建一个产品。

../../../_images/image_J5p5bxQAQoJaM7xcRQlcS7U8nwc.webp
  1. 进入上一步创建好的产品页面,点击 ProductSecret 右边的“查看”。

../../../_images/image_SjsDbqcP0octZrxglJTc64UFnrd.webp
  1. 获取我们连接需要的两个参数:ProductKeyProductSecret。

../../../_images/image_QXpHbDCqyoDLlrxkbNKchcZGnUd.webp

获取设备证书

  1. 创建一个新设备,如图所示。

../../../_images/image_M6bsbHrjWoUVUQxZxM8cp0Fjnrb.webp
  1. 选择上一节中新建的产品,自定义设备名后点击确认即可。

../../../_images/image_PVHNbtpCzoEPNfx7D2wcnDwxnSg.webp
  1. 进入产品页面,点击上方 DeviceSecret 右边的“查看”。

../../../_images/image_F7hzbndeJoNJbJxVKQxc8i0UnZc.webp
  1. 获取 DeviceNameDeviceSecret

../../../_images/image_KLSGbjSCiooU7fxddk3c4n89nef.webp

获取MQTT连接参数

  1. 点此产品页面的自定义Topic查看发布Topic和订阅Topic。如图:

../../../_images/image_L04AbGSJZoF7QuxUbiccQCKpn8e.webp
  1. 点击设备栏“设备信息”页面MQTT连接参数右侧的“查看”,获取MQTT详细连接参数。如图:

../../../_images/image_W4lhb7mBQo18qkxx7Mbc1vgpntf.webp

主要功能接口

参数配置

  • 定义云平台MQTT服务器连接地址、服务器连接端口、客户端ID、订阅主题等参数。

  • 定义云平台连接的产品秘钥、设备名称、设备秘钥。

  • 定义程序运行的任务栈大小、日志标签、消息队列大小等系统设置。

示例代码:

#define ALIOT_BASIC_DEMO_SERVER_ADDR     "iot-0**********9q90x.mqtt.iothub.aliyuncs.com" /*!< Aliot server address */
#define ALIOT_BASIC_DEMO_SERVER_PORT     1883                                      /*!< Aliot server port */
#define ALIOT_BASIC_DEMO_TOPIC_SUB       "/k28*****qN/device_name/user/get"     /*!< MQTT test topic for subscribing messages */
#define ALIOT_BASIC_DEMO_CLIENTID        "k28*****qN.device_name"                  /*!< Aliot client unique identifier */
#define ALIOT_BASIC_DEMO_PRODUCT_KEY     "k28*****qN"                              /*!< Aliot product key */
#define ALIOT_BASIC_DEMO_DEVICE_NAME     ""                                        /*!< Aliot device name */
#define ALIOT_BASIC_DEMO_DEVICE_SECRET   ""                                     /*!< Aliot device secret */
#define ALIOT_BASIC_DEMO_TEST_CONTENT    "Hello Welcome to test ali mqtt!"    /*!< Test message content */
#define ALIOT_BASIC_DEMO_TOPIC_PUB       "/k28*****qN/device_name/user/update" /*!< MQTT test topic for publishing messages */
#define ALIOT_BASIC_DEMO_MQTTS           0                                    /*!< Test MQTT or MQTTS */

#define QOS_LOG_TAG               LOG_TAG_DEMO
#define ALIOT_BASIC_DEMO_TASK_STACK_SIZE 4096 /*!< ALIOT basic demo task stack size in bytes */
#define ALIOT_BASIC_DEMO_MSG_MAX_CNT     5
#define ALIOT_BASIC_DEMO_SIMID           0    /*!< SIM ID */
#define ALIOT_BASIC_DEMO_PDPID           1    /*!< PDP context ID for network connection */
#define ALIOT_BASIC_DEMO_KEEP_ALIVE      60   /*!< Keep alive time in seconds */
#define ALIOT_BASIC_DEMO_DELIVERY_TIME   5    /*!< Retransmission interval in seconds */
#define ALIOT_BASIC_DEMO_DELIVERY_CNT    3    /*!< Retransmission count */
#define ALIOT_BASIC_DEMO_LEN_MAX         257

结构体定义

  • mqtt_aliot_demo_msg_t:作为本示例中消息队列的消息结构。

  • mqtt_aliot_demo_ctx_t:全局保存MQTT连接参数,提供给初始化和反初始化等操作使用。

typedef struct
{
    int   msg_id; /*!< Event ID /
    int   param1; /!< Data */
    void *argv;   /*!< Data */
} mqtt_aliot_demo_msg_t;

typedef struct
{
    qosa_uint8_t      client_idx; /*!< MQTT client handle /
    qosa_uint32_t     port;       /!< MQTT server port /
    int               msg_id;     /!< Packet identifier /
    qosa_msgq_t       msgq;       /!< Message queue */
    qcm_ssl_config_t *ssl_config; /*!< SSL configuration */
    char             *clientID;   /*!< MQTT client identifier */
    char             *username;   /*!< MQTT client username */
    char             *password;   /*!< MQTT client password */
} mqtt_aliot_demo_ctx_t;

unir_mqtt_aliot_demo_ctx_init

  • 功能描述:

初始化MQTT配置上下文,为结构体字段分配内存并填充MQTT连接选项。

  • 具体步骤:
    通过 qosa_malloc() 为全局上下文 g_mqtt_aliot_ctx 分配内存,并用 qosa_memset() 清零。
    调用 qosa_msgq_create() 创建消息队列,用于异步接收MQTT事件,队列深度为 ALIOT_BASIC_DEMO_MSG_MAX_CNT(5条)。
    分别为clientID、username、password字段各分配512字节缓冲区,并清零。
    初始化基础字段:msg_id 置为1(QoS > 0时报文标识符不得为0)、port 置为服务器端口号。
    mqtt_aliot_option 结构体填写MQTT协议版本、SIM卡ID、PDP上下文ID、保活时间、重传间隔、重传次数及会话清除标志等参数。
    若启用了MQTTS(ALIOT_BASIC_DEMO_MQTTS 为非零且编译了 CONFIG_QCM_VTLS_FUNC),则分配并配置 qcm_ssl_config_t 结构体,设置TLS版本、认证模式、传输协议、握手超时时间(30秒)及SNI开关,并将SSL配置绑定到MQTT配置中。

  • 示例代码:

static int unir_mqtt_aliot_demo_ctx_init(qcm_mqtt_config_t *mqtt_aliot_option)
{
    int ret = 0;
    if (mqtt_aliot_option == QOSA_NULL)
    {
        return -1;
    }
    if (g_mqtt_aliot_ctx == QOSA_NULL)
    {
        g_mqtt_aliot_ctx = qosa_malloc(sizeof(mqtt_aliot_demo_ctx_t));
        if (g_mqtt_aliot_ctx == QOSA_NULL)
        {
            return -1;
        }
    }
    qosa_memset(g_mqtt_aliot_ctx, 0, sizeof(mqtt_aliot_demo_ctx_t));

    if (g_mqtt_aliot_ctx->msgq == QOSA_NULL)
    {
        ret = qosa_msgq_create(&g_mqtt_aliot_ctx->msgq, sizeof(mqtt_aliot_demo_msg_t), ALIOT_BASIC_DEMO_MSG_MAX_CNT);
        if (ret != QOSA_OK)
        {
            return -1;
        }
    }
    if (g_mqtt_aliot_ctx->clientID == QOSA_NULL)
    {
        g_mqtt_aliot_ctx->clientID = qosa_malloc(QOSA_ARRAY_BYTE_512);
        if (g_mqtt_aliot_ctx->clientID == QOSA_NULL)
        {
            return -1;
        }
        qosa_memset(g_mqtt_aliot_ctx->clientID, 0, QOSA_ARRAY_BYTE_512);
    }
    if (g_mqtt_aliot_ctx->username == QOSA_NULL)
    {
        g_mqtt_aliot_ctx->username = qosa_malloc(QOSA_ARRAY_BYTE_512);
        if (g_mqtt_aliot_ctx->username == QOSA_NULL)
        {
            return -1;
        }
        qosa_memset(g_mqtt_aliot_ctx->username, 0, QOSA_ARRAY_BYTE_512);
    }
    if (g_mqtt_aliot_ctx->password == QOSA_NULL)
    {
        g_mqtt_aliot_ctx->password = qosa_malloc(QOSA_ARRAY_BYTE_512);
        if (g_mqtt_aliot_ctx->password == QOSA_NULL)
        {
            return -1;
        }
        qosa_memset(g_mqtt_aliot_ctx->password, 0, QOSA_ARRAY_BYTE_512);
    }
    g_mqtt_aliot_ctx->msg_id = 1;
    g_mqtt_aliot_ctx->port = ALIOT_BASIC_DEMO_SERVER_PORT;

    mqtt_aliot_option->version = QCM_MQTT_VERSION_V3_1_1;
    mqtt_aliot_option->sim_id = ALIOT_BASIC_DEMO_SIMID;
    mqtt_aliot_option->pdp_cid = ALIOT_BASIC_DEMO_PDPID;
    mqtt_aliot_option->kalive_time = ALIOT_BASIC_DEMO_KEEP_ALIVE;
    mqtt_aliot_option->delivery_time = ALIOT_BASIC_DEMO_DELIVERY_TIME;
    mqtt_aliot_option->delivery_cnt = ALIOT_BASIC_DEMO_DELIVERY_CNT;
    mqtt_aliot_option->clean_session = QOSA_TRUE;

#ifdef CONFIG_QCM_VTLS_FUNC
    if (ALIOT_BASIC_DEMO_MQTTS)
    {
        mqtt_aliot_option->ssl_enable = QOSA_TRUE;

        if (g_mqtt_aliot_ctx->ssl_config == QOSA_NULL)
        {
            g_mqtt_aliot_ctx->ssl_config = qosa_malloc(sizeof(qcm_ssl_config_t));
            if (g_mqtt_aliot_ctx->ssl_config == QOSA_NULL)
            {
                return -1;
            }
        }
        qosa_memset(g_mqtt_aliot_ctx->ssl_config, 0x00, sizeof(qcm_ssl_config_t));
        g_mqtt_aliot_ctx->ssl_config->ssl_version = QCM_SSL_VERSION_3;
        g_mqtt_aliot_ctx->ssl_config->auth_mode = QCM_SSL_VERIFY_NULL;
        g_mqtt_aliot_ctx->ssl_config->transport = QCM_SSL_TLS_PROTOCOL;
        g_mqtt_aliot_ctx->ssl_config->ssl_negotiate_timeout = 30;
        g_mqtt_aliot_ctx->ssl_config->ssl_log_debug = 4;
        g_mqtt_aliot_ctx->ssl_config->sni_enable = QOSA_TRUE;

        mqtt_aliot_option->ssl_config = g_mqtt_aliot_ctx->ssl_config;
    }
#endif /* CONFIG_QCM_VTLS_FUNC */
    return 0;
}

unir_mqtt_aliot_demo_generate_ali_login_info

  • 功能描述:

按照阿里云物联网平台的签名规范,使用HMAC-SHA1算法生成MQTT登录所需的clientID、username和password。

  • 具体步骤:
    调用 qosa_get_system_time_seconds() 获取当前系统时间戳,通过位运算保证其为正数,用作签名防重放参数。
    按照阿里云物联网平台规定的拼接格式,构造待签名内容字符串:clientId{CLIENTID}deviceName{DEVICE_NAME}productKey{PRODUCT_KEY}timestamp{timestamp}
    将clientID格式化为 {CLIENTID}|securemode=3,signmethod=hmacsha1,timestamp={ts}|
    将username格式化为 {DEVICE_NAME}&{PRODUCT_KEY}
    ALIOT_BASIC_DEMO_DEVICE_SECRET 为密钥,调用 qcm_hmac_sha1() 对待签名内容进行HMAC-SHA1运算,得到20字节摘要。
    将摘要格式化为40位十六进制字符串,作为MQTT连接的password字段。

  • 示例代码:

static void unir_mqtt_aliot_demo_generate_ali_login_info(void)
{
    qosa_time_t   tv_sec;
    qosa_int32_t  secure_mode = 3;
    char         *content = QOSA_NULL;
    unsigned char digset[20] = {0};

    tv_sec = qosa_get_system_time_seconds();
    tv_sec &= 0x7FFFFFFFFFFFFFFF;

    content = qosa_malloc(QOSA_ARRAY_BYTE_1024);
    if (content == QOSA_NULL)
    {
        return;
    }
    qosa_memset(content, 0, QOSA_ARRAY_BYTE_1024);
    char tv_sec_buf[65] = {0};
    qcm_utils_int64_to_text(tv_sec, tv_sec_buf, 10);
    qosa_snprintf(
        (char *)content,
        1024,
        "clientId%sdeviceName%sproductKey%stimestamp%s",
        ALIOT_BASIC_DEMO_CLIENTID,
        ALIOT_BASIC_DEMO_DEVICE_NAME,
        ALIOT_BASIC_DEMO_PRODUCT_KEY,
        tv_sec_buf
    );
    qosa_snprintf(g_mqtt_aliot_ctx->clientID, 512,
        "%s|securemode=%d,signmethod=hmacsha1,timestamp=%s|",
        ALIOT_BASIC_DEMO_CLIENTID, (int)secure_mode, tv_sec_buf);
    qosa_snprintf((char *)g_mqtt_aliot_ctx->username, 512,
        "%s&%s", ALIOT_BASIC_DEMO_DEVICE_NAME, ALIOT_BASIC_DEMO_PRODUCT_KEY);

    qcm_hmac_sha1(
        (unsigned char *)ALIOT_BASIC_DEMO_DEVICE_SECRET,
        qosa_strlen((char *)ALIOT_BASIC_DEMO_DEVICE_SECRET),
        (unsigned char *)content,
        qosa_strlen((char *)content),
        (unsigned char *)digset
    );
    qosa_snprintf(
        (char *)g_mqtt_aliot_ctx->password, 512,
        "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02X",
        digset[0],  digset[1],  digset[2],  digset[3],
        digset[4],  digset[5],  digset[6],  digset[7],
        digset[8],  digset[9],  digset[10], digset[11],
        digset[12], digset[13], digset[14], digset[15],
        digset[16], digset[17], digset[18], digset[19]
    );
}

unir_mqtt_aliot_demo_open

  • 功能描述:

完成MQTT客户端的完整初始化,并建立与阿里云物联网平台的TCP连接(对应MQTT协议中网络层连接建立阶段)。

  • 具体步骤:
    调用 qcm_mqtt_client_default_config() 获取MQTT客户端默认配置作为基础参数。
    调用 unir_mqtt_aliot_demo_ctx_init() 初始化上下文并将业务相关参数覆写至配置结构体。
    调用 qcm_mqtt_client_create() 创建MQTT客户端实例,获取 client_idx 句柄。
    调用 qcm_mqtt_client_init() 将MQTT配置和事件回调函数 unir_mqtt_aliot_demo_event_cb 绑定到该客户端实例。
    调用 qcm_mqtt_client_open() 发起TCP连接,目标地址为 ALIOT_BASIC_DEMO_SERVER_ADDR,端口为上下文中已配置的端口号。上述步骤任意一步失败均通过 goto exit 跳过后续操作并返回-1。

  • 示例代码:

static int unir_mqtt_aliot_demo_open(void)
{
    int               ret = 0;
    qcm_mqtt_config_t mqtt_aliot_option = {0};
    ret = qcm_mqtt_client_default_config(&mqtt_aliot_option);
    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("default config failed!");
        goto exit;
    }
    ret = unir_mqtt_aliot_demo_ctx_init(&mqtt_aliot_option);
    if (ret != 0)
    {
        QLOGE("init failed!");
        goto exit;
    }
    g_mqtt_aliot_ctx->client_idx = qcm_mqtt_client_create();
    QLOGI("init client_idx=%d", g_mqtt_aliot_ctx->client_idx);
    ret = qcm_mqtt_client_init(g_mqtt_aliot_ctx->client_idx, &mqtt_aliot_option, unir_mqtt_aliot_demo_event_cb, QOSA_NULL);
    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("init failed!");
        goto exit;
    }
    ret = qcm_mqtt_client_open(g_mqtt_aliot_ctx->client_idx, ALIOT_BASIC_DEMO_SERVER_ADDR, g_mqtt_aliot_ctx->port);
    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("open failed!");
        goto exit;
    }

    return 0;
exit:
    return -1;
}

unir_mqtt_aliot_demo_connect

  • 功能描述:

在TCP连接建立成功后,发送MQTT CONNECT报文,完成与阿里云物联网平台的应用层鉴权握手。

  • 具体步骤:
    调用 unir_mqtt_aliot_demo_generate_ali_login_info() 生成符合阿里云物联网平台签名规范的clientID、username和password。
    调用 qcm_mqtt_client_connect() 传入上述三组凭据及其长度,发起MQTT协议层的CONNECT请求。
    检查返回值,若失败则记录错误日志并返回-1。

  • 示例代码:

static int unir_mqtt_aliot_demo_connect(void)
{
    qcm_mqtt_eercode_e ret = 0;
    unir_mqtt_aliot_demo_generate_ali_login_info();
    ret = qcm_mqtt_client_connect(
        g_mqtt_aliot_ctx->client_idx,
        g_mqtt_aliot_ctx->clientID,
        qosa_strlen(g_mqtt_aliot_ctx->clientID),
        g_mqtt_aliot_ctx->username,
        qosa_strlen(g_mqtt_aliot_ctx->username),
        g_mqtt_aliot_ctx->password,
        qosa_strlen(g_mqtt_aliot_ctx->password)
    );

    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("connect fail=%x", ret);
        return -1;
    }
    return 0;
}

unir_mqtt_aliot_demo_subscribe

  • 功能描述:

向阿里云物联网平台订阅指定主题,以便接收云端下发的消息。

  • 具体步骤:
    调用 qcm_mqtt_client_get_state_info() 检查客户端当前状态,仅在 QCM_MQTT_STATE_MQTT_CONNECTED 状态下才执行订阅操作。
    调用 qcm_mqtt_malloc_data() 为订阅主题 ALIOT_BASIC_DEMO_TOPIC_SUB 分配内存,QoS级别设置为 QCM_MQTT_AT_LEAST_ONCE_DELIVERY(QoS 1)。
    自增报文标识符后,调用 qcm_mqtt_client_subscribe() 发起订阅请求。
    订阅操作完成后,调用 qcm_mqtt_free_data() 释放主题缓冲区内存。

  • 示例代码:

static void unir_mqtt_aliot_demo_subscribe(void)
{
    qcm_mqtt_client_info_t client_info = {0};
    qcm_mqtt_sub_topic_t   sub_topic[QCM_MQTT_MAX_TOPIC_NUM] = {0};
    int                    i, topic_cnt = 0;
    qcm_mqtt_eercode_e     ret = 0;
    qcm_mqtt_sub_config_t  sub_info = {0};

    if (qcm_mqtt_client_get_state_info(g_mqtt_aliot_ctx->client_idx, &client_info) != QCM_MQTT_RES_OK
        || client_info.client_state != QCM_MQTT_STATE_MQTT_CONNECTED)
    {
        QLOGE("state err");
        return;
    }

    topic_cnt = 0;
    qcm_mqtt_malloc_data(&sub_topic[topic_cnt].topic, qosa_strlen(ALIOT_BASIC_DEMO_TOPIC_SUB), ALIOT_BASIC_DEMO_TOPIC_SUB);
    sub_topic[topic_cnt].qos = QCM_MQTT_AT_LEAST_ONCE_DELIVERY;
    topic_cnt += 1;

    sub_info.msg_id = g_mqtt_aliot_ctx->msg_id++;
    sub_info.topics = sub_topic;
    sub_info.topic_cnt = topic_cnt;
    ret = qcm_mqtt_client_subscribe(g_mqtt_aliot_ctx->client_idx, &sub_info);

    QLOGD("topic_cnt=%d,err=%x", topic_cnt, ret);
    for (i = 0; i < topic_cnt; i++)
    {
        qcm_mqtt_free_data(&sub_topic[i].topic);
    }

    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("ret=%x", ret);
    }
}

unir_mqtt_aliot_demo_publish

  • 功能描述:

向阿里云物联网平台的指定发布主题上报消息内容。

  • 具体步骤:
    构造 qcm_mqtt_pub_config_t 发布配置结构,填写自增的报文标识符、QoS级别(QoS 1)、保留标志(不保留)、发布主题 ALIOT_BASIC_DEMO_TOPIC_PUB 及消息载荷 ALIOT_BASIC_DEMO_TEST_CONTENT
    调用 qcm_mqtt_client_publish() 发送消息,若返回值非 QCM_MQTT_RES_OK 则记录错误日志。

  • 示例代码:

static void unir_mqtt_aliot_demo_publish(void)
{
    qcm_mqtt_quality_of_service_e qos = QCM_MQTT_AT_LEAST_ONCE_DELIVERY;
    qosa_bool_t                   retain = QOSA_FALSE;
    qcm_mqtt_eercode_e            ret = 0;
    qcm_mqtt_pub_config_t         pub_info = {0};

    pub_info.msg_id = g_mqtt_aliot_ctx->msg_id++;
    pub_info.qos = qos;
    pub_info.retain = retain;
    pub_info.topic.data_ptr = ALIOT_BASIC_DEMO_TOPIC_PUB;
    pub_info.topic.data_len = qosa_strlen(ALIOT_BASIC_DEMO_TOPIC_PUB);
    pub_info.payload.data_ptr = (char *)ALIOT_BASIC_DEMO_TEST_CONTENT;
    pub_info.payload.data_len = qosa_strlen(ALIOT_BASIC_DEMO_TEST_CONTENT);

    ret = qcm_mqtt_client_publish(g_mqtt_aliot_ctx->client_idx, &pub_info);
    if (ret != QCM_MQTT_RES_OK)
    {
        QLOGE("publish err=%x", ret);
    }
}

unir_mqtt_aliot_demo_event_handle

  • 功能描述:

处理来自MQTT客户端的各类异步事件,根据事件类型驱动连接状态机的状态转移,是整个连接流程的核心调度函数。

  • 具体步骤:
    从消息结构的 argv 字段取得 qcm_mqtt_common_resp_t 响应结构指针,获取 client_id
    msg_id 分支处理各类事件:

    QCM_MQTT_CLIENT_OPEN_EVENT:TCP连接结果回调。连接成功时调用 unir_mqtt_aliot_demo_connect() 发起MQTT鉴权握手。

    QCM_MQTT_CLIENT_CONNECT_EVENT:MQTT CONNACK回调。连接成功时调用 unir_mqtt_aliot_demo_subscribe() 订阅目标主题。

    QCM_MQTT_CLIENT_PUBLISH_EVENT:消息发布结果回调,记录报文标识符和发送结果。

    QCM_MQTT_CLIENT_SUBSCRIBE_EVENT:订阅请求发送结果回调。

    QCM_MQTT_CLIENT_SUBACK_EVENT:SUBACK回调。订阅成功后释放QoS列表内存,随即调用 unir_mqtt_aliot_demo_publish() 上报测试消息。

    QCM_MQTT_CLIENT_UNSUBSCRIBE_EVENT:取消订阅请求发送结果回调。

    QCM_MQTT_CLIENT_UNSUBACK_EVENT:UNSUBACK回调。取消订阅成功后调用 unir_mqtt_aliot_demo_disconnect() 断开MQTT连接。

    QCM_MQTT_CLIENT_STATE_EVENT:连接状态变更事件,可从 qcm_mqtt_close_cause_t 中获取断连原因。

    QCM_MQTT_CLIENT_DISCONNECT_EVENT:DISCONNECT事件回调,记录协议层返回码。

    QCM_MQTT_CLIENT_CLOSE_EVENT:TCP连接关闭事件回调。
    处理完毕后,释放 resp_ptr->dataresp_ptr 占用的内存,避免内存泄漏。

  • 示例代码:

static int unir_mqtt_aliot_demo_event_handle(mqtt_aliot_demo_msg_t *msg)
{
    qosa_uint8_t client_idx = 0;
    int          ret = 0;

    if (msg == QOSA_NULL)
    {
        return -1;
    }
    qcm_mqtt_common_resp_t *resp_ptr = (qcm_mqtt_common_resp_t *)msg->argv;
    client_idx = resp_ptr->client_id;
    QLOGV("msg->msg_id=%d, client_idx=%d", msg->msg_id, client_idx);

    if (msg->msg_id == QCM_MQTT_CLIENT_OPEN_EVENT)
    {
        if (resp_ptr->result == QCM_MQTT_RES_OK)
        {
            ret = unir_mqtt_aliot_demo_connect();
            if (ret != 0)
            {
                QLOGE("connect err");
            }
        }
    }
    else if (msg->msg_id == QCM_MQTT_CLIENT_CONNECT_EVENT)
    {
        if (resp_ptr->result == QCM_MQTT_RES_OK)
        {
            unir_mqtt_aliot_demo_subscribe();
        }
    }
    else if (msg->msg_id == QCM_MQTT_CLIENT_SUBACK_EVENT)
    {
        qcm_mqtt_suback_resp_t *suback_ptr = (qcm_mqtt_suback_resp_t *)resp_ptr->data;
        if (resp_ptr->result == QCM_MQTT_RES_OK)
        {
            if (suback_ptr != QOSA_NULL)
            {
                QLOGI("qos_cnt:%d", suback_ptr->qos_cnt);
                qosa_free(suback_ptr->qoss);  //!!! need free
            }
            unir_mqtt_aliot_demo_publish();
        }
    }
    else if (msg->msg_id == QCM_MQTT_CLIENT_UNSUBACK_EVENT)
    {
        if (resp_ptr->result == QCM_MQTT_RES_OK)
        {
            unir_mqtt_aliot_demo_disconnect();
        }
    }
    else if (msg->msg_id == QCM_MQTT_CLIENT_STATE_EVENT)
    {
        qcm_mqtt_close_cause_t *close_cause_ptr = (qcm_mqtt_close_cause_t *)resp_ptr->data;
        if (close_cause_ptr != QOSA_NULL)
        {
            QLOGV("close cause = %d", close_cause_ptr->close_cause);
        }
    }
    else if (msg->msg_id == QCM_MQTT_CLIENT_DISCONNECT_EVENT)
    {
        QLOGE("state disconnect = %d", resp_ptr->pocotrol_code);
    }

    if (resp_ptr->data != QOSA_NULL)
    {
        qosa_free(resp_ptr->data);
    }
    qosa_free(resp_ptr);
    return ret;
}

unir_mqtt_aliot_demo_recv_new_message

  • 功能描述:

从MQTT客户端接收缓冲中读取云端下发的订阅消息,并根据主题执行相应的业务处理。

  • 具体步骤:
    从消息结构的 argv 字段取得 qcm_mqtt_common_resp_t 指针,进而获取 qcm_mqtt_new_msg_notify_t 通知结构中的 store_id(消息存储索引)。
    调用 qcm_mqtt_client_read_subcribe_message(),通过 store_id 读取完整的发布消息,包含主题和载荷。
    比较接收到的主题与预设的订阅主题 ALIOT_BASIC_DEMO_TOPIC_SUB,若匹配则调用 unir_mqtt_aliot_demo_unsubscribe() 取消该主题的订阅。
    调用 qcm_mqtt_free_data() 释放主题和载荷的内存,随后释放 resp_ptr->dataresp_ptr

  • 示例代码:

static void unir_mqtt_aliot_demo_recv_new_message(mqtt_aliot_demo_msg_t *msg)
{
    qosa_uint8_t               client_idx = 0;
    qosa_uint32_t              payload_len = 0;
    qcm_mqtt_recv_pub_t        recv_pub = {0};
    qcm_mqtt_new_msg_notify_t *new_msg_ptr = QOSA_NULL;
    qosa_uint8_t               store_id = 0;

    qcm_mqtt_common_resp_t *resp_ptr = (qcm_mqtt_common_resp_t *)msg->argv;
    client_idx = resp_ptr->client_id;

    new_msg_ptr = (qcm_mqtt_new_msg_notify_t *)resp_ptr->data;
    store_id = new_msg_ptr->store_id;
    QLOGD("client_idx=%d, new_message=%d", client_idx, store_id);

    if (qcm_mqtt_client_read_subcribe_message(client_idx, store_id, &recv_pub) == QCM_MQTT_RES_OK)
    {
        QLOGD("topic = %s, payload_len = %d", recv_pub.topic.data_ptr, payload_len);

        if (qosa_memcmp(ALIOT_BASIC_DEMO_TOPIC_SUB, recv_pub.topic.data_ptr,
                        qosa_strlen(ALIOT_BASIC_DEMO_TOPIC_SUB)) == 0)
        {
            unir_mqtt_aliot_demo_unsubscribe();
        }
        qcm_mqtt_free_data(&recv_pub.topic);
        qcm_mqtt_free_data(&recv_pub.payload);
    }

    if (resp_ptr->data != QOSA_NULL)
    {
        qosa_free(resp_ptr->data);
    }
    qosa_free(resp_ptr);
}

应用逻辑流程图

基于UniRTOS的MQTT客户端连接阿里云物联网平台的完整流程采用全异步消息驱动模式:任务在消息队列上永久阻塞等待,MQTT驱动层通过事件回调 unir_mqtt_aliot_demo_event_cb 将异步通知打包投递到队列,任务取出消息后分发至对应处理函数,驱动状态机按序推进,无需轮询。

image

程序运行结果

  1. 程序运行后,进入阿里云物联网平台后台设备页面,设备会显示上线。如图:

../../../_images/image_YkVMbyf33okkYSxTWLCckBHOnAf.webp
  1. 点击左侧菜单的“监控运维 -> 日志服务”,选择对应的产品,此时可以看到设备上线、订阅主题和发送消息的3条日志。如图:

../../../_images/image_ELAbbp2MooUIyKxj3MIcEEznnsg.webp
  1. 点击查看类型为“设备到云”消息的日志,日志内容应为我们源码中编写的消息内容,也就是源码开头定义的 ALIOT_BASIC_DEMO_TEST_CONTENT,默认内容即为“Hello Welcome to test ali mqtt!”。如图:

../../../_images/image_QIFObYOLNoCg5VxSt55ciPadnld.webp
  1. 回到设备页面,点击“Topic列表”,找到源码中订阅的主题,格式为“/k28gt*****N/device_name/user/get”,其中的“device_name”应替换成真实的设备名,点击发布消息,发布自定义内容。如图:

../../../_images/image_PboObsVCUoAHMDxKnXActEBCnIe.webp ../../../_images/image_Y9tibpNcFobta3xSuWUcA8GJnRg.webp
  1. 在EPAT工具中抓取日志搜索关键词“unir_mqtt_aliot”,可以看到设备收到了云端下发的消息。

../../../_images/image_RoQQbj4N4ocOjCxrIylcM6MTnab.webp
  1. 程序收到消息后会主动断开MQTT连接,释放系统资源。