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"
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);// sha1System.out.println(calculateHMACSHA1(content, Base64.getDecoder().decode(DEVICE_PSK)));// sha256System.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.Hashmac = 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.Hashmac = 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。
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;DeviceTimestamppublic static void main(String[] args) throws Exception {String content = String.format(ContentFormat,PRODUCT_ID, DEVICE_NAME, CONN_ID, TIMESTAMP);// sha1System.out.println(calculateHMACSHA1(content, Base64.getDecoder().decode(DEVICE_PSK)));// sha256System.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 = 1694141664contentFmt = 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.Hashmac = 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;DeviceTimestampchar *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.1content-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.1content-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.1content-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.1content-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 无效。 |