KLink
简介
KLink协议,是IoT OS为开发者提供的设备与云端之间数据交换的标准协议,采用JSON格式。
协议特点
每一帧应都带上msgId,该字段用于设备端和云端做消息请求匹配,如果短时间内msgId一样即可认为是一对请求和回复;如果不填则每条消息都默认为0。云端允许范围是 有符号 int64范围,设备端可以根据自身资源情况设计,比如可以设计成2Byte无符号范围;如果超出int64范围则会造成数值溢出,导致msgId回应不准确。
重要说明
云端对设备发送的数据中一定包含 pk和devId,如果设备不需要这些信息,可以使用自定义解码器进行过滤后再转发。
文档格式说明
为了文档清晰,下面的 json 指令均进行了格式化输出,在实际发送数据的时候应该将json数据压缩成一行并且没有多余空格的数据,只保留最后一个换行符发送。比如下面的指令只是为了阅读方便
{ "action": "devSend" }
设备实际发送的的数据应该是
{"action":"devSend"}
KLink指令详解
指令列表
指令功能 | 发送形式 | 详情 |
---|---|---|
设备上报数据 | D => C | devSend |
云端回复设备上报数据 | C => D | devSendResp |
网关批量上报设备数据 | D => C | batchDevSend |
云端回复网关批量上报设备数据 | C => D | batchDevSendResp |
云端给设备下发指令 | C => D | cloudSend |
设备回复云端下发指令 | D => C | cloudSendResp |
设备上报固件信息 | D => C | reportFirmware |
云端回应设备上报固件信息 | C => D | reportFirmwareResp |
云端给设备下发固件升级指令 | C => D | devUpgrade |
设备回应固件升级指令 | D => C | devUpgradeResp |
设备上报升级进度 | D => C | devUpgradeProgress |
动态注册设备 | D => C | register |
云端回复动态注册设备 | C => D | registerResp |
网关添加拓扑关系(子设备) | D => C | addTopo |
云端回复网关添加拓扑关系(子设备) | C => D | addTopoResp |
网关查询拓扑关系(子设备) | C => D | getTopo |
云端回复网关查询拓扑关系(子设备) | D => C | getTopoResp |
网关删除拓扑关系(子设备) | D => C | delTopo |
云端回复网关删除子设备(子设备) | C => D | delTopoResp |
子设备上线 | D => C | devLogin |
云端回复子设备上线 | C => D | devLoginResp |
子设备下线 | D => C | devLogout |
云端回复子设备下线 | C => D | devLogoutResp |
设备上报数据
D => C
{
"action": "devSend",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"data": {
"cmd": "标识符",
"params": {
"power": 1,
"light": 99.2
}
}
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devSend。 |
pk | 否 | string | 要发送数据的设备产品PK,如果是子设备必填。 |
devId | 否 | string | 要发送数据的设备ID,如果是子设备必填。 |
data | 是 | object | 上报的指令和参数数据。 |
data.cmd | 是 | string | 标识符 |
data.params | 否 | object | 参数,如果只有指令,没有参数允许不填;否则应该填写该指令下的参数标识符。 可以少不能多,值做强较验(类型,长度等必须符合协议规定)。 |
注意: 如果是子设备上报数据,且是透传数据,需要在网关上统一解码成云端要求的格式,否则云端解码失败。
云端回复设备上报数据
C => D
{
"action": "devSendResp",
"pk": "pk",
"devId": "devId",
"msgId": 1,
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devSendResp。 |
pk | 是 | string | 设备所属产品PK。 |
devId | 是 | string | 设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |
网关批量上报设备数据
D => C
{
"action": "batchDevSend",
"msgId": 1,
"data": [{
"pk": "pk",
"devId": "devId",
"cmd": "标识符",
"params": {
"power": 1,
"light": 99.2
}
},{
"pk": "pk1",
"devId": "devId2",
"cmd": "标识符",
"params": {
"power": 1,
"light": 99.2
}
}]
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 batchDevSend |
data.pk | 是 | string | 要发送数据的设备的 productKey |
data.devId | 是 | string | 要发送数据的设备的 devId |
data.cmd | 是 | string | 标识符 |
data.params | 否 | object | 参数,如果只有指令,没有参数允许不填;否则应该填写该指令下的参数标识符。 |
云端回复网关批量上报设备数据
C => D
{
"action": "batchDevSendResp",
"pk": "pk",
"devId": "devId",
"msgId": 1,
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 batchDevSendResp。 |
pk | 是 | string | 设备所属产品PK。 |
devId | 是 | string | 设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |
云端给设备下发指令
云端给设备(包括子设备)下发指令,设备需要处理所接收的数据。
C => D
{
"action": "cloudSend",
"pk": "pk",
"devId": "devId",
"msgId": 1,
"data": {
"cmd": "cmdFlag",
"params": {
"power": 1,
"light": 99.2
}
}
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 cloudSend |
pk | 是 | string | 设备所属产品PK。 |
devId | 是 | string | 要控制的设备ID。 |
data | 是 | object | 指令数据。 |
data.cmd | 是 | string | 命令标识符。 |
data.params | 否 | object | 参数,如果只有指令,没有参数允许不填,否则应该填写该指令下的参数标识符。 |
设备回复云端下发指令
D => C
{
"action": "cloudSendResp",
"pk":"pk",
"devId":"devId",
"msgId": 1,
"code": 0
}
设备必须回复,如果没有错误是0;错误码在产品上增加说明。 如果云端没有收到回复则认为是设备没有收到控制指令,控制失败。
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 cloudSendResp。 |
pk | 否 | string | 设备所属产品PK,如果是子设备必填。 |
devId | 否 | string | 要控制的设备ID,如果是子设备必填。 |
code | 是 | uint | 如果没有错误回复 0。 |
设备上报固件信息
D => C
{
"action": "reportFirmware",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"type": "module/mcu/config",
"version": "1.2.1"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 reportFirmware。 |
pk | 否 | string | 设备所属产品PK。 |
devId | 否 | string | 要控制的设备ID。 |
type | 是 | string | module/mcu/config。 |
version | 是 | string | 版本,格式随意,比如可以是 a.b.c,也可以是 1.0.1。 |
云端回应设备上报固件信息
C => D
{
"action": "reportFirmwareResp",
"pk":"pk",
"devId":"devId",
"msgId": 1,
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 reportFirmwareResp。 |
pk | 否 | string | 设备所属产品PK, 如果是子设备必填。 |
devId | 否 | string | 要控制的设备ID,如果是子设备必填。 |
code | 是 | uint | 如果没有错误回复 0。 |
云端给设备下发固件升级指令
C => D
{
"action": "devUpgrade",
"msgId": 1,
"pk":"pk",
"devId":"devId",
"url": "http://xx.xx/ss.bin",
"md5": "md5",
"type": "module/mcu/config",
"version":"currentVersion"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devUpgrade。 |
pk | 是 | string | 要控制的设备所属产品PK。 |
devId | 是 | string | 要控制的设备ID。 |
url | 是 | string | 固件下载地址(http,非https)。 |
md5 | 是 | string | 固件的md5值。 |
type | 是 | string | 更新类型 module(模组),mcu(mcu),config(远程配置)。 |
version | 是 | string | 目标版本。 |
设备回应固件升级指令
设备必须回复,否则云端认为下发指令失败,设备未收到控制指令。
D => C
{
"action": "devUpgradeResp",
"pk":"pk",
"devId":"devId",
"type": "module/mcu",
"msgId": 1,
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devUpgradeResp。 |
pk | 否 | string | 要控制的设备的所属产品PK, 如果是子设备必填。 |
devId | 否 | string | 要控制的设备ID,如果是子设备必填。 |
code | 是 | uint | 如果没有错误回复 0。 |
type | 是 | string | 升级类型 module,mcu。 |
设备上报升级进度
注意 只是记录升级进度,具体升级到什么版本还需要设备主动上报,参见上报固件版本
D => C
{
"action": "devUpgradeProgress",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"progress": 19,
"type": "module/mcu/config",
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devUpgradeProgress。 |
pk | 否 | string | 要控制的设备的所属产品PK, 如果是子设备必填。 |
devId | 否 | string | 要控制的设备ID,如果是子设备必填。 |
type | 是 | string | 升级类型 module,mcu,config。 |
code | 是 | uint | 如果没有错误回复 0。 |
progress | 是 | uint | 取值范围 [0,100]。 |
如果code=0,progress=100 只能代表设备端升级完成,真正升级完成必须是上报的版本和预期的一样。设备升级完成,需要再次发送上报固件信息到云端以便更新云端设备固件版本信息,如果版本号跟预期不一样算作失败处理。
动态注册设备
D => C
{
"action": "register",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"random": "random",
"hashMethod": "method",
"sign": "sign"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 register。 |
pk | 是 | string | 要注册的设备的所属产品PK。 |
devId | 是 | string | 要注册的设备ID。 |
sign | 否 | string | 要注册的设备的产品认证签名。 |
random | 否 | string | 设备加密校验,随机字符串,可以使用当前时间毫秒数的字符串,也可以使用uuid生成的,也可以是 math.random()等等。 |
hashMethod | 否 | string | hash 方法,选填 HmacMD5 、HmacSHA1 、HmacSHA256 或者 HmacSHA512 。 |
注意 在产品上设置有安全开关:动态注册设备是否需要鉴权,如果开启则 sign,random 和 hashMethod 字段必填,关闭则不需要填写。开启能够增强注册设备的安全性,建议开启。
sign算法说明
sign=hash(pk+productSecrect+random),加密密钥(密码)填写 productSecrect
其中 hash
算法支持: HmacMD5
、HmacSHA1
、HmacSHA256
和 HmacSHA512
。
比如 pk=pk123
,productSecrect=excvw2cw
,random=QWExm
,则要hash的值应该为 pk123excvw2cwQWExm
使用不同 hash 算法得到的值如下,可以使用在线工具测试 进行测试。 使用 hash 算法得到sign后,需要使用对应的 toHex 方法将其编码为 hex string。
- HmacMD5: fea83bd79fb090b1529f1468bb1051f7
- HmacSHA1: 2c32e0bfbdee359eb71afb9efeb7ad922e1321c7
- HmacSHA256: 09e17c16188da122ff5cf6dd384df44260f546c5a38b6764c7e9f4b05f8e2452
- HmacSHA512: 0009dcd96b7f0d6c5667aa0a1b0aa8a354391598d7375152342c37a30fab5ec2ba17f85b9006dded114181447e29bb9ad616f61c24e77a103c99b9f25ccc9f59
云端回复动态注册设备
云端允许多次调用激活指令,注册成功后返回该设备的信息。
C => D
{
"action": "registerResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"devSecret": "devSecret",
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 registerResp。 |
pk | 是 | string | 设备所属产品PK。 |
devId | 是 | string | 设备ID。 |
devSecret | 是 | string | 设备的密钥,添加拓扑关系的时候需要使用。 |
code | 是 | uint | 如果没有错误回复 0。 |
网关添加拓扑关系(子设备)
设备如果要构建自身和子设备的拓扑关系,同时,这种拓扑关系也是一种约束,只有在这个网关下的子设备才允许通过该网关上报数据,所以需要向云端发送添加子设备的指令,将子设备添加到网关拓扑关系中。
- 添加拓扑的时候,如果云端没有注册该子设备,则会自动注册子设备。
添加关系的时候,云端会自动设置子设备状态为在线状态。
支持一次性添加一个
- 支持多级拓扑关系,如下图
- 允许重复请求(防止云端添加成功,网关本地没有添加成功)
- 网关应该等待云端回复网关添加子设备返回信息,code=0的时候才将子设备信息挂载到自身下。
dev1 ---| 在该拓扑关系中,加上网关(顶层dev1)设备
/ \ | 一有3层,最多支持3层。
dev2 dev3 |
/ \ | dev1 是 dev2 和 dev3 的网关节点;
dev4 dev5 | 反过来说,dev2 和 dev3 是 dev1 子设备节点。
注意:
- 不允许两个设备相互设置为子设备
- 子设备层级最多支持2级
- 整个网关所包含的设备最多支持400个
- 添加的子设备必的父级设备必须已经挂载到该拓扑中
D => C
{
"action": "addTopo",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"sub": {
"pk": "pk",
"devId": "devId",
"random": "random",
"sign": "sign",
"hashMethod": "hashMethod"
}
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 addTopo。 |
pk | 否 | string | 父级设备节点所属产品PK,如果是子设备必填。 |
devId | 否 | string | 父级设备节点设备ID,如果是子设备必填。 |
sub | 是 | object | 子设备节点。 |
sub.pk | 是 | string | 子设备节点所属产品PK。 |
sub.devId | 是 | string | 子设备节点设备ID。 |
sub.random | 是 | string | 同设备登录认证的 random 。 |
sub.sign | 是 | string | 子设备认证签名,算法说明。 MQTT登录认证 |
sub.hashMethod | 是 | string | hash 方法。 |
注意 子设备上有安全开关:添加拓扑关系,是否关闭安全认证,如果关闭,random、sign和hashMethod不需要填,开启则必填。出于安全考虑,建议开启安全认证。
添加拓扑子设备 sign 计算方法
云端回复网关添加拓扑关系(子设备)
C => D
{
"action": "addTopoResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"sub": {
"pk": "pk",
"devId": "devId"
},
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 addTopoResp。 |
pk | 是 | string | 父设备节点所属产品PK。 |
devId | 是 | string | 父设备节点设备ID。 |
sub | 是 | object | 子设备节点信息。 |
sub.pk | 是 | string | 子设备节点所属产品PK。 |
sub.devId | 是 | string | 子设备节点设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |
网关查询拓扑关系(子设备)
注意 只支持查询直属下级的设备,不支持查询所有设备。
C => D
{
"action": "getTopo",
"msgId": 1,
"pk": "pk",
"devId": "devId"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 addTopo。 |
pk | 否 | string | 父级设备节点所属产品PK,如果是子设备必填。 |
devId | 否 | string | 父级设备节点设备ID,如果是子设备必填。 |
云端回复网关查询拓扑关系(子设备)
D => C
{
"action": "getTopoResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"subs": [
{
"pk": "pk",
"subPk": "subPk",
"devId": "subDevId"
}
]
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 addTopo。 |
pk | 否 | string | 父级设备节点所属产品PK,如果是子设备必填。 |
devId | 否 | string | 父级设备节点设备ID,如果是子设备必填。 |
subs | 是 | array | 直属下级的所有设备,如果没有则数组为空。 |
网关删除拓扑关系(子设备)
前置条件:网关设备已经登录并保持连接。
网关删除拓扑关系,仅仅是在逻辑上解除了与子设备的关系,并没有删除设备注册信息。
D => C
{
"action": "delTopo",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"sub": {
"pk": "pk",
"devId": "devId"
}
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 delTopo。 |
pk | 否 | string | 父设备节点所属产品PK,如果是子设备必填。 |
devId | 否 | string | 父设备节点设备ID,如果是子设备必填。 |
sub | 是 | object | 子设备节点信息。 |
sub.pk | 是 | string | 子设备节点所属产品PK。 |
sub.devId | 是 | string | 子设备节点设备ID。 |
云端回复网关删除子设备(子设备)
C => D
{
"action": "delTopoResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"sub": {
"pk": "pk",
"devId": "devId"
},
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 delTopoResp。 |
pk | 是 | string | 父设备节点所属产品PK。 |
devId | 是 | string | 父设备节点设备ID。 |
sub | 是 | object | 子设备节点信息。 |
sub.pk | 是 | string | 子设备节点所属产品PK。 |
sub.devId | 是 | string | 子设备节点设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |
子设备上线
注意,该指令仅供子设备使用
前置条件:网关设备已经登录并保持连接。
D => C
{
"action": "devLogin",
"msgId": 1,
"pk": "pk",
"devId": "devId"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devLogin。 |
pk | 是 | string | 子设备节点所属产品PK。 |
devId | 是 | string | 子设备节点设备ID。 |
云端回复子设备上线
C => D
{
"action": "devLoginResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devLoginResp。 |
pk | 是 | string | 子设备节点所属产品PK。 |
devId | 是 | string | 子设备节点设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |
子设备下线
注意,该指令仅供子设备使用
前置条件:网关设备已经登录并保持连接。
D => C
{
"action": "devLogout",
"msgId": 1,
"pk": "pk",
"devId": "devId"
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devLogout。 |
pk | 是 | string | 子设备节点所属产品PK。 |
devId | 是 | string | 子设备节点设备ID。 |
云端回复子设备下线
C => D
{
"action": "devLogoutResp",
"msgId": 1,
"pk": "pk",
"devId": "devId",
"code": 0
}
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
action | 是 | string | 动作,固定为 devLogoutResp。 |
pk | 是 | string | 子设备节点所属产品PK。 |
devId | 是 | string | 子设备节点设备ID。 |
code | 是 | uint | 如果没有错误回复 0。 |