Files
softbus_OPC/docs/softbus_opcua.md
2026-06-09 17:27:24 +08:00

297 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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