Skip to content

概述

AWS IoT Core(亚马逊云物联网平台)是亚马逊云服务 AWS 中的物联网平台,设备基于 MQTT(物联网最主流的轻量消息协议)与平台收发消息,并通过 X.509 证书认证身份(证书 = 云平台发给设备的"数字身份证",配合 TLS 加密传输,相当于把消息装进防窃听的加密信封)。本教程通过官方 aws_iot_core 示例工程,把 Ai-WB2 开发板接入 AWS IoT Core:连接成功后循环向云端主题发布 Light ON/OFF 消息、订阅云端主题,示例还附带影子设备(Shadow,云端的设备"替身",随时保存设备最新状态)功能演示。

用大白话讲:AWS IoT 就像国外版的「微信服务器」,但登录方式不一样——国内平台用「账号密码」(三元组),AWS 用「三把钥匙」:设备证书(你的身份证)、私钥(只有你有的钥匙)、根 CA 证书(验明正身的"公章")。三把钥匙都嵌进程序里,开发板才能通过 AWS 的「门卫」(TLS 加密连接)登录平台发消息。本教程就是帮你在 AWS 控制台办出这三把钥匙,再把它们装进代码里。

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

🎯本页目标在 AWS IoT Core 创建事物(Thing)与证书,让 Ai-WB2 开发板通过 MQTT + TLS 接入平台,实现主题发布/订阅,并认识影子设备(Shadow)功能。
🧰前置条件① Ai-WB2 开发板一块(Type-C 数据线)② 2.4GHz 路由器(能访问公网)③ 一个 AWS 账号(注册需绑卡验证,可免费试用)④ 已按 [SDK 安装](../sdk/sdk_intro) 完成环境搭建,并完成 [连接 Wi-Fi](../wireless/wifi/wifi_connect)。
🔗相关章节另两个云平台见 [连接阿里云物联网平台](./ali_iot) 与 [连接腾讯云物联网平台](./qcloud);MQTT 基础见 [MQTT 通信](../wireless/wifi/mqtt)。

注册 AWS 账号,创建事物与证书

这一步在云端"办三把钥匙":创建事物(Thing,AWS 里把"设备"叫事物),生成并下载证书,再把钥匙装进代码(第③步)。

  1. 打开 AWS 官网,注册并登录账号(需绑定银行卡验证,新账号有免费试用额度)。
  2. 在控制台搜索 IoT Core,进入 AWS IoT Core 控制台(区域建议选 us-east-1us-east-2,区域 = 服务器所在位置,之后配置端点要用同一个区域)。
  3. 左侧菜单「管理 → 事物」,点击「创建事物」→ 选「创建单个事物」→ 输入事物名称(如 Ai-WB2-M1,记好它,后面配置要用)。
  4. 为事物生成证书:选「一键创建证书」(1-Click certificate),生成后立即下载三个文件(只生成一次,务必保存):
    • xxx.cert.pem——设备证书(身份证)
    • xxx.private.key——私钥(钥匙)
    • AmazonRootCA1.pem——根 CA 证书(公章)
  5. 创建策略(Policy,= 给证书开的"通行证",声明允许做什么):「安全 → 策略 → 创建策略」,添加 iot:Connectiot:Subscribeiot:Receiveiot:Publish 四条操作(Actions),资源(Resources)选 *(本教程测试够用),创建后「安全 → 证书 → 选择刚才的证书 → 附加策略」。
  6. 记下端点(Endpoint,= 服务器地址):「设置 → 设备数据端点」,形如 xxxxxxxx-ats.iot.us-east-2.amazonaws.com
  7. 打开控制台「MQTT 测试客户端」,订阅主题 $aws/things/<你的事物名>/shadow/update,等开发板连上来发消息(后面验证用)。
进入示例工程

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

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

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

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

文件 作用
aws_iot_core/main.c 主程序:Wi-Fi 连接 + 启动 AWS 控制任务
aws_iot_core/aws_control.c 主流程:初始化 → 连接 → 订阅 → 循环发布 Light ON/OFF
aws_iot_core/demo_publish.c 独立发布示例(仅发不收)
aws_iot_core/demo_subscribe.c 独立订阅示例(仅收不发)
aws_iot_core/demo_shadow.c 影子设备(Shadow)示例:把灯状态同步到云端"替身"
aws_iot_core/aws_test_cert.h 证书与端点配置在这里(三把钥匙 + 服务器地址 + 主题)

💡 官方在 applications/iot-solution/ 下还有证书版示例工程 aws_iot_cert(把证书做成文件放进文件系统读取),本教程用的 aws_iot_core 把证书直接编译进固件,更适合新手上手。

