Skip to content

概述

阿里云物联网平台(物联网平台 = 云端的设备管理后台,设备连上去之后,你在网页控制台上就能看到它的状态、给它下发指令)是阿里云提供的一站式设备接入与管理云服务,设备基于 MQTT(物联网最主流的轻量消息协议)与平台收发消息。本教程通过官方 ali_iot 示例工程,把 Ai-WB2 开发板接入阿里云物联网平台:连接成功后自动上报设备属性(上报 = 设备→云端发数据),示例还集成了 OTA(空中升级,不用数据线就能远程更新程序)和 NTP(网络时间同步)功能。

用大白话讲:阿里云物联网平台就像「微信服务器」——开发板是用户,用平台发的「账号密码」(三元组:ProductKey 产品密钥、DeviceName 设备名称、DeviceSecret 设备密钥)登录后,就能「发朋友圈」(上报属性,云端能看到你的状态)和「收私信」(平台下发指令)。本教程带你注册账号、创建产品与设备、拿到三元组,然后让开发板成功「登录」阿里云。

本教程基于安信可官方 SDKAi-Thinker-Open/Ai-Thinker-WB2,版本 release_bl_iot_sdk_1.6.40)的官方示例 applications/iot-solution/ali_iot 编写,代码可在本地 SDK 中直接找到。

🎯本页目标在阿里云物联网平台创建产品与设备,让 Ai-WB2 开发板通过 MQTT 接入平台并成功上报属性,同时认识 OTA 与 NTP 功能的代码结构。
🧰前置条件① Ai-WB2 开发板一块(Type-C 数据线)② 2.4GHz 路由器(能访问公网)③ 一个阿里云账号(需实名认证)④ 已按 [SDK 安装](../sdk/sdk_intro) 完成环境搭建,并完成 [连接 Wi-Fi](../wireless/wifi/wifi_connect)。
🔗相关章节MQTT 基础见 [MQTT 通信](../wireless/wifi/mqtt);另两个云平台见 [连接AWS IoT 平台](./aws_iot) 与 [连接腾讯云物联网平台](./qcloud)。

注册阿里云账号,创建产品与设备

这一步要在云端先"办账号":创建好产品和设备,拿到设备登录平台用的三元组(ProductKey/DeviceName/DeviceSecret)。

  1. 打开阿里云官网,注册并登录账号(新用户需完成实名认证)。
  2. 在控制台搜索「物联网平台」,进入物联网平台控制台(首次进入需开通服务,公共实例即可,无需购买)。
  3. 点击「创建产品」:产品名称随意(如 WB2_Light),所属品类选自定义品类,联网方式选 Wi-Fi,数据格式选 ICA 标准数据格式
  4. 创建成功后,在产品详情页可以看到 ProductKey(产品密钥)——这是产品的"账号"。
  5. 进入「设备管理 → 添加设备」,输入设备名称(如 wb2_test),创建成功后显示 DeviceName(设备名称)DeviceSecret(设备密钥)

💡 三元组 = ProductKey + DeviceName + DeviceSecret,是开发板登录云平台的"账号密码",下一步要填进代码里。DeviceSecret 只在设备创建成功时显示一次,务必立刻复制保存,丢了只能重新添加设备。

进入示例工程

打开终端,进入官方 ali_iot 示例工程目录:

cd ~/Ai-Thinker-WB2/applications/iot-solution/ali_iot

说明:cd 是「进入目录」的命令,进入官方示例工程;后面所有 make 命令都要在这个目录下执行。

📌 该工程由多个源文件组成,完整代码章节只展示 main.c,其余文件可在官方工程中找到,这里先认识一下:

文件 作用
main/main.c 主程序:Wi-Fi 连接 + 启动 MQTT,本教程主要看的文件
ali_cloud/ali_mqtt/ali_mqtt_init.c MQTT 连接核心:三元组在这里配置,还含发布/订阅示例
ali_cloud/ali_ota/ali_ota_init.c OTA 固件升级(固件 = 烧进开发板的程序),版本号在 ali_ota_init.h 配置
ali_cloud/ali_ntp/ali_ntp_init.c NTP 网络时间同步(从云端自动校准开发板的时钟)
ali_cloud/ali_csdk/ 阿里官方 C-SDK(aiot_mqtt_* 系列接口所在)
修改参数(换成你自己的 Wi-Fi 和三元组)

