当前位置: 首页 > news >正文

涂鸦智能的TuyaOpen框架入门指南:智能插座实战

目录

引言

TuyaOpen框架简介

程序下载和编译

安装依赖

克隆仓库

设置与编译

step1. 设置环境变量

step2. 选择待编译项目

step3. 编译

step4. menuconfig 配置

在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);// ...
    }
    

    工作流程

    1. 设备初始化

      • 初始化系统组件(日志、存储、定时器等)。
      • 读取或设置设备授权信息(UUID/AuthKey)。
      • 初始化涂鸦 IoT 客户端,注册事件处理函数。
    2. 网络连接与配网

      • 初始化网络(WiFi 或有线)。
      • 连接成功后生成配网二维码(URL 格式:https://smartapp.tuya.com/s/p?p={产品ID}&uuid={设备UUID})。
      • 用户通过涂鸦 APP 扫描二维码完成配网。
    3. 数据交互

      • 通过 MQTT 协议与涂鸦云平台通信。
      • 接收云平台下发的数据点指令(如开关控制)。
      • 上报设备状态(如开关状态、电量等)。
    4. 事件处理

      • 处理网络连接状态变化、OTA 升级通知、时间同步等事件。

    关键特性

    1. 多网络支持

      • 支持 WiFi 和有线网络连接(通过编译选项配置)。
      • 提供网络状态检查回调 user_network_check()
    2. 配网机制

      • 支持多种配网方式(BLE、WiFi AP)。
      • 自动生成配网二维码,简化设备绑定流程。
    3. 数据点(DP)协议

      • 支持标准数据点类型(布尔、数值、字符串、枚举、位图)。
      • 自动处理 DP 指令的接收和响应上报。
    4. OTA 升级

      • 接收升级通知并显示详细信息(版本号、大小、下载 URL)。
      • 可扩展实现固件升级流程。
    5. 命令行接口

      • 通过 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 连接的认证信息(clientidusernamepassword),激活设备使用seckey的 MD5 哈希生成密码,未激活设备使用authkey,确保通信安全。
    • 加密传输
      • 协议数据通过tuya_pack_protocol_datatuya_parse_protocol_data进行加解密,使用cipherkey(本地密钥或 AuthKey)保障数据安全。

    核心数据结构与逻辑

    1. 关键结构体
    • tuya_mqtt_context_t:存储 MQTT 上下文,包括客户端句柄、订阅列表、协议处理器列表、认证信息(signature)、连接状态等。
    • mqtt_subscribe_handle_t:管理订阅主题及其回调函数,形成链表结构。
    • tuya_protocol_handle_t:管理协议 ID 与回调函数的映射关系,用于消息分发。
    2. 流程示例
    1. 设备激活场景
      • 初始化时传入devidseckeylocalkey,生成激活设备的认证信息(clientiddevid,密码为seckey的 MD5 哈希后 8 字节)。
      • 连接成功后订阅smart/device/in/{devid}主题,接收云端指令。
    2. 未激活设备配网场景
      • 使用uuidauthkey生成认证信息(clientidacon_{uuid}),订阅特定主题(如d/ai/{uuid}),仅支持接收配网指令。
    3. 消息处理流程
      • 接收到消息 → 解析主题匹配订阅列表 → 调用回调函数 → 解析协议数据 → 根据protocol_id触发业务逻辑(如设备控制、状态上报)。

    关键特性

    1. 双模式支持
      • 区分激活设备(长期连接,支持双向通信)和未激活设备(配网阶段临时连接,仅接收配网消息),适配不同设备生命周期。
    2. 安全机制
      • 认证信息基于 MD5 哈希生成,避免明文传输密钥;协议数据使用对称加密(AES),确保通信内容不可篡改。
    3. 可扩展性
      • 通过注册协议处理器(tuya_mqtt_protocol_register)支持多协议扩展,不同业务逻辑(如升级、控制)可通过不同protocol_id解耦。
    4. 可靠性设计
      • 重连机制(退避算法避免服务器压力)、QoS 1 保证消息至少一次送达、异步发布带回调确认,确保消息不丢失。

    总结

    该程序是涂鸦设备接入云端的核心组件,实现了安全可靠的 MQTT 通信,支持设备激活、配网、指令处理、状态上报等功能。通过模块化设计(连接管理、消息处理、协议解析分离)和安全机制,确保设备与云端的高效交互,适用于智能家居、工业物联网等场景的设备开发。

    结语

    相关文章:

  • Vue 组件 - 指令
  • Python中re模块结合正则表达式的应用
  • springboot拦截器的基本配置
  • OSCP备战-SickOs1.2靶场详细步骤
  • WPF 按钮悬停动画效果实现
  • 大数据如何赋能市场情报分析?——精准决策,从数据开始
  • Bently Nevada 135473-01振动监控模块3500系列状态系统
  • 强化学习极简入门笔记
  • 技术文档撰写指南:从结构到细节的全流程解析
  • 小白玩串口控制的ASCII避坑
  • 计算机网络常见体系结构、分层必要性、分层设计思想以及专用术语介绍
  • MySQL 查询语句的执行顺序
  • 在 WSL Ubuntu-24.04 上安装 Nacos 2.5.1 并使用 MySQL 数据库
  • Knife4j框架的使用
  • HOW - 简历和求职面试宝典(二)
  • 基于MATLAB实现SFA(Slow Feature Analysis,慢特征分析)算法
  • 湖北理元理律师事务所债务优化实践:在还款与生活间寻找平衡支点
  • 网络摄像机POE交换机选型指南:技术参数与场景适配深度解析
  • 多语种OCR识别系统,引领文字识别新时代
  • 深入剖析网络协议:七层协议与四层协议详解
  • 南宁网站建设公司电话/引流推广是什么意思
  • wordpress建立视频网站/某网站seo策划方案
  • 吉林奶茶加盟网站建设/2020年百度搜索排名
  • python做博客网站/重庆seo网站管理
  • 怎么做网站截图/手机游戏性能优化软件
  • 体验做黑客的网站/百度快速收录账号购买