涂鸦智能云平台设备接入使用说明

1、前言

本文主要介绍如何使用非涂鸦智能设备基于MQTT协议连接涂鸦智能云平台。
本文档涉及的示例程序demo在:https://github.com/Cohen0415/tuya_mqtt

2、涂鸦智能云平台简介

涂鸦开发者平台 致力于打造互联互通的物联网开发标准,连接品牌、OEM 厂商、开发者、零售商和各行业的智能化需求。基于全球化部署的公有云,涂鸦开发者平台实现了智慧场景和智能设备的互联互通,承载着每日数以亿计的设备请求交互。平台服务涵盖硬件开发工具、App 开发工具、物联网云服务和智慧行业开发,为开发者提供从技术到营销渠道的全面赋能。

此次任务中,仅把涂鸦智能云平台当成一个MQTT代理(broker)。

3、生态设备接入流程

下图是生态设备(非涂鸦智能设备)接入流程框图:

3.1、涂鸦平台设备创建

3.1.1、产品创建

进入涂鸦开发者平台:https://platform.tuya.com/,点击“创建产品”:

3.1.2、添加自定义功能


在这里插入图片描述

3.1.3、设备开发

3.2、测试程序编写

以下将使用python来编写测试程序。

3.2.1、设备证书信息确认

设备MQTT连接涂鸦broker需要如下所谓的设备证书:

  • ProductID:产品 ID(实际没有用到)
  • DeviceID:设备的身份信息,用于连接云端授权和通信使用
  • DeviceSecre:设备的密码信息,用于连接云端授权使用

还需要:

  • User Name
# 格式
${deviceId}|signMethod=hmacSha256,timestamp=${当前 10 位时间戳},secureMode=1,accessType=1
# 举例
2632d4478100fda674lxlu|signMethod=hmacSha256,timestamp=1607837283,secureMode=1,accessType=1
  • Password
# password的生成需要使用HMAC算法,HMAC算法需要两个输入参数:秘钥、消息
# 消息的内容组成如下:
deviceId=2632d4478100fda674lxlu,timestamp=1607635284,secureMode=1,accessType=1
# 秘钥就是deviceSecret:
qxZS1LhriSGzzqiE

3.2.2、MQTT主题确认

在此之前,我们创建了一个自定义功能test_fuc

通过主题tylink/${deviceId}/thing/property/report来上报数据,数据格式如下:

{
  "msgId":"45lkj3551234***",
  "time":1626197189638,
  "data":{
    "test_fuc":{
      "value":"pub",
      "time": 1626197189638  
    }
  }
}

3.2.3、完整示例程序如下

import paho.mqtt.client as mqtt
import time
import hmac
import json
from hashlib import sha256
import uuid

# 设备信息
DeviceID = '2632d4478100fda674lxlu'         # 替换成自己的DeviceID
DeviceSecret = 'qxZS1LhriSGzzqiE'           # 替换成自己的DeviceSecret

# MQTT服务器信息
Address = 'm1.tuyacn.com'
Port = 8883
ClientID = 'tuyalink_' + DeviceID  

# 认证信息
T = int(time.time())
UserName = f'{DeviceID}|signMethod=hmacSha256,timestamp={T},secureMode=1,accessType=1'
data_for_signature = f'deviceId={DeviceID},timestamp={T},secureMode=1,accessType=1'.encode('utf-8')
appsecret = DeviceSecret.encode('utf-8')
Password = hmac.new(appsecret, data_for_signature, digestmod=sha256).hexdigest()

# MQTT回调函数(可选)
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to MQTT broker")
    else:
        print(f"Failed to connect to MQTT broker with code {rc}")

# 创建MQTT客户端
client = mqtt.Client(ClientID)
client.username_pw_set(UserName, Password)
client.tls_set()  				# 必须启用TLS
client.on_connect = on_connect  # 设置连接回调函数(可选)

# 连接到MQTT服务器
client.connect(Address, Port, 60)

# 等待连接建立
client.loop_start()
time.sleep(2)  

