Files
softbus_OPC/docs/softbus_opcua.md

297 lines
9.0 KiB
Markdown
Raw Normal View History

2026-06-09 17:27:24 +08:00
# softbus_opcua
**路径:** `src/softbus_opcua`
**构建目标:** `softbus_opcua`STATIC 库)
**依赖:** open62541 v1.4.6
**层级:** L2 服务层
## 1. 概述
`softbus_opcua` 基于 **open62541** 封装 OPC UA 服务端,将 SoftBus 对象模型动态映射为 OPC UA 地址空间,实现:
-`ObjectModelTree` **动态构建**地址空间节点树
-`DOMMessage` **实时绑定**到 UA Variable 节点
- 暴露 `ExecuteCommand` 为 OPC UA **Method**(反向控制入口)
> **Phase 1 范围:** 动态地址空间、Double Variable、ExecuteCommand MethodTLS 与 Event 为 stub。
## 2. CONSTRAINTS
- OPC UA 层不得引入 SoftBus 业务逻辑,仅负责地址空间构建、值绑定与方法转发。
- NodeId 策略统一Namespace Index = 1Identifier 类型 = String值为 `objectRef.toPath()`
- 所有 open62541 调用须包裹 `#if SOFTBUS_HAS_OPCUA` 条件编译。
- Method 入参/出参均使用 JSON 字符串UA String`softbus_api::ExecuteCommand` 对齐。
- Event 发射 Phase 1 为 stub仅打日志不得伪装为已生效功能。
- Phase 2 静态 NodeSet`config/ua_model.xml`)导入时,不得破坏动态构建的 NodeId 约定。
## 3. 组件架构
```
UaServerEngine ← open62541 生命周期管理
├── UaAddressSpaceBuilder ← JSON 模型 → UA 节点树
├── UaModelBinder ← DOMMessage → Variable 写值
├── UaMethodBinder ← ExecuteCommand Method 回调
└── UaEventBridge ← Event 发射Phase 1 stub
```
## 4. UaServerEngine
### 4.1 职责
管理 `UA_Server` 实例的创建、配置、运行与销毁。
### 4.2 公共 API
| 方法 | 入参 | 返回 | 说明 |
|------|------|------|------|
| `start(port, applicationName, security)` | 端口、应用名、安全配置 | bool | 启动 OPC UA 服务 |
| `stop()` | — | void | 停止服务 |
| `iterate()` | — | void | 驱动事件循环(主循环调用) |
| `isRunning()` | — | bool | 运行状态 |
| `nativeServer()` | — | UA_Server* | 获取原生服务器指针 |
### 4.3 SecurityConfig
| 字段 | 类型 | Phase 1 |
|------|------|---------|
| `enableTls` | bool | 未实现,忽略 |
| `certPath` | string | 未实现 |
| `keyPath` | string | 未实现 |
| `trustListPath` | string | 未实现 |
Phase 1 使用 `UA_ServerConfig_setMinimal()` 创建无安全策略的服务端。
### 4.4 配置来源
| 字段 | 配置路径 | 默认值 |
|------|----------|--------|
| 端口 | `daemon_profile.json``opcua.port` | 4840 |
| 应用名 | `daemon_profile.json``opcua.applicationName` | SoftBusDaemon |
| TLS | `daemon_profile.json``security.*` | 关闭 |
**连接端点:** `opc.tcp://localhost:4840`
## 5. 地址空间
### 5.1 节点树结构
```
ObjectsFolder (NS0, 标准节点)
├── SoftBusControl (Object, NS1)
│ └── ExecuteCommand (Method, NS1)
│ ├── InputArguments: commandJson (String)
│ └── OutputArguments: resultJson (String)
└── {Site} (Object, NS1)
└── {System} (Object, NS1)
└── {Asset} (Object, NS1)
└── {stableDeviceKey} (Object, NS1)
└── {pointName} (Variable, NS1, Double, R/W)
```
### 5.2 示例(基于默认模型)
```
ObjectsFolder
├── SoftBusControl
│ └── ExecuteCommand
└── DemoSite
└── DemoSystem
└── DemoAsset
└── SimModbusDevice
└── Temperature (Double, 初始值 0.0)
```
### 5.3 NodeId 约定
| 节点类型 | Namespace | Identifier 类型 | Identifier 值 |
|----------|-----------|----------------|----------------|
| Site | 1 | String | `{siteName}` |
| System | 1 | String | `{systemName}` |
| Asset | 1 | String | `{assetName}` |
| Device | 1 | String | `{stableDeviceKey}` |
| Point (Variable) | 1 | String | `{objectRef.toPath()}` |
| SoftBusControl | 1 | String | `SoftBusControl` |
| ExecuteCommand | 1 | String | `ExecuteCommand` |
**Point 节点完整路径示例:**
```
NodeId: ns=1;s=DemoSite/DemoSystem/DemoAsset/SimModbusDevice/Temperature
```
### 5.4 Variable 属性
| 属性 | 值 |
|------|-----|
| DataType | Double (`UA_TYPES_DOUBLE`) |
| AccessLevel | Read + Write |
| TypeDefinition | BaseDataVariableType |
| 初始值 | 0.0 |
| ReferenceType | HasComponent |
### 5.5 模型映射规则
| softbus_model.json 字段 | OPC UA 节点 |
|------------------------|-------------|
| `site` | Site Object |
| `system` | System ObjectSite 子节点) |
| `asset` | Asset ObjectSystem 子节点) |
| `devices[].stableDeviceKey` | Device ObjectAsset 子节点) |
| `devices[].points[].name` | VariableDevice 子节点) |
构建完成后,`UaModelBinder::registerPointNode(objectRef, nodeId)` 建立 `objectRef → UA_NodeId` 映射。
## 6. UaModelBinder
### 6.1 职责
维护 `objectRef → UA_NodeId` 映射表,将 `DOMMessage` 实时写入对应 Variable。
### 6.2 公共 API
| 方法 | 说明 |
|------|------|
| `registerPointNode(objectRef, nodeId)` | 注册映射(构建阶段调用) |
| `bind(DOMMessage)` | 写值到 OPC UA Variable |
### 6.3 绑定逻辑
1. 查找键 = `message.id`(非空时)或 `message.sourceId`
2.`message.value` 提取数值:
- 优先 `value["value"]`
- 备选 `value["registerValue"]`
3. 调用 `UA_Server_writeValue(server, nodeId, doubleValue)`
### 6.4 数据流
```
PipelineEngine::process(RawPacket)
→ ModbusParser → DOMMessage
→ UaModelBinder::bind(DOMMessage)
→ UA_Server_writeValue
→ OPC UA Client 可读
```
## 7. UaMethodBinder — ExecuteCommand Method
### 7.1 Method 定义
| 属性 | 值 |
|------|-----|
| BrowseName | `ExecuteCommand` |
| Parent Object | `SoftBusControl` |
| InputArguments | `commandJson` (String) — JSON 格式的 ExecuteCommand |
| OutputArguments | `resultJson` (String) — JSON 格式响应 |
### 7.2 入参 JSON Schema
```json
{
"traceId": "string (required)",
"objectRef": "string (required, 五层路径)",
"command": "string (required)",
"params": "object (required)"
}
```
> OPC UA Method 入参不含 `type` 字段,由 `ExecuteCommand::fromJson()` 直接解析。
### 7.3 出参 JSON Schema
**成功:**
```json
{"success": true}
```
**失败:**
```json
{"success": false, "error": "错误描述"}
```
### 7.4 调用流程
```
OPC UA Client 调用 ExecuteCommand(commandJson)
→ executeCommandMethod() 回调
→ nlohmann::json::parse(commandJson)
→ ExecuteCommand::fromJson() + validate()
→ dispatchCommand() → handler_(cmd)
→ CommandDispatcher → TCP 下行
→ 返回 resultJson
```
### 7.5 客户端调用示例UaExpert
1. 连接 `opc.tcp://localhost:4840`
2. 浏览至 `Objects → SoftBusControl → ExecuteCommand`
3. 右键调用 Method输入
```json
{"traceId":"trace-ua-001","objectRef":"DemoSite/DemoSystem/DemoAsset/SimModbusDevice/Temperature","command":"write","params":{"value":42.5}}
```
## 8. UaEventBridgePhase 1 stub
| 方法 | 说明 | Phase 1 行为 |
|------|------|-------------|
| `emitHeartbeat()` | 心跳事件 | 仅日志 |
| `emitDeviceOnline(objectRef)` | 设备上线 | 仅日志 |
| `emitDeviceOffline(objectRef)` | 设备离线 | 仅日志 |
| `emitParseError(traceId, detail)` | 解析错误 | 仅日志 |
## 9. UaAddressSpaceBuilder
### 9.1 职责
`ObjectModelTree` 递归创建 OPC UA 对象树与 Variable 节点。
### 9.2 构建流程
1. 获取 `ObjectsFolder` 标准节点作为根
2. 创建 `SoftBusControl` Object 与 `ExecuteCommand` Method
3. 按 Site → System → Asset → Device → Point 层级递归 `UA_Server_addObjectNode` / `addVariableNode`
4. 每个 Point 调用 `binder->registerPointNode(objectRef, nodeId)`
## 10. 条件编译
| 宏 | 说明 |
|----|------|
| `SOFTBUS_HAS_OPCUA` | CMake 选项 `SOFTBUS_WITH_OPCUA=ON` 时定义 |
| `SOFTBUS_WITH_OPCUA` | CMake option默认 ON |
未启用时,所有 OPC UA 方法返回 false 或空操作。
## 11. open62541 配置
CMake 通过 `SoftbusThirdParty.cmake` 以 vendor 方式引入 `third_party/open62541`v1.4.6
| 选项 | 值 | 说明 |
|------|-----|------|
| UA_ENABLE_SUBSCRIPTIONS | ON | 订阅支持 |
| UA_ENABLE_METHODCALLS | ON | 方法调用 |
| UA_ENABLE_DISCOVERY | ON | 发现服务 |
| UA_ENABLE_ENCRYPTION | OFF | Phase 1 无加密 |
## 12. Phase 路线图
| 阶段 | 功能 | 状态 |
|------|------|------|
| Phase 1 | 动态地址空间、Double Variable、ExecuteCommand、无 TLS | **当前** |
| Phase 2 | `ua_model.xml` NodeSet2 导入、TLS/mTLS、StatusCode 映射 | 规划 |
| Phase 2 | 真实 Event 发射DeviceOnline/Offline、ParseError | 规划 |
| Phase 3 | Subscription 优化、历史数据、多 DataType 支持 | 规划 |
### 12.1 Phase 2 NodeSet 占位
`config/ua_model.xml` 当前为空 shell注释标明 Phase 2 可能导入静态 NodeSet2 XML届时与动态构建策略需协调 NodeId 一致性。
## 13. 依赖
- `softbus_core`ObjectModelTree, DOMMessage, ObjectRef
- `softbus_api`ExecuteCommand
- `open62541`(条件依赖)
- **被依赖:** softbus_daemon