Skip to content

设备接入(概述) ​

推荐阅读:

# 1. 整体架构 ​

# 1.1 消息流转 ​

设备消息的端到端流转过程如下: 整体架构 ① 上行(设备 → 网关 → 平台):

  1. 【设备】通过协议(HTTP / MQTT / TCP 等)发送数据到网关
  2. 【网关】协议处理器解析、认证、反序列化,生成 IotDeviceMessage
  3. 【网关】将消息发布到消息总线,Topic 为 iot_device_message
  4. 【平台】biz 端的消费者订阅该 Topic,消费并处理消息 ② 下行(平台 → 网关 → 设备):
  5. 【平台】biz 端生成下行消息(如属性设置、服务调用)
  6. 【平台】发布到消息总线,Topic 为 iot_device_message_{serverId}(指定目标网关实例)
  7. 【网关】下行订阅者收到消息,序列化后推送给设备

# 1.2 模块说明 ​

设备接入涉及三个模块,协作关系如下: 模块结构 模块 职责 运行进程 yudao-module-iot-gateway 设备网关:协议服务器(HTTP / MQTT / TCP 等),接收设备消息并转发 iot-gateway-server yudao-module-iot-biz IoT 平台:业务消费者,处理设备消息(状态更新、属性存储、规则引擎等),即管理后台的后端 yudao-server yudao-module-iot-core 共享库:消息总线、Topic DTO、消息格式、枚举、工具类,被 gateway 和 biz 共同依赖 — 友情提示:「设备网关」不是「网关设备」,不要理解错!!!

  • 设备网关(iot-gateway-server):指本项目的"设备接入网关"软件,负责接收设备消息并转发到平台。对应 yudao-module-iot-gateway 模块。
  • 网关设备:指物联网中的一类硬件设备,能够代理多个子设备接入平台。详见 《设备网关与子设备》。 友情提示 后续文档中,【biz】 和 【平台】 是等价的,都指 yudao-module-iot-biz 模块。

# 1.3 网关启动 ​

yudao-module-iot-gateway 对应设备网关(iot-gateway-server),它是独立进程,需要单独启动。 启动类为 IotGatewayServerApplication,在 IDEA 中直接运行该 main 方法即可。如下是一个启动日志的例子: 2026-02-11T19:08:00.933+08:00 INFO 46576 --- [iot-gateway-server] [ main] m.i.c.m.c.IotMessageBusAutoConfiguration : [iotRedisMessageBus][创建 IoT Redis 消息总线] 2026-02-11T19:08:00.982+08:00 INFO 46576 --- [iot-gateway-server] [ main] .i.y.m.i.g.s.IotMessageSerializerManager : [IotSerializerManager][序列化器 JSON 创建成功] 2026-02-11T19:08:00.982+08:00 INFO 46576 --- [iot-gateway-server] [ main] .i.y.m.i.g.s.IotMessageSerializerManager : [IotSerializerManager][序列化器 BINARY 创建成功] 2026-02-11T19:08:01.237+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 http-json 未启用,跳过] 2026-02-11T19:08:01.237+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 tcp-json 未启用,跳过] 2026-02-11T19:08:01.237+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 udp-json 未启用,跳过] 2026-02-11T19:08:01.237+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 websocket-json 未启用,跳过] 2026-02-11T19:08:01.237+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 coap-json 未启用,跳过] 2026-02-11T19:08:01.238+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 mqtt-json 未启用,跳过] 2026-02-11T19:08:01.238+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 emqx-1 未启用,跳过] 2026-02-11T19:08:01.238+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 modbus-tcp-client-1 未启用,跳过] 2026-02-11T19:08:01.238+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议实例 modbus-tcp-server-1 未启用,跳过] 2026-02-11T19:08:01.238+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.protocol.IotProtocolManager : [start][协议管理器启动完成,共启动 0 个协议实例] 2026-02-11T19:08:01.244+08:00 INFO 46576 --- [iot-gateway-server] [ main] c.i.y.m.i.g.IotGatewayServerApplication : Started IotGatewayServerApplication in 2.271 seconds (process running for 2.802) 另外,它有独立的 application.yaml 配置文件,可以按需改动。【目前暂时不需要】

