297 lines
9.0 KiB
Markdown
297 lines
9.0 KiB
Markdown
# 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 Method;TLS 与 Event 为 stub。
|
||
|
||
## 2. CONSTRAINTS
|
||
|
||
- OPC UA 层不得引入 SoftBus 业务逻辑,仅负责地址空间构建、值绑定与方法转发。
|
||
- NodeId 策略统一:Namespace Index = 1,Identifier 类型 = 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 Object(Site 子节点) |
|
||
| `asset` | Asset Object(System 子节点) |
|
||
| `devices[].stableDeviceKey` | Device Object(Asset 子节点) |
|
||
| `devices[].points[].name` | Variable(Device 子节点) |
|
||
|
||
构建完成后,`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. UaEventBridge(Phase 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
|