有奖捉虫:办公协同&微信生态&物联网文档专题 HOT

1. 接口描述

接口请求域名: iot.cloud.tencent.com/api/exploreropen/tokenapi。 本接口(AppSigBindDeviceInFamily)用于小程序或 App进行 Wi-Fi 设备配网绑定操作。

2. 输入参数

名称
类型
必选
描述
AccessToken
String
公共参数,AccessToken 用于对一个已经登录的用户鉴权。
RequestId
String
公共参数,唯一请求 ID,可自行生成,推荐使用 uuid。定位问题时,需提供该次请求的 RequestId。
Action
String
公共参数,本接口取值:AppSigBindDeviceInFamily。
FamilyId
String
家庭 ID。
ProductId
String
产品 ID。
DeviceName
String
设备名称。
RoomId
String
房间 ID。
DeviceTimestamp
Int64
设备时间戳,Unix 秒级时间戳。
ConnId
String
随机字符串,建议5个字节长度。
Signature
String
动态签名,由设备根据配网协议传输到小程序、App 端的签名。计算示例见下文。
BindType
String
绑定类型。
wifi_sign:WIFI 绑定 (默认)。
bluetooth_sign:蓝牙绑定。
other_sign:其他。
SignMethod
String
签名算法。
hmacsha1:HMACSHA1 加密算法(默认)。
hmacsha256:HMACSHA256 加密算法。

3. 输出参数

名称
类型
描述
RequestId
String
公共参数,唯一请求 ID,可自行生成,推荐使用 uuid。定位问题时,需提供该次请求的 RequestId。
AppDeviceInfo
Object of AppDeviceInfo
设备信息。

4. 动态签名计算

签名计算步骤:
1. 确认是WIFI配网还是蓝牙或者其他配网,需要加密的明文串拼接略有不同。
2. 获取设备的 psk,可以在控制台查看或者通过 API 获取。
3. 将 psk 通过 base64 解码后作为 hash 的 key 对明文编码。
4. hash 后的结果转十六进制字符串拼接即可。
WIFI 绑定和蓝牙或其他绑定签名计算步骤一致,只是加密明文拼接略有不同,详见示例代码。

WIFI 配网绑定签名

明文拼接格式:"DeviceName=%s&DeviceTimestamp=%d&ProductId=%s&ConnId=%s"
Java
Go
C
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AppBind {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
public static final String DEVICE_PSK = "4B***==";
public static final String PRODUCT_ID = "productId";
public static final String DEVICE_NAME = "d1";
public static final String CONN_ID = "12345";
public static final int TIMESTAMP = 1694141664;
public static final String ContentFormat = "DeviceName=%s&DeviceTimestamp=%d&ProductId=%s&ConnId=%s";

public static void main(String[] args) throws Exception {
String content = String.format(ContentFormat, DEVICE_NAME, TIMESTAMP, PRODUCT_ID, CONN_ID);
// sha1
System.out.println(calculateHMACSHA1(content, Base64.getDecoder().decode(DEVICE_PSK)));
// sha256
System.out.println(calculateHMACSHA256(content, Base64.getDecoder().decode(DEVICE_PSK)));
}
// 计算sha1签名
public static String calculateHMACSHA1(String data, byte[] keyBytes) throws Exception {
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] dataBytes = data.getBytes();
byte[] signatureBytes = mac.doFinal(dataBytes);
return bytesToHex(signatureBytes);
}
// 计算sha256签名
public static String calculateHMACSHA256(String data, byte[] keyBytes) throws Exception {
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
byte[] dataBytes = data.getBytes();
byte[] signatureBytes = mac.doFinal(dataBytes);
return bytesToHex(signatureBytes);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
)

var (
devicePsk = "Re****Q=="
contentFmt = "DeviceName=%s&DeviceTimestamp=%d&ProductId=%s&ConnId=%s"
)

func main() {
fmt.Println(getSign("deviceName", "productId", "connId", 1693898532))
}

// 获取sha1签名
func getSha1Sign() string {
psk, _ := base64.StdEncoding.DecodeString(devicePsk)
var mac hash.Hash
mac = hmac.New(sha1.New, psk)
mac.Write([]byte(contentFmt))
result := mac.Sum(nil)
return hex.EncodeToString(result)
}