修改参数(换成你自己的 Wi-Fi、证书和端点)

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

#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"

打开 aws_iot_core/aws_test_cert.h,做三件事:

  1. 用第一步下载的根 CA 证书内容替换 TEST_ROOT_CA_FILENAME-----BEGIN CERTIFICATE----------END CERTIFICATE----- 之间的内容;
  2. 设备证书替换 TEST_CERTIFICATE_FILENAME,用私钥替换 TEST_PRIVATE_KEY_FILENAME(文件末尾 -----END RSA PRIVATE KEY----- 区域);
  3. 把端点换成你的(形如 xxxxxxxx-ats.iot.us-east-2.amazonaws.com):
#define TEST_MQTT_HOST "你的端点"
#define TEST_MQTT_PORT 8883

再把客户端 ID 与事物名换成你的事物名称,主题里的 AiThinker 也换成你的事物名(topic = 频道名,消息按频道收发):

#define TEST_MQTT_CLIENT_ID "Ai-WB2-M1"
#define TEST_MY_THING_NAME  "Ai-WB2-M1"

#define TEST_MYPUBTOPIC "$aws/things/AiThinker/shadow/update"
#define TEST_MYSUBTOPIC "$aws/things/AiThinker/shadow/update/accepted"

⚠️ 证书是长文本,替换时注意保留前后双引号和 \r\n 换行转义符,别把格式弄坏;建议用编辑器整体替换两个证书宏的内容。证书内容弄错最常见的表现就是连接时 TLS 握手失败

编写代码

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

📜 完整代码 — 位于本页「完整代码」章节,默认折叠,点击展开,与官方示例(applications/iot-solution/aws_iot_core/aws_iot_core/main.c)完全一致。连接与收发主流程在 aws_control.c,影子设备在 demo_shadow.c,其余文件见官方工程。

代码要点:

代码 作用
wifi_mgmr_sta_connect(if, ssid, pwd, ...) 让开发板以 STA 模式(当"客户端")连路由器,不联网后面全白搭
aws_iot_mqtt_init(&client, &params) 初始化客户端,把端点/端口/三把证书填进配置,填错后面全连不上
aws_iot_mqtt_connect(&client, &params) 用证书与 AWS 建立 TLS 加密连接(TLS = 给通信加密的信封,防窃听)
aws_iot_mqtt_subscribe(&client, topic, ...) 订阅主题(topic = 频道名),不订阅就收不到云端发来的消息
aws_iot_mqtt_publish(&client, topic, ...) 向主题发布消息,订阅了该频道的云端/设备都会收到
aws_iot_mqtt_yield(&client, 100) 循环处理收发与心跳保活,不调用收不到消息、还会被平台踢下线
aws_iot_shadow_update(&client, thing, ...) 把设备最新状态同步到云端影子设备(设备的"替身")
编译工程

在工程目录执行编译:

make -j8

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

编译成功后生成固件 build_out/aws_iot_core.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,再连接 AWS。打开串口监视器(串口调试助手软件,波特率选 921600,波特率 = 串口传数据的"语速",两边必须一致),应看到:

[APP] [EVT] GOT IP ...
AWS IoT SDK Version 3.0.1-
Connecting...
...
Connect ok!!!, start Subscribing Topic=[$aws/things/AiThinker/shadow/update/accepted]...

同时回到 AWS 控制台「MQTT 测试客户端」(订阅了 $aws/things/<你的事物名>/shadow/update),应能每 1 秒收到一条 Light ON / LIGHT OFF 交替的消息——说明发布链路打通。

出现 Connect ok!!! 即成功;如果只看到 GOT IP 而没出现 Connect ok,说明还没成功,对照文末「常见问题与踩坑提示」排查。

代码执行流程

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


本文 API 汇总

aws_iot_control(arg)

AWS 接入主流程:初始化客户端 → 连接 → 订阅 TEST_MYSUBTOPIC → 循环发布 Light ON/LIGHT OFF 消息(自研接口,源码在 aws_iot_core/aws_control.c,由 main.c 在 GOT IP 后以任务方式调用)。

参数

  • arg:任务参数,示例传 NULL

返回值:无(任务函数,退出前自动断开并释放客户端)

aws_iot_demo_publish(arg)

独立发布示例:只发布不订阅,循环向 TEST_MYPUBTOPIC 发 Light ON/OFF(自研接口,源码在 aws_iot_core/demo_publish.c)。

参数

  • arg:任务参数,传 NULL

返回值:无(任务函数)

aws_iot_demo_subscribe(arg)

独立订阅示例:只订阅不发布,收到消息后打印主题与内容(自研接口,源码在 aws_iot_core/demo_subscribe.c)。

参数

  • arg:任务参数,传 NULL

