5. 接口文档(v2)
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 获取授权二维码
接口说明:合作方调用该接口获取二维码信息,展示在大屏等设备上进行后续扫码操作
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/user/qrcode/get
参数格式: body 参数
请求参数:
| 参数 | 必选 | 类型 | 说明 |
|---|---|---|---|
| clientId | true | String | 唯一的第三方开发者ID |
| reqId | true | String | 请求ID |
| uuid | true | String | 第三方开放用户唯一标识。约定采用(AES/CBC/PKCS5Padding),加密方法:AES.encrypt(sn, key,IV),并对加密结果转成16进制字符串表示。 注:加密Key由美的云为三方云分配的ClientSecret做SHA256后取字节数组前16字节,其中IV通过伪随机数生成器生成,并且转成十六进制字符串后拼接在加密后的字符串前面,其中加密字符串也采用十六进制,解密时云端会把拼接在前面的iv变量截取下来再做解密。 |
| reponseType | true | String | 授权类型,固定传code |
| state | false | String | 请求授权方的校验字段,回调三方redirectUri透传原值返回 |
| redirectUri | true | String | 授权码回调给第三方的地址,需提前在美的开放者平台中录入 |
JSON示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"clientId": "f6f1ec55481b5dc314bd6555e4d3d3bb",
"uuid": "423wtwet34342346796ikfjdr68e",
"responseType" : "code",
"state": "11111111111111111111",
"redirectUri": "https://xxxxxxx"
}返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| qrcode | String | 二维码信息 |
| reqId | String | 请求Id |
JSON示例:
{
"reqId":"fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"qrcode": "http://iot4.midea.com.cn/downloads/app?type=auth&qrcodeToken=2d2f80ba32d7424badff1ca8038715ba&clientId=0fea920cfb3936b851ea38565b65b998&uuid=25345ui5i34ih5hllhi2yf253365285r&responseType=qrcode&expired=600&state=11111111111111111111"
}5.2.3 获取令牌
接口说明: 该接口获取或刷新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": [{
"openHomegroupId": 3121311,
"homegroupName": "我的家1"
}, {
"openHomegroupId": 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、调用文档5.4.2.1接口返回成功前为第一阶段,调用文档5.4.2.2接口返回成功前后为第二阶段,第二阶段允许文档5.4.2.2接口轮询调用
2、在进行相关确权动作之前(第一阶段)需要先明确设备处于未确权状态(返回值为2)后才进行后确权相关接口调用,明确设备确权状态可考虑通过调用文档5.4.2.2接口进行查询,但该接口此阶段在调用并成功返回的情况下只允许调用一次,如果有失败的情况最多重试不超过3次
3、在调用文档5.4.2.1接口并收到成功返回后(第二阶段)才允许开始轮询调用文档5.4.2.2接口进行实时确权状态查询
4、轮询调用文档5.4.2.2接口(第二阶段)时频率为每5秒一次,即每一次请求成功或失败后5秒才重新发起请求
5、轮询调用文档5.4.2.2接口(第二阶段)时总次数不超过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 | 服务调用失败 |
5.4.2.1 设备确权
接口说明: 该接口用于支持后确权的设备,使用这个接口让设备进入待确权状态,设备进入待确权状态后,用户在设备上确权
请求协议: 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 | 异常,无法切换 |
5.4.2.2 确权状态查询
接口说明: 该接口用于获取设备确权状态
请求协议: 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/thing/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 | 设备列表 |
| spid | String | 美的产品唯一标识 |
| sn8 | String | 设备型号 |
| modelNumber | String | 特殊设备型号(A0) |
| applianceCode | String | 设备虚拟ID,用于设备相关操作 |
| type | String | 设备类型 |
| name | String | 设备名称 |
| onlineStatus | String | 设备在线状态,1为在线,0为离线 |
| enterprise | String | 设备企业码 |
| roomName | String | 设备所在美居房间名称 |
| roomId | String | 设备所在美居房间id |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"applianceList": [{
"applianceCode": "17592186044420",
"spid": "123456",
"type": "0xAC",
"name": "客厅空调",
"sn8": "1",
"modelNumber": "",
"onlineStatus": "1",
"enterprise": "0000",
"roomName": "客厅",
"rommId": "123456"
}]
}错误码说明:
| 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 |
| spid | String | 美的产品唯一标识 |
| sn8 | String | 设备型号 |
| modelNumber | String | 特殊设备型号(A0) |
| applianceCode | String | 设备虚拟ID,用于设备相关操作 |
| type | List | 设备类型 |
| name | String | 设备名称 |
| enterprise | String | 设备企业码 |
返回示例:
{
"reqId": "fe8234bf-e94c-4cdf-8ea9-c3112962ab01",
"applianceCode": "17592186044420",
"spid": "123456",
"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 操作(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.5.5 属性(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.5.6 属性(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.5.7 全属性(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.5.8 属性(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.6 设备通知相关
5.6.1 设备订阅
接口说明: 设备订阅接口,被订阅的设备才会有消息通知,返回reqId则接口调用成功
请求协议: HTTPS
请求方式: POST
请求地址: /v2/open/thing/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/thing/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.3 消息通知
接口说明: 此接口由第三方定义及实现,由美的云调用,用于通知设备订阅信息,接口鉴权方式由第三方定义,通知内容基于下面请求体定义
请求协议: 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 | 设备名称 |
| spid | 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",
"spid": "123456"
"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",
"openHomegroupId": "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",
"openHomegroupId": "12099672"
}]
}错误码说明:
| error | 说明 |
|---|---|
| 1000 | 未知系统错误 |
| 1001 | sceneType,homegroupId类型转化异常 |
| 1002 | 参数非法 |
| 1003 | ClientId校验失败或服务返回解析失败 |
| 1004 | 服务调用失败 |
| 1006 | 签名或用户验证失败 |
| 1009 | 开发者账号不存在 |
| 1200 | 该用户不属于设备所在家庭组 |
| 2001 | 非法开发者 |
5.7.2 执行场景
接口说明: 执行场景
请求协议: 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",
"openHomegroupId": "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 签名摘要规则说明
(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.9 客户端加密说明
(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();
}
}
}