// 获取sha256签名
func getSha256Sign() string {
psk, _ := base64.StdEncoding.DecodeString(devicePsk)
var mac hash.Hash
mac = hmac.New(sha256.New, psk)
mac.Write([]byte(contentFmt))
result := mac.Sum(nil)
return hex.EncodeToString(result)
}
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>

const char *devicePsk = "Re5***==";
const char *contentFmt = "DeviceName=%s&DeviceTimestamp=%ld&ProductId=%s&ConnId=%s";

char *getSign(char *deviceName, char *productId, char *connId, long deviceTimestamp);

int main() {
printf("%s\\n", getSign("d1", "BRS**F", "9102344", 1693898532));
return 0;
}

char *getSign(char *deviceName, char *productId, char *connId, long deviceTimestamp) {
unsigned char psk[16];
int psk_len = EVP_DecodeBlock(psk, devicePsk, strlen(devicePsk));
printf("%s\\n", psk);
char content[256];
sprintf(content, contentFmt, deviceName, deviceTimestamp, productId, connId);
printf("%s\\n", content);
unsigned char result[20];
unsigned int result_len;
HMAC(EVP_sha1(), psk, psk_len, (unsigned char *) content, strlen(content), result, &result_len);
char *hexResult = malloc(result_len * 2 + 1);
for (int i = 0; i < result_len; i++) {
sprintf(hexResult + i * 2, "%02X", result[i]);
}
hexResult[result_len * 2] = '\\0';
return hexResult;
}

蓝牙和其他配网绑定签名

明文拼接格式:"%s%s;%s;%d",字段依次是ProductId、DeviceName、ConnId、DeviceTimestamp。
Java
Go
C
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AppBind {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
public static final String DEVICE_PSK = "4B****==";
public static final String PRODUCT_ID = "productId";
public static final String DEVICE_NAME = "d1";
public static final String CONN_ID = "12345";
public static final int TIMESTAMP = 1694141664;
public static final String ContentFormat = "%s%s;%s;%d"; // ProductId;DeviceName;ConnId;DeviceTimestamp
public static void main(String[] args) throws Exception {
String content = String.format(ContentFormat,PRODUCT_ID, DEVICE_NAME, CONN_ID, TIMESTAMP);
// sha1
System.out.println(calculateHMACSHA1(content, Base64.getDecoder().decode(DEVICE_PSK)));
// sha256
System.out.println(calculateHMACSHA256(content, Base64.getDecoder().decode(DEVICE_PSK)));
}
// 计算sha1签名
public static String calculateHMACSHA1(String data, byte[] keyBytes) throws Exception {
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] dataBytes = data.getBytes();
byte[] signatureBytes = mac.doFinal(dataBytes);
return bytesToHex(signatureBytes);
}
// 计算sha256签名
public static String calculateHMACSHA256(String data, byte[] keyBytes) throws Exception {
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
byte[] dataBytes = data.getBytes();
byte[] signatureBytes = mac.doFinal(dataBytes);
return bytesToHex(signatureBytes);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
)