# 2. 设备消息 ​

# 2.1 消息格式 ​

设备消息统一使用 IotDeviceMessage 类,定义在 yudao-module-iot-core 模块。 它的设计类似一次 Java 方法调用:method 是方法名,params 是入参,data 是返回值,code + msg 是异常信息。 请求字段(类比方法调用):

字段类型说明
requestIdString请求编号,由设备生成
methodString请求方法,参见 IotDeviceMessageMethodEnum 枚举
paramsObject请求参数(根据 method 反序列化为对应的 Topic DTO,见「2.2 消息方法」)
响应字段(类比返回结果):
字段类型说明
---------
dataObject响应结果
codeInteger响应错误码
msgString响应信息
其它字段(后端自动填充):
字段类型说明
---------
idString消息编号,后端自动生成
reportTimeLocalDateTime上报时间,后端自动生成
deviceIdLong设备编号,后端根据认证信息查询获取
tenantIdLong租户编号,后端根据认证信息查询获取
serverIdString服务编号,标识消息来源的网关协议实例

# 2.2 消息方法 ​

所有消息方法定义在 IotDeviceMessageMethodEnum 枚举中,upstream 字段标识消息方向(true 为设备上行,false 为平台下行)。 它与阿里云 Alink 协议中的 Topic 是类似的概念 —— 都用于标识一次设备交互的类型。区别在于,阿里云使用 Topic 路径(如 /sys/{pk}/{dn}/thing/event/property/post),我们则简化为 method 字符串(移除 {pk}、{dn} 设备相关身份标识)。 数据结构类定义在 yudao-module-iot-core 模块的 core.topic 包中。 ① 认证 / 注册 / 状态:

方法名称方向数据结构类
thing.auth.register设备动态注册上行IotDeviceRegisterReqDTO / IotDeviceRegisterRespDTO
thing.auth.register.sub子设备动态注册上行IotSubDeviceRegisterReqDTO / IotSubDeviceRegisterRespDTO
thing.state.update设备状态更新上行IotDeviceStateUpdateReqDTO
② 属性 / 事件 / 服务(核心):
方法名称方向数据结构类
------------
thing.property.post属性上报上行IotDevicePropertyPostReqDTO
thing.property.set属性设置下行IotDevicePropertySetReqDTO
thing.event.post事件上报上行IotDeviceEventPostReqDTO
thing.service.invoke服务调用下行IotDeviceServiceInvokeReqDTO
thing.event.property.pack.post批量上报上行IotDevicePropertyPackPostReqDTO
③ 拓扑关系【仅网关设备相关】:
方法名称方向数据结构类
------------
thing.topo.add添加拓扑关系上行IotDeviceTopoAddReqDTO
thing.topo.delete删除拓扑关系上行IotDeviceTopoDeleteReqDTO
thing.topo.get获取拓扑关系上行IotDeviceTopoGetReqDTO / IotDeviceTopoGetRespDTO
thing.topo.change拓扑关系变更下行IotDeviceTopoChangeReqDTO
④ 配置 / OTA:
方法名称方向数据结构类
------------
thing.config.push配置推送下行IotDeviceConfigPushReqDTO
thing.ota.upgradeOTA 固件推送下行IotDeviceOtaUpgradeReqDTO
thing.ota.progressOTA 升级进度上行IotDeviceOtaProgressReqDTO

# 2.3 消息总线 ​

消息总线用于 gateway 和 biz 之间的消息传递,定义在 yudao-module-iot-core 模块的 messagebus 包中。 核心接口为 IotMessageBus,提供两个方法:

  • #post(topic, message):发布消息到指定 Topic
  • #register(subscriber):注册消息订阅者(IotMessageSubscriber 接口)

# 2.3.1 实现方式 ​

类型实现类适用场景
redisIotRedisMessageBus默认,开发 / 测试 / 轻量部署
rocketmqIotRocketMQMessageBus生产环境,高吞吐
localIotLocalMessageBus单进程(gateway 与 biz 合一部署)
可通过 yudao.iot.message-bus.type 配置项切换,默认为 redis。

# 2.3.2 消息主题 ​

