【BBF系列协议】USP/TR-369 Agent 开发计划

USP/TR-369 Agent 开发计划

Context

为什么需要开发 USP Agent

  1. 端到端测试需求:已有 Controller 模块(75-80% 完成度),但缺乏真实的 Agent 进行联调测试
  2. 产品化需求:某些场景下设备需要作为 USP Agent 被远程管理(如智能网关、IoT 设备)
  3. 技术完整性: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) → ObjectInstance
    • getParameterValue(String path) → String
    • setParameterValue(String path, String value) → void
    • createObjectInstance(String objPath, Map<String,String> params) → String (返回实例路径)
    • deleteObjectInstance(String objPath) → void
    • getSupportedObjects(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 + SerialNumber
  • uuid: - UUID
  • self: - 自生成标识

验证:启动 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)

处理流程:

  1. ProtobufCodec.decodeRecord → Record
  2. 安全层处理(解密/验签)
  3. ProtobufCodec.decodeMessage → Msg
  4. 提取 MsgHeader(session_id, msg_id)→ 更新 SessionManager
  5. 提取 msg_type → 映射到 UspMsgTypeEnum
  6. 请求类型分发
    • Get → IotUspGetHandler
    • Set → IotUspSetHandler
    • Add → IotUspAddHandler
    • Delete → IotUspDeleteHandler
    • Operate → IotUspOperateHandler
    • GetSupportedDM → IotUspGetSupportedDMHandler
    • GetInstances → IotUspGetInstancesHandler
  7. 构建响应 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-id User 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 并发送

验证

  1. 修改 WiFi SSID 名称 → 确认发送 ValueChange 通知
  2. 创建新的 SSID 实例 → 确认发送 ObjectCreation 通知
  3. 删除 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)策略
  • 实现证书吊销检查

认证流程

  1. TLS 握手时获取 Controller 证书
  2. 验证证书有效性(有效期、签名、吊销状态)
  3. 提取 subjectAltName 中的 Endpoint ID
  4. 检查 Endpoint ID 是否在白名单/黑名单
  5. 分配角色(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}.EndpointID
  • Device.LocalAgent.Controller.{i}.AssignedRole
  • Device.Security. 下的参数

验证

  1. 使用未授权 Controller 尝试读取 secured 参数 → 确认拒绝
  2. 使用已授权 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

核心职责:

  • 记录发送的通知
  • 用于审计和故障排查
  • 支持重发失败的通知

验证

  1. 创建/修改/删除对象 → 确认数据库记录
  2. 重启 Agent → 确认实例和参数恢复
  3. 检查通知日志 → 确认记录完整

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 验证

  1. 启动 Agent,确认 Endpoint ID 正确配置
  2. 使用 MQTTX 发送 Get 请求 → 确认返回正确的参数值
  3. 发送 Set 请求 → 确认参数更新成功
  4. 发送 Add 请求创建 WiFi SSID → 确认创建成功并返回实例路径
  5. 发送 Delete 请求删除 SSID → 确认删除成功

Phase 2 验证

  1. 发送 GetSupportedDM 请求 → 确认返回完整的数据模型结构
  2. 发送 GetInstances 请求 → 确认返回所有实例列表
  3. 通过唯一键寻址(Device.WiFi.SSID.[Name=="MyNetwork"].)→ 确认正确解析

Phase 3 验证

  1. 配置 ValueChange 订阅 → 修改参数 → 确认收到 Notify
  2. 创建新对象 → 确认收到 ObjectCreation Notify
  3. 删除对象 → 确认收到 ObjectDeletion Notify

Phase 4 验证

  1. 使用无效证书尝试连接 → 确认拒绝
  2. 使用有效证书但未授权 → 确认只能访问 UntrustedRole 权限范围
  3. 使用已授权证书 → 确认可以访问授权范围

Phase 5 验证

  1. 创建对象 → 重启 Agent → 确认对象恢复
  2. 修改参数 → 重启 Agent → 确认参数值恢复
  3. 检查数据库表 → 确认数据持久化正确

Phase 6 验证

  1. 发送 Register 请求 → 确认注册成功
  2. 执行异步命令 → 确认完成后发送 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 的具体实现逻辑不同)

联调测试

  1. Controller 发送 Get → Agent 响应
  2. Controller 发送 Set → Agent 更新并返回
  3. Agent 发送 Notify → Controller 接收
  4. Controller 发送 Add → Agent 创建对象
  5. Controller 发送 Delete → Agent 删除对象
  6. 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 复杂得多,主要挑战在于:

  1. 完整的数据模型管理 - 需要实现实例化数据模型和支持的数据模型
  2. 复杂的权限控制 - 需要实现 RBAC 和 SecuredRole 机制
  3. 通知机制 - 需要监听数据模型变化并主动发送通知
  4. 唯一键管理 - 需要处理唯一键约束和自动生成

建议采用渐进式实现策略,从 MVP(Phase 0-3)开始,逐步扩展到完整功能。

相关推荐
m0_528174452 小时前
用Python读取和处理NASA公开API数据
jvm·数据库·python
重庆小透明2 小时前
【java基础内容】ConcurrentHashmap源码万字解析
java·开发语言
Yupureki2 小时前
《MySQL数据库基础》4. 数据类型
c语言·开发语言·数据结构·数据库·c++·mysql
C++ 老炮儿的技术栈2 小时前
C++、C#常用语法对比
c语言·开发语言·c++·qt·c#·visual studio
共享家95272 小时前
Java入门(继承)
java·开发语言
Bert.Cai2 小时前
Python默认参数详解
开发语言·python
_饭团2 小时前
指针核心知识:5篇系统梳理4
c语言·开发语言·c++·笔记·深度学习·算法·面试
0xDevNull2 小时前
Java 高频面试题
java·开发语言
Ronin3052 小时前
【Qt常用控件】多元素控件
开发语言·qt·常用控件·多元素控件