概述
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 控制台办出这三把钥匙,再把它们装进代码里。
本教程基于安信可官方 SDK(Ai-Thinker-Open/Ai-Thinker-WB2,版本
release_bl_iot_sdk_1.6.40)的官方示例applications/iot-solution/aws_iot_core编写,代码可在本地 SDK 中直接找到。
这一步在云端"办三把钥匙":创建事物(Thing,AWS 里把"设备"叫事物),生成并下载证书,再把钥匙装进代码(第③步)。
- 打开 AWS 官网,注册并登录账号(需绑定银行卡验证,新账号有免费试用额度)。
- 在控制台搜索 IoT Core,进入 AWS IoT Core 控制台(区域建议选
us-east-1或us-east-2,区域 = 服务器所在位置,之后配置端点要用同一个区域)。 - 左侧菜单「管理 → 事物」,点击「创建事物」→ 选「创建单个事物」→ 输入事物名称(如
Ai-WB2-M1,记好它,后面配置要用)。 - 为事物生成证书:选「一键创建证书」(1-Click certificate),生成后立即下载三个文件(只生成一次,务必保存):
xxx.cert.pem——设备证书(身份证)xxx.private.key——私钥(钥匙)AmazonRootCA1.pem——根 CA 证书(公章)
- 创建策略(Policy,= 给证书开的"通行证",声明允许做什么):「安全 → 策略 → 创建策略」,添加
iot:Connect、iot:Subscribe、iot:Receive、iot:Publish四条操作(Actions),资源(Resources)选*(本教程测试够用),创建后「安全 → 证书 → 选择刚才的证书 → 附加策略」。 - 记下端点(Endpoint,= 服务器地址):「设置 → 设备数据端点」,形如
xxxxxxxx-ats.iot.us-east-2.amazonaws.com。 - 打开控制台「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把证书直接编译进固件,更适合新手上手。
打开 aws_iot_core/main.c,修改开头的 Wi-Fi 账号密码(占位符 = 代码里先写好的示例值,你需要换成自己的真实值):
#define ROUTER_SSID "your ssid"
#define ROUTER_PWD "your password"
打开 aws_iot_core/aws_test_cert.h,做三件事:
- 用第一步下载的根 CA 证书内容替换
TEST_ROOT_CA_FILENAME中-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----之间的内容; - 用设备证书替换
TEST_CERTIFICATE_FILENAME,用私钥替换TEST_PRIVATE_KEY_FILENAME(文件末尾-----END RSA PRIVATE KEY-----区域); - 把端点换成你的(形如
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, ¶ms) |
初始化客户端,把端点/端口/三把证书填进配置,填错后面全连不上 |
aws_iot_mqtt_connect(&client, ¶ms) |
用证书与 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 接口)。
参数:
client:AWS_IoT_Client结构体指针,存放客户端状态mqttInitParams:IoT_Client_Init_Params结构体指针,iotClientInitParamsDefault为默认值,按需覆盖成员
返回值:成功返回 SUCCESS(0);失败返回错误码(IoT_Error_t 枚举,如 FAILURE)
aws_iot_mqtt_connect(&client, &connectParams)
与 AWS IoT Core 建立 TLS 加密连接(TLS = 加密信封,防窃听),连接参数含保活间隔、客户端 ID、MQTT 版本等。
参数:
client:aws_iot_mqtt_init初始化后的客户端connectParams:IoT_Client_Connect_Params结构体指针,含keepAliveIntervalInSec、pClientID、MQTTVersion、isCleanSession等
返回值:成功返回 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, ¶ms)
向主题发布消息(示例发布 Light ON/OFF 文本消息)。
参数:
client:客户端结构体指针topicName:主题字符串(示例为TEST_MYPUBTOPIC)topicNameLen:主题长度params:IoT_Publish_Message_Params结构体指针,含qos、isRetained、payload(消息内容)、payloadLen
返回值:成功返回 SUCCESS(0);失败返回错误码(发布 ACK 超时返回 MQTT_REQUEST_TIMEOUT_ERROR)
aws_iot_mqtt_yield(&client, timeout_ms)
让 SDK 处理网络收发与心跳保活,必须在循环里反复调用,否则收不到消息还会被平台踢下线;断线后返回 NETWORK_ATTEMPTING_RECONNECT,此时应跳过业务逻辑等待重连。
参数:
client:客户端结构体指针timeout_ms:等待收包的超时毫秒数,示例用100
返回值:SUCCESS、NETWORK_ATTEMPTING_RECONNECT、NETWORK_RECONNECTED 等 IoT_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:透传数据,无则传NULLtimeout_sec:超时秒数,示例4isPersistent:是否保持订阅,示例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.c、demo_shadow.c 等,其余文件见官方工程):
📜 点击展开 aws_iot_core/main.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:Connect、iot:Subscribe、iot:Receive、iot: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

