网关 MQTT 接入
网关 MQTT 接入
在物联网中,网关的作用是将那些本身不能直接连接云平台的设备,通过网关的中转,让设备接入云平台。网关起到的作用是数据转发和协议转换。
网关和云平台的通信主要分为:
- 网关设备自身和云平台的通信,例如:上报网关自身的设备状态和属性,接收云平台对网关的控制指令等。
- 网关子设备和云平台的通信,例如:网关连接的 Zigbee 温湿度传感器向云平台上报温湿度,以及网关连接的 RS485/Modbus 8路继电器,接收云平台下发的实时指令。这些子设备的通信都需要经过网关的转发。
提示
网关本身也是一类设备,网关自身和云平台的通信,和普通设备接入完全相同,请浏览 MQTT 接入。
这一节,我们主要介绍的是网关如何实现子设备和云平台的通信,ThingsCloud 提供了一套网关专用的 MQTT 协议,包括独立的主题和消息格式。
为网关添加子设备
在使用网关 MQTT 协议时,需要先在 ThingsCloud 云平台上为网关和子设备绑定关系。
设备类型
首先,网关和子设备都是 设备,它们的区别仅仅在于所属的 设备类型 不同:
- 网关设备必须归属于 网关 设备类型。
- 网关子设备必须归属于 网关子设备 设备类型。
创建子设备
对于网关设备,在 设备详情页 > 子设备 中可以添加子设备,如下图:

在云平台的设备视角中,网关和子设备是同样的存在形式,如下图:

网关和子设备具有和其它直连设备同样的功能,例如:属性、事件、命令、规则、任务、OTA固件升级、可视化、零代码应用开发等。
子设备地址
子设备地址是子设备的身份标识,帮助云平台和网关识别不同的子设备。因此,子设备地址在同一个网关的多个子设备中需保持唯一,
在网关中添加子设备后,您可以为每个子设备设置子设备地址,如下图:

未设置子设备地址的子设备,无法通过网关设备上报数据,也无法接收云平台通过网关下发给它的数据。
根据不同的子设备通信方式,子设备地址有不同的格式要求。例如:
- Modbus 子设备地址,就是子设备的从机站号。
- BLE 子设备通常使用模组芯片的 UUID。
您也可以按照一定的规则生成 子设备地址 ,可以是数字或字符串,只要确保在同一个网关中唯一即可,然后将它烧录到子设备中。
网关与云平台的连接
要实现子设备和云平台的通信,首先必须让网关通过 MQTT 接入云平台。网关设备的 MQTT 接入点和身份认证方式,和普通直连设备完全相同,详细介绍请浏览 MQTT 接入。
网关 MQTT 主题一览
对于子设备和云平台的通信,网关可使用以下 MQTT 主题:
发布主题
网关设备通过以下主题,将子设备的消息上报到云平台。
| 消息类型 | 主题 |
|---|---|
| 子设备已连接 | gateway/connect |
| 子设备已断开 | gateway/disconnect |
| 上报子设备属性 | gateway/attributes |
| 上报子设备历史属性 | gateway/attributes/series |
| 获取子设备属性 | gateway/attributes/get |
| 上报子设备事件 | gateway/event/report |
| 上报子设备命令回复 | gateway/command/reply |
订阅主题
网关设备通过以下主题,接收云平台下发给子设备的消息。
| 消息类型 | 主题 |
|---|---|
| 接收子设备连接响应 | gateway/connect/response |
| 接收子设备上报属性的响应 | gateway/attributes/response |
| 接收子设备上报历史属性的响应 | gateway/attributes/series/response |
| 接收子设备获取属性的响应 | gateway/attributes/get/response |
| 接收下发给子设备的属性 | gateway/attributes/push |
| 接收子设备事件上报的响应 | gateway/event/response |
| 接收下发给子设备的命令 | gateway/command/send |
下面我们重点介绍一些常用的发布主题和订阅主题。
子设备已连接
当网关确定子设备已连接时,可上报消息通知云平台。
发布主题
gateway/connect
消息格式
提示
网关 MQTT 的所有消息都必须是 JSON 格式,如果发布的不是 JSON 格式,设备会被云平台主动断开 MQTT 连接。
{
"device": "SUB_DEVICE_ADDR"
}
device:子设备地址。
自动创建子设备
在一些面向终端用户的场景中,用户可根据自己的实际需要,将不同子设备连接到网关,当网关识别到新的子设备后,我们需要能够在云平台自动创建新的子设备。
例如:智能家居 Zigbee 网关识别到传感器子设备,或草莓温室中的 LoRaWAN 网关识别到新的光照传感器。
ThingsCloud 云平台支持网关自动创建子设备,任何使用 ThingsCloud 网关 MQTT 协议的网关硬件,都可以实现自动创建子设备。
这里支持两种方式,原理类似于直连或网关设备动态获取证书时自动创建设备。
使用设备类型 TypeKey
消息格式如下:
{
"device": "SUB_DEVICE_ADDR",
"type_key": "TYPE_KEY"
}
type_key:设备类型的TypeKey。需要事先创建好设备类型,接入类型必须是网关子设备,且设备类型开启了允许自动创建设备。
使用产品识别码 ProductKey
消息格式如下:
{
"device": "SUB_DEVICE_ADDR",
"product_key": "PRODUCT_KEY"
}
product_key:产品识别码。应使用已发布的产品识别码,以便在任何 ThingsCloud 项目中可以自动创建该设备类型。详细介绍请浏览 产品识别码。
响应主题
gateway/connect/response
响应消息格式
{
"result": 1,
"ts": 1704070800123,
"message": "Sub device found",
"device": {
"id": "{id}",
"name": "{name}",
"sub_device_addr": "{sub_device_addr}",
}
}
result:处理结果,1表示成功,0表示失败。ts:服务器接收到请求的时间戳(毫秒)。message:响应消息描述Sub device found:子设备地址在云平台存在。Sub device created:子设备地址在云平台不存在,已自动创建新的子设备,并添加到当前网关。
device:子设备信息id:子设备 IDname:子设备名称sub_device_addr:子设备地址

