如何用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;
}
相关推荐
王哈哈^_^几秒前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
Chrikk25 分钟前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*28 分钟前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue28 分钟前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man30 分钟前
【go从零单排】go语言中的指针
开发语言·后端·golang
Power20246661 小时前
NLP论文速读|LongReward:基于AI反馈来提升长上下文大语言模型
人工智能·深度学习·机器学习·自然语言处理·nlp
数据猎手小k1 小时前
AIDOVECL数据集:包含超过15000张AI生成的车辆图像数据集,目的解决旨在解决眼水平分类和定位问题。
人工智能·分类·数据挖掘
好奇龙猫1 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
沉下心来学鲁班1 小时前
复现LLM:带你从零认识语言模型
人工智能·语言模型
数据猎手小k1 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型