设备通信
概述¶
联网功能组件 是基础通信组件,设备和云端通信,APP 和云端通信,或者 APP 和设备之间相互通信都可以通过这个组件的 API 来实现。
组件功能点:
- 设备查询所属产品信息
- 设备和云端建立通道
- 设备与云端通信
- 设备发送数据到 APP
说明:本文档是从业务使用场景的角度说明云端提供的各服务接口,方便开发者迅速了解各接口功能点,以及在什么场景下使用哪些接口。
前置条件¶
设备已经链接互联网,配网方式请开发者自行研发,比如可以通过网口,或者直接固化 WiFi 信息等。
Note
注意使用 websocket 或者 TCP 方式 请求体后末尾添加一个"\n"换行符,否则会得到 timeout 的结果。
getProdInfo¶
设备真正链接服务器进行数据发送接收之前,需要先通过链接调度服务器查询链接地址,获取到设备当前所处地域最佳链接地址,以达到最佳稳定通信效果,所以不建议设备固件写死下面的地址。 如果使用氦氪固件或氦氪嵌入式SDK,您并不需要关注这些细节,固件和SDK会封装好。
通信链接调度服务地址¶
地址 | 功能 | 协议 | 数据安全级别 | 服务区域 |
---|---|---|---|---|
info.hekr.me:91 | 产品信息查询服务 | TCP | 非SSL | 全球 |
结果说明¶
- 从应答里解析出serviceHost和servicePort,得到连接的目标地址。
- 从应答里解析出connectType,决定建立tcp长连接还是websocket长连接。
- 从应答里解析出encryptType,决定使用非加密还是加密通道。
- 确定以上信息后,和云端建立真正的连接。
请求参数说明¶
请求参数说明¶
参数 | 值 | 必填 | 说明 |
---|---|---|---|
msgId | 0-65535 | 是 | 消息 id |
action | getProdInfo | 是 | 固定为 getProdInfo |
params.devTid | 设备地址 | 是 | |
params.prodKey | 产品密钥 | 是 | 产品密钥 ,可以从 console 的产品管理页面中找到 |
结果参数说明¶
参数 | 值 | 说明 |
---|---|---|
msgId | 0-65535 | 对应于请求中的 msgId 的值 |
action | getProdInfoResp | 固定为 getProdInfoResp |
mid | 产品标志 | |
workMode | ||
tokenType | 1,2 | 1:静态,2:动态。 静态 token 就是一旦生成,永久不变,DYNAMI 每次登录都需要更换,已经废弃,用户现在无需关心这个字段,只需要将第一次获取到的 token 永久保存,登录的时候携带即可。 |
serviceHost | 设备发起通信链接的主机地址 | |
servicePort | 设备发起通信链接的端口 | |
connectType | 通信协议,上面提到的 http,tcp 或者 websocket 中的一种 | |
encryptType | 加密类型,None,无加密,SSL则是 ssl 方式加密 | |
code | 详见下面错误码 | 错误说明,200 ok,其他参见下表 |
错误码¶
错误码 | 提示信息 | 中文释义 | 可能造成的原因 |
---|---|---|---|
9200000 | Success | 调用成功 | |
9400000 | Error | 未知错误 | 该行以下所有9400开头的错误码需要单独处理 |
9400001 | Bad param | 非法参数 | |
9400002 | Action does not exist | action不存在 | |
9400003 | Product does not exist | 产品不存在 | |
9400004 | Time out | 超时 | |
9400005 | Method not support | 方法不支持 | |
9500000 | Server error | 服务错误 | |
9500001 | Server response error | 服务应答错误 |
通过TCP协议¶
请求地址: tcp://info.hekr.me:91
请求体¶
Note
注意请求体后末尾添加一个"\n"换行符
{
"msgId": 90,
"action": "getProdInfo",
"params": {
"devTid": "TEST_DEV001",
"prodKey": "test_prod_key"
}
}
返回体¶
{
"msgId": 90,
"action": "getProdInfoResp",
"code": 200,
"desc": "success",
"params": {
"mid": "test_mid",
"workMode": 1,
"tokenType": 2,
"serviceHost": "host",
"servicePort": 83,
"encryptType": "None",
"connectType": "tcp"
}
}
TCP调试¶
主流编程语言或者平台(Java、Python、NodeJS、PHP等)都有提供TCP开发包(即Socket开发包),开发者可以在命令行工具中通过“telnet”命令来调试TCP接口。
调试步骤如下:
- 在命令行工具输入:
telnet info.hekr.me 91
。 - 输入请求参数:
{"msgId" : 90,"action" : "getProdInfo","params" : {"devTid" : "TEST_DEV001","prodKey" : "0126736378c6ba606ca72d9"}}
。 - 回车。
- 查看服务器返回结果。
通信地址¶
Info
所有请求消息、返回以换行("\n")分割,文档中为了美观将json以缩进换行表示,实际调用中JSON体内不换行,仅在消息末尾换行。通信数据格式需要根据产品接入协议编写,详细信息参见产品接入协议
地址 | 功能 | 协议 | 数据安全级别 | 服务区域 |
---|---|---|---|---|
hub.hekr.me:83 | 设备<->云端通道 | TCP长连接 | 非SSL | 亚太 |
hub.hekr.me:183 | 设备<->云端通道 | TCP长连接 | SSL | 亚太 |
hub.hekr.me:84 | 设备<->云端通道 | WebSocket长连接 | 非SSL | 亚太 |
hub.hekr.me:184 | 设备<->云端通道 | WebSocket长连接 | SSL | 亚太 |
fra-hub.hekreu.me:83 | 设备<->云端通道 | TCP长连接 | 非SSL | 欧洲 |
fra-hub.hekreu.me:183 | 设备<->云端通道 | TCP长连接 | SSL | 欧洲 |
fra-hub.hekreu.me:84 | 设备<->云端通道 | WebSocket长连接 | 非SSL | 欧洲 |
fra-hub.hekreu.me:184 | 设备<->云端通道 | WebSocket长连接 | SSL | 欧洲 |
va-hub.hekrus.me:83 | 设备<->云端通道 | TCP长连接 | 非SSL | 北美东部+南美 |
va-hub.hekrus.me:183 | 设备<->云端通道 | TCP长连接 | SSL | 北美东部+南美 |
va-hub.hekrus.me:84 | 设备<->云端通道 | WebSocket长连接 | 非SSL | 北美东部+南美 |
va-hub.hekrus.me:184 | 设备<->云端通道 | WebSocket长连接 | SSL | 北美东部+南美 |
ca-hub.hekrus.me:83 | 设备<->云端通道 | TCP长连接 | 非SSL | 北美西部+南美 |
ca-hub.hekrus.me:183 | 设备<->云端通道 | TCP长连接 | SSL | 北美西部+南美 |
ca-hub.hekrus.me:84 | 设备<->云端通道 | WebSocket长连接 | 非SSL | 北美西部+南美 |
ca-hub.hekrus.me:184 | 设备<->云端通道 | WebSocket长连接 | SSL | 北美西部+南美 |
devBind¶
用户要想控制设备,必须将用户和设备绑定,这样该用户才能拥有该设备的控制权,该用户也被称为设备属主。 设备绑定成功后无需再调用 devLogin 进行设备登录操作。
{
"msgId" : 123,
"action" : "devBind",
"params" : {
"devTid" : "ESP_34ABE",
"prodKey" : "0cc175b9c0f1b6a831c399e269772661",
"PINCode" : "1234",
"SSID" : "HEKR",
"token" : "" , //首次配网填空,其他情况填设备端保存的token
"zoneOffSet":480 // 时区偏移量,比如北京+8*60=480,则填写480,如果该参数不填写,则不会返回下面应答中的timeInfo信息,一般情况下不需要该参数,如果设备需要校准时间可以使用该参数
}
}
参数说明¶
参数 | 必填 | 说明 |
---|---|---|
action | 是 | 固定位 devBind |
devTid | 是 | 设备地址 |
prodKey | 是 | 可以在console 控制台产品中心查看 |
PINCode | 是 | 校验码,用户通过 获取 PINCode 接口获取 |
SSID | 是 | 当前 WIFI ssid |
token | 否 | 设备第一次登录或者绑定,填写空,以后必须用云端返回的这个 token 进行登录或者绑定 |
{
"msgId": 123,
"action": "devBindResp",
"code": 200,
"desc": "success",
"params": {
"devTid": "ESP_34ABE",
"token": "4a8a08f09d37b737956490",
"ctrlKey": "20005c97f94aff9d7ff8",
"bindKey": "92eb5ffee6ae2fec3ad7",
"timeInfo": { // 如果想要返回该参数,则请求的时候需要带上 zoneOffSet 参数
"timestamp": 1521467915917,
"year": 2018,
"month": 2, // 从0开始,1月份是0,以此类推
"day": 19,
"hour": 21,// 24小时制
"minute": 58,
"second": 35,
"millisecond": 917,
"dayOfWeek": 2,
"dayOfYear": 78,
"weekOfMonth": 4,
"weekOfYear": 12,
"zoneOffSet": 480, // 传入的时区偏移量
"serverZoneOffSet": 480 // 服务器所在时区偏移量
}
}
}
返回体¶
字段 | 含义 |
---|---|
params.token | 新的设备token。设备下次再和云端建立通道时,务必使用这个新token,否则有可能导致设备被锁。 |
params.ctrlKey | 控制码。APP远程控制设备时,必须使用这个key。 |
params.bindKey | 绑定码。APP绑定、解绑设备时,必须使用这个key。 |
devLogin¶
该指令用于设备和云端建立连接,支持 tcp 和 websocket 长连接方式,方式的选择在 getProdInfo 接口调用时确定。
{
"msgId" : 123,
"action" : "devLogin",
"params" : {
"devTid" : "ESP_34ABE",
"prodKey" : "0cc175b9c0f1b6a831c399e269772661",
"token" : "4a8a08f09d37b737956490", // 设备第一次联网时填""
"zoneOffSet":480 // 时区偏移量,比如北京+8*60=480,则填写480,如果该参数不填写,则不会返回下面应答中的timeInfo信息,一般情况下不需要该参数,如果设备需要校准时间可以使用该参数
}
}
{
"msgId" : 123,
"action" : "devLoginResp",
"code" : 200,
"desc" : "success",
"params" : {
"devTid" : "ESP_34ABE",
"token" : "4a8a08f09d37b737956490", // 新的设备token
"ctrlKey" : "20005c97f94aff9d7ff8",
"bindKey" : "92eb5ffee6ae2fec3ad7",
"forceBind" : true,
"timeInfo": { // 如果想要返回该参数,则请求的时候需要带上 zoneOffSet 参数
"timestamp": 1521467915917,
"year": 2018,
"month": 2,
"day": 19,
"hour": 21,
"minute": 58,
"second": 35,
"millisecond": 917,
"dayOfWeek": 2,
"dayOfYear": 78,
"weekOfMonth": 4,
"weekOfYear": 12,
"zoneOffSet": 480,
"serverZoneOffSet": 480
}
}
}
返回体¶
字段 | 含义 |
---|---|
params.token | 新的设备token,设备下次再和云端建立通道时,务必使用这个新token,否则有可能导致设备被锁。 |
params.ctrlKey | 控制码。APP远程控制设备时,必须使用这个key。 |
params.bindKey | 绑定码。APP绑定、解绑设备时,必须使用这个key。 |
设备第一次和云端建立通道时,token填写空字符串"",表示新设备。
requestVerify¶
该指令用于网关和云端建立连接并进行初步校验,支持 tcp 和 websocket 长连接方式。
{
"msgId" : 123,
"action" : "requestVerify",
"params" : {
"devTid" : "ESP_34ABE",
"prodKey" : "0cc175b9c0f1b6a831c399e269772661",
}
}
{
"msgId" : 123,
"action" : "requestVerifyResp",
"code" : 200,
"desc" : "success",
"params" : {
"randomKey" : "534a2dfd20e24db2acd548c81449b3e8"
}
}
}
返回体¶
字段 | 含义 |
---|---|
params.randomKey | 32字节,用于网关登录校验,参见下面的gatewayLogin指令 |
gatewayLogin¶
该指令用于网关登录云端,支持 tcp 和 websocket 长连接方式。该指令有两种数据格式,需要根据产品高级设置中的【二次验证】配置来进行上报数据。
如果开启了二次验证(默认),则第一步需要上面的 requestVerify
指令,拿到 randomKey
后进行编码,得到 authKey
,编码方式为:
authKey = MD5(randomKey+devTid+devPrivKey),以 devTid=ESP_34ABE,prodKey=0cc175b9c0f1b6a831c399e269772661,devPrivKey=3e9c0dfeb25b4861b2c9b4f33033fca3为例:
authKey=MD5("ESP_34ABE0cc175b9c0f1b6a831c399e2697726613e9c0dfeb25b4861b2c9b4f33033fca3")(仅引号中间的值参与运算)=34193d9b7924b564c0ba0e5aa1373c58
{
"msgId" : 123,
"action" : "gatewayLogin",
"params" : {
"devTid" : "ESP_34ABE",
"prodKey" : "0cc175b9c0f1b6a831c399e269772661",
"authKey" : "34193d9b7924b564c0ba0e5aa1373c58"
}
}
如果关闭了二次验证,则 authKey 也相应的去掉,示例如下:
{
"msgId" : 123,
"action" : "gatewayLogin",
"params" : {
"devTid" : "ESP_34ABE",
"prodKey" : "0cc175b9c0f1b6a831c399e269772661"
}
}
{
"msgId" : 123,
"action" : "gatewayLoginResp",
"code" : 200,
"desc" : "success"
}
设备上报固件 WIFI 等信息¶
该指令用于设备向云端上报基本设备信息,这些信息包括固件信息,路由器信息的,在设备登录到云端的时候会主动调用此接口上报设备信息。注意 reportDevInfo
和 devSend
的区别。
{
"msgId" : 291,
"action" : "reportDevInfo",
"params" : { // 字段可扩展
"devTid" : "ESP_4387EF",
"mid" : "0cc175b9c0f1",
"workMode" : 0,
"MAC" : "08EFA809DE6D", // 设备MAC地址
"tokenType" : 2,
"binVer" : "3.0.61.2", // 固件版本
"binType" : "A", // 固件类型
"SDKVer" : "3.0.61.2", // 固件SDK版本
"serviceHost" : "hub.hekr.me", // 服务器地址
"servicePort" : 83, // 服务器端口
"SSID" : "HEKR-TEST" // 路由器SSID
}
}
{
"msgId" : 291,
"action" : "reportDevInfoResp",
"code" : 200,
"desc" : "success"
}
devSend¶
该指令是上报设备所属产品在 Console 上配置的协议模板中的命令和参数。当设备状态改变的时候,应该发送 devSend,比如灯泡亮度改变,应该立即发送一个指令消息到云端,这样云端就会将该指令转发给 app,如果 app 在线,会立即更改亮度的数值。
devSend (JSON主控)¶
{
"msgId" : 382,
"action" : "devSend",
"params" : {
"devTid" : "ESP_2M_245EC89",
"appTid" : [],
"data" : {
"cmdId" : 9,
"key1" : "value1",
"key2" : "value2",
}
}
}
{
"msgId" : 382,
"action" : "devSendResp",
"code" : 200,
"desc" : "success"
}
请求体¶
字段 | 是否必须 | 含义 |
---|---|---|
params.devTid | 是 | 设备devTid |
params.appTid | 是 | 希望转发的appTid 暂时只支持转发到所有APP,appTid为[] |
params.data.cmdId | 是 | 命令ID |
params.data.key1 | 否 | 自定义键值对1 |
params.data.key2 | 否 | 自定义键值对2 |
cmdId, key1, key2 这些值可以在 氦氪云控制台-产品管理-产品协议-命令-示例帧 查看它们的使用方法
devSend (JSON透传)¶
{
"msgId" : 382,
"action" : "devSend",
"params" : {
"devTid" : "ESP_2M_245EC89",
"appTid" : [],
"data" : {
"raw" : "48EFDFAB"
}
}
}
{
"msgId" : 382,
"action" : "devSendResp",
"code" : 200,
"desc" : "success"
}
请求体¶
字段 | 是否必须 | 含义 |
---|---|---|
params.devTid | 是 | 设备devTid |
params.appTid | 是 | 希望转发的appTid 暂时只支持转发到所有APP,appTid为[] |
params.data.cmdId | 是 | 命令ID |
params.data.raw | 是 | 透传数据 |
raw 值可以在 氦氪云控制台-产品管理-产品协议-命令-示例帧 查看它们的使用方法
devSend (48透传)¶
48EFDFAB
值可以在 氦氪云控制台-产品管理-产品协议-命令-示例帧 查看它们的使用方法
heartbeat¶
注意
如果30秒内云端没有收到任何数据,则会主动断开连接,所以设备、APP必须定时发送心跳指令来保持连接。
{
"msgId" : 98,
"action" : "heartbeat"
}
{
"msgId" : 98,
"action" : "heartbeatResp",
"code" : 200,
"desc" : "success"
}
appSendResp¶
该指令用于回复 app 下发的控制指令 appSend
。如果设备成功收到消息并且执行成功,那么应该立即发送该指令。参数中应该返回当前设备的状态,期望回应的参数值应该和 appSend 的参数值一样。
{
"msgId" : 291,
"action" : "appSendResp",
"code" : 200,
"desc" : "success",
"params" : {
"devTid" : "ESP_2M_245EC89",
"ctrlKey" : "123456789123456789",
"appTid" : "54354353454",
"data" : {
"cmdId" : 0,
"raw": "0F2CABDEG",
"customKey" : 0
}
}
}
getTimerList¶
该指令用于设备获取云端的定时任务列表。
指令格式:
{
"msgId" : 291,
"action" : " getTimerList",
"params" : {
"devTid" : "ESP_245EC89", // 设备唯一id
"taskFormat" : "single", // 定时任务应答格式:single:按task数量逐条回复,list:task以数组返回。 默认list
"timeFormat" : " countdown " // 定时时间应答格式: cronexpr:cron表达式;countdown倒计时。 默认countdown
}
}
应答格式: single 任务格式:
// 第一条任务
{
"msgId": 291,//保持一致
"action": "getTimerListResp",
"code": 200,
"desc": "success",
"params": {
"tasksCount": 2,//任务数量
"taskList": [
{
"taskId": 1952511811, // 预约任务编号,int32
"delayTime": 248, // 延时时间,单位秒(s),最大3600s
"count": 3, // 循环执行次数,1表示执行一次、n表示执行n次(间隔为looptime)
"loopTime": 600, // 循环时间间隔,单位秒(s)
"task": {
"cmdId": 1,
"k1": "v1"
} //执行代码,通常为appSend中data部分
}
]
}
}
// 第二条任务
{
"msgId": 291,//保持一致
"action": "getTimerListResp",
"code": 200,
"desc": "success",
"params": {
"tasksCount": 2,//任务数量
"taskList": [
{
"taskId": 1958890357,//预约任务编号,int32
"delayTime": 248,//延时时间,单位秒(s),最大3600s
"count": 3,//循环执行次数,1表示执行一次、n表示执行n次(间隔为looptime)
"loopTime": 600,//循环时间间隔,单位秒(s)
"task": {
"cmdId": 1,
"k1": "v1"
}//执行代码,通常为appSend中data部分
}
]
}
}
list 任务格式:
{
"msgId": 291,
"action": "getTimerListResp",
"code": 200,
"desc": "success",
"params": {
"tasksCount": 2,//任务数量
"taskList": [
{
"taskId": 1952511811,//预约任务编号,int32
"delayTime": 305,//延时时间,单位秒(s),最大3600s
"count": 3,//循环执行次数,1表示执行一次、n表示执行n次(间隔为looptime)
"loopTime": 600,//循环时间间隔,单位秒(s)
"task": {"raw":"4808020122115533"} //执行代码,根据APP添加,通常为appSend消息体中data部分
},
{
"taskId": 1958890357,
"delayTime": 1505,
"count": 1,
"loopTime": 0,
"task": {"raw":"4808020122115533"}
}
]
}
}
timerReport¶
定时任务执行完后上报结果 指令格式:
{
"msgId" : 291,
"action" : "timerReport",
"params" : {
"devTid" : "ESP_245EC89",
"taskId" : 1, //预约任务编号,int32
"task" : {"raw":"4808020122115533"}, //对应appSendResp中data部分:透传时为MCU应答帧内容。
"code" : 200 //表示任务已经触发
}
}
应答格式:
{
"msgId" : 291,
"action" : "timerReportResp",
"code" : 200,
"desc" : "success"
}
devSync¶
该指令用于云端要求设备同步信息,例如同步定时计划任务。设备接收到该指令后会自动调用getTimerList指令同步一次定时计划任务。具体流程参考4.x定时设计方案。
指令格式:
{
"msgId" : 291,
"action" : "devSync",
"params" : {
"ctrlKey" : "123456789ABCDE" // 设备控制码
}
}
应答格式
{
"msgId" : 291,
"action" : "devSyncResp",
"code" : 200,
"desc" : "success"
}
错误码表¶
错误码 | 提示信息 | 中文释义 | 可能造成的原因 |
---|---|---|---|
1200000 | Success | 调用成功 | 无 |
1400000 | Error | 未知错误 | 该行以下所有1400开头的错误码需要单独处理 |
1400001 | Json parse error | json解析错误 | json格式错误 |
1400002 | JWT parse error | jwt_token解析错误 | jwt token错误 |
1400003 | The field {0} contains a value that is too high | 属性值过高 | 发送报文中某属性的值超过了其上限 |
1400004 | The field {0} contains a value that is too low | 属性值过低 | 发送报文中某属性的值低于了其下限 |
1400005 | The value of the field {0} must be an enumerated value | 属性值必须为范围内枚举值 | 发送报文中某属性值不符合其定义的取值范围 |
1400006 | Field not exist | 属性不存在 | 发送报文中存在了未定义的属性 |
1400008 | devTid not match | 设备ID不匹配 | 报文填写的devTid与登录设备的devTid不一致 |
1400009 | App repeat login | APP重复登录 | 同一个appTid的app重复登录 |
1400010 | User does not exist | 用户不存在 | 用户不存在或者uid填错了 |
1400011 | The device does not have this instruction | 设备不具有该指令 | 设备不具备该指令 |
1400012 | Device does not belong to user | 设备不属于该用户 | 设备不再属于该用户 |
1400013 | Device repeat login | 设备重复登录 | 设备同时登录 |
1400014 | Frame parse error | 帧解析错误 | 报文格式或内容错误 |
1400015 | Device last token can not use | 设备上一次token已过期无法使用 | 使用的旧token已经超过上限 |
1400016 | Action not support | 该帧行为不被支持 | 报文中的action填错了 |
1400017 | Device token can not verification | 设备token校验错误 | 设备token错误 |
1400018 | Device not online | 设备不在线 | 设备离线 |
1400019 | App is not logged in | app未登录 | app未登录或其他原因导致云端认为app已经离线 |
1400020 | Device is not logged in | 设备未登录 | 设备未登录或其他原因导致云端认为设备已经离线 |
1400022 | The device is not found | 找不到指定(devTid)设备 | 当前产品下不存在该设备 |
1400023 | appTid does not match | app设备id不匹配 | 当前发送报文的appTid与绑定设备时的appTid不一致 |
1400024 | You report info does not match your connect server | 上报节点信息与实际不符 | 上报的内容与当时连接节点信息不一致 |
1400025 | RAW not valid, Please check your protocol template | 协议不合法,请参照协议模板 | 48协议串不合法 |
1400026 | AuthKey can't auth | authKey 认证失败 | 填写了错误的authkey |
1400027 | Product key not available | 不是有效的pk | 填写了错误的pk |
1400028 | PinCode or SSID not available | pinCode或者ssid无效 | 填写了无效的pinCode或者ssid |
1400029 | Bind failed due to timeout error | 绑定设备超时错误 | 绑定设备超时 |
1400030 | Can not bind other manufacture's device | 无法绑定其它厂商的设备 | APP绑定了非该厂家的设备 |
1400039 | Device license can not verification | 设备license不合法 | 请填写正确的license |
1400031 | Can not force bind device | 无法强绑设备 | 设备设定为无法强绑,强绑失败 |
1400032 | Invalid Param | 参数不合法 | 协议参数不合法 |
1400040 | frame payload error | 帧内容校验失败 | 可能帧内容或者求和不对 |
1500000 | Internal error | 内部错误 | 服务内部错误 |
1500001 | Link error | 链路错误 | 链路错误 |