OPC UA/DA - Snet Docs

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)

参见