如何用C语言实现 IoT Core

涂鸦 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 开发平台")创建产品,获取授权信息,然后将产品和授权相关信息写入到代码中,实现云服务的接入。详细步骤如下:

  1. 登录 [涂鸦 IoT 开发平台]( "涂鸦 IoT 开发平台")。

  2. 单击 创建产品

  3. 选择 行业解决方案 > 智慧工业 > 工业网关 品类。

  4. 智能化方式 区域选择 生态设备接入,并填写产品相关信息,完成产品创建。

  5. 功能定义 界面,单击 添加功能 并填写相关参数,完成产品功能定义。

  6. 设备开发 界面,选择并下载 SDK 方案,单击 下一步 进入激活信息获取页面。

  7. 领取授权码,然后单击 注册设备。设备相应信息会显示在下方。

    涂鸦提供免费的授权码供测试使用,可以免费领取 2 个激活码。

  8. 将注册的设备信息,填写到 examples/subdevice_basic_demo/subdevice_basic_demo.c 文件中,编译并运行 Demo 即可连接云服务,关于编译的具体流程,请参考下文编译执行章节内容。

    复制代码
    const char productId[] = "rwosj58aaqjk **** ";
    const char deviceId[] = "6c95875d0f5ba69607 **** ";
    const char deviceSecret[] = " ******************* ";

    可通过购买授权码,在设备管理页面进行设备注册,获取 productIddeviceIddeviceSecret 等信息。

第三步:编译执行(Ubuntu)

本小节以 Ubuntu 系统为例,介绍 SDK 编译步骤。本节介绍同样适用于 Debian 系统。

  1. 安装 make 等相关环境依赖。

    复制代码
    sudo apt-get install make cmake
  2. 进入获取到的 SDK 文件内,新建一个 build 文件夹并且进入该文件夹,输入 cmake.. 先进行环境编译,再输入 make 开始编译固件。编译完成后,固件会生成在 build 文件夹下的 bin 文件夹。

    复制代码
    mkdir build && cd build
    cmake ..
    make
  3. 进入 bin 文件夹,运行 Demo。SDK 内置了基础的通信 Demo 代码,例如子设备管理基础 Demo。

    复制代码
    ./bin/subdevice_basic_demo
  4. 在设备端查看运行接口。

    以下日志显示设备与云端连接成功。

  5. 设备成功连接到[涂鸦 IoT 开发平台]( "涂鸦 IoT 开发平台")后,单击进行刷新,设备状态会显示为在线。

应用示例

  1. 实例化和初始化一个设备对象 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
    });
  2. 定义应用层事件回调,回调函数用于应用层接收 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");
    }
  3. 启动 TuyaOS SDK 服务。

    复制代码
    ret = tuya_mqtt_connect(client);
    //TuyaOS SDK 服务任务,数据接收处理,设备在线保活等任务处理:
  4. 循环调用将当前线程产生给底层的 Link SDK 客户端。

    复制代码
    tuya_mqtt_loop(client);
  5. 定义上报函数,调用相关上报接口函数实现数据上报。下方示例为产品连接时,将部分产品数据上报到云端。大家可以根据自己产品的数据上报需求,参考该函数编写自身应用代码。

    复制代码
     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 开发平台]( "涂鸦 IoT 开发平台")设备调试页面对设备进行调试。

  1. 进入 设备调试 页面,单击 选择设备 ,填入上线设备的 DeviceID,即可获取到设备当前定义的功能点合集。

  2. 设备操作的日志信息都会显示在右侧实时日志处,大家可以通过日志确认设备当前的信息。

  3. 单击功能点操作列的 获取 选项,可以获取到当前设备的数据。

  4. 单击功能点操作列的 设置 选项,可以对设备当前的数据进行设置,日志处会显示当前云端下发的 payload 日志信息,通过本地 log 也可以看到云端下发的 payload 信息。

接口说明