打开 main/main.c,修改开头的 Wi-Fi 账号密码(占位符 = 代码里先写好的示例值,你需要换成自己的真实值):

#define ROUTER_SSID "你的Wi-Fi名称"
#define ROUTER_PWD  "你的Wi-Fi密码"

打开 ali_cloud/ali_mqtt/ali_mqtt_init.c,把示例三元组换成你在控制台创建设备拿到的值:

char *product_key  = "你的ProductKey";
char *device_name  = "你的DeviceName";
char *device_secret = "你的DeviceSecret";

⚠️ 最容易踩的坑ali_mqtt_init.cpub_msg() 上报用的 topic(topic = 频道名,消息按频道收发)和订阅用的 topic 中,也写死了示例三元组(/sys/a1Rq1D1yQnu/bl602-test/...)。只改上面的三个变量、不改这两处 topic,云平台会因为频道名里是别人的账号而拒绝消息。要把 a1Rq1D1yQnu 换成你的 ProductKey、bl602-test 换成你的 DeviceName。

可选:OTA 固件升级需要版本号,打开 ali_cloud/ali_ota/ali_ota_init.h,确认 PRJ_VERSION "1.0.0" 是你想要的版本号即可。

编写代码

本教程使用官方示例工程,无需新写代码,main/main.c 完整代码已移至文末,见:

📜 完整代码 — 位于本页「完整代码」章节,默认折叠,点击展开,与官方示例(applications/iot-solution/ali_iot/main/main.c)完全一致。MQTT 连接的详细逻辑在 ali_cloud/ali_mqtt/ali_mqtt_init.c,其余文件见官方工程。

代码要点:

代码 作用
wifi_mgmr_sta_connect(if, ssid, pwd, ...) 让开发板以 STA 模式(当"客户端")连路由器,不联网后面全白搭
aos_register_event_filter(EV_WIFI, cb, NULL) 注册 Wi-Fi 事件回调(事件 = 系统的通知),Wi-Fi 有动静系统自动调用它
aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0) 主动发出"Wi-Fi 初始化"事件,没有它整个启动流程不会开始
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile) 把阿里 SDK 的底层依赖(内存/网络)接到本 SDK,不接 SDK 跑不起来
ali_mqtt_init() 创建 MQTT 客户端并连接阿里云,三元组在它所在文件(ali_mqtt_init.c)里配置
编译工程

在工程目录执行编译:

make -j8

说明:make 是「编译」命令,把代码变成开发板能运行的固件(烧进开发板的程序);-j8 表示用 8 个 CPU 核并行编译,更快。

编译成功后生成固件 build_out/main.bin

⚠️ 若提示 riscv64-unknown-elf-gcc: command not found,说明工具链权限未配置,先执行 cd toolchain/riscv/Linux && . chmod755.sh 再重新编译。

烧录固件

开发板保持 USB 连接,确认串口设备号后执行烧录:

make flash p=/dev/ttyUSB0 b=921600

说明:make flash 是「烧录」命令,把编译好的固件写进开发板芯片。p= 后面是串口设备号(Linux 下常为 /dev/ttyUSB0,Windows 下是 COM3 之类,以你电脑实际为准,可用 ls /dev/ttyUSB* 查看),b=921600 是烧录波特率(串口传数据的速度),保持默认即可。

⏳ 烧录过程中按提示长按开发板 EN 键进入下载模式,等待进度条完成即烧录成功。

运行验证

烧录完成后开发板自动重启,先连 Wi-Fi,再连接阿里云。打开串口监视器(串口调试助手软件,波特率选 921600,波特率 = 串口传数据的"语速",两边必须一致),应看到:

[APP] [EVT] GOT IP ...
Start linkkit mqtt
aiot_mqtt_connect successs
AIOT_MQTTEVT_CONNECT
sub data from server

同时打开阿里云物联网平台控制台 → 产品 → 设备管理,你的设备状态变为**「在线」**;进入「物模型数据」页面,能看到设备上报的属性记录(官方示例每按一次 start_update_data() 触发上报,属性示例为 Power=on)。

出现 aiot_mqtt_connect successsAIOT_MQTTEVT_CONNECT(“successs” 是官方示例原样的打印,多了一个 s),且控制台设备显示在线,即为成功;如果只看到 GOT IP 而没出现连接成功日志,说明还没成功,对照文末「常见问题与踩坑提示」排查。

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):


本文 API 汇总

