USP/TR-369 Agent 开发计划
Context
为什么需要开发 USP Agent:
- 端到端测试需求:已有 Controller 模块(75-80% 完成度),但缺乏真实的 Agent 进行联调测试
- 产品化需求:某些场景下设备需要作为 USP Agent 被远程管理(如智能网关、IoT 设备)
- 技术完整性:USP 生态需要 Controller + Agent 双向能力,形成完整的设备管理解决方案
开发目标:
- 实现一个完整的 USP Agent,可作为独立设备运行
- 支持常用数据模型子集(Device.DeviceInfo、Device.LocalAgent、Device.WiFi 等)
- 实现MQTT 和 WebSocket 两种 MTP协议
- 能够与现有 Controller 模块进行完整的 CRUD-ON 消息交互
与 Controller 开发的关系:
- Controller 计划位于:
C:\Users\zhuangpengli\AppData\Roaming\Qoder\SharedClientCache\cli\specs\usp-tr369-controller-dev.md - Agent 可复用 Controller 的 Protobuf 定义、MTP 实现、安全层等基础设施
- Agent 的核心复杂度在于数据模型管理 和通知机制,而非消息编解码
Phase 0: Agent 核心框架搭建
0.1 Agent 协议主类
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/agent/IotUspAgentProtocol.java
- 实现
IotProtocol接口(与 Controller 共享) - 核心职责:
- 聚合 Agent 特有的管理器(数据模型管理器、通知管理器、订阅管理器)
- 协议生命周期管理(init/start/stop/destroy)
- MTP 初始化与注册
参照 Controller 的 IotUspProtocol.java 架构,但增加 Agent 特有组件
0.2 数据模型管理器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/IotUspDataModelManager.java
核心职责:
- 管理实例化数据模型(Instantiated Data Model)
- 管理支持的数据模型(Supported Data Model)
- 提供数据模型查询接口:
getObjectInstance(String path)→ ObjectInstancegetParameterValue(String path)→ StringsetParameterValue(String path, String value)→ voidcreateObjectInstance(String objPath, Map<String,String> params)→ String (返回实例路径)deleteObjectInstance(String objPath)→ voidgetSupportedObjects(String rootPath)→ List
数据模型模块设计:
java
interface DataModelModule {
String getRootPath(); // 如 "Device.WiFi."
boolean isSupported(String path);
void initialize(); // 初始化默认实例
}
// 模块化实现
class DeviceInfoDataModel implements DataModelModule
class LocalAgentDataModel implements DataModelModule
class WiFiDataModel implements DataModelModule
class IPDataModel implements DataModelModule
0.3 实例与唯一键管理器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/IotUspInstanceManager.java
核心职责:
- 实例号分配与管理([R-ARC.8] 要求:实例号持久化,不可修改)
- 唯一键约束验证([R-KEY.1], [R-KEY.2])
- 唯一键寻址支持(
Device.WiFi.SSID.[Name=="MyNetwork"].)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/IotUspUniqueKeyManager.java
核心职责:
- 注册唯一键约束(每个多实例对象的唯一键参数)
- 生成唯一键值(当 Add 消息未指定时)
- 验证唯一性约束
- 通过唯一键查找实例
0.4 搜索表达式解析器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/IotUspSearchExpressionParser.java
核心职责:
- 解析 Search Expression(
[Type=="Normal"&&Stats.ErrorsSent>0]) - 支持运算符:
==,!=,~=,<,>,<=,>= - 支持逻辑运算符:
&&,|| - 支持数据类型比较(string, boolean, int, unsignedInt, dateTime)
技术选型:
- 方案 1:使用 ANTLR 生成解析器(推荐,最规范)
- 方案 2:手写递归下降解析器(轻量级)
- 方案 3:使用正则表达式 + 简单解析(快速实现)
0.5 通知与订阅管理器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/notification/IotUspNotificationManager.java
核心职责:
- 管理 ValueChange 订阅
- 管理 ObjectCreation/ObjectDeletion 订阅
- 管理 Event 订阅
- 管理 OperationComplete 通知
- 批量通知优化(合并多个变更,减少消息数量)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/notification/IotUspSubscriptionManager.java
核心职责:
- 创建/删除订阅(通过 Set 消息配置
Device.LocalAgent.Subscription.{i}.) - 订阅过滤(根据 Controller 权限、订阅条件)
- 周期性通知管理(
PeriodicNotifInterval)
0.6 Endpoint ID 管理
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/identity/IotUspEndpointIdManager.java
核心职责:
- 生成 Agent 的 Endpoint ID(支持多种 authority-scheme)
- 验证 Endpoint ID 格式([R-ARC.5], [R-ARC.6])
- 证书中的 Endpoint ID 提取与验证
支持的 scheme:
os:- OUI + SerialNumber(推荐用于设备)ops:- OUI + ProductClass + SerialNumberuuid:- UUIDself:- 自生成标识
验证:启动 Agent,确认可通过配置设置 Endpoint ID,且格式符合规范。
Phase 1: 消息处理层实现
1.1 Agent 消息流水线
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/IotUspAgentMessagePipeline.java
核心方法:byte[] processIncoming(byte[] rawPayload, String controllerId, UspMtpTypeEnum mtpType)
处理流程:
ProtobufCodec.decodeRecord→ Record- 安全层处理(解密/验签)
ProtobufCodec.decodeMessage→ Msg- 提取 MsgHeader(session_id, msg_id)→ 更新 SessionManager
- 提取 msg_type → 映射到 UspMsgTypeEnum
- 请求类型分发 :
- Get → IotUspGetHandler
- Set → IotUspSetHandler
- Add → IotUspAddHandler
- Delete → IotUspDeleteHandler
- Operate → IotUspOperateHandler
- GetSupportedDM → IotUspGetSupportedDMHandler
- GetInstances → IotUspGetInstancesHandler
- 构建响应 Msg →
ProtobufCodec.encodeRecord→ 返回 byte[]
与 Controller Pipeline 的差异:
- Agent 不处理 Notify(Agent 是 Notify 的发送方)
- Agent 需要维护数据模型状态
- Agent 需要触发通知机制
1.2 Get Handler(Agent 侧)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspGetHandler.java(Agent 版本)
核心逻辑:
- 解析
Get.param_paths(支持 Object Path、Object Instance Path、Parameter Path、Search Path) - 处理 Wildcard 搜索(
Device.WiFi.SSID.*.) - 处理 Search Expression(
Device.WiFi.SSID.[SSID=="MyNetwork].) - 处理 max_depth 参数(USP 1.2+)
- 从 DataModelManager 查询参数值
- 构建
GetResp(包含完整的对象树和参数值)
关键要求:
-
R-GET.0\] - 无效路径返回 7026 错误
-
R-GET.2\] - Parameter Path 返回父对象路径
-
R-GET.4\] - 无读权限的参数不包含在 result_params 中
1.3 Set Handler(Agent 侧)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspSetHandler.java(Agent 版本)
核心逻辑:
- 解析
Set.update_objs(obj_path + param_settings) - 验证参数可写性(白名单机制)
- 验证参数值类型和范围
- 处理 allow_partial 语义([R-SET.0], [R-SET.1], [R-SET.2c], [R-SET.2d])
- 处理 required 参数([R-SET.2])
- 处理 Search Path 匹配多个对象的场景
- 更新 DataModelManager
- 触发 ValueChange 通知(如配置了订阅)
- 构建
SetResp
事务处理:
- allow_partial=false 时使用
@Transactional保证原子性 - 任何失败都回滚([R-SET.1])
关键要求:
-
R-SET.1a\] - 错误条件检查
-
R-SET.2d\] - allow_partial=true 时的独立处理
1.4 Add Handler(Agent 侧)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspAddHandler.java(Agent 版本)
核心逻辑:
- 解析
Add.create_objs(obj_path + param_settings) - 验证对象路径可写性
- 分配实例号(InstanceManager)
- 验证/生成唯一键(UniqueKeyManager)
- 创建对象实例(DataModelManager)
- 处理 allow_partial 语义([R-ADD.0], [R-ADD.1])
- 处理 required 参数([R-ADD.2a], [R-ADD.2b], [R-ADD.3])
- 触发 ObjectCreation 通知
- 构建
AddResp(返回 instantiated_path 和 unique_keys)
关键要求:
-
R-ADD.1a\] - 错误条件检查
-
R-ADD.2b\] - allow_partial=true 时 Search Path 独立处理
-
R-ADD.4\] - 参数失败时返回 param_errs
-
R-ADD.6\] - 无读权限的唯一键不返回
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspDeleteHandler.java(Agent 版本)
核心逻辑:
- 解析
Delete.obj_paths - 验证对象可删除性
- 处理强引用/弱引用([R-ARC.12])
- 删除对象实例及子对象
- 处理 allow_partial 语义([R-DEL.0], [R-DEL.1], [R-DEL.1a])
- 触发 ObjectDeletion 通知
- 构建
DeleteResp
引用处理:
- 强引用:被引用对象删除时,引用参数置空
- 弱引用:被引用对象删除时,引用参数保持不变
关键要求:
-
R-DEL.1a\] - allow_partial 时的独立处理
-
R-DEL.2\] - 无读权限的对象不返回
-
R-DEL.3\] - 删除失败时返回 unaffected_path_errs
1.6 Operate Handler(Agent 侧)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspOperateHandler.java(Agent 版本)
核心逻辑:
- 解析
Operate.command_path - 验证命令可执行性
- 解析输入参数
- 执行命令(同步/异步)
- 处理异步命令([R-OP.4], [R-OP.5])
- 构建
OperateResp或返回异步请求 ID
内置命令处理器:
java
interface CommandHandler {
String getCommandPath(); // 如 "Device.Reboot()"
Map<String,String> execute(Map<String,String> inputArgs);
CmdType getCommandType(); // SYNC/ASYNC
}
// 内置命令实现
class RebootCommandHandler implements CommandHandler
class ResetCommandHandler implements CommandHandler
class PingCommandHandler implements CommandHandler
class FactoryResetCommandHandler implements CommandHandler
关键要求:
-
R-OP.0\] - 命令不存在返回错误
-
R-OP.2\] - 输出参数返回
-
R-OP.4\] - 异步命令返回异步请求 ID
1.7 GetSupportedDM Handler(Agent 侧)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspGetSupportedDMHandler.java
核心逻辑:
- 解析
GetSupportedDM.obj_paths - 处理 first_level_only 标志
- 处理 return_commands/return_events/return_params/return_unique_key_sets 标志
- 遍历支持的数据模型
- 处理 diverging data model([R-GSP.0])
- 构建
GetSupportedDMResp
支持的数据模型定义:
java
class SupportedDataModelDefinition {
String objPath; // 对象路径
ObjAccessType access; // 访问权限
boolean isMultiInstance; // 是否多实例
List<SupportedParam> params; // 参数列表
List<SupportedCommand> commands; // 命令列表
List<SupportedEvent> events; // 事件列表
List<UniqueKeySet> uniqueKeys; // 唯一键集合
}
关键要求:
-
R-GSP.0\] - 无读权限的对象视为不存在
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspGetInstancesHandler.java
核心逻辑:
- 解析
GetInstances.obj_paths - 处理 first_level_only 标志
- 查询实例化数据模型
- 返回实例路径和唯一键
- 构建
GetInstancesResp
关键要求:
-
R-GIN.0\] - 无读权限的实例视为不存在
验证:通过 Controller 发送 GetSupportedDM 和 GetInstances 请求,确认返回正确的数据模型结构和实例列表。
Phase 2: 数据模型实现(常用子集)
2.1 Device.DeviceInfo 数据模型
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/modules/DeviceInfoDataModel.java
实现的对象:
Device.DeviceInfo.(Single-Instance)- 参数:Manufacturer, ModelName, SerialNumber, HardwareVersion, SoftwareVersion, Description, ProductClass, etc.
- 命令:Reboot(), Reset(), FactoryReset()
- 事件:Boot!, TransferComplete!
数据库表:
sql
CREATE TABLE iot_usp_device_info (
id BIGINT PRIMARY KEY,
manufacturer VARCHAR(128),
model_name VARCHAR(128),
serial_number VARCHAR(128) UNIQUE,
hardware_version VARCHAR(64),
software_version VARCHAR(64),
product_class VARCHAR(128),
-- ... 其他参数
tenant_id BIGINT,
create_time DATETIME,
update_time DATETIME
);
2.2 Device.LocalAgent 数据模型
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/modules/LocalAgentDataModel.java
实现的对象:
Device.LocalAgent.(Single-Instance)Device.LocalAgent.Controller.{i}.(Multi-Instance)- 参数:Enable, EndpointID, Alias, Name, MTPs, AssignedRole, etc.
Device.LocalAgent.MTP.{i}.(Multi-Instance)- 参数:Enable, Protocol, Alias, WebSocket, MQTT, etc.
Device.LocalAgent.Subscription.{i}.(Multi-Instance)- 参数:Enable, ID, Recipient, NotifType, Path, etc.
关键功能:
- Controller 注册管理
- MTP 配置管理
- 订阅配置管理
2.3 Device.WiFi 数据模型
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/modules/WiFiDataModel.java
实现的对象:
Device.WiFi.(Single-Instance)Device.WiFi.Radio.{i}.(Multi-Instance)- 参数:Enable, Status, Channel, ChannelWidth, SSIDAdvertisementEnabled, etc.
- 命令:NeighboringWiFiDiagnostic()
Device.WiFi.SSID.{i}.(Multi-Instance)- 参数:Enable, Status, SSID, BSSID, Name, Alias, etc.
- 唯一键:BSSID, Name, Alias
Device.WiFi.AccessPoint.{i}.(Multi-Instance)- 参数:Enable, Status, SSIDReference, Alias, etc.
- 唯一键:Alias, SSIDReference
Device.WiFi.AccessPoint.{i}.AssociatedDevice.{i}.(Multi-Instance)- 参数:MACAddress, Associated, Active, etc.
- 唯一键:MACAddress
数据库表:
sql
-- WiFi Radio
CREATE TABLE iot_usp_wifi_radio (
instance_number INT PRIMARY KEY,
enable BOOLEAN,
status VARCHAR(32),
channel INT,
channel_width INT,
-- ... 其他参数
UNIQUE KEY uk_instance (instance_number)
);
-- WiFi SSID
CREATE TABLE iot_usp_wifi_ssid (
instance_number INT PRIMARY KEY,
enable BOOLEAN,
status VARCHAR(32),
ssid VARCHAR(64),
bssid VARCHAR(32) UNIQUE,
name VARCHAR(64) UNIQUE,
alias VARCHAR(64) UNIQUE,
-- ... 其他参数
UNIQUE KEY uk_bssid (bssid),
UNIQUE KEY uk_name (name),
UNIQUE KEY uk_alias (alias)
);
-- WiFi AccessPoint
CREATE TABLE iot_usp_wifi_ap (
instance_number INT PRIMARY KEY,
enable BOOLEAN,
status VARCHAR(32),
ssid_reference VARCHAR(128),
alias VARCHAR(64) UNIQUE,
-- ... 其他参数
FOREIGN KEY (ssid_reference) REFERENCES iot_usp_wifi_ssid(path)
);
-- AssociatedDevice
CREATE TABLE iot_usp_wifi_assoc_device (
ap_instance INT,
instance_number INT,
mac_address VARCHAR(32),
associated BOOLEAN,
active BOOLEAN,
-- ... 其他参数
PRIMARY KEY (ap_instance, instance_number),
UNIQUE KEY uk_mac (ap_instance, mac_address)
);
2.4 Device.IP 数据模型
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/modules/IPDataModel.java
实现的对象:
Device.IP.(Single-Instance)Device.IP.Interface.{i}.(Multi-Instance)- 参数:Enable, Status, Name, Alias, IPAddresses, etc.
- 唯一键:Name, Alias
Device.IP.Interface.{i}.IPv4Address.{i}.(Multi-Instance)- 参数:IPAddress, SubnetMask, AddressingType, etc.
Device.IP.Interface.{i}.IPv6Address.{i}.(Multi-Instance)- 参数:IPAddress, PrefixLength, AddressingType, ValidLifetime, etc.
2.5 Device.Ethernet 数据模型
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/modules/EthernetDataModel.java
实现的对象:
Device.Ethernet.(Single-Instance)Device.Ethernet.Interface.{i}.(Multi-Instance)- 参数:Enable, Status, Name, MACAddress, MTU, Speed, etc.
- 唯一键:Name, MACAddress
2.6 数据模型初始化器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/datamodel/IotUspDataModelInitializer.java
核心职责:
- 应用启动时初始化数据模型
- 从数据库加载已存在的实例
- 创建默认实例(如 Device.DeviceInfo.)
- 注册唯一键约束
- 初始化 MTP 配置对象
验证:启动 Agent 后,通过 GetSupportedDM 确认可查看完整的数据模型结构,通过 GetInstances 确认实例存在。
Phase 3: MTP 集成 + 通知机制
3.1 Agent MTP 连接管理器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/mtp/IotUspAgentMtpManager.java
核心职责:
- 管理 Agent 发起的 MTP 连接(MQTT/WebSocket 客户端)
- 管理接受 Controller 连接的 MTP 服务(WebSocket 服务端)
- MTP 健康检查与自动重连
- 多 MTP 负载均衡(如配置了多个 MTP)
与 Controller MTP 的差异:
- Agent 通常主动发起连接(特别是 MQTT/WebSocket)
- Agent 需要订阅 "to_agent" 主题/目的地
- Agent 需要在 PUBLISH 时包含 "reply-to" 主题
3.2 MQTT MTP(Agent 客户端模式)
修改 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/mtp/IotUspMqttMtp.java(增强)
Agent 特有逻辑:
- CONNECT 时包含
usp-endpoint-idUser Property(MQTT 5.0) - SUBSCRIBE 订阅 "to_agent" 主题:
usp/{agentEndpointId}/to_agent/# - PUBLISH 时包含 Response Topic:
usp/{agentEndpointId}/to_controller/{sessionId} - 处理来自 Controller 的消息
- 发送 Notify 消息到 Controller
关键要求:
-
R-MQTT.13\] - CONNECT 包含 usp-endpoint-id
-
R-MQTT.20\] - 支持 QoS 0 和 QoS 1
-
R-MQTT.48\] - 使用 TLS 1.2+
修改 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/mtp/IotUspWebSocketMtp.java(增强)
Agent 客户端模式:
- 主动连接 Controller:
ws://controller-host:port/usp?eid={agentEndpointId} - 设置
Sec-WebSocket-Protocol: v1.usp - 处理来自 Controller 的消息
- 发送 Notify 消息
Agent 服务端模式(可选):
- 接受 Controller 连接
- 验证 Controller 证书
- 消息处理
关键要求:
-
R-WS.5\] - 支持作为客户端发起连接
-
R-WS.9\] - Sec-WebSocket-Protocol 为 v1.usp
-
R-WS.17\] - Ping/Pong 保活
-
R-WS.22\] - TLS 1.2+
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/notification/IotUspNotificationTrigger.java
核心职责:
- 监听参数值变化 → 触发 ValueChange 通知
- 监听对象创建 → 触发 ObjectCreation 通知
- 监听对象删除 → 触发 ObjectDeletion 通知
- 监听命令执行完成 → 触发 OperationComplete 通知
- 监听数据模型事件 → 触发 Event 通知
实现方式:
- 方案 1:在 DataModelManager 中嵌入通知逻辑(紧耦合)
- 方案 2:使用 Spring Event 事件机制(推荐,解耦)
- 方案 3:使用 AOP 切面拦截参数设置(高级)
推荐方案 2 示例:
java
// 定义事件
class ParameterValueChangedEvent extends ApplicationEvent {
String endpointId;
String parameterPath;
String oldValue;
String newValue;
}
// 发布事件
applicationEventPublisher.publishEvent(new ParameterValueChangedEvent(...));
// 监听事件
@EventListener
public void handleParameterChange(ParameterValueChangedEvent event) {
notificationManager.notifyValueChange(...);
}
3.5 Notify 消息构建器
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/notification/IotUspNotifyMessageBuilder.java
核心职责:
- 构建 ValueChange Notify
-
- 构建 ObjectCreation Notify
-
- 构建 ObjectDeletion Notify
-
- 构建 Event Notify
-
- 构建 OperationComplete Notify
- 设置正确的 msg_id, session_id
- 封装为 USP Record 并发送
验证:
- 修改 WiFi SSID 名称 → 确认发送 ValueChange 通知
- 创建新的 SSID 实例 → 确认发送 ObjectCreation 通知
- 删除 SSID 实例 → 确认发送 ObjectDeletion 通知
Phase 4: 安全与认证
4.1 Agent 证书管理
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/security/IotUspAgentCertificateManager.java
核心职责:
- 加载 Agent 证书和私钥
- 验证证书中的 Endpoint ID([R-SEC.0a])
- 管理证书链
- 证书更新与轮换
证书要求:
- subjectAltName 必须包含 Endpoint ID(URN 或 dNSName 形式)
- 支持 X.509 v3 证书
- 支持证书链验证
4.2 Controller 认证
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/security/IotUspControllerAuthenticator.java
核心职责:
- 验证 Controller 证书
- 提取 Controller 的 Endpoint ID
- 验证证书链(Trusted CA)
- 实现 TOFU(Trust on First Use)策略
- 实现证书吊销检查
认证流程:
- TLS 握手时获取 Controller 证书
- 验证证书有效性(有效期、签名、吊销状态)
- 提取 subjectAltName 中的 Endpoint ID
- 检查 Endpoint ID 是否在白名单/黑名单
- 分配角色(UntrustedRole / AssignedRole)
4.3 基于角色的访问控制(RBAC)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/security/IotUspRoleBasedAccessControl.java
核心职责:
- 加载角色定义(从数据库或配置)
- 验证 Controller 的角色
- 检查对象/参数访问权限
- 处理 SecuredRole 访问(v1.3+)
角色权限检查:
java
boolean hasPermission(String controllerId, String path, PermissionType type) {
Role role = roleManager.getRole(controllerId);
return role.hasPermission(path, type);
}
enum PermissionType {
READ, // r
WRITE, // w
EXECUTE, // x (Create/Command)
NOTIFY // n
}
关键要求:
-
R-SEC.1\] - 确认 Controller 有必要权限
-
R-RBAC.1\] - 权限字符串格式(rwxn)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/security/IotUspSecuredParameterProtection.java
核心职责:
- 识别 secured 参数(需要特殊角色访问)
- 阻止未授权访问
- 记录安全审计日志
Secured 参数示例:
Device.LocalAgent.Controller.{i}.EndpointIDDevice.LocalAgent.Controller.{i}.AssignedRoleDevice.Security.下的参数
验证:
- 使用未授权 Controller 尝试读取 secured 参数 → 确认拒绝
- 使用已授权 Controller 读取 → 确认允许
Phase 5: 持久化与高可用
5.1 实例持久化
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/dataobject/IotUspObjectInstanceDO.java
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/mysql/IotUspObjectInstanceMapper.java
核心职责:
- 持久化多实例对象实例
- 保存实例号和唯一键
- 支持按实例号/唯一键查询
数据库表:
sql
CREATE TABLE iot_usp_object_instance (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
endpoint_id VARCHAR(128),
object_path VARCHAR(256),
instance_number INT,
unique_keys_json JSON,
parent_instance_id BIGINT,
create_time DATETIME,
update_time DATETIME,
UNIQUE KEY uk_endpoint_object_instance (endpoint_id, object_path, instance_number),
KEY idx_object_path (object_path),
KEY idx_unique_keys ((CAST(unique_keys_json->>'$.Name' AS CHAR(64))))
);
5.2 参数值持久化
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/dataobject/IotUspParameterValueDO.java
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/mysql/IotUspParameterValueMapper.java
核心职责:
- 持久化参数值
- 支持按对象实例查询所有参数
- 支持批量更新
数据库表:
sql
CREATE TABLE iot_usp_parameter_value (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
endpoint_id VARCHAR(128),
object_instance_id BIGINT,
parameter_name VARCHAR(256),
parameter_value TEXT,
parameter_type VARCHAR(32),
last_modified DATETIME,
UNIQUE KEY uk_endpoint_object_param (endpoint_id, object_instance_id, parameter_name),
KEY idx_object_instance (object_instance_id)
);
5.3 会话持久化
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/dataobject/IotUspSessionDO.java
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/mysql/IotUspSessionMapper.java
核心职责:
- 持久化 USP 会话
- 保存 session_id, sequence_id, expected_id
- 支持会话恢复(应用重启后)
数据库表:
sql
CREATE TABLE iot_usp_session (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
endpoint_id VARCHAR(128),
controller_id VARCHAR(128),
session_id BIGINT,
sequence_id BIGINT,
expected_id BIGINT,
mtp_type VARCHAR(32),
status TINYINT,
start_time DATETIME,
last_active_time DATETIME,
UNIQUE KEY uk_endpoint_controller_session (endpoint_id, controller_id, session_id),
KEY idx_controller (controller_id)
);
5.4 通知日志持久化
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/dataobject/IotUspNotificationLogDO.java
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/dal/mysql/IotUspNotificationLogMapper.java
核心职责:
- 记录发送的通知
- 用于审计和故障排查
- 支持重发失败的通知
验证:
- 创建/修改/删除对象 → 确认数据库记录
- 重启 Agent → 确认实例和参数恢复
- 检查通知日志 → 确认记录完整
Phase 6: 高级功能
6.1 Register/Deregister Handler(v1.3+)
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspRegisterHandler.java
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/handler/upstream/IotUspDeregisterHandler.java
核心逻辑:
- 处理 USP Service 注册([R-REG.0], [R-REG.1])
- 处理 USP Service 注销
- 维护已注册路径列表
- 支持 allow_partial 语义
应用场景:USP Broker 架构中的 USP Service 动态注册
6.2 异步命令管理
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/command/IotUspAsyncCommandManager.java
核心职责:
- 管理异步命令执行
- 跟踪异步命令状态
- 命令完成后发送 OperationComplete 通知
- 支持命令超时和取消
6.3 批量数据采集支持
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/bulkdata/IotUspBulkDataCollector.java
核心职责:
- 支持 HTTP/HTTPS 批量数据上报
- 支持 MQTT 批量数据采集
- 配置 BulkDataProfile
- 周期性数据采集
6.4 软件模块管理支持
新建 yudao-module-iot/yudao-module-iot-tr369/src/main/java/cn/iocoder/yudao/module/iot/tr369/software/IotUspSoftwareModuleManager.java
核心职责:
- 管理部署单元(DU)生命周期
- 管理执行单元(EU)状态
- 支持软件安装/更新/卸载
验证:通过 Controller 发送 Register 请求,确认成功注册服务元素。
关键文件清单
Phase 0 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/agent/IotUspAgentProtocol.java |
Agent 协议主类 |
tr369/datamodel/IotUspDataModelManager.java |
数据模型管理器 |
tr369/datamodel/IotUspInstanceManager.java |
实例管理器 |
tr369/datamodel/IotUspUniqueKeyManager.java |
唯一键管理器 |
tr369/datamodel/IotUspSearchExpressionParser.java |
搜索表达式解析器 |
tr369/notification/IotUspNotificationManager.java |
通知管理器 |
tr369/notification/IotUspSubscriptionManager.java |
订阅管理器 |
tr369/identity/IotUspEndpointIdManager.java |
Endpoint ID 管理 |
Phase 1 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/handler/IotUspAgentMessagePipeline.java |
Agent 消息流水线 |
tr369/handler/upstream/IotUspGetHandler.java |
Get 处理器(Agent) |
tr369/handler/upstream/IotUspSetHandler.java |
Set 处理器(Agent) |
tr369/handler/upstream/IotUspAddHandler.java |
Add 处理器(Agent) |
tr369/handler/upstream/IotUspDeleteHandler.java |
Delete 处理器(Agent) |
tr369/handler/upstream/IotUspOperateHandler.java |
Operate 处理器(Agent) |
tr369/handler/upstream/IotUspGetSupportedDMHandler.java |
GetSupportedDM 处理器 |
tr369/handler/upstream/IotUspGetInstancesHandler.java |
GetInstances 处理器 |
Phase 2 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/datamodel/modules/DeviceInfoDataModel.java |
DeviceInfo 模块 |
tr369/datamodel/modules/LocalAgentDataModel.java |
LocalAgent 模块 |
tr369/datamodel/modules/WiFiDataModel.java |
WiFi 模块 |
tr369/datamodel/modules/IPDataModel.java |
IP 模块 |
tr369/datamodel/modules/EthernetDataModel.java |
Ethernet 模块 |
tr369/datamodel/IotUspDataModelInitializer.java |
数据模型初始化器 |
Phase 3 - 新建/修改文件
| 文件路径 | 用途 |
|---|---|
tr369/mtp/IotUspAgentMtpManager.java |
Agent MTP 管理器 |
tr369/mtp/IotUspMqttMtp.java |
增强 MQTT 客户端逻辑 |
tr369/mtp/IotUspWebSocketMtp.java |
增强 WebSocket 客户端/服务端 |
tr369/notification/IotUspNotificationTrigger.java |
通知触发器 |
tr369/notification/IotUspNotifyMessageBuilder.java |
Notify 消息构建器 |
Phase 4 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/security/IotUspAgentCertificateManager.java |
Agent 证书管理 |
tr369/security/IotUspControllerAuthenticator.java |
Controller 认证 |
tr369/security/IotUspRoleBasedAccessControl.java |
RBAC 实现 |
tr369/security/IotUspSecuredParameterProtection.java |
Secured 参数保护 |
Phase 5 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/dal/dataobject/IotUspObjectInstanceDO.java |
对象实例 DO |
tr369/dal/dataobject/IotUspParameterValueDO.java |
参数值 DO |
tr369/dal/dataobject/IotUspSessionDO.java |
会话 DO |
tr369/dal/dataobject/IotUspNotificationLogDO.java |
通知日志 DO |
tr369/dal/mysql/IotUspObjectInstanceMapper.java |
对象实例 Mapper |
tr369/dal/mysql/IotUspParameterValueMapper.java |
参数值 Mapper |
tr369/dal/mysql/IotUspSessionMapper.java |
会话 Mapper |
tr369/dal/mysql/IotUspNotificationLogMapper.java |
通知日志 Mapper |
Phase 6 - 新建文件
| 文件路径 | 用途 |
|---|---|
tr369/handler/upstream/IotUspRegisterHandler.java |
Register 处理器 |
tr369/handler/upstream/IotUspDeregisterHandler.java |
Deregister 处理器 |
tr369/command/IotUspAsyncCommandManager.java |
异步命令管理 |
tr369/bulkdata/IotUspBulkDataCollector.java |
批量数据采集 |
tr369/software/IotUspSoftwareModuleManager.java |
软件模块管理 |
验证方案
Phase 0-1 验证
- 启动 Agent,确认 Endpoint ID 正确配置
- 使用 MQTTX 发送 Get 请求 → 确认返回正确的参数值
- 发送 Set 请求 → 确认参数更新成功
- 发送 Add 请求创建 WiFi SSID → 确认创建成功并返回实例路径
- 发送 Delete 请求删除 SSID → 确认删除成功
Phase 2 验证
- 发送 GetSupportedDM 请求 → 确认返回完整的数据模型结构
- 发送 GetInstances 请求 → 确认返回所有实例列表
- 通过唯一键寻址(
Device.WiFi.SSID.[Name=="MyNetwork"].)→ 确认正确解析
Phase 3 验证
- 配置 ValueChange 订阅 → 修改参数 → 确认收到 Notify
- 创建新对象 → 确认收到 ObjectCreation Notify
- 删除对象 → 确认收到 ObjectDeletion Notify
Phase 4 验证
- 使用无效证书尝试连接 → 确认拒绝
- 使用有效证书但未授权 → 确认只能访问 UntrustedRole 权限范围
- 使用已授权证书 → 确认可以访问授权范围
Phase 5 验证
- 创建对象 → 重启 Agent → 确认对象恢复
- 修改参数 → 重启 Agent → 确认参数值恢复
- 检查数据库表 → 确认数据持久化正确
Phase 6 验证
- 发送 Register 请求 → 确认注册成功
- 执行异步命令 → 确认完成后发送 OperationComplete 通知
与 Controller 开发的协同
可复用的组件:
- Protobuf 编解码器(
IotUspProtobufCodec) - MTP 实现(MQTT/WebSocket/STOMP/UDS)
- 安全层(AES-GCM/RSA/X.509)
- Session 管理器
- 消息路由框架
需要独立实现的组件:
- 数据模型管理器(Agent 特有)
- 通知与订阅管理器(Agent 特有)
- 实例与唯一键管理器(Agent 特有)
- 搜索表达式解析器(Agent 特有)
- Handler 层(Get/Set/Add/Delete/Operate 的具体实现逻辑不同)
联调测试:
- Controller 发送 Get → Agent 响应
- Controller 发送 Set → Agent 更新并返回
- Agent 发送 Notify → Controller 接收
- Controller 发送 Add → Agent 创建对象
- Controller 发送 Delete → Agent 删除对象
- Controller 发送 Operate → Agent 执行命令
开发优先级建议
P0 - 必须完成(MVP):
- Phase 0: Agent 核心框架
- Phase 1: Get/Set/Add/Delete/Operate 基础 Handler
- Phase 2: Device.DeviceInfo + Device.LocalAgent 数据模型
- Phase 3: MQTT MTP 客户端 + 基础通知机制
P1 - 重要功能:
- Phase 2: WiFi/IP/Ethernet 数据模型
- Phase 3: WebSocket MTP + 完整通知机制
- Phase 4: 安全认证与 RBAC
- Phase 5: 数据持久化
P2 - 高级功能:
- Phase 6: Register/Deregister
- Phase 6: 异步命令管理
- Phase 6: 批量数据采集
- Phase 6: 软件模块管理
总结
实现 USP Agent 比 Controller 复杂得多,主要挑战在于:
- 完整的数据模型管理 - 需要实现实例化数据模型和支持的数据模型
- 复杂的权限控制 - 需要实现 RBAC 和 SecuredRole 机制
- 通知机制 - 需要监听数据模型变化并主动发送通知
- 唯一键管理 - 需要处理唯一键约束和自动生成
建议采用渐进式实现策略,从 MVP(Phase 0-3)开始,逐步扩展到完整功能。