SDK 初始化

接口信息 说明
函数原型 int tuya_mqtt_init(tuya_mqtt_context_t* context, const tuya_mqtt_config_t* config);
功能描述 设备初始化
输入参数 * context:设备管理句柄 * 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);
功能描述 使用该函数获取设备的物模型
输入参数 * context:设备管理句柄 * device_id:设备 ID
输出参数
返回值 参考通用错误码

设备属性上报

接口信息 说明
函数原型 int tuyalink_thing_property_report(tuya_mqtt_context_t* context, const char* device_id, const char* data);
功能描述 设备属性上报
输入参数 * context:设备管理句柄 * device_id:设备 ID
输出参数
返回值 参考通用错误码

设备属性上报(包含应答)

接口信息 说明
函数原型 int tuyalink_thing_property_report_with_ack(tuya_mqtt_context_t* context, const char* device_id, const char* data);
功能描述 上报设备的属性并得到云端应答
输入参数 * context:设备管理句柄 * device_id:设备 ID * data:上报的属性数据
输出参数
返回值 参考通用错误码

设备事件响应

接口信息 说明
函数原型 int tuyalink_thing_event_trigger(tuya_mqtt_context_t* context, const char* device_id, const char* data);
功能描述 设备事件响应
输入参数 * context:设备管理句柄 * device_id:设备 ID * data:事件数据
输出参数
返回值 参考通用错误码

设备批量上报

接口信息 说明
函数原型 int tuyalink_thing_batch_report(tuya_mqtt_context_t* context, const char* data);
功能描述 设备批量上报数据
输入参数 * context:设备管理句柄 * data:数据
输出参数
返回值 参考通用错误码

子设备绑定

接口信息 说明
函数原型 int tuyalink_subdevice_bind(tuya_mqtt_context_t* context, const char* data);
功能描述 子设备绑定
输入参数 * context:设备管理句柄 * data:数据
输出参数
返回值 参考通用错误码

子设备上线

接口信息 说明
函数原型 int tuyalink_subdevice_bind_login(tuya_mqtt_context_t* context, const char* data);
功能描述 子设备上线
输入参数 * context:设备管理句柄 * data:数据
输出参数
返回值 参考通用错误码

子设备下线

接口信息 说明
函数原型 int tuyalink_subdevice_bind_logout(tuya_mqtt_context_t* context, const char* data);
功能描述 子设备下线
输入参数 * context:设备管理句柄 * data:数据
输出参数
返回值 参考通用错误码

子设备拓扑添加

接口信息 说明
函数原型 int tuyalink_subdevice_topo_add(tuya_mqtt_context_t* context, const char* data);
功能描述 子设备拓扑添加
输入参数 * context:设备管理句柄 * data:数据
输出参数
返回值 参考通用错误码

子设备拓扑删除

接口信息 说明
函数原型 int tuyalink_subdevice_topo_delete(tuya_mqtt_context_t* context, const char* data);
功能描述 子设备拓扑删除
输入参数 * context:设备管理句柄 * 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;
}
相关推荐
march_birds4 分钟前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
掘金一周13 分钟前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
白雪讲堂30 分钟前
AI搜索品牌曝光资料包(精准适配文心一言/Kimi/DeepSeek等场景)
大数据·人工智能·搜索引擎·ai·文心一言·deepseek
小麦嵌入式31 分钟前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
The Future is mine34 分钟前
Python计算经纬度两点之间距离
开发语言·python
Enti7c35 分钟前
HTML5和CSS3的一些特性
开发语言·css3
斯汤雷35 分钟前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
爱吃巧克力的程序媛42 分钟前
在 Qt 创建项目时,Qt Quick Application (Compat) 和 Qt Quick Application
开发语言·qt
ejinxian42 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
葡萄成熟时_1 小时前
【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【代码篇】A题解题全流程(持续更新)
人工智能·数据挖掘