ali_mqtt_init()

初始化阿里云 MQTT 客户端并建立与平台的连接(自研接口,源码在 ali_cloud/ali_mqtt/ali_mqtt_init.c,内部使用 aiot_mqtt_* 系列接口完成创建、配置、连接、订阅与线程创建)。

参数

  • 无(三元组在 ali_mqtt_init.c 顶部以全局变量配置)

返回值:成功返回 0;失败返回 -1

start_update_data()

触发一次属性上报:给上报信号量发信号,aiot_mqtt_send_thread 线程收到后调用 pub_msg() 向平台发布属性(自研接口,源码在 ali_cloud/ali_mqtt/ali_mqtt_init.c)。

参数

返回值:无

aiot_mqtt_stop()

断开 MQTT 连接并销毁客户端实例,释放资源(自研接口,源码在 ali_cloud/ali_mqtt/ali_mqtt_init.c)。

参数

返回值:成功返回 0;失败返回 -1

aiot_mqtt_init()

创建 1 个阿里云 MQTT 客户端实例并初始化默认参数(阿里官方 SDK 接口,头文件 ali_cloud/ali_csdk/core/aiot_mqtt_api.h)。

参数

返回值:成功返回客户端句柄(void *);失败返回 NULL

aiot_mqtt_setopt(handle, option, data)

配置 MQTT 客户端参数:服务器地址(HOST)、端口(PORT)、三元组(PRODUCT_KEY/DEVICE_NAME/DEVICE_SECRET)、安全凭据、收发回调等。

参数

  • handleaiot_mqtt_init 返回的客户端句柄
  • option:配置项枚举(AIOT_MQTTOPT_HOSTAIOT_MQTTOPT_PORTAIOT_MQTTOPT_PRODUCT_KEYAIOT_MQTTOPT_DEVICE_NAMEAIOT_MQTTOPT_DEVICE_SECRETAIOT_MQTTOPT_NETWORK_CREDAIOT_MQTTOPT_RECV_HANDLERAIOT_MQTTOPT_EVENT_HANDLER 等)
  • data:对应配置项的值(按选项类型传字符串指针或数值指针)

返回值:成功返回 STATE_SUCCESS(0);失败返回负值错误码

aiot_mqtt_connect(handle)

与阿里云物联网平台建立 MQTT 连接,连接失败时示例代码会每 5 秒自动重连(aiot_mqtt_reconn)。

参数

  • handle:客户端句柄

返回值:成功返回 STATE_SUCCESS(0);失败返回负值错误码(可用 -0x%04X 格式打印)

aiot_mqtt_pub(handle, topic, payload, payload_len, qos)

向指定主题(topic = 频道名)发布消息,订阅了该主题的云端/设备都会收到。

参数

  • handle:客户端句柄
  • topic:主题字符串,格式 /sys/${productKey}/${deviceName}/thing/event/property/post
  • payload:消息数据指针(示例为 JSON 格式属性报文)
  • payload_len:消息长度
  • qos:QoS 等级(0 最多一次 / 1 至少一次),示例传 0

返回值:成功返回 STATE_SUCCESS(0);失败返回负值错误码

aiot_mqtt_sub(handle, topic, handler, qos, userdata)

订阅主题,之后该主题收到消息时调用 handler 回调(或默认接收回调)。

