设备网关与子设备

物联网平台支持设备直连,也支持设备挂载在网关上,作为网关的子设备,由网关直连。

使用场景:适用于子设备不能直连或者需要拓扑关系管理的场景,例如接入 Wi-Fi 网关、蓝牙网关、ZigBee 网关等。

(图片来自阿里云)

网关与子设备架构图

1. 概述

1.1 设备类型

创建产品时,需要选择设备类型。设备类型由 IotProductDeviceTypeEnum 枚举定义,包含以下三种:

产品设备类型

名称 说明
直连设备 直接连接物联网平台,独立进行数据上报和接收命令
网关子设备 不能直接连接物联网平台,需要通过网关设备代理接入
网关设备 可以直接连接物联网平台,并且能代理多个子设备接入,管理子设备的拓扑关系

设备创建时,会自动继承所属产品的设备类型。

1.2 网关子设备使用同一套协议

网关连接物联网平台后,将拓扑关系同步至物联网平台的云端,"代理"子设备进行设备认证、消息上传、指令接收等与物联网平台的通信。

简单理解

网关设备就像子设备的"路由器" —— 子设备自身不具备直连物联网平台的能力,需要通过网关进行消息转发和代理通信。

网关子设备与直连设备使用完全相同的协议。 以 MQTT 协议为例,子设备的属性上报、事件上报、服务调用等,都跟直连设备使用相同的主题和消息格式:

操作 直连设备主题 网关子设备主题
属性上报 /sys/{productKey}/{deviceName}/thing/property/post /sys/{productKey}/{deviceName}/thing/property/post
事件上报 /sys/{productKey}/{deviceName}/thing/event/post /sys/{productKey}/{deviceName}/thing/event/post
服务调用 /sys/{productKey}/{deviceName}/thing/service/invoke /sys/{productKey}/{deviceName}/thing/service/invoke

具体来说,子设备不直接连接物联网平台,而是将消息发给网关设备,再由网关设备转发到物联网平台:

  • 认证:网关设备使用子设备的三元组(productKey + deviceName + deviceSecret)向平台执行认证
  • 上报:网关设备以子设备的 {productKey}/{deviceName} 为主题,将子设备的数据上报到平台
  • 下发:平台以子设备的 {productKey}/{deviceName} 为主题下发指令,由网关设备接收后转发给子设备