var (
devicePsk = "Re****=="
ProductId = "productId"
DeviceName = "d1"
ConnId = "12345"
DeviceTimestamp int64 = 1694141664
contentFmt = fmt.Sprintf("%s%s;%s;%d", ProductId, DeviceName, ConnId, DeviceTimestamp) // ProductId;DeviceName;ConnId;DeviceTimestamp)
func main() {
fmt.Println(getSign())
}
func getSign() string {
psk, _ := base64.StdEncoding.DecodeString(devicePsk)
var mac hash.Hash
mac = hmac.New(sha1.New, psk)
mac.Write([]byte(contentFmt))
result := mac.Sum(nil)
return hex.EncodeToString(result)
}
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>

const char *devicePsk = "Re5***==";
const char *contentFmt = "%s%s;%s;%d"; // ProductId;DeviceName;ConnId;DeviceTimestamp

char *getSign(char *deviceName, char *productId, char *connId, long deviceTimestamp);

int main() {
printf("%s\\n", getSign("d1", "BRS**F", "9102344", 1693898532));
return 0;
}

char *getSign(char *deviceName, char *productId, char *connId, long deviceTimestamp) {
unsigned char psk[16];
int psk_len = EVP_DecodeBlock(psk, devicePsk, strlen(devicePsk));
printf("%s\\n", psk);
char content[256];
sprintf(content, contentFmt, productId, deviceName, connId, deviceTimestamp);
printf("%s\\n", content);
unsigned char result[20];
unsigned int result_len;
HMAC(EVP_sha1(), psk, psk_len, (unsigned char *) content, strlen(content), result, &result_len);
char *hexResult = malloc(result_len * 2 + 1);
for (int i = 0; i < result_len; i++) {
sprintf(hexResult + i * 2, "%02X", result[i]);
}
hexResult[result_len * 2] = '\\0';
return hexResult;
}5. 示例
默认 WIFI 配网绑定请求输入示例1:
POST https://iot.cloud.tencent.com/api/exploreropen/tokenapi HTTP/1.1
content-type: application/json
{
"DeviceTimestamp": 1694141664,
"Action": "AppSigBindDeviceInFamily",
"ConnId": "1938",
"RequestId": "dd7b-1014bc4-rey76",
"AccessToken": "51dbxxx4d4fdb",
"FamilyId": "f_8xxxxfb1a",
"Signature": "7CE3518***69EA8C",
"ProductId": "productId",
"RoomId": ""
"BindType": "wifi_sign",
"DeviceName": "d1"
}
默认 WIFI 配网绑定请求输入示例2:
POST https://iot.cloud.tencent.com/api/exploreropen/tokenapi HTTP/1.1
content-type: application/json
{
"DeviceTimestamp": 1694141664,
"Action": "AppSigBindDeviceInFamily",
"ConnId": "1938",
"RequestId": "dd7b-1014bc4-rey76",
"AccessToken": "51dbxxx4d4fdb",
"FamilyId": "f_8xxxxfb1a",
"Signature": "7CE3518***69EA8C",
"ProductId": "productId",
"RoomId": ""
"BindType": "wifi_sign",
"SignMethod":"hmacsha256",
"DeviceName": "d1"
}
默认蓝牙配网绑定请求输入示例3:
POST https://iot.cloud.tencent.com/api/exploreropen/tokenapi HTTP/1.1
content-type: application/json
{
"DeviceTimestamp": 1694141664,
"Action": "AppSigBindDeviceInFamily",
"ConnId": "1938",
"RequestId": "dd7b-1014bc4-rey76",
"AccessToken": "51dbxxx4d4fdb",
"FamilyId": "f_8xxxxfb1a",
"Signature": "7CE3518***69EA8C",
"ProductId": "productId",
"RoomId": ""
"BindType": "bluetooth_sign",
"DeviceName": "d1"
}
默认蓝牙配网绑定请求输入示例4:
POST https://iot.cloud.tencent.com/api/exploreropen/tokenapi HTTP/1.1
content-type: application/json
{
"DeviceTimestamp": 1694141664,
"Action": "AppSigBindDeviceInFamily",
"ConnId": "1938",
"RequestId": "dd7b-1014bc4-rey76",
"AccessToken": "51dbxxx4d4fdb",
"FamilyId": "f_8xxxxfb1a",
"Signature": "7CE3518***69EA8C",
"ProductId": "productId",
"RoomId": ""
"BindType": "bluetooth_sign",
"SignMethod":"hmacsha256",
"DeviceName": "d1"
}
输出示例: 成功。
{
"Response": {
"RequestId": "req_1",
"data": {
"AppDeviceInfo": {
"DeviceId" : "45454/d2",
"ProductId": "45454",
"DeviceName": "d2",
"AliasName": "",
"CreateTime": 1552910676,
"UpdateTIme": 1552910676,
"FamilyId": "1",
"RoomId": "0",
"IconUrl": ""
}
}
}
}

5. 错误码

错误码
描述
InternalError
内部错误。
InvalidParameterValue
参数取值错误。
InvalidParameterValue.BindDeviceNotConnected
设备近期没有连接到云。
InvalidParameterValue.InvalidAccessToken
Token 无效。