# 5. 接口文档(v2)
# 5.1 通用说明
# 5.1.1 请求域名
线上请求域名:https://api-prod.smartmidea.net
# 5.1.2 请求说明
请求ID说明:请求ID长度为32位,由数字和字母组成,不能带有#和*等特殊字符
# 5.1.3 返回说明
接口返回值说明: 授权相关接口遵循标准OAuth 2.0授权规范,所有请求返回遵循HTTP请求状态的Http状态编码,在HTTP Status Code不为200的时候才返回相对应的错误提示
HTTP状态码说明:
HTTP Status Code | 描述 |
---|---|
200 | OK |
409 | 业务异常 |
4xx | 请求错误,参考http请求返回标准状态码 |
500 | 服务器异常 |
返回结果:
字段 | 类型 | 说明 |
---|---|---|
error | String | 错误码 |
error_description | String | 错误提示 |
返回示例:
{
"error": "1000",
"error_description": "system error"
}
# 5.2 授权相关
# 5.2.1 获取授权页
接口说明: 根据颁发的clientId返回相应的授权登录页面,获取美居标准授权需要用OAuth2授权方式,目前只支持response_type=code
请求协议: HTTPS
请求方式: GET
请求地址: /v2/open/oauth2/authorize
参数格式: query 参数
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
client_id | true | String | 唯一的第三方开发者ID |
state | true | String | 请求授权方的校验字段,授权服务透传原值返回 |
response_type | true | String | 授权类型 code - 授权码方式 |
redirect_uri | true | String | 重定向 URI,需要与应用创建时回调url保持一致 |
请求示例:
/v2/open/oauth2/authorize?client_id=client_id********************1234&state=1&response_type=code&redirect_uri=************************
返回结果:
返回登录页面,让用户输入用户名、密码
返回示例:
登录返回uri示例:
redirect_uri?code=h4GJTCPEb***********************&state=1
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1009 | 开发者账号不存在 |
1100 | 短信验证码不合法 |
# 5.2.2 获取令牌
接口说明: 该接口获取或刷新AccessToken,如需要做消息订阅,则调用此接口获取令牌后必须调用文档2.1接口做用户绑定
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/oauth2/token
参数格式: body 参数
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
client_id | true | String | 唯一的第三方开发者ID |
client_secret | true | String | 第三方开发者密钥 |
grant_type | false | String | 使用的授权模式,获取/刷新AccessToken分别传值如下。 获取:authorization_code 刷新:refresh_token |
code | false | String | 文档1.1接口调用后返回的授权码,grant_type为authorization_code时需要 |
refresh_token | false | String | 上一步获得的refresh_token,grant_type为refresh_token时需要 |
请求示例:
{
"client_id": "client_id********************1234",
"client_secret": "client_secret******************abcd",
"grant_type": "authorization_code",
"code": "code******************abcd"
}
{
"client_id": "client_id********************1234",
"client_secret": "client_secret******************abcd",
"grant_type": "refresh_token",
"refresh_token": "refresh_token****************abcdd"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
access_token | String | 访问令牌 |
expires_in | Integer | 访问令牌有效期,目前有效期为24小时 单位:秒 |
refresh_token | String | 刷新令牌 |
token_type | String | 令牌类型,目前只支持bearer类型 |
返回示例:
{
"access_token": "access_token***************1234",
"expires_in": 7200,
"refresh_token": "refresh_token****************abcd",
"token_type": "bearer"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | redirect_uri解析失败 |
1002 | 参数非法 |
1003 | 服务返回解析失败 |
1004 | 服务调用失败 |
2001 | 非法开发者 |
2003 | 授权过程失败 |
# 5.3 用户相关
# 5.3.1 用户绑定
接口说明: 第三方提供给美的授权凭证与绑定用户,如需要做消息订阅,则此接口必须调用
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/user/accept
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
type | false | String | 授权类型,授权码授权为:OAuth2.AuthorizationCode,客户端授权为:OAuth2.ClientCredentials,不授权为空,为空则不会提前获取令牌 |
thirdUid | true | String | 第三方开放用户唯一标识 |
code | false | String | 授权码,type为OAuth2.AuthorizationCode时需要传 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"type": "0",
"thirdUid": "cc225bbb3540f99dedef91eddd789609",
"code": "code******************abcd"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
openUid | String | 用户ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"openUid": "b3540cc225bbf99dd789609edef91edd"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
2001 | 非法开发者 |
2005 | 三方刷新令牌过期,无法刷新访问令牌 |
2006 | 无法从三方云平台获取oauth2令牌 |
# 5.3.2 获取用户基本信息
接口说明: 获取美居开放的用户信息以及家庭信息
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/user/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
openUid | String | 美的用户ID |
userName | String | 用户名称 |
homegroupList | List | 用户创建的家庭列表(不包含加入的家庭) |
homegroupId | Long | 用户创建的家庭ID |
homegroupName | String | 用户创建的家庭名字 |
返回示例:
{
"openUid": "b3540cc225bbf99dd789609edef91edd",
"userName": "小明",
"homegroupList": [{
"homegroupId": 3121311,
"homegroupName": "我的家1"
}, {
"homegroupId": 3121312,
"homegroupName": "我的家2"
}]
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
2001 | 非法开发者 |
# 5.3.3 用户取消授权
接口说明: 取消当前access token的授权
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/user/cancel
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
thirdUid | false | String | 第三方开放用户唯一标识,文档2.1交换双方用户标识传入的thirdUid,如调用文档2.1用户绑定接口则此项必传 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"thirdUid": "b3540cc225bbf99dd789609edef91edd",
"stamp": "20181201160518000"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId": "b3540cc225bbf99dd789609edef91edd"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
2001 | 非法开发者 |
2003 | 取消授权过程失败 |
# 5.4 设备配网及确权
# 5.4.1 设备配网指引
接口说明: 该接口用于获取设备的配网指引信息
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/connect/guide/info
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
enterprise | true | String | 企业码,如果接入的是美的牌,则为0000,其他企业码请联系对接人 |
type | true | String | 设备品类(格式如AC) |
sn8 | true | String | 设备型号 |
modelNumber | false | String | 特殊设备型号(A0),如果存在则必传 |
mode | true | String | 配网模式 (0:AP,1:快连,2:声波,3:蓝牙,4:零配,5:WIFI,6:ZigBee) |
请求示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "1593740640770",
"enterprise": "0000",
"type": "AC",
"sn8": "010A0307",
"modelNumber":"1",
"mode":"0"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
id | String | 指引记录Id |
enterprise | String | 企业码 |
type | String | 设备品类(格式如AC) |
modelCode | String | 设备型号(SN8)或特殊设备型号(A0)的值 |
modelType | String | modelCode类型 0:A0设备型号(SN8),1:特殊设备型号(A0)的值 |
mode | String | 配网模式 (0:AP,1:快连,2:声波,3:蓝牙,4:零配,5:WIFI,6:ZigBee) |
wifiFrequencyBand | String | WIFI频段:1:2.4G,2:2.4G/5G |
isAutoConnect | String | 上电默认连接模式(0 不启动,1 AP,2 WIFI零配) |
mainConnectTypeUrlList | JSONArray | 主配网图列表 |
mainConnectTypeDesc | String | 配网介绍 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"id": "204",
"enterprise": "0000",
"type": "CA",
"modelCode": "010A0307",
"modelType": "0",
"mode": "0",
"wifiFrequencyBand": "1",
"isAutoConnect": "0",
"mainConnectTypeUrlList": [
"http://fcmms.midea.com/zhiyin_new/6be6fbe5032768fc885956cc877418e3.png",
"http://fcmms.midea.com/zhiyin_new/5ffa25acd859baeabc4e6e70b266187d.jpg"
],
"mainConnectTypeDesc": "① 查看显示板是否已经“解锁”,若已经解锁执行第2步。在锁定状态,长按“锁定/解锁”按键3秒,解锁显示板 \r\n② 长按“智能”按键5秒,直至显示板显示“AP”或“WiFi模块恢复出厂设置”字样 \r\n③ 长按“锁定/解锁”按键3秒,锁定显示板,锁定时冰箱进入配置模式"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | 服务返回解析失败 |
1004 | 服务调用失败 |
# 5.4.2 设备后确权
后确权方案说明
交互逻辑说明:
部分美的设备的模组上电后默认进入配网模式,配网绑定后需要手动进行后确权操作后,才能对设备进行远程控制。后确权逻辑设计如下:
1、用户配网绑定设备成功后,应先查询设备是否支持后确权以及当前的后确权状态
2、若设备支持后确权,且当前未确权,则需要下发指令给设备模组,让其进入待确权状态
3、此时向用户提示确权操作(线下提供后确权文档)
4、用户按照指引完成设备操作,确权结束
5、设备模组记住确权状态,直至下次重新配网
注意:设备进入待确权状态后,需要在60s内完成确权动作,否则设备会退出待确权状态,重新进入未确权状态。
交互时序图:
规范要求:
综合考虑到设备性能及接口安全性,特规定如下规则:
1、调用文档3.2.2接口返回成功前为第一阶段,调用文档3.2.3接口返回成功前后为第二阶段,第二阶段允许文档3.2.3接口轮询调用
2、在进行相关确权动作之前(第一阶段)需要先明确设备处于未确权状态(返回值为2)后才进行后确权相关接口调用,明确设备确权状态可考虑通过调用文档3.2.3接口进行查询,但该接口此阶段在调用并成功返回的情况下只允许调用一次,如果有失败的情况最多重试不超过3次
3、在调用文档3.2.2接口并收到成功返回后(第二阶段)才允许开始轮询调用文档3.2.3接口进行实时确权状态查询
4、轮询调用文档3.2.3接口(第二阶段)时频率为每5秒一次,即每一次请求成功或失败后5秒才重新发起请求
5、轮询调用文档3.2.3接口(第二阶段)时总次数不超过12次
(1)设备确权指引
接口说明: 该接口用于获取设备的确权指引信息
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/appliance/auth/guide/info
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
enterprise | true | String | 企业码 |
type | true | String | 设备品类 |
sn8 | false | String | 设备型号。sn8和modelNumber两者至少传其一 |
modelNumber | false | String | 特殊设备型号(A0)。sn8和modelNumber两者至少传其一 |
请求示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "1593740640770",
"enterprise": "0000",
"type": "AC",
"sn8": "010A0307",
"modelNumber":"1"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
id | String | 指引记录Id |
enterprise | String | 企业码 |
type | String | 设备品类(格式如AC) |
modelCode | String | 设备型号(SN8)或特殊设备型号(A0)的值 |
modelType | String | modelCode类型 0:A0设备型号(SN8),1:特殊设备型号(A0)的值 |
confirmImgUrl | String | 确权指引图片地址 |
confirmDesc | String | 确权指引文案 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"id": "204",
"enterprise": "0000",
"type": "CA",
"modelCode": "010A0307",
"modelType": "0",
"confirmDesc": "长按“WIFI键”5秒,听到“滴”的一声表示验证成功。",
"confirmImgUrl": "http://oss-cn-foshan.midea.com:17480/userDownload/3348D039BD4B470E8182F486A54F348F/dcpprod/86d98b0b7c6940c286883e986691ff85"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | 服务返回解析失败 |
1004 | 服务调用失败 |
# 3.2.2 设备确权
接口说明: 该接口用于支持后确权的设备,使用这个接口让设备进入待确权状态,设备进入待确权状态后,用户在设备上确权
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/appliance/auth/confirm
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID |
请求示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "1593740640770",
"applianceCode":"17592186044420"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | 服务返回解析失败 |
1004 | 服务调用失败 |
1105 | 账户不存在 |
1300 | 设备不存在 |
1304 | 设备不属于此用户 |
1305 | 用户不是设备的管理员 |
1306 | 设备超时没响应 |
1307 | 设备离线 |
1393 | 异常,无法切换 |
# 3.2.3 确权状态查询
接口说明: 该接口用于获取设备确权状态
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/appliance/auth/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID |
请求示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "1593740640770",
"applianceCode":"17592186044420"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
status | Integer | 设备确权状态值 0 已确权 1 待确权 2 未确权 3 不支持确权 |
返回示例:
{
"status":1
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | 服务返回解析失败 |
1004 | 服务调用失败 |
1105 | 账户不存在 |
1300 | 设备不存在 |
1304 | 设备不属于此用户 |
1305 | 用户不是设备的管理员 |
1306 | 设备超时没响应 |
1307 | 设备离线 |
1394 | 获取授权状态出错(支持确权的情况下查询状态出错) |
# 5.4.3 获取ADS动态路由地址
接口说明: 该接口用于获取ADS动态路由相关信息,ADS(appliance domain_name service) ,用于提供给设备获取有效登录接入层的域名等信息。接入新版配网SDK需要接入该接口。
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/connect/ads
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求体:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
字段 | 类型 | 说明 |
reqId | String | 请求ID |
adsId | String | ADS集群ID,十进制 |
adsDomain | String | 域名 |
adsPort | int | 端口 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"adsId": "65793",
"adsDomain": "ads.smartmidea.net",
"adsPort": 28850
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
# 5.5 设备控制相关
# 5.5.1 获取设备列表
接口说明: 该接口用于获取用户名下的设备列表
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/list/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
homegroupId | false | String | 家庭ID,传入查询指定家庭下的设备 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
applianceList | JSONArray | 设备列表 |
sn8 | String | 设备型号 |
modelNumber | String | 特殊设备型号(A0) |
applianceCode | String | 设备虚拟ID,用于设备相关操作 |
type | String | 设备类型 |
name | String | 设备名称 |
onlineStatus | String | 设备在线状态,1为在线,0为离线 |
enterprise | String | 设备企业码 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"applianceList": [{
"applianceCode": "17592186044420",
"type": "0xAC",
"name": "客厅空调",
"sn8": "1",
"modelNumber": "",
"onlineStatus": "1",
"enterprise": "0000"
}]
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1105 | 用户不存在 |
2001 | 非法开发者 |
# 5.5.2 获取设备信息
接口说明: 该接口用于获取用户名指定设备信息
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/info/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本号,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"applianceCode": "1099511629543"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
sn8 | String | 设备型号 |
modelNumber | String | 特殊设备型号(A0) |
applianceCode | String | 设备虚拟ID,用于设备相关操作 |
type | List | 设备类型 |
name | String | 设备名称 |
enterprise | String | 设备企业码 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"applianceCode": "17592186044420",
"type": "0xAC",
"name": "客厅空调",
"sn8": "1",
"modelNumber": "",
"enterprise": "0000"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
2001 | 非法开发者 |
2012 | 静态密钥错误 |
# 5.5.3 绑定设备
接口说明: 该接口用于绑定设备,需要结合美居配网用的OpenSDK,返回reqId则接口调用成功
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/bind
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
bindType | false | String | 绑定类型,默认AP配网可不传,例如大屏扫码的类型为qrcode |
qrcodeToken | false | String | 扫描的二维码字符串,bindType为qrcode时必传 |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
verificationCode | false | String | 验证码,bindType不传或者为ap时必传 |
procotolVersion | false | String | 【固件版本号】 对应 Android/iOS AP配网返回的参数【设备协议版本号】 |
applianceType | false | String | 【品类码】 对应Android/iOS AP配网返回的参数deviceTpye【设备品类】 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"applianceCode": "17592186044420",
"verificationCode": "000100"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 二维码或家电类型格式错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1011 | 设备标识解密失败 |
1105 | 用户不存在 |
1200 | 该用户不属于设备所在家庭组 |
1202 | 不是家庭的主人 |
1212 | 房间不属于家庭(如果指定了房间) |
1300 | 设备不存在 |
1301 | 验证码验证失败 |
1307 | 设备离线 |
1309 | 家电型号不存在 |
1322 | 缓存中未获取到设备标识 |
1360 | 设备注册的绑定消息不存在 |
1361 | 设备的随机码的补充字段和设备标识不匹配 |
1383 | 绑定超时(设备连接上云端到绑定操作时间间隔不能大于60s) |
1384 | 校验码错误 |
1501 | 家电家庭组超过最大上限(150) |
2001 | 非法开发者 |
2014 | 此设备不支持绑定 |
# 5.5.4 解绑设备
接口说明: 该接口用于解绑设备,返回reqId则接口调用成功
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/unbind
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"applianceCode": "17592186044420"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1105 | 用户不存在 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
2001 | 非法开发者 |
# 5.5.5 控制设备
接口说明: 该接口用于发送控制设备指令至设备
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/control
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
command | true | String | 设备控制命令,内容需要进行转义 示例:"{\"control\":{\"power\":\"on\"}}" 注:control为控制设备指令,格式为JSON字符串,具体指令请联系不同品类对接人 |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"applianceCode":"1099511833333",
"command":"{\"control\":{\"power\":\"off\"}}"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
status | Object | 设备状态返回值 |
返回示例:
{
"status":{
"show_h":"off",
"single_wash":"off",
"efficient":"off",
"passwater_lowbyte":0,
"winter":"off",
"screen_off":"off",
"cur_rate":0,
"ali_manager":"off",
"mom_wash":"off",
"baby_wash":"off",
"appoint_power":"off",
"error_code":0,
"scroll_hot":"off",
"elec_warning":"off",
"sensor_error":"off",
"sleep":"off",
"end_time_minute":26,
"frequency_hot":"off",
"big_water":"off",
"top_temp":26,
"safe":"off",
"mode":"none",
"ti_protect":"off",
"appoint_wash":"off",
"wash":"off",
"need_discharge":"off",
"cloud":"off",
"sterilization":"off",
"fast_hot_power":"off",
"warm_power":"off",
"protect_show":"off",
"sterilize_high_temp":"off",
"always_fell":"off",
"power":"off",
"wash_with_temp":"off",
"cur_temperature":26,
"temperature":50,
"heat":"whole",
"memory":"off",
"flow":0,
"bath_person":"off",
"two_egg":"off",
"version":25,
"ele_exception":"off",
"door_status":"off",
"bash_end":"0",
"communication_error":"off",
"sound_dad":"off",
"get_temp":"off",
"smart_sterilize":"off",
"cloud_appoint":"off",
"one_egg":"off",
"people_wash":"off",
"limit_error":"off",
"night":"off",
"whole_heat":"on",
"wash_temperature":0,
"machine":"real_machine",
"top_heat":"off",
"protect":"off",
"grea":0,
"scene":"off",
"music":"off",
"t_hot":"off",
"summer":"off",
"waterday_highbyte":0,
"bottom_heat":"on",
"scene_id":0,
"fast_wash":"off",
"dad_wash":"off",
"clean":"off",
"auto_off":"off",
"rate":0,
"sterilize_left_days":157,
"water_quality":0,
"water_flow":"off",
"volume":50,
"mg_remain":0,
"get_time":"off",
"midea_manager":"on",
"water_cyclic":"off",
"discharge_left_time":0,
"shower":"off",
"negative_ions":"off",
"end_time_hour":0,
"half_heat":"off",
"discharge_status":0,
"bath":"off",
"func_select":"low",
"type_select":"normal",
"bottom_temp":"off",
"hot_power":"on",
"heat_water_level":0,
"water_system":0,
"tech_water":"off",
"in_temperature":0,
"eplus":"off",
"uv_sterilize":"off",
"now_wash":"on",
"waterday_lowbyte":0,
"passwater_highbyte":0
},
"code":"0",
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.5.6 查询设备
接口说明: 该接口用于查询设备状态
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/status/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID |
command | true | String | 设备查询,可查询全状态 示例:"{"query":{}}" 注:query为查询设备指令,格式为JSON字符串,具体属性请联系不同品类对接人 |
请求示例:
{
"reqId":"8ev6pxru-cny4-cny4-cny4-x80jvf46nidg",
"stamp":"202103161750",
"applianceCode":"1099511833333",
"command":"{\"query\":{}}"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
status | Object | 设备状态返回值 |
返回示例:
{
"status":{
"show_h":"off",
"single_wash":"off",
"efficient":"off",
"passwater_lowbyte":0,
"winter":"off",
"screen_off":"off",
"cur_rate":0,
"ali_manager":"off",
"mom_wash":"off",
"baby_wash":"off",
"appoint_power":"off",
"error_code":0,
"scroll_hot":"off",
"elec_warning":"off",
"sensor_error":"off",
"sleep":"off",
"end_time_minute":27,
"frequency_hot":"off",
"big_water":"off",
"top_temp":25,
"safe":"off",
"mode":"none",
"ti_protect":"off",
"appoint_wash":"off",
"wash":"off",
"need_discharge":"off",
"cloud":"off",
"sterilization":"off",
"fast_hot_power":"off",
"warm_power":"off",
"protect_show":"off",
"sterilize_high_temp":"off",
"always_fell":"off",
"power":"on",
"wash_with_temp":"off",
"cur_temperature":25,
"temperature":50,
"heat":"whole",
"memory":"off",
"flow":0,
"bath_person":"off",
"two_egg":"off",
"version":25,
"ele_exception":"off",
"door_status":"off",
"bash_end":"0",
"communication_error":"off",
"sound_dad":"off",
"get_temp":"off",
"smart_sterilize":"off",
"cloud_appoint":"off",
"one_egg":"off",
"people_wash":"off",
"limit_error":"off",
"night":"off",
"whole_heat":"on",
"wash_temperature":0,
"machine":"real_machine",
"top_heat":"off",
"protect":"off",
"grea":0,
"scene":"off",
"music":"off",
"t_hot":"off",
"summer":"off",
"waterday_highbyte":0,
"bottom_heat":"on",
"scene_id":0,
"fast_wash":"off",
"dad_wash":"off",
"clean":"off",
"auto_off":"off",
"rate":0,
"sterilize_left_days":157,
"water_quality":0,
"water_flow":"off",
"volume":50,
"mg_remain":0,
"get_time":"off",
"midea_manager":"on",
"water_cyclic":"off",
"discharge_left_time":0,
"shower":"off",
"negative_ions":"off",
"end_time_hour":0,
"half_heat":"off",
"discharge_status":0,
"bath":"off",
"func_select":"low",
"type_select":"normal",
"bottom_temp":"off",
"hot_power":"on",
"heat_water_level":0,
"water_system":0,
"tech_water":"off",
"in_temperature":0,
"eplus":"off",
"uv_sterilize":"off",
"now_wash":"on",
"waterday_lowbyte":0,
"passwater_highbyte":0
},
"code":"0",
"reqId":"8ev6pxru-cny4-cny4-cny4-x80jvf46nidg"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.6 设备通知相关
# 5.6.1 设备订阅
接口说明: 设备订阅接口,被订阅的设备才会有消息通知,返回reqId则接口调用成功
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/subscribe
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,以英文分号分隔开 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"applianceCode": "17592186044420;1099511824211;1099511824212"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1300 | 设备不存在 |
# 5.6.2 取消设备订阅
接口说明: 取消设备订阅,取消后第三方不会再收到这些设备的通知,返回reqId则接口调用成功
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/device/subscribe/cancel
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,以英文分号分隔开 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"applianceCode": "17592186044420;1099511824211;1099511824212"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1300 | 设备不存在 |
# 5.6.5 消息通知
接口说明: 此接口由第三方定义及实现,由美的云调用,用于通知设备订阅信息,接口鉴权方式由第三方定义,通知内容基于下面请求体定义
请求协议: HTTPS
请求方式: POST
请求地址: 由第三方定义,并提前注册到美的IoT开发者平台(申请开发者ID时)
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
clientId | true | String | 唯一的第三方开发者ID |
signature | true | String | 签名摘要,签名方式请参照附录 |
Authorization | false | String | 设备订阅通知授权模式选择授权码授权或客户端授权时会传 Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
header | true | Object | 请求体头部 |
namespace | true | String | 通知事件类型 ApplianceBind - 设备绑定 ApplianceUnbind - 设备解绑 ApplianceState - 设备状态 |
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
openUid | true | String | 用户ID |
payload | true | Object | 请求体负载,不同namespace时内容不同,下列示例中分别说明 |
设备绑定通知payload内容及示例:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
appliance | true | Object | 设备实体 |
name | true | String | 设备名称 |
type | true | String | 设备类型 |
applianceCode | true | String | 设备虚拟ID |
modelNumber | true | String | 特殊设备型号(A0) |
{
"header": {
"namespace": "ApplianceBind",
"reqId": "1",
"stamp": "201902251110111",
"openUid": "123"
},
"payload": {
"appliance": {
"name": "空调A",
"type": "0xAC",
"applianceCode": "1099511824210",
"modelNumber": "1"
}
}
}
设备解绑通知payload内容及示例:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
applianceCode | true | String | 设备虚拟ID |
{
"header": {
"namespace": "ApplianceUnbind",
"reqId": "1",
"stamp": "201902251110111",
"openUid": "123"
},
"payload": {
"applianceCode":"1099511824210"
}
}
设备状态通知payload内容及示例:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
onlineStatus | true | String | 设备在线状态,0代表离线,1代表在线 |
applianceCode | true | String | 设备虚拟ID |
status | true | Object | 设备状态 |
设备离线通知:
{
"header": {
"namespace": "ApplianceState",
"openUid": "37310c0fa4c179b20b897c4f8c109fdc",
"reqId": "75fc02e9ce59baf8365ba5f1abb46f4a",
"stamp": "1599190860000"
},
"payload": {
"onlineStatus": "0",
"applianceCode": 70368744268027,
"status": { }
}
}
设备上线通知:
{
"header": {
"namespace": "ApplianceState",
"openUid": "37310c0fa4c179b20b897c4f8c109fdc",
"reqId": "75fc02e9ce59baf8365ba5f1abb46f4b",
"stamp": "1599190960147"
},
"payload": {
"onlineStatus": "1",
"applianceCode": 70368744268027,
"status": { }
}
}
设备变化通知:
{
"header": {
"namespace": "ApplianceState",
"reqId": "1",
"stamp": "201902251110111",
"openUid": "123"
},
"payload": {
"onlineStatus":"1",
"applianceCode":"1099511824210",
"status": {
"power": "on",
"light": "off",
"dry": "on"
}
}
}
返回结果:
美的IoT开发者平台不处理
# 5.7 场景相关
# 5.7.1 获取场景列表
接口说明: 获取美居家庭下的一键场景列表
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/scene/item/list
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
homegroupId | true | String | 家庭ID,从用户信息接口中选择 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"homegroupId": "12099672"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
sceneList | List | 场景列表 |
sceneId | String | 场景ID |
sceneType | String | 场景类型 2 - 一键场景 注:目前云云对接只返回一键场景数据 |
sceneName | String | 场景名称 |
enable | String | 场景是否禁用 0 - 禁用 1 - 启用 |
homegroupId | String | 家庭ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"sceneList": [{
"sceneId": "4512121",
"sceneType": "2",
"sceneName": "回家",
"enable": "1",
"homegroupId": "12099672"
}]
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | sceneType,homegroupId类型转化异常 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1200 | 该用户不属于设备所在家庭组 |
2001 | 非法开发者 |
# 5.7.2 获取场景详情
接口说明: 获取美居家庭下的一键场景详情
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/scene/item/get
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
sceneId | true | String | 场景ID,从场景列表接口中选择 |
homegroupId | true | String | 家庭ID,从用户信息接口中选择 |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"sceneId": "4512121",
"homegroupId": "12099672"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
sceneId | String | 场景ID |
sceneName | String | 场景名称 |
enable | String | 场景是否禁用 0 - 禁用 1 - 启用 |
homegroupId | String | 家庭ID |
applianceList | List | 设备列表 |
applianceCode | String | 设备虚拟ID |
applianceName | String | 设备名称 |
applianceType | String | 设备类型 |
command | JSONObject | 设备执行动作 |
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"sceneId": "4512121",
"sceneName": "回家",
"enable": "1",
"applianceList": [{
"applianceCode": "4565215",
"applianceType": "0xAC",
"applianceName": "空调",
"command": {
"mode": "auto",
"power": "on"
}
}]
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | sceneType,homegroupId,sceneId类型转化异常 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1200 | 该用户不属于设备所在家庭组 |
1700 | 该用户没有操作权限 |
1701 | 场景不存在 |
2001 | 非法开发者 |
# 5.7.3 执行场景
接口说明: 执行场景
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/scene/item/execute
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
homegroupId | true | String | 家庭ID,从用户信息接口中选择 |
sceneId | true | String | 场景ID |
请求示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"stamp": "20181201160518000",
"homegroupId": "12099672",
"sceneId": "4512121"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
reqId | String | 请求ID |
resultId | String | 执行记录ID |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"resultId": "5746727"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | homegroupId,sceneId类型转化异常 |
1002 | 参数非法 |
1003 | ClientId校验失败或服务返回解析失败 |
1004 | 服务调用失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1200 | 该用户不属于设备所在家庭组 |
1202 | 非主人无法操作 |
1300 | 设备不存在 |
1700 | 该用户没有操作权限 |
1701 | 场景不存在 |
1702 | 该场景未启用 |
1704 | 此场景不做推送 |
2001 | 非法开发者 |
# 5.8 物模型相关
# 5.8.1 操作(action)调用
接口说明: 触发物模型定义的action,从而控制设备
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/action
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
moduleCode | true | String | 物模型模块编码 |
actionCode | true | String | 物模型动作编码 |
action | true | Object | 说明: 1、JSON格式的对象类型,单层结构参数 2、由调用的物模型Action中定义的input为准,且接口会对其类型进行校验,因此送入的JSON参数必须符合入参定义(包括参数名、类型、约束范围),具体请联系不同品类对接人 3、如果物模型的入参定义有默认值,则可以不送入参数,接口会将默认使用默认值 |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"applianceCode":"1099511833333",
"moduleCode":"fans",
"actionCode":"power",
"action": {
"power": true
}
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
requestId | String | 请求ID |
code | String | 接口响应码 |
data | Object | 物模型定义的返回结果 |
返回示例:
{
"requestId": "t11122233344",
"code": "0",
"data": {
"prop1": "aaa",
"prop2": "bbb",
"prop3": "ccc"
}
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.8.2 属性(property)查询
接口说明: 用于查询设备的属性,可指定查询属性名称,不指定则返回错误
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/properties
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
properties | true | Array | 说明: 1、模块和参数之间展开表示,以简化数据结构,模块和属性之间使用“.”号进行分隔 2、如果只输入模块编码,则查询此模块下所有属性 3、仅支持物模型中op参数包含read属性的查询 |
disablePropIntegrityCheck | false | boolean | 禁用完整性校验,属性查询时,若设备返回属性存在缺失,将忽略此异常,并将其余属性返回,不传默认false |
disablePropLegalityCheck | false | boolean | 禁用合法性校验,属性查询时,若设备返回属性与物模型中定义不一致,将忽略此异常,返回原始值,不传默认false |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"applianceCode":"1099511833333",
"properties": [
"module1.prop1", //模块module1的prop1
"module1.prop2", //模块module1的prop2
"module2", //模块module2的所有属性
...
]
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
requestId | String | 请求ID |
code | String | 接口响应码 |
data | Object | 说明: 1、响应的参数也是展开格式,符合请求入参规范,所有响应参数符合物模型中属性的定义 2、对于查询模块所有属性的,默认展开并填充所有的属性结果 3、查询全部属性的也使用模块所有属性的相同规则 |
返回示例:
{
"requestId": "t1112223334445",
"code":"0",
"data": {
"fan.power": "true",
"fan.workMode": "natural",
"fan.speedLevel": "level3",
"fan.swingType": "leftRight",
"schdeule.timer": "50 7 * * *"
}
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.8.3 属性(property)批量查询
接口说明: 用于批量查询设备的属性,可指定查询属性名称,不指定则返回错误
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/batch/properties
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
properties | true | Array | 批量查询设备的数组,一次请求查询设备数量不超过20 |
props | true | Array | 说明: 1、模块和参数之间展开表示,以简化数据结构,模块和属性之间使用“.”号进行分隔 2、如果只输入模块编码,则查询此模块下所有属性 3、仅支持物模型中op参数包含read属性的查询 |
disablePropIntegrityCheck | false | boolean | 禁用完整性校验,属性查询时,若设备返回属性存在缺失,将忽略此异常,并将其余属性返回,不传默认false |
disablePropLegalityCheck | false | boolean | 禁用合法性校验,属性查询时,若设备返回属性与物模型中定义不一致,将忽略此异常,返回原始值,不传默认false |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"properties": [
{
"applianceCode": 1001,
"props": [
"module1.prop1", //模块module1的prop1
"module1.prop2", //模块module1的prop2
"module2" //模块module2的所有属性
],
"disablePropIntegrityCheck": true,
"disablePropLegalityCheck": true
},
{
"applianceCode": 1002,
"props": [
"module1.prop1", //模块module1的prop1
"module1.prop2", //模块module1的prop2
"module2" //模块module2的所有属性
]
}
]
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
requestId | String | 请求ID |
code | String | 接口响应码 |
data | Object | 说明: 1、响应的参数也是展开格式,符合请求入参规范,所有响应参数符合物模型中属性的定义 2、对于查询模块所有属性的,默认展开并填充所有的属性结果 3、查询全部属性的也使用模块所有属性的相同规则 |
返回示例:
{
"requestId": "xxxxx",
"code": "0",
"data": [
{
"code": "0",
"applianceCode": 1001,
"data": {
"module1.prop1": "value1",
"module1.prop2": "value2",
"module2.prop1": "value3",
"module2.prop2": "value4",
"module2.prop3": "value5"
}
},
{
"code": "12345",
"applianceCode": 1002,
"msg": "error msg"
}
]
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.8.4 全属性(properties)查询
接口说明: 用于查询设备的所有属性
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/entire/properties
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"applianceCode":"123456"
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
requestId | String | 请求ID |
code | String | 接口响应码 |
data | Object | 说明: 1、响应的参数也是展开格式,符合请求入参规范,所有响应参数符合物模型中属性的定义 2、模块所有属性默认展开并填充所有的属性结果 |
返回示例:
{
"requestId": "xxxxx",
"code": "0",
"data": {
"module1.prop1": "value1",
"module1.prop2": "value2",
"module2.prop1": "value3",
"module2.prop2": "value4",
"module2.prop3": "value5"
}
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.8.5 属性(properties)设置
接口说明: 用于设置设备属性
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/properties/modify
参数格式: body 参数
请求头:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
Authorization | true | String | Bearer开头的访问令牌 例如:Bearer 0lemRvfLicjkHtno8r6wolAq8V7oLGe6 |
ClientId | true | String | 唯一的第三方开发者ID |
SignatureVersion | true | String | 签名版本,默认值为2.0 |
Signature | true | String | 签名摘要,签名方式请参照附录 |
请求参数:
字段 | 必选 | 类型 | 说明 |
---|---|---|---|
reqId | true | String | 请求ID |
stamp | true | String | 请求时间戳,毫秒级区分 |
applianceCode | true | String | 设备虚拟ID,用于设备相关操作 |
properties | true | Object | 说明: 1、模块和参数之间展开表示,以简化数据结构,模块和属性之间使用“.”号进行分隔 2、仅支持物模型属性的op定义中包含“write”枚举的属性 3、属性值需要符合物模型中的类型定义及约束 |
请求示例:
{
"reqId":"c1pebi7h-zslx-zslx-zslx-iar8loygqjt7",
"stamp":"202103161750",
"applianceCode":"123456",
"properties":{
"module1.prop1": "value1", //设置模块module1的prop1属性
"module1.prop2": "value1", //设置模块module1的prop2属性
"module2.prop3": "value1" //设置模块module2的prop3属性
}
}
返回结果:
字段 | 类型 | 说明 |
---|---|---|
requestId | String | 请求ID |
code | String | 接口响应码 |
data | Object | 说明: 1、响应的参数也是展开格式,符合请求入参规范,响应仅包含是否成功 2、响应的属性与请求交互的一致 |
返回示例:
{
"requestId": "xxxxx",
"code": "0",
"data": "success"
}
错误码说明:
error | 说明 |
---|---|
1000 | 未知系统错误 |
1001 | 指令格式化错误 |
1002 | 参数非法 |
1003 | ClientId校验失败 |
1006 | 签名或用户验证失败 |
1009 | 开发者账号不存在 |
1014 | lua脚本内部转换错误 |
1200 | 该用户不属于设备所在家庭组 |
1300 | 设备不存在 |
1305 | 该设备不属于该用户 |
1307 | 设备离线 |
1321 | 设备未确权 |
# 5.9 签名摘要规则说明
(1)说明
为保证消息的完整性,防止消息在途中被第三方修改。在请求的参数中增加一个sign参数作为信息摘要值。服务器端与手机端用相同的规则生成sign值,服务器端接收到请求后对比sign值是否正确,如果正确才处理请求,否则视为非法请求。
(2)生成摘要原串
请求信息摘要(即sign值)生成规则:
摘要原串B = Http Method(如POST)+请求URI串(去除URL串host部分,如:/v2/open/device/list/get)+ URL请求参数QueryString + 请求消息体bodyBytes的字符串(utf-8编码)
比如(仅作示例,与原接口请求参数不同):
POST /v2/open/device/list/get?client_id=f6f1ec55481b5dc314bd6555e4d3d3bb×tamp=1556193552988 HTTP/1.1
Host: xx.com
Content-Type: **/*
{"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01","applianceList":[{"applianceCode":"17592186044420","type":"0xAC","name":"客厅空调","modelNumber":"1","onlineStatus":"1"}]}
则摘要原串B:
POST/v2/open/device/list/getclient_id=f6f1ec55481b5dc314bd6555e4d3d3bb×tamp=1556193552988{"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01","applianceList":[{"applianceCode":"17592186044420","type":"0xAC","name":"客厅空调","modelNumber":"1","onlineStatus":"1"}]}
(3)由摘要原串生成sign值
使用HmacSHA256签名算法对字符串B进行签名,得到对应的签名数组再使用Base64进行编码(除了Base64编码外还需注意所有String <==> byte[]地方显式设置了编码为UTF-8 ) 注:其中密钥使用美的云为三方云分配的clientSecret Signature = Base64(HMAC_SHA_256 (clientSecret, Http Method + RequestURI + QueryString + 请求消息体bodyBytes的字符串(utf-8编码)))
(4)实现示例
JAVA版
package com.midea.smart.iot.open.common.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLDecoder;
/**
* @Description: 签名摘要工具类
* @Author: musilin
* @Date: 2019-4-18
* @Version: 1.0.0
*/
public class SignatureUtil {
private static Logger LOGGER = LoggerFactory.getLogger(SignatureUtil.class);
/**
* 获取消息认证码
*
* @param clientSecret 密钥
* @param requestMethod 请求方法
* @param requestURI 请求URI
* @param queryString url中的查询参数
* @param bodyBytes 消息体
* @return
*/
public static String getSignature(final String clientSecret,
final String requestMethod, final String requestURI,
final String queryString, final byte[] bodyBytes) {
try {
String queryStringAfterDeal = StringUtils.isBlank(queryString) ? ""
: URLDecoder.decode(queryString,
"utf-8");
String payload = ((bodyBytes != null) && (bodyBytes.length > 0))
? new String(bodyBytes, "utf-8") : "";
StringBuilder valueToDigest = new StringBuilder();
valueToDigest.append(requestMethod).append(requestURI)
.append(queryStringAfterDeal).append(payload);
return createSignature(clientSecret, valueToDigest.toString());
} catch (Exception e) {
LOGGER.error("createSignature error : {}", e);
}
return null;
}
/**
* 生成消息认证码
*
* @param clientSecret 密钥
* @param valueToDigest 待签名字段
* @return
*/
public static String createSignature(final String clientSecret,
final String valueToDigest) {
LOGGER.info("strValue to digest : {};clientSecret:{}", valueToDigest,
clientSecret);
final byte[] digest = HmacUtils.hmacSha256(clientSecret, valueToDigest);
return Base64.encodeBase64String(digest);
}
public static void main(String[] args) {
try {
String clientSecret = "o8dk8vm6cbuyxdrl4se4c6i3h4tdea9b";
String method = "POST";
String requestURI = "/v1/open/device/list/get";
String queryString = "client_id=f6f1ec55481b5dc314bd6555e4d3d3bb×tamp=1556193552988";
byte[] bodyBytes = "reqId:fe8234bf-e94c-4cdf-8ea9-c3112962ab01".getBytes(
"utf-8");
String signature = SignatureUtil.getSignature(clientSecret, method,
requestURI, queryString, bodyBytes);
System.out.println(signature); //输出结果:v+YGWmfylFSF9rhSPSYJAzo8IY+NZxhOdAhs9ii7Aig=
} catch (Exception e) {
}
}
}
Golang版
package main
import("bytes""crypto/hmac""crypto/sha256""encoding/base64""fmt""net/url")
/**
* 获取消息认证码
* @param clientSecret 密钥
* @param requestMethod 请求方法
* @param requestURI 请求URI
* @param queryString url中的查询参数
* @param bodyBytes 消息体
* @return
*/
func getSignature(clientSecret string, requestMethod string, requestURI string, queryString string, bodyBytes[] byte) string {
var buffer bytes.Buffer buffer.WriteString(requestMethod) buffer.WriteString(requestURI) if queryString != "" {
queryStringAfterDeal,
_: =url.QueryUnescape(queryString) buffer.WriteString(queryStringAfterDeal)
}
buffer.WriteString(string(bodyBytes)) return createSignature(buffer.String(), clientSecret)
}
/**
* 生成消息认证码
* @param apiSecret 密钥
* @param valueToDigest 待签名字段
* @return
*/
func createSignature(valueToDigest string, clientSecret string) string {
fmt.Println("valueToDigest=" + valueToDigest) fmt.Println("clientSecret=" + clientSecret) key: =[] byte(clientSecret) h: =hmac.New(sha256.New, key) h.Write([] byte(valueToDigest)) return base64.URLEncoding.EncodeToString(h.Sum(nil))
}
func main() {
var clientSecret = "o8dk8vm6cbuyxdrl4se4c6i3h4tdea9b"
var method = "POST"
var requestURI = "/v1/open/device/list/get"
var queryString = "client_id=f6f1ec55481b5dc314bd6555e4d3d3bb×tamp=1556193552988"
var bodyBytes = [] byte("reqId:fe8234bf-e94c-4cdf-8ea9-c3112962ab01") fmt.Println(getSignature(clientSecret, method, requestURI, queryString, bodyBytes))
}
NodeJs版
const crypto = require('crypto');
const urlencode = require('urlencode');
/**
* 获取消息认证码
* @param clientSecret 密钥
* @param requestMethod 请求方法
* @param requestURI 请求URI
* @param queryString url中的查询参数
* @param bodyBytes 消息体
* @return
*/
function getSignature(clientSecret, requestMethod, requestURI, queryString, bodyBytes) {
var queryStringAfterDeal = queryString ? urlencode.decode(queryString, 'utf-8') : "";
var payload = Buffer.from(bodyBytes).toString('utf-8');
var valueToDigest = requestMethod + requestURI + queryStringAfterDeal + payload;
return createSignature(valueToDigest, clientSecret);
}
/**
* 生成消息认证码
* @param apiSecret 密钥
* @param valueToDigest 待签名字段
* @return
*/
function createSignature(valueToDigest, clientSecret) {
console.log("valueToDigest=" + valueToDigest);
return crypto.createHmac('SHA256', clientSecret).update(valueToDigest).digest('base64');
}
module.exports = getSignature;
var clientSecret = "o8dk8vm6cbuyxdrl4se4c6i3h4tdea9b";
var method = "POST";
var requestURI = "/v1/open/device/list/get";
var queryString = "client_id=f6f1ec55481b5dc314bd6555e4d3d3bb×tamp=1556193552988";
var bodyBytes = Buffer.from('reqId:fe8234bf-e94c-4cdf-8ea9-c3112962ab01', 'utf-8');
let signature = getSignature(clientSecret, method, requestURI, queryString, bodyBytes);
console.log(signature);
# 5.10 客户端加密说明
(1)说明
客户端对敏感信息加密时约定采用(AES/CBC/PKCS5Padding),其中IV通过伪随机数生成器生成,并且转成十六进制字符串后拼接在加密后的字符串前面,其中加密字符串也采用十六进制,解密的时候云端会把拼接在前面的iv变量截取下来再做解密。 伪代码示例(以clientSecret作为密钥来源数据为例):
byte[] iv=randomBytes(16);//1.生成随机IV值
byte[] key=subArray(SHA256(clientSecret.getBytes()),0,16);//2.处理clientSecret得到密钥字节数组,由clientSecret做SHA256后取字节数组前16字节
String sn;//3.待加密原文,如这里的uuid
return hexString(iv)+hexString(AES128CBC(uuid.getBytes(),key,iv))//4.最后把转成16进制字符串的IV字符串拼接在对称加密后的十六进制密文字符串前面,作为加密后的值
(2)实现示例
JAVA版
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* @Description: AES对称加密(CBC模式-动态IV)
* @Author: musilin
* @Date: 2020-12-25
* @Version: 1.0.0
*/
public class AESCBCForClient {
/**
* 对称加密算法类型
*/
private static String Algorithm = "AES";
/**
* 定义算法/模式/补码方式
*/
private static final String AES_CBC_ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* 默认IV长度
*/
public static final int DEFAULT_IV_SIZE = 16;
/**
* 获取IV Byte
*
* @return 初始化向量
*/
public static byte[] getIvByte() {
final byte[] iv = new byte[DEFAULT_IV_SIZE];
new SecureRandom().nextBytes(iv);
return iv;
}
/**
* 获取IV
*
* @return 初始化向量
*/
public static IvParameterSpec getIv(byte[] iv){
return new IvParameterSpec(iv);
}
/**
* 加密(CBC模式)
*
* @param src 原文
* @param keyByte 密钥字节数组,由访问令牌做SHA256后取字节数组前16字节
*/
public static String encryptByCBC(String src, byte[] keyByte) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
byte[] ivByte = getIvByte();
IvParameterSpec ivParameterSpec = getIv(ivByte);
String ivStr = byteToHexString(ivByte);
return ivStr+byteToHexString(encrypt(src.getBytes("utf-8"), keyByte, AES_CBC_ENCRYPTION_ALGORITHM, ivParameterSpec));
}
/**
* 加密
*
* @param srcByte 原文byte数组
* @param keyByte 密钥byte数组
* @param algorithmProvider 对称算法及对应模式
*/
private static byte[] encrypt(byte[] srcByte, byte[] keyByte, String algorithmProvider, IvParameterSpec ivParameterSpec) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
SecretKey secretKey = new SecretKeySpec(keyByte, Algorithm);
Cipher cipher = Cipher.getInstance(algorithmProvider);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] cipherBytes = cipher.doFinal(srcByte);
return cipherBytes;
}
/**
* 将byte转换为16进制字符串
*/
public static String byteToHexString(byte[] src) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xff;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
sb.append("0");
}
sb.append(hv);
}
return sb.toString();
}
public static void main(String[] args) {
try {
String src = "18826410885";
String dynamicKey = "1234bafcb5943f67";
System.out.println("密钥:" + dynamicKey);
System.out.println("原文:" + src);
String beforeDecryptStr = encryptByCBC(src, subArray(SHA256(dynamicKey.getBytes()),0,16));
System.out.println("加密:" + beforeDecryptStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}