参数

  • handle:客户端句柄
  • topic:主题字符串,如 /sys/${productKey}/${deviceName}/thing/event/property/post_reply
  • handler:该主题的消息回调,示例传 NULL(走默认回调 aiot_mqtt_default_recv_handler
  • qos:QoS 等级,示例传 1
  • userdata:透传给回调的用户数据,无则传 NULL

返回值:成功返回 STATE_SUCCESS(0);失败返回负值错误码

wifi_mgmr_sta_connect(wifi_interface, ssid, psk, pmk, mac, band, chan_id)

让开发板以 STA 模式(当"客户端")连接路由器(Wi-Fi 管理接口,头文件 components/network/wifi_manager/.../wifi_mgmr_ext.h)。

参数

  • wifi_interfacewifi_mgmr_sta_enable() 返回的 STA 接口句柄
  • ssid:Wi-Fi 名称
  • psk:Wi-Fi 密码
  • pmk / mac / band / chan_id:预共享密钥、MAC、频段、信道,示例均传 NULL/0

返回值:成功返回 0;失败返回负值错误码

📌 阿里云 SDK 的事件回调中不要做耗时操作(示例回调只打印);属性上报报文是 JSON 格式,字段要与控制台「物模型」中定义的功能一致,否则平台会拒绝。


完整代码

以下为 main/main.c 完整源码,与官方示例(applications/iot-solution/ali_iot/main/main.c)完全一致(MQTT 相关逻辑在 ali_cloud/ali_mqtt/ali_mqtt_init.c,其余文件见官方工程):

📜 点击展开 main/main.c 完整代码
c
/*
 * @Author: xuhongv@yeah.net xuhongv@yeah.net
 * @Date: 2022-10-03 15:02:19
 * @LastEditors: xuhongv@yeah.net xuhongv@yeah.net
 * @LastEditTime: 2022-10-08 14:55:16
 * @FilePath: \bl_iot_sdk_for_aithinker\applications\get-started\helloworld\helloworld\main.c
 * @Description: Hello world
 */
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <string.h>
#include "blog.h"
#include <aos/yloop.h>
#include <aos/kernel.h>
#include <lwip/tcpip.h>
#include <wifi_mgmr_ext.h>
#include <hal_wifi.h>

#include "aiot_state_api.h"
#include "aiot_sysdep_api.h"
#include "aiot_mqtt_api.h"
#include "aiot_ota_api.h"
#include "ali_mqtt_init.h"

/* 位于portfiles/aiot_port文件夹下的系统适配函数集合 */
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;

void ali_linkkit_main(void)
{
    TaskHandle_t xAliTaskHandle = NULL;
    /* start linkkit mqtt */
    printf("Start linkkit mqtt");
    /* 配置SDK的底层依赖 */
    aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
    ali_mqtt_init();
}

#define ROUTER_SSID "WIFI SSID"
#define ROUTER_PWD "WIFI PWS"

static wifi_conf_t conf =
    {
        .country_code = "CN",
};

static void wifi_sta_connect(char *ssid, char *password)
{
    wifi_interface_t wifi_interface;

    wifi_interface = wifi_mgmr_sta_enable();
    wifi_mgmr_sta_connect(wifi_interface, ssid, password, NULL, NULL, 0, 0);
}

static void event_cb_wifi_event(input_event_t *event, void *private_data)
{
    static char *ssid;
    static char *password;

    switch (event->code)
    {
    case CODE_WIFI_ON_INIT_DONE:
    {
        blog_info("[APP] [EVT] INIT DONE %lld", aos_now_ms());
        wifi_mgmr_start_background(&conf);
    }
    break;
    case CODE_WIFI_ON_MGMR_DONE:
    {
        blog_info("[APP] [EVT] MGMR DONE %lld", aos_now_ms());
        //_connect_wifi();

        wifi_sta_connect(ROUTER_SSID, ROUTER_PWD);
    }
    break;
    case CODE_WIFI_ON_SCAN_DONE:
    {
        blog_info("[APP] [EVT] SCAN Done %lld", aos_now_ms());
        // wifi_mgmr_cli_scanlist();
    }
    break;
    case CODE_WIFI_ON_DISCONNECT:
    {
        blog_info("[APP] [EVT] disconnect %lld", aos_now_ms());
    }
    break;
    case CODE_WIFI_ON_CONNECTING:
    {
        blog_info("[APP] [EVT] Connecting %lld", aos_now_ms());
    }
    break;
    case CODE_WIFI_CMD_RECONNECT:
    {
        blog_info("[APP] [EVT] Reconnect %lld", aos_now_ms());
    }
    break;
    case CODE_WIFI_ON_CONNECTED:
    {
        blog_info("[APP] [EVT] connected %lld", aos_now_ms());
    }
    break;
    case CODE_WIFI_ON_PRE_GOT_IP:
    {
        blog_info("[APP] [EVT] connected %lld", aos_now_ms());
    }
    break;
    case CODE_WIFI_ON_GOT_IP:
    {
        ali_linkkit_main();
        blog_info("[APP] [EVT] GOT IP %lld", aos_now_ms());
        blog_info("[SYS] Memory left is %d Bytes", xPortGetFreeHeapSize());
    }
    break;
    case CODE_WIFI_ON_PROV_SSID:
    {
        blog_info("[APP] [EVT] [PROV] [SSID] %lld: %s",
                  aos_now_ms(),
                  event->value ? (const char *)event->value : "UNKNOWN");
        if (ssid)
        {
            vPortFree(ssid);
            ssid = NULL;
        }
        ssid = (char *)event->value;
    }
    break;
    case CODE_WIFI_ON_PROV_BSSID:
    {
        blog_info("[APP] [EVT] [PROV] [BSSID] %lld: %s",
                  aos_now_ms(),
                  event->value ? (const char *)event->value : "UNKNOWN");
        if (event->value)
        {
            vPortFree((void *)event->value);
        }
    }
    break;
    case CODE_WIFI_ON_PROV_PASSWD:
    {
        blog_info("[APP] [EVT] [PROV] [PASSWD] %lld: %s", aos_now_ms(),
                  event->value ? (const char *)event->value : "UNKNOWN");
        if (password)
        {
            vPortFree(password);
            password = NULL;
        }
        password = (char *)event->value;
    }
    break;
    case CODE_WIFI_ON_PROV_CONNECT:
    {
        blog_info("[APP] [EVT] [PROV] [CONNECT] %lld", aos_now_ms());
        blog_info("connecting to %s:%s...", ssid, password);
        wifi_sta_connect(ssid, password);
    }
    break;
    case CODE_WIFI_ON_PROV_DISCONNECT:
    {
        blog_info("[APP] [EVT] [PROV] [DISCONNECT] %lld", aos_now_ms());
    }
    break;
    default:
    {
        blog_info("[APP] [EVT] Unknown code %u, %lld", event->code, aos_now_ms());
        /*nothing*/
    }
    }
}

static void proc_main_entry(void *pvParameters)
{
    aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL);
    hal_wifi_start_firmware_task();
    aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);
    vTaskDelete(NULL);
}