返回值:无(任务函数)

aws_iot_demo_shadow(arg)

影子设备示例:把 lightstatus 属性(ON/OFF)周期同步到云端影子(Shadow = 云端的设备"替身",存设备最新状态),并注册 delta 回调接收云端对影子的修改(自研接口,源码在 aws_iot_core/demo_shadow.c)。

参数

  • arg:任务参数,传 NULL

返回值:无(任务函数)

aws_iot_mqtt_init(&client, &mqttInitParams)

初始化 MQTT 客户端:配置服务器地址(pHostURL)、端口(port)、三把证书(pRootCALocation/pDeviceCertLocation/pDevicePrivateKeyLocation)、超时与断线回调等(AWS 官方 Device SDK 接口)。

参数

  • clientAWS_IoT_Client 结构体指针,存放客户端状态
  • mqttInitParamsIoT_Client_Init_Params 结构体指针,iotClientInitParamsDefault 为默认值,按需覆盖成员

返回值:成功返回 SUCCESS(0);失败返回错误码(IoT_Error_t 枚举,如 FAILURE

aws_iot_mqtt_connect(&client, &connectParams)

与 AWS IoT Core 建立 TLS 加密连接(TLS = 加密信封,防窃听),连接参数含保活间隔、客户端 ID、MQTT 版本等。

参数

  • clientaws_iot_mqtt_init 初始化后的客户端
  • connectParamsIoT_Client_Connect_Params 结构体指针,含 keepAliveIntervalInSecpClientIDMQTTVersionisCleanSession

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

aws_iot_mqtt_subscribe(&client, topicName, topicNameLen, qos, pApplicationHandler, pApplicationHandlerData)

订阅主题(topic = 频道名),该主题收到消息时回调 pApplicationHandler

参数

  • client:客户端结构体指针
  • topicName:主题字符串(示例为 TEST_MYSUBTOPIC
  • topicNameLen:主题长度
  • qos:QoS 等级,示例用 QOS1(至少一次)
  • pApplicationHandler:消息回调函数
  • pApplicationHandlerData:透传给回调的数据,无则传 NULL

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

aws_iot_mqtt_publish(&client, topicName, topicNameLen, &params)

向主题发布消息(示例发布 Light ON/OFF 文本消息)。

参数

  • client:客户端结构体指针
  • topicName:主题字符串(示例为 TEST_MYPUBTOPIC
  • topicNameLen:主题长度
  • paramsIoT_Publish_Message_Params 结构体指针,含 qosisRetainedpayload(消息内容)、payloadLen

返回值:成功返回 SUCCESS(0);失败返回错误码(发布 ACK 超时返回 MQTT_REQUEST_TIMEOUT_ERROR

aws_iot_mqtt_yield(&client, timeout_ms)

让 SDK 处理网络收发与心跳保活,必须在循环里反复调用,否则收不到消息还会被平台踢下线;断线后返回 NETWORK_ATTEMPTING_RECONNECT,此时应跳过业务逻辑等待重连。

参数

  • client:客户端结构体指针
  • timeout_ms:等待收包的超时毫秒数,示例用 100

返回值SUCCESSNETWORK_ATTEMPTING_RECONNECTNETWORK_RECONNECTEDIoT_Error_t

aws_iot_shadow_update(&mqttClient, thingName, jsonDocument, callback, contextData, timeout_sec, isPersistent)

把设备最新状态(JSON 报文)同步到云端影子设备(Shadow = 云端的"替身"),云端/App 读影子即可拿到设备最新状态。

参数

  • mqttClient:客户端结构体指针
  • thingName:事物名称(TEST_MY_THING_NAME
  • jsonDocument:状态 JSON 报文(由 aws_iot_shadow_init_json_document/aws_iot_shadow_add_reported/aws_iot_finalize_json_document 构造)
  • callback:更新结果回调(收到 SHADOW_ACK_ACCEPTED 表示云端接受)
  • contextData:透传数据,无则传 NULL
  • timeout_sec:超时秒数,示例 4
  • isPersistent:是否保持订阅,示例 true

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

📌 AWS 的 SDK 头文件(aws_iot_mqtt_client_interface.h 等)来自 AWS 官方 Device SDK for Embedded C v3.0.1,随 SDK 构建自动拉取;本工程把证书以宏字符串形式编译进固件,属于"演示用"做法,量产建议改用 aws_iot_cert 工程把证书放文件系统。


完整代码

以下为 aws_iot_core/main.c 完整源码,与官方示例(applications/iot-solution/aws_iot_core/aws_iot_core/main.c)完全一致(收发与影子逻辑在 aws_control.cdemo_shadow.c 等,其余文件见官方工程):

📜 点击展开 aws_iot_core/main.c 完整代码
c

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>  
#include <string.h>
#include <aos/yloop.h>
#include <aos/kernel.h>
#include <lwip/tcpip.h>
#include <wifi_mgmr_ext.h>
#include <hal_wifi.h>

#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"

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)
{
    switch (event->code)
    {
        case CODE_WIFI_ON_INIT_DONE:
        {
            printf("[APP] [EVT] INIT DONE %lld\r\n", aos_now_ms());
            wifi_mgmr_start_background(&conf);
        }
        break;
        case CODE_WIFI_ON_MGMR_DONE:
        {
            printf("[APP] [EVT] MGMR DONE %lld\r\n", aos_now_ms());
            wifi_sta_connect(ROUTER_SSID, ROUTER_PWD);
        }
        break;
        case CODE_WIFI_ON_DISCONNECT:
        {
            printf("[APP] [EVT] disconnect %lld\r\n", aos_now_ms());
        }
        break;
        case CODE_WIFI_ON_CONNECTING:
        {
            printf("[APP] [EVT] Connecting %lld\r\n", aos_now_ms());
        }
        break;
        case CODE_WIFI_CMD_RECONNECT:
        {
            printf("[APP] [EVT] Reconnect %lld\r\n", aos_now_ms());
        }
        break;
        case CODE_WIFI_ON_CONNECTED:
        {
            printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
        }
        break;
        case CODE_WIFI_ON_PRE_GOT_IP:
        {
            printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
        }
        break;
        case CODE_WIFI_ON_GOT_IP:
        {
            printf("[APP] [EVT] GOT IP %lld\r\n", aos_now_ms());
            printf("[SYS] Memory left is %d Bytes\r\n", xPortGetFreeHeapSize());
            void aws_iot_control(void *arg);
            xTaskCreate(aws_iot_control, (char*)"aws_iot_control", 4096, NULL, 10, NULL);            
        }
        break;
        case CODE_WIFI_ON_PROV_CONNECT:
        {
            printf("[APP] [EVT] [PROV] [CONNECT] %lld\r\n", aos_now_ms());
            wifi_sta_connect(ROUTER_SSID, ROUTER_PWD);
        }
        break;
        case CODE_WIFI_ON_PROV_DISCONNECT:
        {
            printf("[APP] [EVT] [PROV] [DISCONNECT] %lld\r\n", aos_now_ms());
        }
        break;
        default:
        {
            printf("[APP] [EVT] Unknown code %u, %lld\r\n", 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()
{
    xTaskCreate(proc_main_entry, (char*)"main_entry", 1024, NULL, 15, NULL);
    tcpip_init(NULL, NULL);
}

常见问题与踩坑提示

⚠️ 一直没出现 Connect ok!!!,日志里 TLS 握手失败 / certificate verify failed
原因:三把证书没替换干净或格式损坏(多/少 \r\n、引号错位)、端点填错、证书与设备不匹配,或证书已过期(AWS 设备证书过期后需重新生成)
解决:重新逐字替换 aws_test_cert.h 中的 TEST_ROOT_CA_FILENAME/TEST_CERTIFICATE_FILENAME/TEST_PRIVATE_KEY_FILENAME 三个宏,保留首尾引号与 \r\n;确认 TEST_MQTT_HOST 是你账号控制台「设置 → 设备数据端点」里的地址;证书过期到控制台重新创建并下载

⚠️ 连接被拒绝,日志报权限/策略错误
原因:证书没有附加策略(Policy),或策略里没允许 Connect/Subscribe/Publish/Receive 操作
解决:控制台「安全 → 证书」选中你的证书 → 「操作 → 附加策略」;确认策略包含 iot:Connectiot:Subscribeiot:Receiveiot:Publish 四条操作

⚠️ 连接成功但测试客户端收不到消息
原因:主题里的事物名不一致——TEST_MY_THING_NAME/TEST_MYPUBTOPIC/TEST_MYSUBTOPIC 中的 AiThinker 没换成你的事物名,或测试客户端订阅的主题与发布主题不同
解决:把 aws_test_cert.h 中主题里的 AiThinker 全部换成你的事物名;测试客户端订阅 $aws/things/<你的事物名>/shadow/update,与 TEST_MYPUBTOPIC 保持一致

⚠️ 一直打印 Connecting 不 GOT IP(连不上路由器)
原因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 口或数据线重试

运行自检

串口出现 Connect ok!!!,且 AWS 控制台「MQTT 测试客户端」订阅 $aws/things/<你的事物名>/shadow/update 后能持续收到 Light ON / LIGHT OFF 消息,即接入 AWS IoT 平台验证通过。

遇到问题?

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

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