You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
6.5 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2025 WenJY 保留所有权利。
* CLR版本4.0.30319.42000
* 机器名称Mr.Wen's MacBook Pro
* 命名空间Sln.Imm.Daemon.Opc.Impl
* 唯一标识3143E6AC-55C1-46DA-BDF8-8A19682A8A26
*
* 创建者WenJY
* 电子邮箱:
* 创建时间2025-09-22 17:25:33
* 版本V1.0.0
* 描述:
*
*--------------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using Sln.Imm.Daemon.Model.dto;
using TitaniumAS.Opc.Client;
using TitaniumAS.Opc.Client.Common;
using TitaniumAS.Opc.Client.Da;
using TitaniumAS.Opc.Client.Da.Browsing;
namespace Sln.Imm.Daemon.Opc.Impl;
public class OpcDaService : IOpcService, IDisposable
{
private OpcDaServer _server;
private bool _disposed = false;
public OpcDaService()
{
// 初始化 TitaniumAS.Opc.Client 库
Bootstrap.Initialize();
}
public async Task<bool> ConnectAsync(string serverUrl)
{
try
{
// 构建服务器URL
Uri url = UrlBuilder.Build(serverUrl);
// 创建服务器实例并连接
_server = new OpcDaServer(url);
_server.Connect();
return _server.IsConnected;
}
catch (Exception ex)
{
Console.WriteLine($"连接到 OPC DA 服务器失败: {ex.Message}");
return false;
}
}
public async Task DisconnectAsync()
{
if (_server != null && _server.IsConnected)
{
_server.Disconnect();
_server.Dispose();
_server = null;
}
}
public async Task<List<OpcNode>> ReadNodeAsync(List<string> nodeId)
{
if (_server == null || !_server.IsConnected)
throw new Exception("未连接到 OPC DA 服务器");
try
{
// 创建临时组和项进行读取
using (var group = _server.AddGroup("TempReadGroup"))
{
group.IsActive = true;
OpcDaItemDefinition[] definitions = new OpcDaItemDefinition[nodeId.Count];
for (int i = 0; i < nodeId.Count; i++)
{
var definition = new OpcDaItemDefinition
{
ItemId = nodeId[i],
IsActive = true
};
definitions[i] = definition;
}
// 添加要读取的项
var results = group.AddItems(definitions);
if (results[0].Error.Failed)
throw new Exception($"添加项失败: {results[0].Error}");
// 读取项值
var values = await group.ReadAsync(group.Items);
if (values[0].Error.Failed)
throw new Exception($"读取失败: {values[0].Error}");
var indexedNodeIds = nodeId.Select((value, index) => new { Index = index, Value = value });
List<OpcNode> result = new List<OpcNode>();
foreach (var item in indexedNodeIds)
{
var dataValue = values[item.Index];
result.Add(new OpcNode()
{
NodeId = item.Value,
DisplayName = item.Value,
Value = dataValue.Value,
SourceTimestamp = dataValue.Timestamp,
DataType = values[0].Value?.GetType().Name ?? "Unknown"
});
}
return result;
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"OPC DA 读取节点时出错:{ex.Message}");
}
}
public async Task WriteNodeAsync(string nodeId, object value)
{
if (_server == null || !_server.IsConnected)
throw new Exception("未连接到 OPC DA 服务器");
try
{
// 创建临时组和项进行写入
using (var group = _server.AddGroup("TempWriteGroup"))
{
group.IsActive = true;
// 添加要写入的项
var definition = new OpcDaItemDefinition
{
ItemId = nodeId,
IsActive = true
};
var results = group.AddItems(new[] { definition });
if (results[0].Error.Failed)
throw new Exception($"添加项失败: {results[0].Error}");
// 写入值
var item = results[0].Item;
var writeResult = await group.WriteAsync(new[] { item }, new[] { value });
if (writeResult[0].Failed)
throw new Exception($"写入失败: {writeResult[0]}");
}
}
catch (Exception ex)
{
Console.WriteLine($"写入节点时出错: {ex.Message}");
throw;
}
}
public async Task<List<OpcNode>> BrowseNodesAsync(string startingNodeId = null)
{
if (_server == null || !_server.IsConnected)
throw new Exception("未连接到 OPC DA 服务器");
var nodes = new List<OpcNode>();
try
{
// 使用浏览功能浏览服务器地址空间
var browser = new OpcDaBrowserAuto(_server);
var elements = browser.GetElements(startingNodeId);
foreach (var element in elements)
{
nodes.Add(new OpcNode
{
NodeId = element.ItemId,
DisplayName = element.Name,
DataType = "Unknown" // OPC DA 浏览不直接提供数据类型
});
// 如果元素有子元素,递归浏览
if (element.HasChildren)
{
var childNodes = await BrowseNodesAsync(element.ItemId);
nodes.AddRange(childNodes);
}
}
return nodes;
}
catch (Exception ex)
{
Console.WriteLine($"浏览节点时出错: {ex.Message}");
throw;
}
}
public void Dispose()
{
if (!_disposed)
{
DisconnectAsync().Wait();
_disposed = true;
}
}
}