② 网关设备独有的操作包括:

  • 拓扑管理:thing.topo.addthing.topo.deletething.topo.getthing.topo.change
  • 子设备动态注册:thing.auth.register.sub(详见 《设备动态注册》
  • 批量上报:thing.event.property.pack.post(网关一次上报自身 + 多个子设备的数据)

1.3 拓扑关系的两种管理方式

拓扑关系(即网关与子设备的绑定关系)支持两种管理方式

方式 说明 适用场景
方式一:后台绑定 管理员在管理后台手动绑定/解绑子设备,操作完成后平台下发 thing.topo.change 通知给网关 部署阶段、手动配置
方式二:协议绑定 网关设备通过 MQTT 协议主动上报 thing.topo.add/delete/get 消息,动态管理拓扑关系 运行阶段、自动发现

两种方式可以并存,互不影响。

1.4 表结构设计

iot_device 表中,通过 device_typegateway_id 字段支持网关与子设备的关联关系:

字段 类型 说明
device_type tinyint 设备类型,参见 IotProductDeviceTypeEnum 枚举
gateway_id bigint 网关设备 ID,子设备需要关联的网关设备 ID(直连/网关设备为空)

2. 拓扑关系管理(后台绑定)

管理员在管理后台手动管理子设备与网关的绑定关系。由 IotDeviceController 提供接口。

① 在设备详情页,仅「网关设备」显示【子设备管理】Tab 页签。对应前端项目的 @/views/iot/device/device/detail/DeviceDetailsSubDevice.vue

设备详情 - 子设备管理

展示当前网关下已绑定的所有子设备,包括设备名称、备注名称、所属产品、设备状态、最后上线时间等信息。

② 点击【添加子设备】按钮,弹出对话框。支持按产品筛选(仅显示「网关子设备」类型的产品),选中未绑定的子设备后确认绑定。

绑定子设备

支持单个解绑和批量解绑。选中已绑定的子设备,点击【解绑】或【批量解绑】按钮即可解除绑定关系。

后台绑定或解绑操作完成后,平台会通过 thing.topo.change 下行消息主动通知网关设备,网关设备可据此更新本地拓扑缓存。

3. 拓扑关系管理(协议绑定)

网关设备也可以通过 MQTT 协议主动管理拓扑关系,实现运行时动态添加/删除子设备。

3.1 MQTT 主题格式

操作 方向 消息方法 MQTT 主题
添加拓扑关系 上行 thing.topo.add /sys/{productKey}/{deviceName}/thing/topo/add
删除拓扑关系 上行 thing.topo.delete /sys/{productKey}/{deviceName}/thing/topo/delete
获取拓扑关系 上行 thing.topo.get /sys/{productKey}/{deviceName}/thing/topo/get
拓扑变更通知 下行 thing.topo.change /sys/{productKey}/{deviceName}/thing/topo/change

其中 {productKey}{deviceName}网关设备的标识。回复主题在原主题后追加 _reply 后缀。

3.2 快速测试

可以通过以下集成测试类快速体验,具体步骤见各类的注释:

协议 网关设备 网关子设备
MQTT IotGatewayDeviceMqttProtocolIntegrationTest IotGatewaySubDeviceMqttProtocolIntegrationTest
HTTP IotGatewayDeviceHttpProtocolIntegrationTest IotGatewaySubDeviceHttpProtocolIntegrationTest
CoAP IotGatewayDeviceCoapProtocolIntegrationTest IotGatewaySubDeviceCoapProtocolIntegrationTest
TCP IotGatewayDeviceTcpProtocolIntegrationTest IotGatewaySubDeviceTcpProtocolIntegrationTest
UDP IotGatewayDeviceUdpProtocolIntegrationTest IotGatewaySubDeviceUdpProtocolIntegrationTest
WebSocket IotGatewayDeviceWebSocketProtocolIntegrationTest IotGatewaySubDeviceWebSocketProtocolIntegrationTest

3.3 消息数据结构

拓扑相关的消息数据结构定义在 yudao-module-iot-core 模块的 core.topic.topo 包中:

消息方法 方向 数据结构类 说明
thing.topo.add 上行 IotDeviceTopoAddReqDTO 包含 subDevices 子设备认证信息列表
thing.topo.delete 上行 IotDeviceTopoDeleteReqDTO 包含 subDevices 子设备标识列表
thing.topo.get 上行 IotDeviceTopoGetReqDTO 目前为空,预留扩展
thing.topo.get 上行 IotDeviceTopoGetRespDTO 包含 subDevices 子设备标识列表
thing.topo.change 下行 IotDeviceTopoChangeReqDTO 包含 status(0=创建/1=删除)和 subList 子设备列表

4. 网关批量上报

网关设备支持批量上报功能:一次消息同时上报网关自身和多个子设备的属性、事件数据。这是网关设备独有的操作,对应 thing.event.property.pack.post 消息方法。

以 MQTT 协议为例,网关设备上报批量消息的主题和数据格式如下:

  • MQTT 主题:/sys/{gatewayProductKey}/{gatewayDeviceName}/thing/event/property/pack/post
  • 数据格式:对应 IotDevicePropertyPackPostReqDTO 类
    {
      "method": "thing.event.property.pack.post",
      "params": {
        "properties": {
          "cpuUsage": 45.2
        },
        "events": {
          "alert": {
            "value": { "level": 1 },
            "time": 1739265600000
          }
        },
        "subDevices": [
          {
            "identity": {
              "productKey": "YzvHxd4r67sT4s2B",
              "deviceName": "small"
            },
            "properties": {
              "temperature": 36.5,
              "humidity": 60
            },
            "events": {
              "eat": {
                "value": { "rice": 3 },
                "time": 1739265600000
              }
            }
          }
        ]
      }
    }
    

平台收到后,会将批量消息拆分为各设备独立的 thing.property.postthing.event.post 消息分别处理。具体可见 IotDeviceMessageServiceImpl 的 #handlePackMessage(...) 方法。