网关 MQTT 接入
网关设备通过 MQTT 接入 ZhiLian.Yun 后,可以代无法直接联网的子设备上报数据、接收平台下发消息,并维护子设备在线状态。
网关自身仍然使用设备证书连接平台,连接参数、接入点和身份认证方式与 设备 MQTT 接入 一致。区别在于:网关代子设备通信时,协议报文使用 gw 表示子设备数据,gw 的键通常是子设备地址。
TIP
直连设备报文使用 data;网关代子设备报文使用 gw。不要把子设备数据放到直连设备的 data 中。
子设备地址
子设备地址由网关侧定义,用于在同一个网关下唯一标识子设备。常见取值包括:
- Modbus 从站地址。
- RS485/LoRa 子设备地址。
- 子设备 SN、MAC、IMEI 或业务编号。
- 网关内部维护的唯一逻辑地址。
示例中使用 SUB_DEVICE_ADDR1 和 SUB_DEVICE_ADDR2 表示子设备地址。
TIP
. 是网关层级的保留分隔符:7.8 表示「地址为 7 的(下级)网关下、地址为 8 的设备」。 子设备地址本身不要包含 .,否则会被当成多级路径解析,导致上报数据无法归属。 多级网关的用法见 多级网关(级联)。
多级网关(级联)
网关下面还可以再挂网关,形成多级网关,例如「集中网关 → 区域网关 → RS485 子设备」。 中间层网关在协议上只作为子设备地址中的一段出现,它自己不需要再连云平台,也不占用额外连接。
拓扑与地址
层级之间用 . 分隔,从最上层网关往下依次拼接:
集中网关(连云平台)
└── 区域网关 子设备地址 "7"
└── 温度子设备 子设备地址 "7.8"- 区域网关在集中网关下的子设备地址是
7。 - 温度子设备在区域网关下的子设备地址是
8;上报给平台时用完整路径7.8。 - 服务端按
.从最上层开始逐级解析;相邻两级的msgProtocol必须一致,层级深度受子设备地址长度限制。
控制台配置顺序:先在「设备类型」里准备网关类型与最下层设备的类型,建好设备,然后
- 打开集中网关的「子设备」页,关联区域网关,并设置子设备地址
7; - 打开区域网关的「子设备」页,关联温度子设备,并设置子设备地址
8。
两条关联都要求父子 msgProtocol 一致,且不能把设备关联到自己的下级(平台会拒绝成环的拓扑)。
上报
中间层网关自己的数据用它的地址,它下面设备的数据用完整路径。网关始终只用一条连接:
{
"id": 1,
"ack": 1,
"time": 1626197189638,
"gw": {
"7": { "temp": 30 },
"7.8": { "temperature": 26.5, "humidity": 62 }
}
}7 的数据归属到区域网关,7.8 的数据归属到温度子设备,不会互相串扰。
下发
平台把下行报文发到最上层网关那一条连接,gw 的键是完整路径:
{
"id": 3,
"time": 1626197189638,
"method": "attributes/set",
"data": {},
"gw": { "7.8": { "temperature": 27 } }
}属性下发、属性采集、命令下发都是这个形态。目标不是最上层网关自身时,data 会是空对象(命令下发时 data.key 为空字符串),按 gw 处理即可。
在线状态
最上层网关要为每一个层级的设备上报 gateway/connect,地址同样用完整路径:
{ "id": 101, "ack": 1, "gw": { "device": "7", "typeKey": "区域网关类型KEY" } }
{ "id": 102, "ack": 1, "gw": { "device": "7.8", "typeKey": "温度子设备类型KEY" } }WARNING
中间层网关与最下层设备一样,不上报连接状态平台就不会向它下发消息。
网关 MQTT 主题一览
以下主题中的 网关设备码 是网关设备在平台中的 deviceCode。
发布主题
网关向平台发布消息。
| 消息类型 | 主题 |
|---|---|
| 子设备上报属性值 | up/网关设备码/attributes/post |
| 子设备获取属性值 | up/网关设备码/attributes/get |
| 子设备获取期望属性 | up/网关设备码/attributes/desired_get |
| 子设备清除期望属性 | up/网关设备码/attributes/desired_delete |
| 子设备回复下发属性 | up/网关设备码/attributes/set_reply |
| 子设备回复属性采集 | up/网关设备码/attributes/acquisition_reply |
| 子设备上报事件 | up/网关设备码/event/post |
| 子设备批量上报或历史上报 | up/网关设备码/batch/post |
| 子设备回复命令 | up/网关设备码/command/send_reply |
| 子设备已连接 | up/网关设备码/gateway/connect |
| 子设备已断开 | up/网关设备码/gateway/disconnect |
| 获取子设备列表 | up/网关设备码/gateway/device_list |
订阅主题
网关订阅平台下发给子设备的消息。
| 消息类型 | 主题 |
|---|---|
| 子设备属性上报响应 | down/网关设备码/attributes/post_reply |
| 子设备属性获取响应 | down/网关设备码/attributes/get_reply |
| 子设备期望属性响应 | down/网关设备码/attributes/desired_get_reply |
| 子设备清除期望属性响应 | down/网关设备码/attributes/desired_delete_reply |
| 子设备接收下发属性 | down/网关设备码/attributes/set |
| 子设备接收属性采集 | down/网关设备码/attributes/acquisition |
| 子设备事件上报响应 | down/网关设备码/event/post_reply |
| 子设备批量上报响应 | down/网关设备码/batch/post_reply |
| 子设备接收下发命令 | down/网关设备码/command/send |
| 子设备已连接响应 | down/网关设备码/gateway/connect_reply |
| 子设备已断开响应 | down/网关设备码/gateway/disconnect_reply |
| 获取子设备列表响应 | down/网关设备码/gateway/device_list_reply |
子设备已连接
当网关确认子设备已连接时,向平台上报子设备连接状态。平台可根据 typeKey 或 productKey 自动创建子设备。
这是平台向子设备下发消息的前提
网关必须为每个子设备上报一次连接状态,否则平台不会向该子设备下发任何消息: 属性下发、命令下发、属性采集都会直接返回「设备离线」。子设备的在线状态不会因为网关在线而自动置位。
发布主题:
up/网关设备码/gateway/connect网关发送消息:
{
"id": 101,
"ack": 1,
"time": 1626197189638,
"gw": {
"device": "SUB_DEVICE_ADDR1",
"typeKey": "TYPE_KEY",
"productKey": "PRODUCT_KEY"
}
}字段说明:
| 字段 | 说明 |
|---|---|
id | 消息序号,用于匹配请求和响应。 |
ack | 是否需要平台应答,1 表示需要,0 或不填表示不需要。 |
time | 设备采集时间戳,毫秒级,可选。 |
gw | 网关数据。 |
gw.device | 子设备地址,必须。 |
gw.typeKey | 设备类型 KEY,可选。自动创建时与 productKey 至少传一个。 |
gw.productKey | 产品识别码,可选。自动创建时与 typeKey 至少传一个。 |
TIP
自动创建子设备 在一些面向终端用户的场景中,用户可根据自己的实际需要,将不同子设备连接到网关。当网关识别到新的子设备后,平台可自动创建并关联该子设备。 使用 typeKey 时,需事先创建好对应设备类型,并开启允许自动创建设备;使用 productKey 时,平台会按产品识别码匹配或创建设备类型。二者至少上传一个。
平台响应主题:
down/网关设备码/gateway/connect_reply平台回复消息:
{
"id": 101,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"id": 122,
"deviceCode": "10000003",
"typeKey": "TYPE_KEY",
"productKey": "PRODUCT_KEY"
}
}
}字段说明:
| 字段 | 说明 |
|---|---|
id | 消息序号,与请求中的 id 一致。 |
time | 平台时间戳,毫秒级。 |
code | 业务状态码,200 表示成功。 |
gw | 子设备信息,键为子设备地址。 |
gw.<addr>.id | 子设备 ID(平台侧设备 ID,不是消息序号)。 |
gw.<addr>.deviceCode | 子设备设备码。 |
gw.<addr>.typeKey | 设备类型 KEY。 |
gw.<addr>.productKey | 产品识别码。 |
子设备已断开
当网关确认子设备已断开时,向平台上报断开状态。
发布主题:
up/网关设备码/gateway/disconnect网关发送消息:
{
"id": 102,
"ack": 1,
"time": 1626197189638,
"gw": {
"device": "SUB_DEVICE_ADDR1"
}
}平台响应主题:
down/网关设备码/gateway/disconnect_reply平台回复消息:
{
"id": 102,
"time": 1626197189640,
"code": 200
}子设备上报属性
网关代子设备上报属性值。gw 的每个键是子设备地址,值是该子设备的属性键值。
发布主题:
up/网关设备码/attributes/post网关发送消息:
{
"id": 1,
"ack": 1,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"temperature": 26.5,
"humidity": 62
},
"SUB_DEVICE_ADDR2": {
"switch": true,
"voltage": 220
}
}
}平台响应主题:
down/网关设备码/attributes/post_reply平台回复消息:
{
"id": 1,
"time": 1626197189640,
"code": 200
}子设备获取属性
网关代子设备获取平台保存的属性当前值。
发布主题:
up/网关设备码/attributes/get网关发送消息:
{
"id": 2,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"keys": ["temperature", "humidity"]
},
"SUB_DEVICE_ADDR2": {
"keys": []
}
}
}平台响应主题:
down/网关设备码/attributes/get_reply平台回复消息:
{
"id": 2,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"temperature": {
"value": 26.5,
"time": 1626197189640
},
"humidity": {
"value": 62,
"time": 1626197189640
}
},
"SUB_DEVICE_ADDR2": {
"switch": {
"value": true,
"time": 1626197189640
}
}
}
}子设备获取期望属性
网关代子设备获取平台暂存的期望属性。
发布主题:
up/网关设备码/attributes/desired_get网关发送消息:
{
"id": 3,
"ack": 1,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"id": 31,
"keys": ["switch", "brightness"]
},
"SUB_DEVICE_ADDR2": {
"id": 32,
"keys": []
}
}
}平台响应主题:
down/网关设备码/attributes/desired_get_reply平台回复消息:
{
"id": 3,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"switch": {
"value": true,
"time": 1626197189640,
"version": 1
},
"brightness": {
"value": 80,
"time": 1626197189640,
"version": 2
}
}
}
}子设备清除期望属性
子设备成功执行期望属性后,网关代子设备清除对应期望值。
发布主题:
up/网关设备码/attributes/desired_delete网关发送消息:
{
"id": 4,
"ack": 1,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"switch": {
"version": 1
},
"brightness": {
"version": 2
}
}
}
}平台响应主题:
down/网关设备码/attributes/desired_delete_reply平台回复消息:
{
"id": 4,
"time": 1626197189640,
"code": 200
}子设备事件上报
网关代子设备上报事件。
发布主题:
up/网关设备码/event/post网关发送消息:
{
"id": 5,
"ack": 1,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"id": 51,
"key": "alarmEvent",
"value": {
"temperature": -10
}
},
"SUB_DEVICE_ADDR2": {
"id": 52,
"key": "doorEvent",
"value": {
"open": true
}
}
}
}平台响应主题:
down/网关设备码/event/post_reply平台回复消息:
{
"id": 5,
"time": 1626197189640,
"code": 200
}子设备批量上报或历史上报
网关可代多个子设备一次上报多条属性和事件数据。
发布主题:
up/网关设备码/batch/post网关发送消息:
{
"id": 6,
"ack": 1,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"attributes": [
{
"key": "temperature",
"value": 26.5,
"time": 1626197182640
},
{
"key": "humidity",
"value": 62,
"time": 1626197189640
}
],
"events": [
{
"key": "alarmEvent",
"time": 1626197189640,
"value": {
"temperature": -10
}
}
]
}
}
}平台响应主题:
down/网关设备码/batch/post_reply平台回复消息:
{
"id": 6,
"time": 1626197189640,
"code": 200
}子设备属性下发
平台向子设备下发属性时,网关从订阅主题接收消息,并转发给对应子设备。
订阅主题:
down/网关设备码/attributes/set网关接收消息:
{
"id": 7,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"switch": true,
"brightness": 80
}
}
}网关回复主题:
up/网关设备码/attributes/set_reply网关回复消息:
{
"id": 7,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"code": 200
}
}
}子设备属性采集
平台向子设备发起属性采集时,网关负责采集子设备实时值并回复。
订阅主题:
down/网关设备码/attributes/acquisition网关接收消息:
{
"id": 8,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"keys": ["temperature", "humidity"]
}
}
}网关回复主题:
up/网关设备码/attributes/acquisition_reply网关回复消息:
{
"id": 8,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"temperature": 26.5,
"humidity": 62
}
}
}子设备命令下发
平台向子设备下发命令时,网关接收命令并转发给对应子设备,随后返回执行结果。
订阅主题:
down/网关设备码/command/send网关接收消息:
{
"id": 9,
"time": 1626197189638,
"gw": {
"SUB_DEVICE_ADDR1": {
"id": 91,
"key": "set_param",
"input": {
"mode": "auto",
"threshold": 30
}
}
}
}网关回复主题:
up/网关设备码/command/send_reply网关回复消息:
{
"id": 9,
"time": 1626197189640,
"code": 200,
"gw": {
"SUB_DEVICE_ADDR1": {
"id": 91,
"key": "set_param",
"code": 200,
"output": {
"result": "ok"
}
}
}
}获取子设备列表
网关向平台分页查询已关联的子设备列表。每次最多返回 100 条子设备;总数超过一页时,网关需按 page 继续拉取。
发布主题:
up/网关设备码/gateway/device_list网关发送消息:
{
"id": 10,
"ack": 1,
"time": 1626197189638,
"gw": {
"page": 1,
"pageSize": 100
}
}字段说明:
| 字段 | 说明 |
|---|---|
id | 消息序号,用于匹配请求和响应。 |
ack | 是否需要平台应答。本接口应传 1,否则平台不返回子设备列表。 |
time | 设备采集时间戳,毫秒级,可选。 |
gw.page | 页码,从 1 开始,可选,默认 1。 |
gw.pageSize | 每页数量,可选,默认 100,最大 100。超过最大值时按 100 处理。 |
平台响应主题:
down/网关设备码/gateway/device_list_reply平台回复消息:
{
"id": 10,
"time": 1626197189638,
"code": 200,
"gw": {
"page": 1,
"pageSize": 100,
"total": 2,
"data": {
"SUB_DEVICE_ADDR1": {
"id": 122,
"deviceCode": "10000003"
},
"SUB_DEVICE_ADDR2": {
"id": 123,
"deviceCode": "10000004"
}
}
}
}字段说明:
| 字段 | 说明 |
|---|---|
id | 消息序号,与请求中的 id 一致。 |
time | 平台时间戳,毫秒级。 |
code | 业务状态码,200 表示成功。 |
gw.page | 当前页码。 |
gw.pageSize | 当前页请求的每页数量。 |
gw.total | 子设备总数。可根据 gw.total 与 gw.pageSize 判断是否还有下一页。 |
gw.data | 当前页子设备列表,键为子设备地址;本页最多 100 条。 |
gw.data.<addr>.id | 子设备 ID(平台侧设备 ID,不是消息序号)。 |
gw.data.<addr>.deviceCode | 子设备设备码。 |
