涂鸦智能的TuyaOpen框架入门指南:智能插座实战
目录
引言
TuyaOpen框架简介
程序下载和编译
安装依赖
克隆仓库
设置与编译
step1. 设置环境变量
step2. 选择待编译项目
step3. 编译
在Ubuntu上测试示例程序Switch Demo
创建产品并获取产品的 PID
确认 TuyaOpen 授权码
运行程序
程序简单分析
apps/tuya_cloud/switch_demo/src/tuya_main.c
核心功能模块
1. 初始化与配置
2. 事件处理
3. 数据点(DP)处理
4. OTA 升级支持
工作流程
关键特性
代码扩展建议
src/tuya_cloud_service/cloud/mqtt_service.c
功能模块概述
1. MQTT 连接管理
2. 消息订阅与处理
3. 消息发布与协议处理
4. 安全与认证
核心数据结构与逻辑
1. 关键结构体
2. 流程示例
关键特性
总结
结语
引言
往年上过我的《智能物联网应用设计》课程的同学,都是参加大学生物联网应用设计竞赛的海思赛题。今年大学生物联网应用设计竞赛没有了华为赛道,我需要研究一下其他赛道,看看学生参加哪个赛道比较合适。我最新关注的就是涂鸦智能的赛道。以前参加过T2-U模块的测试:【涂鸦T2-U开发板试用体验】命令行编译环境的构建及烧写故障排除 - 涂鸦开发者 - 电子技术论坛 - 广受欢迎的专业电子论坛!,所以对这个平台还是有点熟悉的。以前涂鸦有几个类似的接入框架:tuya-connect-kit-for-mqtt-embedded-c、tuya/tuya-iot-core-sdk: Tuya IoT Core SDK,现在主推的应该是TuyaOpen。
TuyaOpen框架简介
来自厂商的介绍:
TuyaOpen 是一款跨芯片平台、操作系统的 AI+IoT 开发框架。它基于通用南向接口设计,支持 Bluetooth、Wi-Fi、Ethernet 等通信协议,提供了物联网开发的核心功能,包括配网,激活,控制,升级等;它具备强大的安全合规能力,包括设备认证、数据加密、通信加密等,满足全球各个国家和地区的数据合规需求。
基于 TuyaOpen 开发的 AI+IoT 产品,如果使用 tuya_cloud_service 组件的功能,就可以使用涂鸦APP、云服务提供的强大生态能力,并与 Power By Tuya 设备互联互通。
我个人的看法是这个框架比直接使用MQTT协议接入涂鸦平台更简单一些,涂鸦智能厂商提供了一些基础服务。不过如果是已有的基于MQTT的产品,也可以考虑直接通过MQTT协议接入。有关涂鸦的MQTT协议不再本文讨论范围,可以参考:Tuya MQTT 标准协议-涂鸦开发者平台-涂鸦开发者。TuyaOpen的底层也是基于这个协议的,如果想深入了解TuyaOpen的原理,看看这个文档也很有必要。
程序下载和编译
TuyaOpen有一个国内的镜像:TuyaOpen: Tuya open source AI+IoT development framework for device for T2, T3, T5AI, esp32, esp32c3, ln882h, bk7231n
其中的说明文档还是比较详细的。
安装依赖
我使用的华为云的开发者云电脑的Ubuntu系统,需要安装以下依赖
$ sudo apt-get install lcov cmake-curses-gui build-essential ninja-build wget git python3 python3-pip python3-venv libc6-i386 libsystemd-dev
克隆仓库
git clone https://gitee.com/tuya-open/TuyaOpen.git
TuyeOpen 仓库中包含多个子模块,涂鸦的编译工具tos会在编译前检查并自动下载子模块,也可以使用 git submodule update --init
命令手工下载。
设置与编译
step1. 设置环境变量
$ cd TuyaOpen
$ export PATH=$PATH:$PWD
或将 TuyaOpen 路径添加到系统环境变量中。
TuyaOpen 通过 tos 命令进行编译、调试等操作,tos 命令会根据环境变量中设置的路径查找 TuyaOpen 仓库,并执行对应操作。tos 命令的详细使用方法,请参考 tos 命令。
step2. 选择待编译项目
先编译一下程序实例 example,可使用命令tos set_example
,根据平台完成选择,目录 examples
会修改为对应平台的示例。
developer@developer:~/TuyaOpen$ tos set_example
Now used: Ubuntu
========================
Platforms1. T22. T33. Ubuntu4. T5AI5. ESP326. LN882H7. BK7231X
------------------------
Please select:
选择待编译 app,如 apps/tuya_cloud/switch_demo , 并切换至对应目录。
使用 tos config_choice
命令选择编译目标平台或目标板。
developer@developer:~/TuyaOpen/apps/tuya_cloud/switch_demo$ tos config_choice
[/home/developer/TuyaOpen/apps/tuya_cloud/switch_demo/config] is empty.
Using boards default config file.
========================
Configs1. BK7231X.config2. ESP32-C3.config3. ESP32.config4. ESP32-S3.config5. EWT103-W15.config6. LN882H.config7. T2.config8. T3.config9. T5AI.config10. Ubuntu.config
------------------------
Please select:
没有开发板,所以先选择Ubuntu作为测试环境,这里我选择10。此处的选项根据版本的不同可能有所不同,我的版本是10个选项,官方文档可能比较早,是9个选项。
step3. 编译
选择当前编译的 examples 或 apps 对应工程,运行如下命令编译:
$ cd apps/tuya_cloud/switch_demo
$ tos build
编译完成后目标文件位于当前编译项目 .build/<project>/bin
目录下,如 apps/tuya_cloud/switch_demo/.build/bin
目录。 编译后的目标文件包括:
- switch_demo_QIO_1.0.0.bin:包括 boot 在内的完整固件,用于烧录。
- switch_demo_UA_1.0.0.bin:未包括 boot 的应用固件,使用该文件需根据不同的 platform/chip 烧录该 bin 至对应的地址,否则可能无法正常运行。
- switch_demo_UG_1.0.0.bin:用于 OTA 升级的 bin 文件,无法直接烧录后运行。
项目名称默认为目录名称,项目版本默认为 1.0.0
,可通过 tos menuconfig
配置中修改。
对于Ubuntu相同,可执行文件是switch_demo_1.0.0 。
step4. menuconfig 配置
如需要修改项目的配置,选择需配置的 examples 或 apps 对应工程,在对应工程目录下运行如下命令进行菜单化配置:
$ cd apps/tuya_cloud/switch_demo
$ tos menuconfig
配置当前工程,配置完成后保存退出,编译工程。
在Ubuntu上测试示例程序Switch Demo
涂鸦云应用是涂鸦 AI+IoT 平台提供的一种应用,通过涂鸦云应用,开发者可以快速实现设备远程控制、设备管理等功能。
switch_demo
演示一个简单的,跨平台、跨系统、支持多种连接的开关示例,通过涂鸦 APP、涂鸦云服务,可以对这个开关进行远程控制。
创建产品并获取产品的 PID
参考文档 https://developer.tuya.com/cn/docs/iot-device-dev/application-creation?id=Kbxw7ket3aujc 在 https://iot.tuya.com 下创建产品,并获取到创建产品的 PID 。
其中的产品类型选择“智能插座”。
产品方案选择“自定义”
然后替换 apps/tuya_cloud/switch_demo/src/tuya_config.h 文件中 TUYA_PRODUCT_KEY
宏分别对应 pid。
确认 TuyaOpen 授权码
Tuyaopen Framework 包括:
- C 版 TuyaOpen:https://github.com/tuya/TuyaOpen
- Arduino 版 TuyaOpen:https://github.com/tuya/arduino-TuyaOpen
- Luanode 版 TuyaOpen:https://github.com/tuya/luanode-TuyaOpen
均采用 TuyaOpen 专用授权码,使用其他授权码无法正常连接涂鸦云。
申请免费授权码可以参考:apps/tuya_cloud · tuya-open/TuyaOpen - 码云 - 开源中国。我是网上申请的,第二天一早就收到了回复,比较快。
收到授权码之后,在然后替换 apps/tuya_cloud/switch_demo/src/tuya_config.h 文件中添加授权码:
// clang-format off
#define TUYA_PRODUCT_KEY "qhivvyqawogv04e4" // Please change your product key
#define TUYA_OPENSDK_UUID "uuidxxxxxxxxxxxxxxxx" // Please change the correct uuid
#define TUYA_OPENSDK_AUTHKEY "keyxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // Please change the correct authkey
运行程序
运行switch_demo_1.0.0之后,程序会显示一个二维码,使用涂鸦官方的智能生活App扫描这个二维码就可以添加一个“智能插座测试” 的产品。
然后就可以使用App对智能插座这个App进行测试。
插座的控制比较简单,只有开启和关闭两种操作。
下面是程序的log,其中可以看到程序收到MQTT的通知并解析其数据的过程。这里的MQTT协议定义和前面提到的涂鸦MQTT协议定义是不同的。
05-29 21:52:05 ty D][tuya_main.c:127] devid.6c0045e433be620eb0iyqq
[05-29 21:52:05 ty D][tuya_main.c:133] idx:0 dpid:1 type:0 ts:1748526725
[05-29 21:52:05 ty D][tuya_main.c:136] bool value:1
[05-29 21:52:05 ty D][tuya_iot_dp.c:239] dp report: devid 6c0045e433be620eb0iyqq, dps 0x19675258, dpscnt 1, flags 0
[05-29 21:52:05 ty D][dp_schema.c:524] dp<1> check. need_update:1 pv_stat:1 trig_t:0 type:0 force_send:0 prop_tp:0
[05-29 21:52:05 ty D][dp_schema.c:531] dp<1> bool: 0, new: 1
[05-29 21:52:05 ty D][dp_schema.c:938] dp rept out: {"1":true}
[05-29 21:52:05 ty D][tuya_iot_dp.c:307] mqtt channel report
[05-29 21:52:05 ty D][mqtt_client_wrapper.c:72] MQTT_PACKET_TYPE_PUBACK id:5
[05-29 21:52:05 ty D][mqtt_service.c:338] PUBACK ID:5
[05-29 21:52:07 ty D][mqtt_service.c:323] recv message TopicName:smart/device/in/6c0045e433be620eb0iyqq, payload len:96
[05-29 21:52:07 ty D][mqtt_service.c:231] Data JSON:{"data":{"dps":{"1":false}},"protocol":5,"t":1748526728}
[05-29 21:52:07 ty W][tuya_iot_dp.c:182] devid is null
[05-29 21:52:07 ty D][tuya_main.c:89] Tuya Event ID:8(TUYA_EVENT_DP_RECEIVE_OBJ)
[05-29 21:52:07 ty I][tuya_main.c:90] Device Free heap 481080
[05-29 21:52:07 ty D][tuya_main.c:125] SOC Rev DP Cmd t1:1 t2:0 CNT:1
[05-29 21:52:07 ty D][tuya_main.c:127] devid.6c0045e433be620eb0iyqq
[05-29 21:52:07 ty D][tuya_main.c:133] idx:0 dpid:1 type:0 ts:1748526727
[05-29 21:52:07 ty D][tuya_main.c:136] bool value:0
[05-29 21:52:07 ty D][tuya_iot_dp.c:239] dp report: devid 6c0045e433be620eb0iyqq, dps 0x19675258, dpscnt 1, flags 0
[05-29 21:52:07 ty D][dp_schema.c:524] dp<1> check. need_update:1 pv_stat:1 trig_t:0 type:0 force_send:0 prop_tp:0
[05-29 21:52:07 ty D][dp_schema.c:531] dp<1> bool: 1, new: 0
[05-29 21:52:07 ty D][dp_schema.c:938] dp rept out: {"1":false}
[05-29 21:52:07 ty D][tuya_iot_dp.c:307] mqtt channel report
[05-29 21:52:07 ty D][mqtt_client_wrapper.c:72] MQTT_PACKET_TYPE_PUBACK id:6
[05-29 21:52:07 ty D][mqtt_service.c:338] PUBACK ID:6
[05-29 21:53:22 ty D][mqtt_service.c:323] recv message TopicName:smart/device/in/6c0045e433be620eb0iyqq, payload len:98
[05-29 21:53:22 ty D][mqtt_service.c:231] Data JSON:{"data":{"reqType":"sigQry"},"protocol":22,"t":1748526803}
[05-29 21:53:39 ty D][mqtt_service.c:323] recv message TopicName:smart/device/in/6c0045e433be620eb0iyqq, payload len:95
[05-29 21:53:39 ty D][mqtt_service.c:231] Data JSON:{"data":{"dps":{"1":true}},"protocol":5,"t":1748526819}
[05-29 21:53:39 ty W][tuya_iot_dp.c:182] devid is null
[05-29 21:53:39 ty D][tuya_main.c:89] Tuya Event ID:8(TUYA_EVENT_DP_RECEIVE_OBJ)
[05-29 21:53:39 ty I][tuya_main.c:90] Device Free heap 481080
[05-29 21:53:39 ty D][tuya_main.c:125] SOC Rev DP Cmd t1:1 t2:0 CNT:1
[05-29 21:53:39 ty D][tuya_main.c:127] devid.6c0045e433be620eb0iyqq
[05-29 21:53:39 ty D][tuya_main.c:133] idx:0 dpid:1 type:0 ts:1748526819
[05-29 21:53:39 ty D][tuya_main.c:136] bool value:1
[05-29 21:53:39 ty D][tuya_iot_dp.c:239] dp report: devid 6c0045e433be620eb0iyqq, dps 0x19675258, dpscnt 1, flags 0
[05-29 21:53:39 ty D][dp_schema.c:524] dp<1> check. need_update:1 pv_stat:1 trig_t:0 type:0 force_send:0 prop_tp:0
[05-29 21:53:39 ty D][dp_schema.c:531] dp<1> bool: 0, new: 1
[05-29 21:53:39 ty D][dp_schema.c:938] dp rept out: {"1":true}
[05-29 21:53:39 ty D][tuya_iot_dp.c:307] mqtt channel report
[05-29 21:53:39 ty D][mqtt_client_wrapper.c:72] MQTT_PACKET_TYPE_PUBACK id:7
[05-29 21:53:39 ty D][mqtt_service.c:338] PUBACK ID:7
程序简单分析
apps/tuya_cloud/switch_demo/src/tuya_main.c
这个程序是基于涂鸦 IoT 开发框架的简单开关设备演示代码,展示了如何使用涂鸦 SDK 开发智能开关产品。程序实现了设备初始化、网络连接、配网二维码生成、数据点处理和 OTA 升级等功能,支持通过涂鸦 APP 或命令行控制开关状态。
核心功能模块
1. 初始化与配置
void user_main() {// 初始化系统组件(日志、KV存储、定时器等)tal_log_init(...);tal_kv_init(...);tal_sw_timer_init();// 读取或设置设备授权信息(UUID和AuthKey)if (OPRT_OK != tuya_authorize_read(&license)) {license.uuid = TUYA_OPENSDK_UUID;license.authkey = TUYA_OPENSDK_AUTHKEY;}// 初始化涂鸦 IoT 客户端tuya_iot_init(&client, &{.software_ver = PROJECT_VERSION,.productkey = TUYA_PRODUCT_KEY,.uuid = license.uuid,.authkey = license.authkey,.event_handler = user_event_handler_on, // 注册事件处理回调.network_check = user_network_check // 注册网络检查回调});// 初始化网络(WiFi或有线)netmgr_init(type);netmgr_conn_set(...);// 启动涂鸦 IoT 任务tuya_iot_start(&client);
}
2. 事件处理
void user_event_handler_on(tuya_iot_client_t *client, tuya_event_msg_t *event) {switch (event->id) {case TUYA_EVENT_BIND_START: // 设备开始配网PR_INFO("Device Bind Start!");break;case TUYA_EVENT_DIRECT_MQTT_CONNECTED: // 直连MQTT连接成功// 生成配网二维码(URL包含产品信息和UUID)example_qrcode_string(...);break;case TUYA_EVENT_MQTT_CONNECTED: // MQTT连接成功(设备上线)PR_INFO("Device MQTT Connected!");break;case TUYA_EVENT_DP_RECEIVE_OBJ: // 接收数据点(DP)指令// 处理开关控制指令(布尔型DP)for (index = 0; index < dpobj->dpscnt; index++) {if (dp->type == PROP_BOOL) {PR_DEBUG("bool value:%d", dp->value.dp_bool);}}// 上报DP响应tuya_iot_dp_obj_report(client, ...);break;case TUYA_EVENT_UPGRADE_NOTIFY: // 接收OTA升级通知user_upgrade_notify_on(client, event->value.asJSON);break;}
}
3. 数据点(DP)处理
- 接收指令:通过
TUYA_EVENT_DP_RECEIVE_OBJ
事件处理开关控制指令。 - 上报状态:使用
tuya_iot_dp_obj_report()
或tuya_iot_dp_raw_report()
上报开关状态或原始数据。
4. OTA 升级支持
void user_upgrade_notify_on(tuya_iot_client_t *client, cJSON *upgrade) {// 打印升级信息(版本、大小、URL等)PR_INFO("OTA Channel: %d", cJSON_GetObjectItem(upgrade, "type")->valueint);PR_INFO("Version: %s", cJSON_GetObjectItem(upgrade, "version")->valuestring);// ...
}
工作流程
-
设备初始化:
- 初始化系统组件(日志、存储、定时器等)。
- 读取或设置设备授权信息(UUID/AuthKey)。
- 初始化涂鸦 IoT 客户端,注册事件处理函数。
-
网络连接与配网:
- 初始化网络(WiFi 或有线)。
- 连接成功后生成配网二维码(URL 格式:
https://smartapp.tuya.com/s/p?p={产品ID}&uuid={设备UUID}
)。 - 用户通过涂鸦 APP 扫描二维码完成配网。
-
数据交互:
- 通过 MQTT 协议与涂鸦云平台通信。
- 接收云平台下发的数据点指令(如开关控制)。
- 上报设备状态(如开关状态、电量等)。
-
事件处理:
- 处理网络连接状态变化、OTA 升级通知、时间同步等事件。
关键特性
-
多网络支持:
- 支持 WiFi 和有线网络连接(通过编译选项配置)。
- 提供网络状态检查回调
user_network_check()
。
-
配网机制:
- 支持多种配网方式(BLE、WiFi AP)。
- 自动生成配网二维码,简化设备绑定流程。
-
数据点(DP)协议:
- 支持标准数据点类型(布尔、数值、字符串、枚举、位图)。
- 自动处理 DP 指令的接收和响应上报。
-
OTA 升级:
- 接收升级通知并显示详细信息(版本号、大小、下载 URL)。
- 可扩展实现固件升级流程。
-
命令行接口:
- 通过
tuya_app_cli_init()
注册自定义命令,支持命令行控制。
- 通过
代码扩展建议
要添加硬件控制在 DP 处理函数中添加 GPIO 控制代码,实现物理开关的操作。
src/tuya_cloud_service/cloud/mqtt_service.c
该程序是涂鸦智能(Tuya)设备的 MQTT 服务实现代码,主要用于处理设备与涂鸦云平台之间的安全通信、消息订阅 / 发布及协议解析。以下从功能模块、核心逻辑、关键特性三方面展开介绍:
功能模块概述
1. MQTT 连接管理
- 初始化与启动:
tuya_mqtt_init
:初始化 MQTT 客户端,配置连接参数(如 CA 证书、服务器地址、认证信息等),支持激活设备(devid
+seckey
)和未激活设备(uuid
+authkey
)的差异化认证。tuya_mqtt_start/stop
:启动 / 停止 MQTT 连接,包含重连逻辑(使用退避算法控制重试间隔)。
- 连接回调:
- 连接成功时自动订阅设备输入主题(
smart/device/in/{devid}
),并触发用户自定义的连接回调函数。
- 连接成功时自动订阅设备输入主题(
2. 消息订阅与处理
- 订阅管理:
tuya_mqtt_subscribe_message_callback_register
:注册主题订阅及回调函数,支持重复订阅过滤。tuya_mqtt_subscribe_message_callback_unregister
:取消订阅主题。
- 消息分发:
- 接收到消息后,根据主题匹配订阅列表,调用对应的回调函数;默认回调函数
on_subscribe_message_default
会解析涂鸦协议数据(JSON 格式),并根据协议 ID(protocol_id
)分发给注册的协议处理器。
- 接收到消息后,根据主题匹配订阅列表,调用对应的回调函数;默认回调函数
3. 消息发布与协议处理
- 数据发布:
tuya_mqtt_client_publish_common
:通用发布接口,支持同步 / 异步模式,带超时机制和回调通知。tuya_mqtt_protocol_data_publish
:发布涂鸦协议数据,自动对数据进行加密打包(使用 AES 等算法,密钥为cipherkey
),主题默认使用设备输出主题(smart/device/out/{devid}
)。
- 协议解析:
tuya_protocol_message_parse_process
:解析接收到的协议数据,验证 JSON 格式并提取protocol_id
,触发对应协议的回调函数(通过tuya_mqtt_protocol_register
注册)。
4. 安全与认证
- 签名工具:
tuya_mqtt_signature_tool
:生成 MQTT 连接的认证信息(clientid
、username
、password
),激活设备使用seckey
的 MD5 哈希生成密码,未激活设备使用authkey
,确保通信安全。
- 加密传输:
- 协议数据通过
tuya_pack_protocol_data
和tuya_parse_protocol_data
进行加解密,使用cipherkey
(本地密钥或 AuthKey)保障数据安全。
- 协议数据通过
核心数据结构与逻辑
1. 关键结构体
tuya_mqtt_context_t
:存储 MQTT 上下文,包括客户端句柄、订阅列表、协议处理器列表、认证信息(signature
)、连接状态等。mqtt_subscribe_handle_t
:管理订阅主题及其回调函数,形成链表结构。tuya_protocol_handle_t
:管理协议 ID 与回调函数的映射关系,用于消息分发。
2. 流程示例
- 设备激活场景:
- 初始化时传入
devid
、seckey
、localkey
,生成激活设备的认证信息(clientid
为devid
,密码为seckey
的 MD5 哈希后 8 字节)。 - 连接成功后订阅
smart/device/in/{devid}
主题,接收云端指令。
- 初始化时传入
- 未激活设备配网场景:
- 使用
uuid
和authkey
生成认证信息(clientid
为acon_{uuid}
),订阅特定主题(如d/ai/{uuid}
),仅支持接收配网指令。
- 使用
- 消息处理流程:
- 接收到消息 → 解析主题匹配订阅列表 → 调用回调函数 → 解析协议数据 → 根据
protocol_id
触发业务逻辑(如设备控制、状态上报)。
- 接收到消息 → 解析主题匹配订阅列表 → 调用回调函数 → 解析协议数据 → 根据
关键特性
- 双模式支持:
- 区分激活设备(长期连接,支持双向通信)和未激活设备(配网阶段临时连接,仅接收配网消息),适配不同设备生命周期。
- 安全机制:
- 认证信息基于 MD5 哈希生成,避免明文传输密钥;协议数据使用对称加密(AES),确保通信内容不可篡改。
- 可扩展性:
- 通过注册协议处理器(
tuya_mqtt_protocol_register
)支持多协议扩展,不同业务逻辑(如升级、控制)可通过不同protocol_id
解耦。
- 通过注册协议处理器(
- 可靠性设计:
- 重连机制(退避算法避免服务器压力)、QoS 1 保证消息至少一次送达、异步发布带回调确认,确保消息不丢失。
总结
该程序是涂鸦设备接入云端的核心组件,实现了安全可靠的 MQTT 通信,支持设备激活、配网、指令处理、状态上报等功能。通过模块化设计(连接管理、消息处理、协议解析分离)和安全机制,确保设备与云端的高效交互,适用于智能家居、工业物联网等场景的设备开发。