子设备已断开
当网关确定子设备已断开时,可上报消息通知云平台。
发布主题
gateway/disconnect
消息格式
{
"device": "SUB_DEVICE_ADDR"
}
SUB_DEVICE_ADDR:子设备地址。
上报子设备属性
当网关接收子设备的属性变化时,向云平台上报子设备属性。
发布主题
gateway/attributes
消息格式
{
"SUB_DEVICE_ADDR1": {
"ATTRIBUTES1": VALUE1,
"ATTRIBUTES2": VALUE2
},
"SUB_DEVICE_ADDR2": {
"ATTRIBUTES1": VALUE1,
"ATTRIBUTES2": VALUE2
}
}
网关支持一次上报多个子设备的属性。
SUB_DEVICE_ADDR1、SUB_DEVICE_ADDR2:子设备地址。
举个例子,网关上报多个子设备的属性,如下:
{
"SUB_DEVICE_ADDR1": {
"battery": 100,
"occupancy": false
},
"SUB_DEVICE_ADDR2": {
"battery": 98,
"occupancy": true
}
}
响应主题
gateway/attributes/response
响应消息格式
{
"result": 1,
"ts": 1704070800123
}
result:处理结果,1表示成功,0表示失败。ts:服务器接收到请求的时间戳(毫秒)。
这时,在控制台的子设备详情页,会实时更新显示设备属性的最新值。

如果我们事先打开子设备的调试状态,可以看到这条上报的消息。虽然是上报给网关设备的,但是消息被转发给了子设备。如下:

接收下发给子设备的属性
网关订阅这个主题,可以实时接收云平台下发给子设备的属性消息。
订阅主题
gateway/attributes/push
消息格式
接收到的消息格式如下:
{
"device": "SUB_DEVICE_ADDR1",
"attributes": {
"ATTRIBUTES1": VALUE1,
"ATTRIBUTES2": VALUE2
}
}
device:表示子设备地址。
举个例子,我们子设备详情页下发属性,如图:

这时,网关会通过该订阅的主题,收到下发给子设备的消息,如图:

收到的消息如下:
{
"device": "SUB_DEVICE_ADDR1",
"attributes": {
"relay1": true
}
}
接下来网关可通过自身的运行机制,将消息转发给 子设备地址 为 SUB_DEVICE_ADDR1 的子设备,或者在转发前对数据包进行必要的处理。
上报子设备离线属性数据
在某些场景下,网关或子设备可能无法保持实时在线状态,例如在信号覆盖不佳的区域或电池供电设备进入低功耗模式时。网关或子设备可以在本地缓存历史属性数据,当网络恢复时,通过网关一次性上报这些历史数据。
与当前属性上报不同,历史属性数据上报有以下特点:
- 数据中需包含时间戳,用于标识属性值产生的实际时间。
- 上报的历史数据不会触发实时消息规则和告警规则。
- 不会推送给应用端 MQTT 订阅。
发布主题
gateway/attributes/series
消息格式
{
"device": "SUB_DEVICE_ADDR",
"series": [
{
"ts": {timestamp},
"values": {
"key1": {value1},
"key2": {value2}
}
},
{
"ts": {timestamp},
"values": {
"key1": {value1},
"key2": {value2}
}
},
...
]
}
device:子设备地址。series:历史属性数据数组,和设备 MQTT 直连中的 设备上报离线属性数据 规范相同。
响应主题
网关订阅以下主题,用来接收云平台对历史属性上报的响应:
gateway/attributes/series/response
响应消息格式
{
"result": 1,
"ts": 1609143039050
}
result:处理结果,1表示成功,0表示失败。ts:服务器接收到请求的时间戳(毫秒)。
提示
建议网关在收到成功响应后,再删除本地已上报的历史数据缓存。
获取子设备属性
网关可以获取子设备在云平台的属性,例如用来初始化子设备的运行状态。
发布主题
gateway/attributes/get
发布消息格式
{
"device": "SUB_DEVICE_ADDR1",
"get": {
"keys": ["KEY1", "KEY2"]
}
}
device:表示子设备地址。keys:要读取的属性标识符数组,空数组[]标识读取所有属性。
订阅主题
网关订阅以下主题,用来接收云平台回复的子设备属性。
gateway/attributes/get/response
回复消息格式
{
"device": "SUB_DEVICE_ADDR1",
"response": {
"result": 1,
"attributes": {
"KEY1": VALUE1,
"KEY1": VALUE2
}
}
}
device:表示子设备地址。response:读取子设备属性的回复内容。
上报子设备的事件
在前边的介绍中,我们已经知道,事件 通常用于设备向云平台发送一些通知或请求,但不希望将相关参数记录到设备属性中。
网关同样可以上报子设备的事件,并触发云平台对子设备设置的事件规则。
发布主题
gateway/event/report
消息格式
{
"device": "SUB_DEVICE_ADDR1",
"event": {
"method": "EVENT_IDENTIFIER",
"params": {
"PARAM1": VALUE1,
"PARAM2": VALUE2
},
"id": 1000
}
}
device:表示子设备地址。event:事件消息体。与直连设备事件上报的格式相同。
响应主题
gateway/event/response
响应消息格式
{
"result": 1,
"ts": 1704070800123
}
result:处理结果,1表示成功,0表示失败。ts:服务器接收到请求的时间戳(毫秒)。
例如,网关上报子设备请求 OTA 固件版本检查的事件,如下:

在子设备的 设备详情页 > 事件 列表中,可以看到刚刚收到的事件上报。

提示
ThingsCloud 提供的 OTA 固件升级功能,对子设备无缝兼容,使用方法和直连设备的 OTA 升级完全相同。详细介绍请浏览 OTA 固件升级。
接收下发给子设备的命令
订阅主题
gateway/command/send
消息格式
接收到的消息格式如下:
{
"device": "SUB_DEVICE_ADDR1",
"command": {
"method": "COMMAND_IDENTIFIER",
"params": {
"PARAM1": VALUE1,
"PARAM2": VALUE2
},
"id": 1000
}
}
device:表示子设备地址。command:命令消息体。与直连设备下发命令消息的格式相同。
举个例子,我们在云平台向子设备下发命令,如图:

这时,网关通过订阅该主题,可以实时接收到下发的命令消息,如下图:

收到的消息如下:
{
"device": "SUB_DEVICE_ADDR1",
"command": {
"method": "restart",
"params": {
"delay": 30
},
"id": 1000
}
}
上报子设备的命令回复
子设备收到命令消息后,在设备端实现特定的功能后,可以回复命令,也可以不回复命令。
云平台会自动接收回复命令,并和下发命令进行匹配,在控制台的设备命令历史中,您可以看到一组包含下发和回复的命令日志。一次下发命令只能接收一次回复命令,它们的匹配是通过使用一致的 <id> 来保证。
当应用端通过 HTTP API 使用同步命令下发模式时,子设备如果成功上报命令回复,应用端会在 HTTP 响应消息中同步接收设备的命令回复,这可以帮助您实现一些在应用端希望同步获得设备端响应消息的场景。
发布主题
gateway/command/reply
消息格式
{
"device": "SUB_DEVICE_ADDR1",
"command": {
"method": "EVENT_IDENTIFIER",
"params": {
"result": VALUE,
},
"id": 1000
}
}
device:表示子设备地址。command:命令消息体。与下发命令的格式相同。
响应主题
gateway/command/reply/response
响应消息格式
{
"result": 1,
"ts": 1704070800123
}
result:处理结果,1表示成功,0表示失败。ts:服务器接收到请求的时间戳(毫秒)。
常见错误响应
当网关上报消息出现错误时,可通过订阅相应的主题,接收云平台返回的错误响应消息。以下是常见的错误消息:
网关设备未找到
{
"result": 0,
"message": "Device not found",
"errcode": 401
}
- 原因:设备证书无效或设备已被删除。
- 处理:检查网关设备是否存在,以及 MQTT 接入证书是否正确。
设备类型不是网关
{
"result": 0,
"message": "Device type is not gateway",
"errcode": 420
}
- 原因:当前设备所属的设备类型不是网关类型。
- 处理:在云平台将设备类型设置为网关类型。
子设备未找到
{
"result": 0,
"message": "Gateway sub device not found",
"errcode": 421
}
- 原因:子设备地址不存在或子设备未添加到当前网关。
- 处理:检查子设备地址是否正确,并在云平台为网关添加该子设备。
消息格式无效
{
"result": 0,
"message": "Message invalid",
"errcode": 422
}
- 原因:消息体格式错误。
- 处理:按照文档要求检查消息格式。
消息频率过高
{
"result": 0,
"message": "Device message frequency is too high, please wait for a moment",
"errcode": 403
}
- 原因:设备上报消息的频率过快。
- 处理:降低上报频率后再重试。