OPC 协议驱动
包: Snet.Opc | 组件数: 4 | 命名空间: Snet.Opc.ua.client, Snet.Opc.ua.service, Snet.Opc.da.client, Snet.Opc.da.http
Snet 通过 4 部分架构提供 OPC 连接能力:OPC UA 客户端(完整 UA 协议栈,支持浏览、读取、写入、订阅)、OPC UA 服务端(内置 UA Server,自定义地址空间)、OPC DA COM 客户端(经典 DCOM Data Access,兼容遗留系统)以及 OPC DA HTTP 转发(HTTP 桥接代理 DA 数据)。
安装
dotnet add package Snet.Opc
组件 1: OPC UA 客户端 (OpcUaClientOperate)
命名空间: Snet.Opc.ua.client | 基类: DaqAbstract<...>, IOu | 接口: IDaq + 7 个来自 IOu 的 OPC UA 专用方法
快速开始
using Snet.Opc.ua.client;
var op = new OpcUaClientOperate(new OpcUaClientData.Basics
{
ServerUrl = "opc.tcp://127.0.0.1:6688/Opc.Ua.Service",
AType = AuType.UserName,
UserName = "shunnet",
Password = "shunnet"
});
await op.OnAsync();
var address = new Address(new List<AddressDetails>
{
new("温度", "ns=2;s=Temperature", DataType.Float),
new("压力", "ns=2;s=Pressure", DataType.Float)
});
var result = await op.ReadAsync(address);
if (result.Status)
{
var data = result.GetSource<ConcurrentDictionary<string, AddressValue>>();
foreach (var kv in data)
Console.WriteLine($"{kv.Key} = {kv.Value.ResultValue}");
}
// 订阅——先绑定事件再订阅
op.OnDataEventAsync += async (sender, e) =>
{
if (e.Status)
{
var data = e.GetSource<ConcurrentDictionary<string, AddressValue>>();
foreach (var kv in data)
Console.WriteLine($"事件数据: {kv.Key} = {kv.Value.ResultValue}");
}
};
await op.SubscribeAsync(new Address(new AddressDetails("温度", "ns=2;s=Temperature", DataType.Float)));
// OPC UA 专用:浏览节点、获取节点元数据
var allNodes = await op.GetAllNode(op.GetNodeID()!);
var iconType = await op.GetNodeIconType(sourceNode, sourceNodeId);
await op.DisposeAsync();
IOu 接口 — OPC UA 专用方法
public interface IOu : IDaq
{
object? GetNodeID(); // 获取当前服务 NodeId
Task<object> GetAllNode(object nodeId); // 浏览子节点
Task<string> GetNodeIconType(object target, object sourceId); // 节点图标类型
object DetailedReadAllNodeData(object nodeIds); // 批量读取节点值
string GetAccessLevel(object value); // 访问级别字符串
DataType TypeConvert(object builtInType); // BuiltInType → Snet DataType
object GetNodeValueType(object nodeId); // 获取节点 BuiltInType
}
配置 (OpcUaClientData.Basics)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SN |
string |
Guid.NewGuid().ToUpperNString() |
唯一标识符 |
ServerUrl |
string |
"opc.tcp://127.0.0.1:6688/Opc.Ua.Service" |
服务端 URL |
AType |
AuType |
AuType.UserName |
认证类型:Anonymous / UserName / Certificate |
UserName |
string? |
"shunnet" |
用户名 |
Password |
string? |
"shunnet" |
密码 |
Cer |
string? |
null |
证书路径 |
SecreKey |
string? |
null |
密钥 |
CustomName |
string? |
自动 GUID | 自定义应用名称 |
Timeout |
int |
5000 |
连接超时(毫秒) |
SessionLifeTime |
uint |
60000 |
会话生存期(毫秒) |
InterruptReconnection |
bool |
true |
断线自动重连 |
ReconnectionInterval |
int |
5000 |
重连间隔(毫秒) |
SamplingInterval |
int |
100 |
采样间隔(毫秒) |
PublishingInterval |
int |
100 |
发布间隔(毫秒) |
KeepAliveCount |
int |
255 * 1024 |
Keep-alive 计数器 |
LifetimeCount |
int |
60 |
生存期计数器 |
QueueSize |
int |
255 * 4 |
内部数据队列容量 |
SubscribeSingleGroupMaxCount |
int |
0 |
每组最大订阅项数 |
TaskNumber |
int |
5 |
并发任务数 |
组件 2: OPC UA 服务端 (OpcUaServiceOperate)
命名空间: Snet.Opc.ua.service | 基类: CoreUnify<...> | 实现: IOn, IOff, IRead, IWrite, IGetStatus, IDisposable, IAsyncDisposable
内置 OPC UA 服务器,支持自定义地址空间,供外部 OPC UA 客户端浏览、读取、写入和订阅。
快速开始
using Snet.Opc.ua.service;
var server = new OpcUaServiceOperate(new OpcUaServiceData.Basics
{
Tag = "Opc.Ua.Service",
IpAddress = "127.0.0.1",
Port = 6688,
AType = AuType.UserName,
UserName = "shunnet",
Password = "shunnet"
});
await server.OnAsync();
// 创建文件夹
server.CreateFolder("工厂1");
var folder = server.GetAddressArray().GetSource<FolderState>();
// 在文件夹中创建地址点
server.CreateAddress(new List<AddressBody>
{
new("温度", DataType.Float, folder),
new("压力", DataType.Float, folder),
new("状态", DataType.Bool, folder)
});
// 读取——服务器作为数据源(外部客户端从此服务器读取)
var readAddr = new Address(new AddressDetails("温度", "温度", DataType.Float));
var result = await server.ReadAsync(readAddr);
// 写入——外部客户端也可写入服务端地址
await server.WriteAsync(new ConcurrentDictionary<string, object> { ["温度"] = 25.6f });
await server.OffAsync();
配置 (OpcUaServiceData.Basics)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SN |
string |
Guid.NewGuid().ToUpperNString() |
唯一标识符 |
Tag |
string |
"Opc.Ua.Service" |
服务器标识/显示名 |
IpAddress |
string? |
"127.0.0.1" |
服务器绑定 IP(正则校验) |
Port |
int |
6688 |
服务器绑定端口 |
AType |
AuType |
AuType.UserName |
认证类型 |
UserName |
string? |
"shunnet" |
用户名 |
Password |
string? |
"shunnet" |
密码 |
AddressSpaceName |
string? |
"Snet" |
地址空间显示名称 |
AutoCreateAddress |
bool |
true |
启动时自动创建地址节点 |
服务端专用方法
| 方法 | 说明 |
|---|---|
CreateFolder(string name, FolderState? parent) |
创建地址空间文件夹 |
RemoveFolder(List<NodeId> ids) |
按 NodeId 移除文件夹 |
CreateAddress(List<AddressBody>, FolderState?) |
在文件夹中创建地址点 |
IncAddress(NodeBody, FolderState?) |
添加单个节点 |
GetAddressArray() |
获取所有已注册地址 |
RemoveAddress(List<AddressBody>) |
移除地址点 |
组件 3: OPC DA COM 客户端 (OpcDaClientOperate)
命名空间: Snet.Opc.da.client | 基类: DaqAbstract<...>, IDaq | 平台: x86(32 位)— OPC DA COM 需 32 位进程
经典 OPC Data Access,基于 DCOM。支持组管理、项读写和订阅轮询。
快速开始
using Snet.Opc.da.client;
// 列举远程/本地主机上的可用 OPC DA 服务器
var servers = OpcDaClientOperate.GetServersArray(
ApiVerType.COM_DA_20,
new NetworkCredential("username", "password"),
host: "localhost"
);
foreach (var s in servers)
Console.WriteLine(s.Name);
// 连接到 DA 服务器
var da = new OpcDaClientOperate(new OpcDaClientData.Basics
{
SName = "Knight.OPC.Server.Demo",
Host = "localhost",
ApiVerType = ApiVerType.COM_DA_20,
UserName = "shunnet",
Password = "shunnet"
});
await da.OnAsync();
// 创建组并添加项
await da.AddGroupAsync("Group1", IsSubscribed: false);
var addr = new Address(new List<AddressDetails>
{
new("通道1.设备1.标签1", "Channel1.Device1.Tag1", DataType.Float)
});
await da.AddNodeAsync(addr, "Group1");
// 读取
var result = await da.ReadAsync(addr);
if (result.Status)
Console.WriteLine(result.GetSource<AddressValue>().ResultValue);
// 订阅(轮询模式)
await da.UpdateGroupSubscribedStateAsync("Group1", IsSubscribed: true);
da.OnDataEventAsync += async (sender, e) =>
{
if (e.Status)
Console.WriteLine($"DA 数据更新: {e.ResultData}");
};
await da.SubscribeAsync(addr);
await da.DisposeAsync();
配置 (OpcDaClientData.Basics)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SN |
string |
Guid.NewGuid().ToUpperNString() |
唯一标识符 |
SName |
string? |
"Knight.OPC.Server.Demo" |
OPC DA 服务器 ProgID / 名称 |
ApiVerType |
ApiVerType |
ApiVerType.COM_DA_20 |
COM API 版本:DA 1.0 / 2.0 / 3.0 |
Host |
string? |
"localhost" |
服务器主机名或 IP |
UserName |
string? |
null |
DCOM 凭据 |
Password |
string? |
null |
DCOM 凭据 |
Domain |
string? |
null |
Windows 域 |
UpdateRate |
int |
100 |
订阅更新速率(毫秒) |
SubscribeSingleGroupMaxCount |
int |
0 |
每组最大项数 |
TaskNumber |
int |
5 |
并发任务数 |
DA 专用方法
| 方法 | 说明 |
|---|---|
static GetServersArray(spec, network, host) |
列举可用 OPC DA 服务器 |
AddGroupAsync(name, isSubscribed) |
创建 OPC 组 |
AddNodeAsync(address, groupName) |
向组中添加项 |
UpdateGroupSubscribedStateAsync(name, subscribed) |
切换组订阅状态 |
RemoveGroupAsync(name) |
移除 OPC 组 |
RemoveNodeAsync(nodeName, groupName?) |
移除项 |
组件 4: OPC DA HTTP 转发 (OpcDaHttpOperate)
命名空间: Snet.Opc.da.http | 基类: DaqAbstract<...>, IDaq | 继承: SubscribeData.SCData(支持订阅轮询)
基于 HTTP 的桥接代理,通过 REST 接口代理 OPC DA 数据。支持 14 种标准请求方法:连接、断开、获取服务器列表、添加/删除组、添加/删除项、读取/写入值等。
快速开始
using Snet.Opc.da.http;
var http = new OpcDaHttpOperate(new OpcDaHttpData.Basics
{
IpAddress = "127.0.0.1",
Port = 6688,
GroupName = "Group1",
ServerName = "Knight.OPC.Server.Demo",
AutoOperate = true
});
// 第 1 步:通过 HTTP 连接到 OPC DA 服务器
var connectResult = await http.RequestAsync(RequestMethod.ConnectToOPC);
// 第 2 步:添加组
var addGroupResult = await http.RequestAsync(RequestMethod.AddGroupOfOPC, new { GroupName = "Group1" });
// 第 3 步:向组中添加项
var items = new List<object> { new { ItemName = "Channel1.Device1.Tag1", ClientHandle = 1 } };
var addItemsResult = await http.RequestAsync(RequestMethod.AddItemsOfGroup, items);
// 第 4 步:使用标准 IDaq 接口读取
var addr = new Address(new AddressDetails("通道1.设备1.标签1", "Channel1.Device1.Tag1", DataType.Float));
var result = await http.ReadAsync(addr);
if (result.Status)
Console.WriteLine(result.GetSource<AddressValue>().ResultValue);
// 写入
var writeResult = await http.RequestAsync(RequestMethod.WriteItemValue,
new { ItemName = "Channel1.Device1.Tag1", Value = 100.5f });
// 订阅
await http.SubscribeAsync(addr);
await http.DisposeAsync();
配置 (OpcDaHttpData.Basics : SubscribeData.SCData)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SN |
string |
Guid.NewGuid().ToUpperNString() |
唯一标识符 |
IpAddress |
string? |
"127.0.0.1" |
HTTP 转发服务器 IP(正则校验) |
Port |
int |
6688 |
HTTP 转发服务器端口 |
GroupName |
string |
"Snet" |
OPC DA 组名 |
ServerName |
string |
"Knight.OPC.Server.Demo" |
目标 OPC DA 服务器名 |
AutoOperate |
bool |
true |
OnAsync 时自动连接/配置 |
RequestType |
RequestType |
RequestType.http |
协议:http / https |
(+ 继承自 SubscribeData.SCData) |
HandleInterval, ChangeOut, AllOut |
HTTP 请求方法 (RequestMethod 枚举, 15 个值)
public enum RequestMethod
{
ReqConnectToOPC, // 建立与 DA 服务器的连接
ReqOPCServerNameList, // 列出可用 DA 服务器
ReqGetConnectStatusOfOPC, // 检查连接状态
ReqReConnectOfOPC, // 重新连接
ReqDisConnectOfOPC, // 断开连接
ReqDeleteConnectOfOPC, // 删除连接
ReqAddGroupOfOPC, // 添加组
ReqDelGroupOfOPC, // 删除组
ReqGetGroupsOfOPC, // 列出所有组
ReqAddItemsOfGroup, // 向组中添加项
ReqDelItemsOfGroup, // 从组中删除项
ReqGetItemsOfGroup, // 获取组中的项
ReqReadItemsValueOfGroup, // 读取项值
ReqWriteItemValue, // 写入单个项
ReqGetALLItemsOfOPC // 获取所有组的所有项
}
支持的操作(全部组件)
| 操作 | UA 客户端 | UA 服务端 | DA 客户端 | DA HTTP |
|---|---|---|---|---|
| 连接 | OnAsync() |
OnAsync() |
OnAsync() |
OnAsync() |
| 断开 | OffAsync() |
OffAsync() |
OffAsync() |
OffAsync() |
| 读取 | ReadAsync(Address) |
ReadAsync(Address) |
ReadAsync(Address) |
ReadAsync(Address) |
| 写入 | WriteAsync(...) |
WriteAsync(...) |
WriteAsync(...) |
WriteAsync(...) |
| 订阅 | SubscribeAsync(Address) |
— | SubscribeAsync(Address) |
SubscribeAsync(Address) |
| 浏览 | GetAllNode() |
— | GetServersArray() |
Request(GetServerList) |
| 组管理 | — | — | AddGroupAsync() |
Request(AddGroupOfOPC) |
参见
- DaqAbstract 基类
- IDaq 接口
- 接口目录 — IOu, IDaq, IOn, IOff, IRead, IWrite 接口
- 地址模型 — Address, AddressDetails, AddressValue