# 准备上报的数据
current_time = int(time.time() * 1000)
payload = json.dumps({
    "msgId":str(uuid.uuid4()),
    "time":current_time,
    "data":{
        "test_fuc":{
            "value": "pub",
            "time": current_time  
        }
    }
})

# 上报数据到云平台
topic = f'tylink/{DeviceID}/thing/property/report'
client.publish(topic, payload)
print(f"Published payload: {payload} to topic: {topic}")

while True:
    time.sleep(1)

client.loop_stop()
client.disconnect()

3.2.4、测试

程序运行后,返回涂鸦云平台,可以看到设备已在线:

查看设备日志:

3.3、Linux c测试程序编写

3.3.1、导入服务器证书

static const char *ca_crt = {
  "-----BEGIN CERTIFICATE-----\n"
  "MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\n"
  "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\n"
  "EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\n"
  "ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\n"
  "NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\n"
  "EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\n"
  "AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\n"
  "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\n"
  "E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n"
  "/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\n"
  "DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\n"
  "GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\n"
  "tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\n"
  "AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n"
  "FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\n"
  "WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n"
  "9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\n"
  "gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n"
  "2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n"
  "LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n"
  "4uJEvlz36hz1\n"
  "-----END CERTIFICATE-----\n"
};

3.3.2、完整示例程序如下

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>
#include <gpiod.h>
#include <math.h>
#include <time.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/sha.h>

#include "mqttclient.h"
#include "cJSON.h"

// 设备信息
#define TUYA_DEVICE_ID			        "2632d447810xxxxxxxxxxx"
#define TUYA_DEVICE_SECRET              "qxZS1LhriSxxxxxx"

// MQTT服务器信息
#define TUYA_HOST                       "m1.tuyacn.com"
#define TUYA_PORT                       "8883"
#define TUYA_CLIENT_ID                  "tuyalink_"TUYA_DEVICE_ID

// MQTT主题
#define TUYA_TOPIC_PUBLISH              "tylink/"TUYA_DEVICE_ID"/thing/property/report"

mqtt_client_t *client = NULL;                     
pthread_t mqtt_publish_thread_obj;                

typedef struct sensor_mes {
    char name[20];
    char value[10];
} sensor_mes_t;

// CA 证书,用于 TLS 连接
static const char *ca_crt = {
  "-----BEGIN CERTIFICATE-----\n"
  "MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\n"
  "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\n"
  "EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\n"
  "ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\n"
  "NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\n"
  "EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\n"
  "AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\n"
  "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\n"
  "E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n"
  "/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\n"
  "DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\n"
  "GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\n"
  "tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\n"
  "AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n"
  "FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\n"
  "WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n"
  "9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\n"
  "gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n"
  "2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n"
  "LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n"
  "4uJEvlz36hz1\n"
  "-----END CERTIFICATE-----\n"
};

void generate_hmac_sha256(const char *key, const char *data, char *output) 
{
    unsigned char *digest;
    digest = HMAC(EVP_sha256(), key, strlen(key), (unsigned char *)data, strlen(data), NULL, NULL);
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) 
    {
        sprintf(output + (i * 2), "%02x", digest[i]);
    }
}

static cJSON *create_tuya_json(sensor_mes_t *sensor) 
{   
    if(sensor == NULL)
        return NULL;

    if(sensor->name == NULL || sensor->value == NULL)
        return NULL;

    time_t t = time(NULL);
    char timestamp[32];
    snprintf(timestamp, sizeof(timestamp), "%ld", t);

    cJSON *root = cJSON_CreateObject();

    cJSON_AddStringToObject(root, "msgID", timestamp);
    cJSON_AddStringToObject(root, "time", timestamp);

    cJSON *data = cJSON_CreateObject();

    cJSON *item = cJSON_CreateObject();
    cJSON_AddStringToObject(item, "value", sensor->value);
    cJSON_AddStringToObject(item, "time", timestamp);

    cJSON_AddItemToObject(data, sensor->name, item);
    cJSON_AddItemToObject(root, "data", data);

    return root;
}

