涂鸦 IoT Core SDK 使用 C 语言实现,支持涂鸦设备模型协议,适用于开发者自主开发硬件设备逻辑业务接入涂鸦。
功能概述
涂鸦 IoT Core SDK 提供设备激活、发送上下行 DP 和固件 OTA 升级等基础业务接口封装。SDK 不依赖具体设备平台及操作系统环境,也可以运行在单任务环境。仅需要支持 TCP/IP 协议栈及提供 SDK 必要的系统依赖接口,即可完成接入。
开发步骤
第一步:下载 SDK
先在在 涂鸦 GitHub 仓库 下载 IoT Core SDK。
该 SDK 的 C 代码文件通过以下目录结构提供:
文件 | 说明 |
---|---|
certs | 设备私钥,设备证书,服务端 CA 根证书 |
docs | 参考文档 |
libraries | 外部依赖库,包含 MQTT client、HTTP client、mbedTLS 等 |
interface | 平台必要移植接口,SDK 功能接口 |
include | SDK 有文件,包含了 SDK API |
src | SDK 源代码 |
platform | 平台移植接口适配 |
utils | 通用工具模块 |
examples | 例程 |
第二步:配置设备信息
首先需要在涂鸦 IoT 开发平台创建产品,获取授权信息,然后将产品和授权相关信息写入到代码中,实现云服务的接入。详细步骤如下:
-
登录 涂鸦 IoT 开发平台。
-
单击 创建产品。
-
选择 行业解决方案 > 智慧工业 > 工业网关 品类。
-
在 智能化方式 区域选择 生态设备接入,并填写产品相关信息,完成产品创建。
-
在 功能定义 界面,单击 添加功能 并填写相关参数,完成产品功能定义。
-
在 设备开发 界面,选择并下载 SDK 方案,单击 下一步 进入激活信息获取页面。
-
领取授权码,然后单击 注册设备。设备相应信息会显示在下方。
涂鸦提供免费的授权码供测试使用,可以免费领取 2 个激活码。
-
将注册的设备信息,填写到
examples/subdevice_basic_demo/subdevice_basic_demo.c
文件中,编译并运行 Demo 即可连接云服务,关于编译的具体流程,请参考下文编译执行章节内容。const char productId[] = "rwosj58aaqjk **** "; const char deviceId[] = "6c95875d0f5ba69607 **** "; const char deviceSecret[] = " ******************* ";
可通过购买授权码,在设备管理页面进行设备注册,获取
productId
、deviceId
、deviceSecret
等信息。
第三步:编译执行(Ubuntu)
本小节以 Ubuntu 系统为例,介绍 SDK 编译步骤。本节介绍同样适用于 Debian 系统。
-
安装
make
等相关环境依赖。sudo apt-get install make cmake
-
进入获取到的 SDK 文件内,新建一个
build
文件夹并且进入该文件夹,输入cmake..
先进行环境编译,再输入make
开始编译固件。编译完成后,固件会生成在 build 文件夹下的 bin 文件夹。mkdir build && cd build cmake .. make
-
进入 bin 文件夹,运行 Demo。SDK 内置了基础的通信 Demo 代码,例如子设备管理基础 Demo。
./bin/subdevice_basic_demo
-
在设备端查看运行接口。
以下日志显示设备与云端连接成功。
-
设备成功连接到涂鸦 IoT 开发平台后,单击进行刷新,设备状态会显示为在线。
应用示例
-
实例化和初始化一个设备对象
tuya_iot_client_t
,用来初始化产品 ID 和授权信息等配置参数。/* instantiate the client */ tuya_mqtt_context_t* client = &client_instance; /* initialize the client */ ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) { .host = "m2.tuyacn.com", .port = 8883, .cacert = tuya_cacert_pem, .cacert_len = sizeof(tuya_cacert_pem), .device_id = deviceId, .device_secret = deviceSecret, .keepalive = 60, .timeout_ms = 2000, .on_connected = on_connected, .on_disconnect = on_disconnect, .on_messages = on_messages });
-
定义应用层事件回调,回调函数用于应用层接收 SDK 事件通知,如数据功能点(DP)下发,云端连接状态通知。
/* Tuya SDK event callback */ void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg) { TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code); switch (msg->type) { case THING_TYPE_MODEL_RSP: TY_LOGI("Model data:%s", msg->data_string); break; case THING_TYPE_PROPERTY_SET: TY_LOGI("property set:%s", msg->data_string); break; case THING_TYPE_PROPERTY_REPORT_RSP: break; default: break; } printf("\r\n"); }
-
启动 TuyaOS SDK 服务。
ret = tuya_mqtt_connect(client); //TuyaOS SDK 服务任务,数据接收处理,设备在线保活等任务处理:
-
循环调用将当前线程产生给底层的 Link SDK 客户端。
tuya_mqtt_loop(client);
-
定义上报函数,调用相关上报接口函数实现数据上报。下方示例为产品连接时,将部分产品数据上报到云端。大家可以根据自己产品的数据上报需求,参考该函数编写自身应用代码。
void on_connected(tuya_mqtt_context_t* context, void* user_data) { TY_LOGI("on connected"); /* data model test code */ tuyalink_thing_data_model_get(context, NULL); tuyalink_thing_desired_get(context, NULL, "[\"power\"]"); tuyalink_thing_property_report(context, NULL, "{\"power\": {\"value\":1234,\"time\":1631708204231}}"); tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}"); tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}"); tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":1},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\": {\"param1\":\"10\"},\"eventTime\":1626197189001}}}}"); }
/*数据上报 API*/ /* data model code */ tuyalink_thing_data_model_get(context, NULL); tuyalink_thing_desired_get(context, NULL, "[\"power\"]"); tuyalink_thing_property_report(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}"); tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}"); tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}"); tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":0},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\":{\"param1\":\"10\"},\"eventTime\":1626197189001}}}}");} /* subdevice code */ tuyalink_subdevice_bind(context, "[{\"productId\":\"jtwe4q9jrs0bbc8q\",\"nodeId\":\"123456\",\"clientId\":\"123455asdf\"}]"); tuyalink_subdevice_bind_login(context, "[\"6c17c5ba952143f592b8g1\",\"6c41626e5cea758aees0ik\"]"); tuyalink_subdevice_bind_logout(context, "[\"6c17c5ba952143f592b8g1\"]"); tuyalink_subdevice_topo_add(context, "[{\"productId\":\"jtwe4q9jrs0bbc8q\",\"deviceId\":\"6c17c5ba952143f592b8g1\",\"sign\":\"366508ed895644e70a3006bdef2dbe77ef73e18a\",\"signMethod\":\"hmacSha1\",\"timestamp\":\"1636989480\"}]"); tuyalink_subdevice_topo_delete(context,"[\"6c41626e5cea758aees0ik\"]"); tuyalink_subdevice_topo_get(context);
设备调试
设备成功连接 MQTT 服务器并上线后,可以在涂鸦 IoT 开发平台设备调试页面对设备进行调试。
-
进入 设备调试 页面,单击 选择设备,填入上线设备的 DeviceID,即可获取到设备当前定义的功能点合集。
-
设备操作的日志信息都会显示在右侧实时日志处,大家可以通过日志确认设备当前的信息。
-
单击功能点操作列的 获取 选项,可以获取到当前设备的数据。
-
单击功能点操作列的 设置 选项,可以对设备当前的数据进行设置,日志处会显示当前云端下发的 payload 日志信息,通过本地 log 也可以看到云端下发的 payload 信息。
接口说明
SDK 初始化
接口信息 | 说明 |
---|---|
函数原型 | int tuya_mqtt_init(tuya_mqtt_context_t* context, const tuya_mqtt_config_t* config); |
功能描述 | 设备初始化 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
启动服务
接口信息 | 说明 |
---|---|
函数原型 | int tuya_mqtt_connect(tuya_mqtt_context_t* context); |
功能描述 | 启动设备 SDK 服务 |
输入参数 | context :设备管理句柄 |
输出参数 | 无 |
返回值 | 参考通用错误码 |
停止服务
接口信息 | 说明 |
---|---|
函数原型 | int tuya_mqtt_disconnect(tuya_mqtt_context_t* context); |
功能描述 | 停止设备 SDK 服务 |
输入参数 | context :设备管理句柄 |
输出参数 | 无 |
返回值 | 参考通用错误码 |
后台运行服务
接口信息 | 说明 |
---|---|
函数原型 | int tuya_mqtt_loop(tuya_mqtt_context_t* context); |
功能描述 | SDK 后台运行服务 |
输入参数 | context :设备管理句柄 |
输出参数 | 无 |
返回值 | 参考通用错误码 |
备注 | 需要在程序主循环调用该服务函数 |
获取设备物模型
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_thing_data_model_get(tuya_mqtt_context_t* context, const char* device_id); |
功能描述 | 使用该函数获取设备的物模型 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
设备属性上报
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_thing_property_report(tuya_mqtt_context_t* context, const char* device_id, const char* data); |
功能描述 | 设备属性上报 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
设备属性上报(包含应答)
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_thing_property_report_with_ack(tuya_mqtt_context_t* context, const char* device_id, const char* data); |
功能描述 | 上报设备的属性并得到云端应答 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
设备事件响应
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_thing_event_trigger(tuya_mqtt_context_t* context, const char* device_id, const char* data); |
功能描述 | 设备事件响应 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
设备批量上报
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_thing_batch_report(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 设备批量上报数据 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备绑定
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_bind(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 子设备绑定 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备上线
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_bind_login(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 子设备上线 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备下线
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_bind_logout(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 子设备下线 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备拓扑添加
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_topo_add(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 子设备拓扑添加 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备拓扑删除
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_topo_delete(tuya_mqtt_context_t* context, const char* data); |
功能描述 | 子设备拓扑删除 |
输入参数 |
|
输出参数 | 无 |
返回值 | 参考通用错误码 |
子设备拓扑获取
接口信息 | 说明 |
---|---|
函数原型 | int tuyalink_subdevice_topo_get(tuya_mqtt_context_t* context); |
功能描述 | 子设备拓扑获取 |
输入参数 | context :设备管理句柄 |
输出参数 | 无 |
返回值 | 参考通用错误码 |
Demo 设备例程
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
#include "tuya_cacert.h"
#include "tuya_log.h"
#include "tuya_error_code.h"
#include "system_interface.h"
#include "mqtt_client_interface.h"
#include "tuyalink_core.h"
const char productId[] = "3jbcpefnn1jxxxxx";
const char deviceId[] = "6ced2aa564727c01xxxxx";
const char deviceSecret[] = "ac5d367db39xxxxx";
tuya_mqtt_context_t client_instance;
void on_connected(tuya_mqtt_context_t* context, void* user_data)
{
TY_LOGI("on connected");
/* data model test code */
tuyalink_thing_data_model_get(context, NULL);
tuyalink_thing_desired_get(context, NULL, "[\"power\"]");
tuyalink_thing_property_report(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}");
tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":0},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\":{\"param1\":\"10\"},\"eventTime\":1626197189001}}}}");
}
void on_disconnect(tuya_mqtt_context_t* context, void* user_data)
{
TY_LOGI("on disconnect");
}
void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg)
{
TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code);
switch (msg->type) {
case THING_TYPE_MODEL_RSP:
TY_LOGI("Model data:%s", msg->data_string);
break;
case THING_TYPE_PROPERTY_SET:
TY_LOGI("property set:%s", msg->data_string);
break;
case THING_TYPE_PROPERTY_REPORT_RSP:
break;
default:
break;
}
printf("\r\n");
}
int main(int argc, char** argv)
{
int ret = OPRT_OK;
tuya_mqtt_context_t* client = &client_instance;
ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) {
.host = "m2.tuyacn.com",
.port = 8883,
.cacert = tuya_cacert_pem,
.cacert_len = sizeof(tuya_cacert_pem),
.device_id = deviceId,
.device_secret = deviceSecret,
.keepalive = 60,
.timeout_ms = 2000,
.on_connected = on_connected,
.on_disconnect = on_disconnect,
.on_messages = on_messages
});
assert(ret == OPRT_OK);
ret = tuya_mqtt_connect(client);
assert(ret == OPRT_OK);
for (;;) {
/* Loop to receive packets, and handles client keepalive */
tuya_mqtt_loop(client);
}
return ret;
}