void main()
{
    puts("[OS] Starting TCP/IP Stack...");
    tcpip_init(NULL, NULL);
    puts("[OS] proc_main_entry task...");
    xTaskCreate(proc_main_entry, (char *)"main_entry", 1024, NULL, 15, NULL);
}

常见问题与踩坑提示

⚠️ 一直没出现 aiot_mqtt_connect successs / AIOT_MQTTEVT_CONNECT
原因:三元组配错(ProductKey/DeviceName/DeviceSecret 与云平台不一致)、产品没创建成功,或阿里云账号未实名/服务未开通
解决:逐一核对 ali_mqtt_init.c 里三个变量与控制台一致(注意区分大小写);确认控制台「产品」和「设备」都存在且已激活;确认物联网平台服务已开通

⚠️ 连接成功但控制台看不到上报的属性
原因ali_mqtt_init.cpub_msg() 的 topic 和订阅 topic 里写死了官方示例三元组(/sys/a1Rq1D1yQnu/bl602-test/...),上报进了别人的"频道"被平台拒绝
解决:把这两处 topic 字符串里的 a1Rq1D1yQnu 换成你的 ProductKey、bl602-test 换成你的 DeviceName;属性字段名要与控制台「物模型」定义一致

⚠️ 一直打印 Connecting 不 GOT IP(连不上路由器)
原因main/main.c 里 ROUTER_SSID/ROUTER_PWD 写错、路由器是 5GHz 频段、或信号过弱
解决:核对 Wi-Fi 账号密码;确认路由器开 2.4GHz;开发板靠近路由器;可先单独跑 连接 Wi-Fi 验证联网

⚠️ 串口找不到设备 / 打不开
原因:USB 转串口驱动未装、权限不足,或数据线只能充电不能传数据
解决:Linux 用 lsusb/dmesg 查看设备,权限不足执行 sudo usermod -aG dialout $USER 后重新登录,或 sudo chmod 666 /dev/ttyUSB0;Windows 装驱动后到设备管理器查 COM 口;换一根能传数据的线

⚠️ 烧录一直等待 / 失败
原因:未进入下载模式、波特率不对、或串口号填错
解决:烧录时按提示长按 EN 键进入下载模式;确认 p=/dev/ttyUSB0 换成你实际的串口;换 USB 口或数据线重试

⚠️ 编译报 command not found
原因:工具链没有执行权限
解决:执行 cd toolchain/riscv/Linux && . chmod755.sh 后重新 make -j8

运行自检

串口出现 aiot_mqtt_connect successsAIOT_MQTTEVT_CONNECT,且阿里云控制台设备状态为「在线」、物模型数据有属性上报记录,即接入阿里云物联网平台验证通过。

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23