static void sensor_mes_init(sensor_mes_t *sensor, const char *name, const char *value)
{
    if(sensor == NULL)
        return;
    
    if(name == NULL || value == NULL)
        return;

    strcpy(sensor->name, name);
    strcpy(sensor->value, value);
}

void *mqtt_publish_thread(void *arg)
{
    mqtt_client_t *client = (mqtt_client_t *)arg;

    int ret;
    mqtt_message_t msg;
    sensor_mes_t temp_mes_t;

    cJSON *tuya_json;
    char *tuya_json_str;

    memset(&msg, 0, sizeof(msg));
    msg.qos = 0;

    sleep(2);

    while(1) 
    {
        sensor_mes_init(&temp_mes_t, "temperature", "25.5");
        tuya_json = create_tuya_json(&temp_mes_t);

        tuya_json_str = cJSON_Print(tuya_json);
        msg.payload = (void *)tuya_json_str;

        mqtt_publish(client, TUYA_TOPIC_PUBLISH, &msg);
        cJSON_Delete(tuya_json);
        tuya_json = NULL;

        sleep(3);
    }
}

int mqtt_init()
{
    int rc = 0;
    char username[256];
    char data_for_signature[256];
    char password[65];

    // 获取当前时间戳
    time_t t = time(NULL);
    char timestamp[32];
    snprintf(timestamp, sizeof(timestamp), "%ld", t);

    // 构建username和password
    snprintf(username, sizeof(username), "%s|signMethod=hmacSha256,timestamp=%s,secureMode=1,accessType=1", TUYA_DEVICE_ID, timestamp);
    snprintf(data_for_signature, sizeof(data_for_signature), "deviceId=%s,timestamp=%s,secureMode=1,accessType=1", TUYA_DEVICE_ID, timestamp);
    generate_hmac_sha256(TUYA_DEVICE_SECRET, data_for_signature, password);
    // printf("UserName: %s\n", username);
    // printf("Password: %s\n", password);

    // 初始化 MQTT 客户端
    client = mqtt_lease();
    if(client == NULL)
        return -1;

    mqtt_set_port(client, TUYA_PORT);               // 设置 MQTT 消息的端口
    mqtt_set_host(client, TUYA_HOST);               // 设置 MQTT 消息的主机
    mqtt_set_ca(client, (char*)ca_crt);             // 设置 CA 证书
    mqtt_set_user_name(client, username);           // 设置 MQTT 用户名
    mqtt_set_password(client, password);            // 设置 MQTT 密码
    mqtt_set_client_id(client, TUYA_CLIENT_ID);     // 设置 MQTT 客户端 ID
    mqtt_set_clean_session(client, 1);              // 设置 MQTT 会话为清除模式  

    // 连接到 MQTT 服务器
    mqtt_connect(client);

    // 创建 MQTT 发布线程
    rc = pthread_create(&mqtt_publish_thread_obj, NULL, mqtt_publish_thread, client);
    if(rc!= 0) 
    {
        MQTT_LOG_E("create mqtt publish thread fail");
        return -1;
    }

    return 0;
}

int main()
{
    int ret;
    
    mqtt_log_init();
    ret = mqtt_init();
    if(ret == -1)
    {
        MQTT_LOG_E("mqtt init fail\n");
        return -1;
    }

    while (1) 
    {
        sleep(1);
    }

    return 0;
}

4、手机APP绑定设备

4.1、设备绑定范围配置

4.2、APP下载

下载“智能生活”APP:

在这里插入图片描述

4.3、APP扫码绑定设备

打开“智能生活”APP,使用与涂鸦智能云平台相同的手机号登录,并扫码绑定设备:

在这里插入图片描述

绑定成功:

查看设备功能数据:

![](https://i-blog.csdnimg.cn/img_convert/2750e84d261d2c568ffd6a3482e619dd.png

5、其它涂鸦官方手册

功能定义-涂鸦开发者平台-涂鸦开发者

MQTT.fx 标准协议接入示例-涂鸦开发者平台-涂鸦开发者

设备属性、动作与事件-涂鸦开发者平台-涂鸦开发者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值