主题方向说明
① iot_device_message上行(设备 → biz)所有协议的上行消息统一发布到此 Topic
② iot_device_message_{serverId}下行(biz → 网关)按 serverId 路由到指定网关协议实例
其中 serverId 由网关自动生成,用于区分不同的协议实例,具体见 IotDeviceMessageUtils#generateServerId(serverPort) 方法。

# 2.4 发布消息 ​

① 网关侧(上行): 协议处理器(如 IotHttpUpstreamHandler)解析设备数据后,调用网关侧 IotDeviceMessageService(位于 yudao-module-iot-gateway)的 #sendDeviceMessage(message, productKey, deviceName, serverId) 方法。该方法内部会补全 deviceId、tenantId 等字段,然后通过 IotDeviceMessageProducer 的 #sendDeviceMessage(message) 发布到上行 Topic。 ② 平台侧(下行): biz 端生成下行消息后,调用 IotDeviceMessageProducer 的 #sendDeviceMessageToGateway(serverId, message) 发布到下行 Topic iot_device_message_{serverId}。

# 2.5 消费消息 ​

① 平台侧(消费上行): biz 端通过实现 IotMessageSubscriber 接口来消费上行消息。订阅者在 #getTopic() 中返回 Topic,在 #onMessage(message) 中处理消息,并通过 IotMessageBus#register(subscriber) 注册。 biz 端有 3 个订阅者消费上行消息(Topic 为 iot_device_message):

订阅者说明
IotDeviceMessageSubscriber核心业务:更新设备状态、记录属性 / 事件 / 消息
IotSceneRuleMessageSubscriber场景联动规则
IotDataRuleMessageSubscriber数据流转规则
② 网关侧(消费下行): 每种协议都有对应的 DownstreamSubscriber,订阅 Topic iot_device_message_{serverId},接收 biz 端下发的消息后推送给设备。例如 MQTT 协议的 IotMqttDownstreamSubscriber 等。
注意:HTTP、COAP 等短连接协议不支持下行推送(IotHttpDownstreamSubscriber 会忽略消息)。

# 3. 设备认证 ​

# 3.1 设备认证(一机一密) ​

设备通过 ProductKey + DeviceName + DeviceSecret 三元组进行身份认证。整体类似 《阿里云物联网 —— 一机一密》 。 认证流程:

  1. 设备端根据三元组,生成 clientId、username、password 三个字段,提交到网关。生成算法可参考 IotDeviceAuthUtils 的 #getAuthInfo(productKey, deviceName, deviceSecret) 方法
  2. 网关调用平台的 IotDeviceCommonApi 的 #authDevice(authReqDTO) RPC 接口进行认证 在管理后台的 [设备详情] 页面,可以直接获取设备的认证信息(clientId、username、password),方便调试: 设备认证信息 每次设备上行,都需要认证么?不需要! ① 【短连接】对于 HTTP、UDP、CoAP 等短连接协议,每次请求都是独立的连接,如果每次都提交三元组认证,开销较大。因此,认证成功后会返回 JWT Token,后续请求携带该 Token 即可(如 HTTP 协议放在 Authorization Header 中),具体方式见各协议文档。 Token 为无状态 JWT(纯签名校验,不存储在 Redis 或数据库中),有效期通过 yudao.iot.gateway.token.expiration 配置,默认 7 天。具体实现见 IotDeviceTokenService 接口。 ② 【长连接】对于 MQTT、TCP、WebSocket 等长连接协议,认证在连接建立时一次完成,后续请求无需再携带认证信息。

# 3.2 动态注册(一型一密) ​

动态注册适用于设备出厂时不预置 DeviceSecret 的场景。设备通过 ProductKey + ProductSecret 进行动态注册,获取 DeviceSecret 后再使用三元组认证。整体类似 《阿里云物联网 —— 一型一密 》 。 详见 《设备网关与子设备》 和 《设备动态注册》。

# 4. 协议管理 ​

# 4.1 IotProtocol 接口 ​

每种协议实现 IotProtocol 接口,定义在 yudao-module-iot-gateway 模块的 protocol 包中。 生命周期方法:

方法说明
#getId()协议实例 ID(对应配置中的 id)
#getType()协议类型(IotProtocolTypeEnum 枚举)
#getServerId()服务标识,用于下行消息路由
#start()启动协议服务
#stop()停止协议服务
#isRunning()是否正在运行
协议实例由 IotProtocolManager 统一管理,通过 Spring SmartLifecycle 自动启动和停止。

# 4.2 支持的协议 ​

所有协议类型定义在 IotProtocolTypeEnum 枚举中,对应实现类如下:

协议类型标识实现类默认端口文档
HTTPhttpIotHttpProtocol8092《设备接入(HTTP 协议)》
MQTTmqttIotMqttProtocol1883《设备接入(MQTT 协议)》
TCPtcpIotTcpProtocol8091《设备接入(TCP 协议)》
UDPudpIotUdpProtocol8093《设备接入(UDP 协议)》
WebSocketwebsocketIotWebSocketProtocol8094《设备接入(WebSocket 协议)》
CoAPcoapIotCoapProtocol5683《设备接入(CoAP 协议)》
EMQXemqxIotEmqxProtocol8090(Hook 端口,设备连 EMQX Broker 1883)《设备接入(EMQX 协议)》
Modbus Clientmodbus_tcp_clientIotModbusTcpClientProtocol502《设备接入(Modbus Client)》
Modbus Servermodbus_tcp_serverIotModbusTcpServerProtocol503《设备接入(Modbus Server)》
如何阅读某个协议的代码?
可以从 IotProtocolManager#createProtocol(config) 方法的 switch 分支进入,找到对应协议的实现类(如 IotHttpProtocol、IotMqttProtocol 等)。
如需扩展新协议,可参考 《设备接入(自定义协议)》。

# 4.3 消息序列化 ​

设备消息(IotDeviceMessage)在网络传输前需要进行序列化/反序列化,由 IotMessageSerializer 接口统一处理。 序列化方式通过协议配置的 serialize 字段指定,由 IotMessageSerializerManager 统一管理。目前支持:

类型实现类说明
jsonIotJsonSerializerJSON 文本格式,可读性好,适合调试
binaryIotBinarySerializer二进制格式,体积小、性能高,适合带宽受限场景
提示
  • 【固定】HTTP、CoAP 协议固定使用 JSON 格式(请求体为 JSON)
  • 【protocol 级别】TCP、UDP、WebSocket 协议通过协议配置的 serialize 字段指定序列化方式,同一协议实例下所有设备使用相同格式
  • 【device 级别】MQTT、EMQX 协议使用按设备的序列化方式:根据设备的 serializeType 字段(继承自产品配置)动态选择序列化器,同一 MQTT Broker 下不同产品的设备可以使用不同格式。具体见 IotDeviceMessageService 的 #serializeDeviceMessage(...) 和 #deserializeDeviceMessage(...) 方法
  • 【自定义】如需扩展新的序列化格式,可参考 《设备接入(自定义协议)》的「C. 自定义序列化」

# 4.4 配置示例 ​

在网关的 application.yaml 中,通过 yudao.iot.gateway.protocols 列表配置协议实例,每个实例包含 id、enabled、protocol、port 等字段。 例如同时启用 HTTP 和 MQTT: yudao: iot: gateway: protocols:

  • id: http-json enabled: true protocol: http port: 8092
  • id: mqtt-json enabled: true protocol: mqtt port: 1883 serialize: json mqtt: max-message-size: 8192 connect-timeout-seconds: 60
  • 通用配置(id、enabled、protocol、port、serialize 等):对应配置类 IotGatewayProperties 的 ProtocolProperties 内部类,所有协议共享。
  • 专属配置(如 mqtt、http 等子节点):每种协议可以有独立的配置类(如 IotMqttConfig、IotHttpConfig 等),用于该协议特有的参数。 .pageB img{width:80px!important;} .wwads-horizontal .wwads-text, .wwads-content .wwads-text{line-height:1;} 设备动态注册 设备接入(HTTP 协议) ← 设备动态注册 设备接入(HTTP 协议)→ Theme by Vdoing | Copyright © 2019-2026 芋道源码 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式 × .windowRB{ padding: 0;} .windowRB .wwads-img{margin-top: 10px;} .windowRB .wwads-content{margin: 0 10px 10px 10px;} .custom-html-window-rb .close-but{ display: none; }
最近更新